Social media · Live on Apify

Hacker News Stories and Comments Scraper

Export Hacker News stories and comments as rows. Each comment keeps its parent ID, so you can rebuild the thread. No API key is needed.

About $0.32 for 1,000 stories and comments$0.00027 per story or comment + $0.05 per run. Apify bills you, not us.One story or comment in a run of its own: about $0.05.Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Run it on Apify Opens apify.com, the website where our tools run. Sign up free with Google or email, no card needed.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure

How to use it: 3 steps

  1. Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
  2. Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example: [] in Exact item IDs. Each start is one run.
  3. Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.

What it does

Export Hacker News stories and comments as rows with stable IDs and parent links. Choose Top, New, Best, Ask HN, Show HN or Jobs, or add exact item IDs. No Hacker News API key is needed.

Who uses it

Startup founders

Read the feedback on your Show HN post in one table.

Tech researchers

Build a dataset of public tech discussions.

Recruiters

Export current Hacker News job posts.

Price

Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.

What you pay forPriceWhen
Start fee$0.05Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more.
Useful HN entity saved$0.00027One live story, job or comment saved to the Dataset. Deleted, dead, unavailable and error rows have no entity fee.

Examples

  • One story or comment: about $0.05.
  • 1,000 stories and comments: about $0.32.
  • Every day 100 stories and comments, for 30 days: about $2.31 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 15,000 stories and comments.

Prices checked on 24 October 2026. See the current price on Apify.

Questions

Does it get every comment of a big thread?

Not always. There are caps per root and per run. The tree status tells you if a tree is complete.

Does it open the linked article?

No. You get the link from Hacker News, not the article text.

Which lists can I use?

Top, New, Best, Ask HN, Show HN and Jobs.

Do I need an API key?

No HN API key, cookie or login is needed. You need your Apify account to run the Actor. API clients use an Apify token in an authorization header, never in this Actor's input.

Does it return every comment?

Only when every reachable child is observed within the caps and treeStatus is complete. The new form intentionally uses small limits. Check the summary for each root. descendants is the source count, not a completeness check.

Why are HTML and plain text different?

textHtml keeps the source. text removes tags, adds block boundaries and decodes entities once. < becomes <, not an HTML tag. Deleted items can have neither value.

What do deleted, dead and null mean?

Deleted and dead are source flags. A null response means the item was unavailable at fetch time. It does not prove why. These observations are kept; they are not silently dropped and do not have an entity fee.

Why is there a start fee?

The scan still makes requests and saves a summary when there are no useful entities. The start fee covers this bounded work. Each fresh run has its own start fee.

Is it a replacement for another HN scraper?

Use a field mapping before switching. This Actor uses numeric IDs, url for the external link and hnUrl for HN. Comments are flat rows with stable IDs, not nested message arrays.

Details

Step by step on Apify
  1. Open Input in Apify Console.
  2. Keep the new form as it is: Top stories, 3 roots, up to 5 comments per root and depth 2.
  3. Keep memory at 256 MB and timeout at 300 seconds. Set a maximum cost of $0.15 for this small example.
  4. Click Start.
  5. Open Dataset. Look for a story row and comment rows linked by rootId and parentId.
  6. Open Key-value store → RUN_SUMMARY. A current busy story can be partial because the example uses small caps.
Use cases
GoalInput choiceFields to use
Track current tech discussionstop, new or bestid, title, score, descendants, retrievedAt
Study project feedbackshow or exact itemIdsrootId, parentId, depth, text, treeStatus
Build a public discussion corpusExact IDs, bounded commentsid, textHtml, text, deleted, dead, summary
Export HN jobsjob, comments offtitle, url, author, createdAt
Tips for better results
  • Add exact item IDs to export one known discussion.
  • Check the tree status to see if a comment tree is complete.
  • Use the plain text field for AI tools and the HTML field for display.
