Turn HN's "Who is hiring?" Thread Into a Spreadsheet With the Algolia API
Disclosure: I'm Ben, and I built the Apify Actor mentioned later in this post. I charge per result for it. Everything in the tutorial part works with free tools too.
On the first weekday of every month, the whoishiring account posts "Ask HN: Who is hiring?". Hundreds of companies reply with one top-level comment each. The October 2026 thread had 266 top-level posts when I counted on 25 Oct 2026. It's one of the best job sources for engineers, and it's a wall of text.
There's a loose convention for the first line of each post:
Company | Role | Location | ONSITE/REMOTE | Salary | ... That convention, plus two free official APIs, gets you most of the way to a spreadsheet.
The two APIs
- The official Hacker News API (Firebase):
hacker-news.firebaseio.com/v0/item/{id}.json. It's exact, but you have to walk the thread item by item. - HN Search by Algolia:
hn.algolia.com/api/v1/.... Full-text search over stories and comments, with tags such asstory_{id}andauthor_{name}, and up to 1,000 hits per page.
Algolia is the practical one for a whole thread.
Step 1: Fetch the thread's top-level posts
This ran as-is on 25 Oct 2026:
import requests A = "https://hn.algolia.com/api/v1" thread = requests.get(f"{A}/search_by_date", params={ "tags": "story,author_whoishiring", "query": "Who is hiring", "hitsPerPage": 1}).json()["hits"][0] tid = int(thread["objectID"]) print(thread["title"], tid) posts, page = [], 0 while True: r = requests.get(f"{A}/search_by_date", params={ "tags": f"comment,story_{tid}", "hitsPerPage": 1000, "page": page}).json() posts += [h for h in r["hits"] if h["parent_id"] == tid] # top-level only page += 1 if page >= r["nbPages"]: break print(len(posts), "top-level posts") first_line = posts[0]["comment_text"].split("<p>")[0] print([p.strip() for p in first_line.split("|")]) Output:
Ask HN: Who is hiring? (October 2026) 49922569 266 top-level posts ['Treat Health', 'Full-stack Engineer (Elixir, Phoenix LiveView, React)', 'Helsinki, Finland', 'ONSITE', 'Full-time', 'Compensation in the link below'] The trick is the filter: tags=comment,story_{id} returns every comment in the thread, including replies, so you keep only those whose parent_id is the thread itself.
Step 2: The pitfalls
- The convention is loose. I counted the October first lines on 25 Oct: 77 had 5 pipe-separated fields, 69 had 4, 60 had 6, 23 had 3, and 28 of 266 had no pipe at all. Extra fields ("Full-time", "Compensation in the link below") and missing ones are both normal, so you can't map fields by position alone.
- "Remote" is spread around. It can be its own field (
REMOTE,ONSITE) or buried in the location (Remote US or Ontario, Canada,REMOTE (Europe / US Eastern)). - Salary formats vary.
$100k-$180k,€75k–80k(with an en dash),$104K–$150K, or "compensation in the link". - HTML.
comment_textis HTML with<p>,<a>and escaped entities. Decode it before you parse, and keep the links. - Relevance search caps at 1,000 results on Algolia. For bigger searches, sort by date and walk back through time windows.
- Sibling threads. The same account posts "Who wants to be hired?" at the same time (IDs 49922568 and 49922569 in October), so match the title exactly.
Step 3: Or use the packaged version
I packaged the parser as an Apify Actor, Hacker News Scraper – Who Is Hiring, Search & Comments. In whoIsHiring mode it reads the latest (or last N) monthly threads and returns one row per post: company, roles, location, remote flag, salary text, visa mention, all URLs, author, timestamp, HN link and the full original text.
Run-ready link: open it in Apify Console with an example input already filled in ({"mode": "whoIsHiring", "keywords": ["engineer"], "maxItems": 50}). Click Start, or change the input first.
{ "mode": "whoIsHiring", "keywords": ["engineer"], "maxItems": 50 } A real run with that input on 17 Oct 2026 took about 6 seconds:
| Company | Roles | Location | Remote | Salary |
|---|---|---|---|---|
| PrairieLearn | Full-Stack Software Engineer | – | True | $100k-$180k |
| PAGNOS | Cloud Engineer, AWS Serverless (TypeScript/Node.js) | – | True | €75k–80k |
| Snout | Multiple Engineering + Product Roles | Remote US or Ontario, Canada | True | – |
| Planlab.ai | Product Engineer (Design) & Platform Engineer | ONSITE in London, UK | False | – |
| Checkly | Senior Product Engineer, Product Manager, … | REMOTE (Europe / US Eastern) | True | – |
Other modes use the same APIs: search (stories and comments with date, points, comments and author filters, walking date windows past the 1,000 cap), feed (top/new/best/ask/show/jobs) and items (specific IDs with full comment trees). I use search with lastDays: 7 for brand mentions.
Parsing accuracy, honestly
Of the 50 posts in that run, 37 had a parsed location, 31 had parsed roles and 25 had a parsed salary range. The misses are mostly posts that don't follow the pipe format, or that genuinely don't mention salary. Those fields come back null, and the raw text and links are always included, so nothing is lost. If you need perfect structure, run an LLM over the text field afterwards. The parser gets you a sortable sheet first.
Other limits
- Only what's posted on HN. It's a self-selected set of mostly startups. It isn't a job market sample.
- Timing. The thread is posted on the first weekday of the month and most posts seem to land early: October had 266 top-level posts both when I tested on 17 Oct and when I recounted on 25 Oct. A run on day 1 will see fewer.
- Visa is a mention flag, not a verified sponsorship policy.
- Not affiliated with Y Combinator, Hacker News or Algolia.
What it costs
$0.003 per result ($3 per 1,000), no start fee. The run stops at your "maximum cost per run". In my test, a run capped at $0.02 saved exactly 6 results. The 50-post run above was 15 cents. The script above is free, and honestly, for one month's thread it's all you need. The tool is for people who want the parser maintained, the filters and the other modes.
Play fair
People post in these threads to hire, not to be added to a sales sequence. Please don't mass-email the posters.
Which posts does a pipe parser get wrong for you? Paste an example (or the HN link) in the comments and I'll test it.