Start free

How to scrape Hacker News

Scrape Hacker News front-page stories into typed JSON: title, points, author, comment count, submission URL and submission time. No CSS selectors.

Site:
news.ycombinator.com
Difficulty:
Easy
Rendering:
Static HTML
Anti-bot:
none

What you can extract from Hacker News

These are the fields teams most often pull from news.ycombinator.com, and why a hand-written selector for each one tends to break over time.

Field Type Why selectors break
title string The headline lives in a span.titleline > a, but HN reuses the same .titleline markup for stories, Ask HN text posts, and job listings, so a selector tuned to one row shape silently grabs the wrong anchor or the trailing (domain) sitelink span on others.
points number Points sit in span.score with an id like score_38123456 and text such as '190 points', but job posts and brand-new submissions render no .score node at all, so a positional selector either throws or shifts every later field up by one when the element is absent.
author string The author is an a.hnuser inside the .subtext row, yet that same subtext also contains 'hide', 'past' and 'discuss' anchors, so an index-based or generic 'a' selector frequently returns a navigation link instead of the actual username for job and dead posts.
comment_count number Comment count is the last anchor in .subtext, but its text varies between '80 comments', 'discuss' (zero comments) and is simply missing on job posts, so a selector expecting a number breaks on the words and on absent nodes across the same listing.
submission_url string The outbound link is the href of span.titleline > a, but for Ask HN and text submissions that href is a relative item?id= link rather than an external URL, so a selector assuming an absolute http(s) target captures an on-site path and conflates self-posts with link posts.
submission_time string Time is rendered as relative text ('3 hours ago') inside span.age, with the absolute timestamp hidden only in the title attribute, so a selector reading the visible text yields a value that drifts every minute and is unparseable without resolving the attribute.

The schema-first approach

Instead of maintaining selectors, you hand Extracto a JSON schema describing the shape you want. Here is a schema that works for Hacker News:

{
  "title": "string",
  "points": "number",
  "author": "string",
  "comment_count": "number",
  "submission_url": "string",
  "submission_time": "string"
}
  1. 1

    Describe the Hacker News fields you want

    Write a small JSON schema listing the fields to pull from news.ycombinator.com (for example title, points, author). No CSS selectors or XPath needed.

  2. 2

    Send the URL and schema to Extracto

    POST the Hacker News page URL and your schema to the Extracto API. Extracto renders the page in a real browser, handling the HTML automatically.

  3. 3

    Get schema-validated JSON back

    Extracto returns JSON that matches your schema exactly, validated before it leaves the API, so your pipeline never receives broken or partial data.

Common pitfalls when scraping Hacker News

Is it legal to scrape Hacker News?

Hacker News is operated by Y Combinator and served from news.ycombinator.com as plain server-rendered HTML. Its robots.txt allows crawling of listing and item pages but disallows interaction endpoints such as /vote, /reply, /submitlink, /login, /hide, /fave, /flag and /x, and it publishes a Crawl-delay of 30 seconds, so automated reads of the same path should be spaced accordingly and kept to a modest volume. The HN Guidelines and Y Combinator's terms govern acceptable use; scraping public listings for research or personal tooling is generally tolerated, but reselling bulk content or hammering the site is not. Note that Y Combinator also offers an official, free Firebase API (hacker-news.firebaseio.com) and an Algolia-powered search API (hn.algolia.com), which are the documented, ToS-friendly way to pull HN data at scale. Use Extracto for HTML-shaped reads of the live front page; prefer those official APIs for high-volume historical pulls, and always honor robots.txt and the 30-second crawl delay.

Extracto follows robots.txt by default and rate-limits politely. You are responsible for compliance with Hacker News's terms and applicable law (GDPR, CCPA) in your use case.

Scraping Hacker News: FAQ

Should I scrape Hacker News HTML or use the official API?
For high-volume or historical work, prefer Y Combinator's official, free endpoints: the Firebase API at hacker-news.firebaseio.com for item and list data, and the Algolia search API at hn.algolia.com for full-text queries. Those are documented and ToS-friendly. Use Extracto when you specifically want the live front-page ordering rendered as HTML, mapped straight into typed JSON without writing selectors or merging multiple API calls per story.
How do I get points and comment counts when some rows do not have them?
Define points and comment_count as numbers in your JSON schema and let Extracto fill them from each row's .score and .subtext markup. Job posts and brand-new submissions legitimately have no score or comment node, so those fields come back as null rather than a fabricated zero or a value copied from an adjacent story. That null-not-guess behavior is exactly what keeps a mixed front page from silently corrupting your dataset.
Does Hacker News use Cloudflare or other anti-bot protection?
No. As of 2026 news.ycombinator.com serves lightweight, static, server-rendered HTML with no JavaScript rendering requirement and no Cloudflare, DataDome or PerimeterX challenge on its listing pages, which is why this target is rated easy. Extracto still routes every request through its managed rendering and proxy infrastructure, so you do not configure anything, but the page itself imposes no special handling beyond honoring the 30-second crawl delay.
How do I scrape more than the first 30 stories?
The front page shows about 30 items, then a 'More' link to ?p=2, ?p=3 and beyond. Each numbered page is a single URL you pass to Extracto with the same schema, so you collect additional stories by iterating the page parameter. Keep at least 30 seconds between requests to the same listing per the robots.txt Crawl-delay, and keep total volume modest so your reads stay within polite, terms-respecting use.