# Hacker News Jobs Scraper | Who Is Hiring Threads (`tqm/hackernews-job-scraper`) Actor

Turn Hacker News 'Ask HN: Who is hiring?' threads into structured job data - one row per posting, with company, location, remote flag, salary, detected skills and a link to the original comment. Up to 12 months in one run. Direct-from-company postings that never reach a job board.

- **URL**: https://apify.com/tqm/hackernews-job-scraper.md
- **Developed by:** [TQM](https://apify.com/tqm) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Hacker News Jobs Scraper collects job postings from Hacker News' monthly **"Ask HN: Who is hiring?"** threads — one of the highest-signal hiring sources on the internet, and one of the least structured.

It turns those free-text comment threads into structured records: company, location, remote flag, salary, detected skills and a link to the original comment.

### What data do I get?

**One dataset item is one job posting.** Thread details are carried on every row, so a single row
tells you everything without a join.

| Field | Description |
|---|---|
| `company` | Hiring company, parsed from the comment |
| `location` | Location as stated |
| `remote` | Whether the posting signals remote work |
| `salary` | Compensation as written — Hacker News has no salary field, so the format varies |
| `description` | The full posting text |
| `skills` | Technologies detected in the text |
| `commentUrl` | Link to the original Hacker News comment |
| `commentId` | Hacker News' own comment id — a stable deduplication key across runs |
| `depth` / `parentCommentId` | 0 is a job post; higher values are replies, returned only if you ask for them |
| `threadId` / `threadTitle` / `threadUrl` / `threadDate` | Which monthly thread this posting came from |
| `threadTotalComments` | How large that thread was, as context |
| `scrapedAt` | When this run collected the row |

> **`company`, `location` and `salary` are parsed from free text, not read from fields.** Hacker News
> has no structured job form — a posting is whatever the poster typed. Most follow the community's
> `Company | Role | Location` convention and parse cleanly (`company` is populated on roughly 95% of
> rows); the ones that do not will show a wrong or missing value. `description` always holds the
> complete original comment, so anything the parser missed is still there for you to read.

### How do I use it?

1. Click **Try for free**.
2. Set `monthsToScrape` — `3` covers the last three monthly threads.
3. Click **Save & Start**.
4. Export as JSON, CSV, Excel or XML from the **Storage** tab.

#### Input sample

```json
{
  "monthsToScrape": 6,
  "techStackFilter": ["rust", "kubernetes"],
  "remoteOnly": true,
  "includeReplies": false,
  "maxItems": 500
}
```

### Input reference

| Option | Type | Default | What it does |
|---|---|---|---|
| `monthsToScrape` | integer | `3` | How many past monthly threads to read, up to **12**. |
| `techStackFilter` | array | *(none)* | Keep only job **posts** (not replies) mentioning these technologies. |
| `remoteOnly` | boolean | `false` | Keep only postings that mention remote or distributed work. |
| `includeReplies` | boolean | `false` | Also return the discussion replies under job posts. A reply is a comment, not a vacancy, and one row is one result — so this is off by default. |
| `maxItems` | integer | `1000` | Hard cap on postings returned across every thread. The run stops when it is reached. |

### How many jobs can I get?

A busy "Who is hiring?" thread carries **200+ postings**, and there is one thread per month. `monthsToScrape: 12` therefore reaches roughly a year of hiring activity — a few thousand rows — in a single run.

Because one row is one posting, that number is also your bill, which is why `maxItems` defaults to **1000** rather than being unbounded. Raise it deliberately; the run tells you in its log when it stopped at the cap.

Because it is free text written by hundreds of different people, **parsing is best-effort**. `company` and `location` are extracted where the poster followed the thread's loose convention; `description` always holds the complete original comment, so anything the parser missed is still there to re-parse for your own fields.

### Who is this for?

- **Job seekers** who want the whole thread as a filterable spreadsheet instead of scrolling hundreds of comments.
- **Recruiters and market researchers** tracking which technologies and locations appear month over month — this is one of the few datasets where you can watch the same question asked every month for years.
- **Lead generation** — companies posting here are hiring engineers directly, usually without a recruiter.

### FAQ

#### Do I need a Hacker News account?

No. Everything read here is public, and there is no login or account to be banned.

#### Why is the data less clean than a job board?

Because Hacker News is not a job board. "Who is hiring?" is a comment thread with a loose convention, not a structured form, so parsed fields are best-effort by nature. That is also why the source is valuable: these are direct-from-company postings that never reach a job board.

#### Will I get blocked?

Very unlikely. The actor reads public content through Hacker News' own search index rather than hammering the site.

#### Is it legal to scrape Hacker News?

This actor reads public comments and extracts no private user data. Results can contain personal data — posters often include their own name or email. You should not scrape or store personal data without a legitimate reason; if unsure, consult your lawyers. See Apify's background on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Can I export to Excel or Google Sheets?

Yes — JSON, CSV, XML and Excel from the **Storage** tab. Rows are flat, one posting each, so a CSV export is directly usable in a spreadsheet.

### Integrations and API

Trigger runs and collect results via the [Apify API](https://docs.apify.com/api/v2), the JavaScript or Python client, or Apify's integrations — **Zapier, Make, Slack, Google Drive, GitHub and webhooks**. A monthly schedule timed to the first of the month picks up each new thread as it appears.

### Support

Parser missed something it should have caught? Open an issue on this actor's **Issues** tab and include the row's `commentUrl` — that is exactly what makes a parser fix possible.

# Actor input Schema

## `monthsToScrape` (type: `integer`):

How many past monthly 'Who is hiring?' threads to scrape, counting back from this month. Each thread commonly holds 200+ postings, and one posting is one result, so this is the main driver of how many rows - and how much - a run produces. Pair it with Max results.

## `techStackFilter` (type: `array`):

Keep only job posts mentioning at least one of these technologies, matched against the skills detected in the comment text. Applied to top-level job posts, not to replies. Leave empty to keep everything.

## `remoteOnly` (type: `boolean`):

Keep only postings whose text signals remote or distributed work.

## `includeReplies` (type: `boolean`):

Also return the discussion replies underneath each job post. Off by default: a reply is a comment, not a vacancy, and one row is one result - so leaving this on means paying for conversation. Turn it on if you are studying the threads rather than the jobs.

## `maxItems` (type: `integer`):

Hard cap on how many job postings the run returns in total, across every thread. The run stops as soon as it is reached. A 'Who is hiring?' thread commonly holds 200+ postings, so a 12-month run without a cap is a few thousand rows.

## Actor input object example

```json
{
  "monthsToScrape": 3,
  "techStackFilter": [],
  "remoteOnly": false,
  "includeReplies": false,
  "maxItems": 1000
}
```

# Actor output Schema

## `results` (type: `string`):

Every job posting this run returned, one row per posting, extracted from the monthly 'Ask HN: Who is hiring?' threads.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("tqm/hackernews-job-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("tqm/hackernews-job-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call tqm/hackernews-job-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tqm/hackernews-job-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/k85LtnYwowODF5iym/builds/YspluMxPrdQmw8RNe/openapi.json