Limits and good to know
  • At most 100 roots, 200 descendant observations per root, depth 10 and 1,000 total reserved nodes. A live Cloud export reached 1,000 observed nodes within the configured limits; this is a cap, not a guaranteed amount
  • Only the six official lists are supported. Lists can be smaller than maxStories and can include jobs. Their order can change while the run is active
  • Source work has a 90-second deadline, at most 1,300 HTTP attempts, concurrency 4, an 8-second request timeout, a 2 MiB response cap and an 8 MiB total response cap. Temporary transport, 429 and 5xx errors are retried up to three attempts within these caps
  • Set platform timeout to 300 seconds. A longer finite timeout also works but does not increase the 90-second source deadline. A smaller timeout reduces the source window to leave time for saved output
  • comment_cap, depth_cap, node_cap, request_cap, byte_cap, response_byte_cap, deadline and charge_cap show a limit. unavailable_child, missing_parent, parent_mismatch, unexpected_child_type and duplicate_or_cycle show an observed source/graph issue
  • treeStatus describes what was fetched. If the charge cap stops saving rows, use run-level status=partial to see that the export is incomplete
  • Original HTML is data. Do not render textHtml, titles or external URLs as trusted HTML in your own app. Use escaped text for display. The Dataset table displays plain text
  • Scores and comments are live. The API is not an atomic snapshot. Dead/deleted/null states may change after a run. A hard platform kill can prevent final KVS writes; rows already saved remain in the Dataset

Troubleshooting

SymptomLikely reasonCheckAction
partial treeA cap stopped childrenRoot treeReasons, source kids and run summaryRaise the relevant input cap within allowed values, then run again.
Only unavailable rowsHN returned null for the IDsid, status, notFoundCheck the HN item link or use a current list.
Fewer comments than descendantsCaps, dead/deleted items or a changing sourcecollectedComments, flags and tree reasonsKeep source count and collected count separate.
Run failed before source workInvalid input or unsupported resourcesreason, resourceErrorUse numeric IDs, known fields and 256 MB memory.
Source error rowsRequest failures or malformed source dataRow reason, failed, retriesRetry a small input. Do not treat this as no matching stories.
Export stopped at budgetNot enough budget for the next entitybilling.chargeLimitReachedCheck saved rows and raise the next run's cap if needed.

For developers

Sample result

One result from a real test run, in JSON. Real values change from run to run. Some values are changed for privacy. In Excel or CSV each field is a column.

one result · JSON
[
  {
    "entityType": "story",
    "id": 8863,
    "type": "story",
    "rootId": 8863,
    "storyId": 8863,
    "parentId": null,
    "depth": 0,
    "title": "My YC app: Dropbox - Throw away your USB drive",
    "hnUrl": "https://news.ycombinator.com/item?id=8863",
    "url": "http://www.getdropbox.com/u/2/screencast.html",
    "author": "example_user",
    "time": 1175714200,
    "score": 104,
    "descendants": 71,
    "status": "complete",
    "treeStatus": "complete",
    "collectedComments": 72
  },
  {
    "entityType": "comment",
    "id": 8917,
    "rootId": 8863,
    "storyId": 8863,
    "parentId": 8863,
    "depth": 1,
    "status": "complete"
  }
]

Use it from code

Actor ID: cliqtomedia/hacker-news-stories-comments-scraper. You need your Apify API token from Apify Console → Settings → API & Integrations.

Python · apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/hacker-news-stories-comments-scraper").call(run_input={
    "listMode": "top",
    "itemIds": []
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
cURL
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~hacker-news-stories-comments-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"listMode": "top", "itemIds": []}'
LangChain · langchain-apify
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/hacker-news-stories-comments-scraper")
result = tool.invoke({"run_input": {"listMode": "top", "itemIds": []}})
print(result)

The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.

Data fields (26)
FieldType
entityTypestring
idinteger
typestring
statusstring
reasonstring
rootIdinteger
storyIdinteger
parentIdinteger
depthinteger
titlestring
hnUrlstring
urlstring
authorstring
timeinteger
createdAtstring
scoreinteger
descendantsinteger
kidsarray
textHtmlstring
textstring
deletedboolean
deadboolean
retrievedAtstring
treeStatusstring
treeReasonsarray
collectedCommentsinteger
Input settings (7)

The main fields of the input form. With the API you send them as JSON.

SettingName in the APITypeExample value
HN listlistModestring"top"
Exact item IDsitemIdsarray[]
Maximum root itemsmaxStoriesinteger3
Include comment treeincludeCommentsbooleantrue
Maximum comments per rootmaxCommentsPerStoryinteger5
Maximum reply depthmaxDepthinteger2
Maximum nodes in the runmaxNodesinteger30

Use cases with this tool

Each guide shows all the steps and the other tools.

Start on Apify

Make a free Apify account: you get $5 of free usage every month. Missing a tool? Suggest it. We read every idea, but we do not promise to build it.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure