# Hacker News Scraper - Who Is Hiring Jobs & Stories API (`teddythebuilder/hacker-news-scraper`) Actor

Scrape Hacker News: the monthly 'Who is hiring?' thread as structured jobs (company, role, location, remote, salary, visa, apply link, ATS) and HN stories by keyword with points and comments. Official HN API, no login. Export JSON/CSV or call via API/MCP.

- **URL**: https://apify.com/teddythebuilder/hacker-news-scraper.md
- **Developed by:** [Teddy Wasserman](https://apify.com/teddythebuilder) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.10 / 1,000 job post returneds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Hacker News Scraper do?

**Hacker News Scraper** turns the monthly **"Ask HN: Who is hiring?"** thread into a clean jobs dataset and searches **Hacker News stories** by keyword. Each job post becomes one structured row with the company, roles, locations, remote/onsite/hybrid flags, parsed salary range and currency, visa sponsorship, apply link and the applicant tracking system (Greenhouse, Lever, Ashby, Workable and more) behind it. Stories come with points, comment counts, links and dates.

Use it as a **Hacker News jobs API**, a **Who is hiring scraper** for startup job boards and recruiting pipelines, or a **Hacker News search API** for brand and topic monitoring. It reads the official HN Search API (by Algolia), needs no login and no API key, and the default run returns 20 parsed job posts from the latest thread in about 5 seconds.

### Why use Hacker News Scraper?

- **Structured jobs, not raw comments.** Most HN scrapers give you a blob of HTML per comment. This actor parses the conventional `Company | Role | Location | REMOTE | Salary` header into separate fields, so you can filter and sort straight away.
- **Salary, remote and visa filters built in.** Ask for "remote Rust jobs with a stated salary that sponsor visas" and get exactly that.
- **Find the hiring company's job board.** When a post links to Greenhouse, Lever, Ashby, Workable, Recruitee, Teamtailor, SmartRecruiters, Work at a Startup or Wellfound, you get the provider and board slug. Feed it to our [Career Site Jobs API](https://apify.com/teddythebuilder/career-site-jobs-api) to pull every open role at that company, not just the ones mentioned on HN.
- **Monitor mode.** Turn on `onlyNew` and schedule the actor daily: each run returns only posts or stories you haven't seen yet. Already-seen items are free.
- **Full history.** The "Who is hiring?" threads go back to 2011. Pick any months for a hiring-trend dataset.
- **Official source, stable schema.** Data comes from the public HN Search API by Algolia. No browser, no proxy, no login, so runs are fast, cheap and reliable.
- **Privacy-aware.** No HN usernames are returned. Personal e-mail addresses and phone numbers inside posts are replaced with `[email]` / `[phone]`; role mailboxes such as `jobs@` or `careers@` are kept as `contactEmail`.

### What data can you extract?

#### Who is hiring? job posts (one row per post)

| Field | Example | Description |
|---|---|---|
| `company` | `River` | Company name from the post header |
| `companyNote` | `Series B` | Text in brackets after the name (funding stage, YC batch, location note) |
| `ycBatch` | `S24` | Y Combinator batch when the post mentions one |
| `roles` | `["Staff Engineers (Elixir)"]` | Role segments from the header |
| `locations` | `["NYC US, Europe, South America"]` | Location segments (city, country, region or time zone) |
| `techStack` | `["TypeScript / Postgres / React"]` | Tech-stack segments when the header lists them |
| `remote` / `onsite` / `hybrid` | `true` / `false` / `false` | Work arrangement flags from the header |
| `employmentType` | `["full-time"]` | full-time, part-time, contract, internship |
| `visaSponsorship` | `true` | `true` if the post offers sponsorship, `false` if it rules it out, `null` if it doesn't say |
| `salaryText` | `$200K-$250K + equity` | The salary as written |
| `salaryMin` / `salaryMax` / `salaryCurrency` | `200000` / `250000` / `USD` | Parsed annual range and currency |
| `applyUrl` | `https://jobs.ashbyhq.com/river` | Best apply link (ATS board first, then careers/jobs pages) |
| `companyUrl` | `https://www.prairielearn.com` | Company website |
| `atsProvider` / `atsSlug` | `ashby` / `river` | Applicant tracking system and board slug |
| `careerSiteJobsApiCompany` | `ashby:river` | Ready-made input for Career Site Jobs API |
| `contactEmail` | `jobs@example.com` | Role mailbox from the post (personal addresses are never returned) |
| `urls` | `[...]` | All links in the post |
| `headline` | `River \| Staff Engineers (Elixir) \| ...` | The header line as posted |
| `text` | `...` | Full post as plain text (optional, redacted) |
| `postedAt` | `2026-10-01T15:30:44Z` | When the post was written |
| `hnUrl` / `hnItemId` | `https://news.ycombinator.com/item?id=49923010` | Link to the post on HN |
| `threadTitle` / `threadMonth` | `Ask HN: Who is hiring? (October 2026)` / `2026-10` | Source thread |
| `replies` | `1` | Number of direct replies |
| `matchedKeywords` | `["rust"]` | Which of your keywords matched |

#### Stories (one row per story)

| Field | Example | Description |
|---|---|---|
| `title` | `My Reddit AMA on the Law of Web Scraping` | Story title |
| `url` / `domain` | `https://...` / `example.com` | Linked article and its domain |
| `points` / `comments` | `113` / `48` | Score and number of comments |
| `storyType` | `story`, `ask_hn`, `show_hn` | Kind of item |
| `postedAt` | `2026-10-12T18:02:32Z` | Submission time |
| `storyText` | `...` | Body of Ask HN / Show HN posts (redacted) |
| `onFrontPage` | `true` | Whether the item is on the front page now |
| `query` | `web scraping` | The search query that found it |
| `hnUrl` / `hnItemId` | `https://news.ycombinator.com/item?id=...` | Discussion link |

### How to use Hacker News Scraper (step by step)

1. Click **Try for free** (or **Start**) on this page. The default input returns 20 job posts from the latest "Who is hiring?" thread.
2. Choose **What to scrape**: *Who is hiring? job posts*, *Stories*, or *Both*.
3. For jobs, add **Job keywords** such as `python` or `machine learning`, and tick **Remote jobs only**, **Visa sponsorship only** or **With salary only** as needed. Add **Months** (e.g. `2026-09`) for past threads.
4. For stories, add **Story search queries** (your brand, a competitor, a technology) and optionally a **Minimum points** or **Published within (days)** filter. Choose *Current front page* to get today's front page without a query.
5. Set **Max results** and click **Start**. Download the dataset as JSON, CSV, Excel or HTML, or open the *Who is hiring? jobs* / *Stories* table views.
6. For monitoring, turn on **Only new items since the last run**, give the monitor a **Watch name**, and add a daily schedule in Apify Console.

### Input example

```json
{
  "mode": "whoIsHiring",
  "keywords": ["python", "rust"],
  "remoteOnly": true,
  "withSalaryOnly": true,
  "months": ["2026-10", "2026-09"],
  "maxResults": 200
}
```

Stories example (brand monitoring, newest first, only new mentions each day):

```json
{
  "mode": "stories",
  "searchQueries": ["apify", "web scraping"],
  "minPoints": 10,
  "sortBy": "date",
  "onlyNew": true,
  "watchName": "brand-mentions",
  "maxResults": 100
}
```

### Output example

```json
[
  {
    "type": "job-post",
    "company": "River",
    "roles": ["Staff Engineers (Elixir)"],
    "locations": ["NYC US, Europe, South America"],
    "remote": true,
    "onsite": false,
    "hybrid": false,
    "employmentType": ["full-time"],
    "visaSponsorship": null,
    "salaryText": "$200K-$250K + equity",
    "salaryCurrency": "USD",
    "salaryMin": 200000,
    "salaryMax": 250000,
    "applyUrl": "https://jobs.ashbyhq.com/river?utm_source=Zp9nJyqvd4",
    "atsProvider": "ashby",
    "atsSlug": "river",
    "careerSiteJobsApiCompany": "ashby:river",
    "headline": "River | Staff Engineers (Elixir) | NYC or REMOTE (US, Europe, South America) | Full-Time | $200K-$250K + equity | https://jobs.ashbyhq.com/river?utm_source=Zp9nJyqvd4",
    "postedAt": "2026-10-01T15:30:44.000Z",
    "hnUrl": "https://news.ycombinator.com/item?id=49923010",
    "threadTitle": "Ask HN: Who is hiring? (October 2026)",
    "threadMonth": "2026-10"
  },
  {
    "type": "story",
    "storyType": "story",
    "query": "web scraping",
    "title": "My Reddit AMA on the Law of Web Scraping",
    "points": 113,
    "postedAt": "2026-10-12T18:02:32Z",
    "hnUrl": "https://news.ycombinator.com/item?id=...",
    "onFrontPage": false
  }
]
```

Every run also writes free `_info` rows when nothing matched (for example "No new job posts since the last run"), so a scheduled run never ends with an empty dataset. You can export the dataset to CSV, Excel, JSON, XML or HTML, or read it through the Apify API.

### How much does it cost?

Hacker News Scraper uses pay-per-event pricing: you pay only for rows you get.

| Event | Price (Free plan) | When it is charged |
|---|---|---|
| Actor start | $0.0005 | Once per run |
| Job post returned | $0.002 ($2 per 1,000) | One parsed "Who is hiring?" post |
| Story returned | $0.001 ($1 per 1,000) | One story or front-page item |

Info rows, errors and already-seen items in monitor mode are **free**. Paid Apify plans get Store discounts on the per-row prices (Bronze −15%, Silver −30%, Gold and up −45%).

Worked examples (Free plan prices):

- **A whole monthly thread** (about 270 job posts in October 2026): 270 × $0.002 + $0.0005 ≈ **$0.54**.
- **A daily monitor of new posts** with `onlyNew` (about 10 new posts a day after the first days of the month): ≈ $0.02 per day, **about $0.60 per month**.
- **Twelve months of history** for a hiring-trend analysis (about 3,500 posts): ≈ **$7**.
- **A daily brand-mention check** across 3 queries returning 5 new stories a day: ≈ $0.005 per day, **about $0.15 per month**.

The Apify Free plan includes monthly platform credit, which covers many runs like these.

### Use cases

- **Job seekers:** get every remote Rust, Go or ML role with a stated salary from this month's thread in one spreadsheet, and track new posts daily.
- **Recruiters and talent sourcers:** see which startups are hiring for which roles, where and at what pay, and link straight to their ATS board.
- **Sales and lead generation:** companies that post on "Who is hiring?" are funded and growing. Use the company, website and ATS slug as warm leads for developer tools, recruiting services or B2B SaaS.
- **Market and salary research:** compare salary ranges, remote share and visa sponsorship across months and years, from 2011 onwards.
- **Developer relations and marketing:** monitor HN for mentions of your product, competitors or technology, with points and comments to spot what is taking off.
- **AI agents and newsletters:** feed today's front page or a topic search into a summarizer or a weekly digest.

### Use with AI agents, MCP and the API

Start a run and get the results with one call (replace `YOUR_TOKEN`):

```bash
curl -X POST "https://api.apify.com/v2/acts/teddythebuilder~hacker-news-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "whoIsHiring", "keywords": ["python"], "remoteOnly": true, "maxResults": 50}'
```

Python with the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("teddythebuilder/hacker-news-scraper").call(
    run_input={"mode": "whoIsHiring", "keywords": ["rust"], "withSalaryOnly": True, "maxResults": 100}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job.get("company"), job.get("salaryMin"), job.get("applyUrl"))
```

AI agents can find and call this actor through the Apify MCP server (`search-actors`, then `call-actor`). The small default input, flat JSON output and $0.0005 start fee keep agent probe calls cheap.

### Integrations

Connect the dataset to **Google Sheets**, **Airtable**, **Slack**, **Make**, **Zapier**, **n8n** or any webhook through Apify integrations. A typical setup is a daily schedule with `onlyNew` turned on and a Slack or e-mail notification for each new matching job post.

### Data source and legality

All data comes from the public **[HN Search API by Algolia](https://hn.algolia.com/api)**, the official search backend that Hacker News links to, which is free to use without a key. The actor requests one thread or search page at a time and respects the API's rate limits.

The actor returns job and story metadata that companies and submitters published publicly on Hacker News. It does **not** return HN usernames, and it redacts personal e-mail addresses and phone numbers in post texts. "Who wants to be hired?" threads, where individuals post about themselves, are deliberately not supported. You are responsible for using the data in line with applicable laws (such as GDPR) and the terms of the sites you contact.

### FAQ

**How many job posts does a "Who is hiring?" thread have?**
Usually 250 to 700 top-level posts. October 2026 had about 270. Replies to posts are not returned as separate rows; the `replies` field shows how many there are.

**How accurate is the parsing?**
Most posts follow the `Company | Role | Location | REMOTE | Salary` convention, and those parse well: in October 2026, 265 of 266 posts had a company, 141 were flagged remote, 67 had a parsed salary range and 47 linked an ATS board. Free-form posts still get a company, links and the full text. The original `headline` and `text` are always included so you can check any row.

**Can I get older threads?**
Yes. Add months such as `2024-01` or `January 2024` to **Months**. The threads go back to April 2011.

**How does monitor mode work?**
With **Only new items since the last run** on, the actor remembers the IDs it returned per **Watch name** in a key-value store in your account. The next run skips them and doesn't charge for them. Use different watch names for different searches.

**Why didn't my story search return anything?**
Search matches words in titles, URLs and story text without typo tolerance. Try a shorter query, remove the **Minimum points** filter, or switch **Sort stories by** to *Relevance*. A free `_info` row tells you when nothing matched.

**Does it work on the Apify Free plan?**
Yes. A full monthly thread costs about $0.54, well within the Free plan's monthly credit.

**Can you add a field or another source?**
Yes, please open an issue on the actor's Issues tab. If the actor saves you time, a rating on the Store page helps other users find it.

### Related actors

- [Career Site Jobs API - Greenhouse, Lever, Ashby & Workable](https://apify.com/teddythebuilder/career-site-jobs-api): all open roles from a company's job board. Use the `careerSiteJobsApiCompany` value from this actor as its input.
- [Tech Stack Detector](https://apify.com/teddythebuilder/tech-stack-detector): which technologies the hiring companies' websites use.
- [Domain WHOIS & DNS Lookup API](https://apify.com/teddythebuilder/domain-whois-dns-api): registration, DNS, mail and SSL data for company domains.
- [Swedish Jobs Scraper - Platsbanken](https://apify.com/teddythebuilder/swedish-jobs-monitor): all Swedish job ads from the official Arbetsförmedlingen API.

### Changelog and support

- **1.0 (October 2026):** first release. Who is hiring? parsing (company, roles, location, remote, salary, visa, ATS), story search and front page, monitor mode.

Found a bug or a post that parses badly? Open an issue with the HN link. We reply within 24 hours.

# Actor input Schema

## `mode` (type: `string`):

'Who is hiring?' returns one structured row per job post from the monthly HN hiring thread. 'Stories' searches HN stories by keyword (or returns the current front page).

## `keywords` (type: `array`):

Keep only job posts that mention at least one of these words, e.g. "python", "rust", "machine learning". Leave empty for all posts.

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

Keep only posts whose header says REMOTE.

## `locations` (type: `array`):

Keep only posts whose header mentions one of these places, e.g. "London", "Berlin", "EU", "NYC".

## `visaSponsorshipOnly` (type: `boolean`):

Keep only posts that offer visa sponsorship.

## `withSalaryOnly` (type: `boolean`):

Keep only posts that state a salary range (parsed into salaryMin / salaryMax).

## `excludeKeywords` (type: `array`):

Drop posts (and stories) that mention any of these words, e.g. "crypto", "onsite only".

## `months` (type: `array`):

Which monthly threads to read, e.g. "2026-10" or "September 2026". Empty = the latest thread. Add several months for a hiring history (threads go back to 2011).

## `includeFullText` (type: `boolean`):

Add the whole post as plain text (personal e-mail addresses are redacted). Turn off for smaller rows.

## `searchQueries` (type: `array`):

Keywords to search HN stories for, e.g. "web scraping", "your-brand.com". Used by the Stories mode.

## `storyType` (type: `string`):

Which kind of HN items to return.

## `minPoints` (type: `integer`):

Only stories with at least this many points, e.g. 50.

## `publishedWithinDays` (type: `integer`):

Only stories from the last N days. 0 = any time.

## `sortBy` (type: `string`):

Newest first suits monitoring; relevance suits research.

## `maxResults` (type: `integer`):

Maximum number of charged rows (job posts + stories) per run. A full monthly hiring thread has about 250-700 posts.

## `onlyNew` (type: `boolean`):

Monitor mode: skip job posts and stories already returned by an earlier run with the same watch name. Schedule the actor daily to get only new posts.

## `watchName` (type: `string`):

Separate seen-lists for different monitors, e.g. "rust-jobs" and "brand-mentions".

## Actor input object example

```json
{
  "mode": "whoIsHiring",
  "keywords": [
    "python"
  ],
  "remoteOnly": false,
  "visaSponsorshipOnly": false,
  "withSalaryOnly": false,
  "includeFullText": true,
  "searchQueries": [
    "apify"
  ],
  "storyType": "story",
  "minPoints": 0,
  "publishedWithinDays": 0,
  "sortBy": "date",
  "maxResults": 20,
  "onlyNew": false,
  "watchName": "default"
}
```

# Actor output Schema

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

No description

# 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 = {
    "mode": "whoIsHiring",
    "keywords": [
        "python"
    ],
    "searchQueries": [
        "apify"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("teddythebuilder/hacker-news-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 = {
    "mode": "whoIsHiring",
    "keywords": ["python"],
    "searchQueries": ["apify"],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("teddythebuilder/hacker-news-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 '{
  "mode": "whoIsHiring",
  "keywords": [
    "python"
  ],
  "searchQueries": [
    "apify"
  ],
  "maxResults": 20
}' |
apify call teddythebuilder/hacker-news-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,teddythebuilder/hacker-news-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/WaeT0MxihK11zhBln/builds/By0l3A49jWkcdCx7H/openapi.json
