# Hacker News Who Is Hiring Jobs, Every Month (`usta/hn-who-is-hiring-jobs`) Actor

Startup jobs from each Hacker News who is hiring thread: company, role, location, remote, salary text, and apply link, one row per top-level post. Failed lookups are not dataset rows. Phrases: startup jobs, hacker news jobs, who is hiring.

- **URL**: https://apify.com/usta/hn-who-is-hiring-jobs.md
- **Developed by:** [US Tech Automations](https://apify.com/usta) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 result rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Hacker News Who Is Hiring Jobs, Every Month

This tool lists startup jobs from the Hacker News who is hiring thread, for people searching hacker news jobs.

Each month, Hacker News posts one "Ask HN: Who is hiring?" thread. The posts are free-text comments. This tool reads the official public item API and returns one row per top-level post: company, role, location, remote, salary text, and an apply link.

### Input

| Field | What it does |
|---|---|
| **Recent monthly threads** | How many of the newest Who is hiring threads to read. Default 1, maximum 36. "Who wants to be hired?" and freelancer threads are skipped. |
| **Thread ids** | Optional. One Hacker News story id per line. When this list is not empty, those threads are read and the month count is not used to search. |
| **Keyword filter** | Optional. Keeps a post only when this text appears in the post, the company, the role, or the location. Matching ignores letter case. |
| **Maximum rows** | Hard ceiling on job rows, and therefore on the cost of the run. Default 100, maximum 2000. |
| **Proxy configuration** | Optional Apify proxy. Off by default, including on a local run. |

### Pricing

**Pay per result. $0.004 per successful job row. No start fee.**

Every row in the results is one charged result. Failed inputs are not rows; they are listed in the run log and the RUN\_SUMMARY record, and cost nothing.

**Maximum rows** is the ceiling on how many job rows a run can return.

### Output (one row per top-level post)

One example row from a real local run on 2026-09-22. Input: 1 month, no keyword, maximum 3 rows. The run returned 3 rows. This is the first. The post text is shortened here. That run's row also had an error flag set to false. Result rows no longer include that flag, so it is left out below. The other fields are the ones from that run.

```json
{
  "thread_month": "September 2026",
  "post_id": 49523712,
  "post_url": "https://news.ycombinator.com/item?id=49523712",
  "posted_at": "2026-09-01T15:53:18Z",
  "company": "QUOBYTE",
  "role": "Berlin, Germany",
  "location": "Full-time",
  "remote": false,
  "salary_text": "60-100k EUR; 50-90k",
  "apply_url": "https://www.quobyte.com/",
  "full_text": "QUOBYTE | Berlin, Germany | Full-time | ONSITE (Germany) | https://www.quobyte.com/\nAt Quobyte we are working on a highly scalable and fault-tolerant software storage system built around a parallel file system core. Our customers use us for large scale AI and HPC clusters in the ...",
  "fetched_at": "2026-09-22T19:23:33Z"
}
```

That role is "Berlin, Germany" because the post's first bar-separated line is company, then city, then "Full-time". The tool does not move those fields into a different order.

| Field | What it holds |
|---|---|
| `thread_month` | The month written in the thread title, such as `September 2026`. Null if the title has no month in parentheses. |
| `post_id` | The comment's numeric id |
| `post_url` | `https://news.ycombinator.com/item?id=` plus that id. The HTML page is not downloaded. |
| `posted_at` | Comment time in UTC |
| `company` | Text before the first vertical bar on the first bar-separated line. Null if that line is missing. |
| `role` | The second slot on that line. Null if there is no second slot. |
| `location` | The third slot on that line. Null if there is no third slot. |
| `remote` | True, false, or null. True only when that same line says remote and does not also say onsite. False when it says onsite (or no remote) and does not also say remote. Null when it says both, or neither. |
| `salary_text` | A later slot on that line that states pay, or a pay phrase in the post such as `60-100k EUR`. Null when no pay phrase was found. |
| `apply_url` | The first `http` or `https` link that is not on `news.ycombinator.com`. Null if there is none. |
| `full_text` | The comment with HTML tags removed. Email addresses and phone numbers are replaced with `[contact removed]`. |

A thread that was missing, blocked, rate-limited, or not a Who is hiring thread is not in this table. The run log and the RUN\_SUMMARY record list that input and the reason. The dataset has no failure rows.

The poster's username is not a column.

### What this does not do

- It does not read "Who wants to be hired?" or freelancer threads.
- It does not read replies under a job post. Only top-level posts.
- It does not guess a company, role, or location when the first bar-separated line is missing or short. Those fields stay null.
- It does not rearrange slots. If a company puts the city in the role slot, the city stays in `role`.
- It does not choose the "best" apply link. You get the first link that is not a Hacker News link. A homepage that appears before a careers link wins.
- It does not log in, use cookies, or solve a CAPTCHA.
- It does not open `news.ycombinator.com` HTML.
- It does not output email addresses, phone numbers, or a username column.
- It does not grant a licence to republish the posts. The text belongs to the people who wrote it.

### Limits

- `months` is 1–36 (default 1). `maxItems` is 1–2000 (default 100).
- At most 36 thread ids.
- Deleted and dead posts are skipped, not turned into rows.
- A keyword that matches nothing returns no rows. That is not an error, and it does not invent posts.
- The official item API says there is currently no rate limit. This tool still waits briefly between requests. One local run's timing is in the local-run note. That timing is not a speed promise.
- A blocked, missing, or refused thread is not a result row. Other threads in the same run still run. The failure is in the run log and the RUN\_SUMMARY record.

### Refunds and support

Refunds: if a run returns zero rows for a valid input, email operations@ustechautomations.com within 7 days and we refund that run. Support: same address, replies within 2 business days.

# Actor input Schema

## `months` (type: `integer`):

How many of the newest Ask HN: Who is hiring? threads to read. Default 1, maximum 36. Ignored when thread ids are set. Who wants to be hired, and freelancer threads, are not included.

## `threadIds` (type: `array`):

Optional Hacker News story ids. When this list is not empty, those threads are read and months is not used to search. An id that is not an Ask HN: Who is hiring? story is listed in the run summary, not in the results.

## `keyword` (type: `string`):

Optional. Case-insensitive. A post is kept only when this text appears in the post, the company, the role, or the location. Leave empty to keep every top-level post up to the row cap.

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

Hard ceiling on job rows, and therefore on the cost of the run. Default 100, maximum 2000. A thread that cannot be read is not a result row and does not count toward this cap.

## `proxyConfiguration` (type: `object`):

Optional Apify proxy. Leave off for a local run. The Hacker News item API and the Algolia search are ordinary HTTPS GET requests.

## Actor input object example

```json
{
  "months": 1,
  "threadIds": [],
  "keyword": "",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `report` (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 = {
    "months": 1,
    "threadIds": [],
    "keyword": "",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("usta/hn-who-is-hiring-jobs").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 = {
    "months": 1,
    "threadIds": [],
    "keyword": "",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("usta/hn-who-is-hiring-jobs").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 '{
  "months": 1,
  "threadIds": [],
  "keyword": "",
  "maxItems": 100
}' |
apify call usta/hn-who-is-hiring-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,usta/hn-who-is-hiring-jobs"
        }
    }
}
```

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/vrEnwKf9vwhzGn5gQ/builds/brvRx74FEsacDMrPd/openapi.json
