# Hiring Intent Signals Scraper - B2B Buying Signals (`angaba92/hiring-intent-signals-scraper`) Actor

B2B buying signals and hiring signals: aggregates months of Hacker News hiring threads into one row per company with a 0-100 hiring intent score, trend, website domain, tech stack detection and role families. Lead generation and company enrichment for outbound, CRM and Clay.

- **URL**: https://apify.com/angaba92/hiring-intent-signals-scraper.md
- **Developed by:** [Andres Garcia-Baquero Leon](https://apify.com/angaba92) (community)
- **Categories:** Lead generation, Business, Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## HN Hiring Intent Signals - Company-Level B2B Buying Signals from Hacker News

Turn the monthly Hacker News **"Ask HN: Who is hiring?"** threads into a clean,
**company-level hiring-intent dataset** you can drop straight into a CRM, Clay
table, or outbound sequence.

The HN API gives you unstructured comments, one month at a time. This Actor
aggregates **several months**, resolves each company, and tells you *how* they
are hiring - the trend, not just the snapshot. One row per company, scored
0-100, with a resolved web domain, tech stack and role families attached.

### Why this instead of a job scraper

| Job scrapers give you | This Actor gives you |
|---|---|
| One row per job post | One row per **company** |
| A single month | **Up to 12 months** rolled up |
| Raw free text | Normalised company + resolved **web domain** |
| No trend | `new` / `consistent` / `always-hiring` / `reaccelerating` / `churned` |
| No prioritisation | **0-100 hiring intent score** |

Hiring is one of the strongest B2B buying signals: a company posting engineering
roles three months in a row is scaling, has budget, and is buying tooling.

### Example output

```json
{
  "company": "Spacelift",
  "domain": "careers.spacelift.io",
  "hiringIntentScore": 86,
  "trend": "always-hiring",
  "activeThisMonth": true,
  "consecutiveMonths": 3,
  "monthsPosted": ["August 2026", "July 2026", "June 2026"],
  "monthsPostedCount": 3,
  "totalListings": 3,
  "roleFamilies": ["backend", "infra-devops"],
  "seniorityLevels": ["senior"],
  "techStack": ["aws", "devops", "go", "kubernetes"],
  "remotePolicy": "remote",
  "locations": ["Remote (EU)"],
  "latestRole": "Senior Backend Engineer",
  "latestSalary": "$120k - $160k",
  "latestMonth": "August 2026",
  "latestHnUrl": "https://news.ycombinator.com/item?id=49160000",
  "latestPostText": "..."
}
```

The same record flattened, the way it lands in a spreadsheet or CRM:

| company | domain | hiringIntentScore | trend | consecutiveMonths | roleFamilies | techStack | remotePolicy | latestRole |
|---|---|---|---|---|---|---|---|---|
| Spacelift | careers.spacelift.io | 86 | always-hiring | 3 | backend, infra-devops | aws, devops, go, kubernetes | remote | Senior Backend Engineer |

### Output fields

| Field | Type | Meaning |
|---|---|---|
| `company` | string | Normalised company name |
| `domain` | string | null | Resolved company website (ATS/social/link-shortener hosts filtered out) |
| `hiringIntentScore` | number | 0-100. Recency + streak + role breadth + stack breadth + enrichment |
| `trend` | string | `new`, `consistent`, `always-hiring`, `reaccelerating`, `churned` |
| `activeThisMonth` | boolean | Posted in the newest thread |
| `consecutiveMonths` | number | Unbroken streak counting back from the newest thread |
| `monthsPosted` / `monthsPostedCount` | array / number | Every month the company appeared |
| `totalListings` | number | Number of posts aggregated |
| `roleFamilies` | array | `backend`, `frontend`, `fullstack`, `data`, `ml-ai`, `infra-devops`, `mobile`, `security`, `product`, `sales-gtm`, `support` |
| `seniorityLevels` | array | `junior`, `senior`, `staff`, `principal`, `lead`, `head`, `director`, `vp`, `founding`, ... |
| `techStack` | array | Deduplicated technologies across all months |
| `remotePolicy` | string | `remote`, `hybrid`, `onsite`, `unspecified` |
| `locations` | array | Locations seen across posts |
| `latestRole`, `latestSalary`, `latestMonth`, `latestHnUrl`, `latestPostText` | - | Most recent post details |

### How to use it

1. Open the Actor and click **Try for free**.
2. Leave the input empty (`{}`) to get the last 3 months of hiring signals, or
   set `monthsBack` up to 12 for a deeper rollup.
3. Narrow the list with `trendFilter`, `minIntentScore`, `techFilter` or
   `requireDomain` so you only pay for accounts you would actually work.
4. Export the dataset to **CSV, JSON, Excel, the API or a webhook** and push it
   into your CRM, Clay table, Google Sheet or outbound sequence.

### Input

All fields are optional - running with `{}` returns the last 3 months of signals.

| Field | Type | Default | Description |
|---|---|---|---|
| `monthsBack` | integer | `3` | How many monthly threads to aggregate (1-12) |
| `trendFilter` | array | `[]` | Keep only these trends, e.g. `["always-hiring","consistent"]` |
| `minIntentScore` | integer | `0` | Keep only companies scoring at least this |
| `techFilter` | array | `[]` | Keep companies whose stack contains ANY of these, e.g. `["rust","kubernetes"]` |
| `requireDomain` | boolean | `false` | Only companies with a resolved website (best for CRM enrichment) |
| `maxResults` | integer | `500` | Cap on returned companies (1-2000) |

#### Example: high-intent, domain-resolved infra buyers

```json
{
  "monthsBack": 6,
  "trendFilter": ["always-hiring", "consistent"],
  "minIntentScore": 60,
  "techFilter": ["kubernetes", "terraform", "aws"],
  "requireDomain": true,
  "maxResults": 200
}
```

#### Example: fresh companies that just started hiring

```json
{ "monthsBack": 4, "trendFilter": ["new"], "requireDomain": true }
```

### Use cases

- **Outbound prospecting** - target companies scaling engineering right now.
- **Clay / CRM enrichment** - company + domain + stack + trend, ready to join.
- **DevTool GTM** - filter by `techFilter` to find accounts on your stack.
- **Recruiting intelligence** - see which competitors keep hiring and for what.
- **Market research** - monthly tech-stack and role-family demand shifts.

### Integrations

The dataset is standard Apify output, so it plugs into the tools you already run:

- **Zapier**, **Make** and **n8n** - trigger a flow on every new run.
- **Slack** - post the top-scoring new companies to a sales channel.
- **Google Sheets** - export straight into a shared prospecting sheet.
- **Airbyte** - sync results into your warehouse.
- **LangChain** - feed company signals into an agent or RAG pipeline.
- **REST API** - pull results directly from the Apify dataset endpoint.
- **Webhooks** - fire on run success and push results anywhere.
- **Scheduling** - run it monthly, right after each new "Who is hiring?" thread
  goes up, so your signal list refreshes itself.

### Pricing

Pay per result - you only pay for company signals actually delivered.

| Event | Price |
|---|---|
| Actor start | $0.00005 |
| `company-signal` (one enriched company) | **$0.015** |

A typical 3-month run returns a few hundred companies. Use `maxResults`,
`minIntentScore` or `requireDomain` to control both volume and spend, and set
a max total charge on the run to hard-cap it.

### FAQ

**Do I need a Hacker News account or API key?**
No. The Actor uses public, official HN APIs. There is nothing to log into and
no credentials to configure.

**Is this legal?**
Yes. It reads publicly available Hacker News comments through HN's own public
APIs. No login walls are bypassed and no HTML is scraped.

**How is `hiringIntentScore` calculated?**
It combines recency (did they post in the newest thread), streak length
(consecutive months), role breadth (how many role families), stack breadth (how
many technologies mentioned) and enrichment completeness (domain, salary,
location resolved). The result is normalised to 0-100.

**Why is `domain` sometimes missing?**
Some HN posts link only to an ATS, a Google Doc, a social profile or a link
shortener - those hosts are deliberately filtered out rather than passed off as
a company website. Set `requireDomain: true` if you only want rows with a
resolved domain.

**How far back can I go?**
Up to 12 monthly threads via `monthsBack`. More months means longer streaks,
richer stacks and more reliable trend classification.

**Will it break?**
It is built on official APIs with retries and exponential backoff, and
thread-level failures degrade gracefully instead of killing the run. Parsing is
heuristic because HN posts are free text, so field coverage is high but not 100%
(see Notes).

### Troubleshooting

| Problem | Fix |
|---|---|
| Empty dataset | Lower `minIntentScore` or clear `trendFilter` / `techFilter` - your filters are too strict |
| Too few companies returned | Increase `monthsBack` to aggregate more monthly threads |
| Missing domains on many rows | Set `requireDomain` to `false` to keep companies whose website could not be resolved |

### Data source & reliability

100% official APIs - HN Algolia Search (thread discovery) and the HN Firebase
API (comments). No HTML scraping, no login, no anti-bot fragility. Requests use
retries with exponential backoff, and thread-level failures degrade gracefully
instead of killing the run.

### Notes

- HN posts are free text, so parsing is heuristic. Measured on a real
  111-company sample from the August 2026 thread: **role 85%**, **location 95%**,
  **domain 74%**, **role families 96%**, **tech stack 86%**.
- Fields are classified by **content**, not by position - a missing role does not
  shift the location into the wrong column.
- Non-job comments (replies, candidate self-posts) are filtered out, so you are
  never charged for a row that is not a real listing.
- Companies are matched by a normalised key, so `Acme, Inc.` and `Acme` merge.

# Actor input Schema

## `monthsBack` (type: `integer`):

How many recent monthly 'Who is hiring?' threads to aggregate (1-12). More months = better trend detection, longer run.

## `trendFilter` (type: `array`):

Only return companies with these trends: new, consistent, always-hiring, reaccelerating, churned, active, inactive. Empty = all.

## `minIntentScore` (type: `integer`):

Only return companies scoring at least this (0-100).

## `techFilter` (type: `array`):

Only return companies whose aggregated tech stack contains ANY of these tags, e.g. rust, kubernetes, llm. Empty = all.

## `requireDomain` (type: `boolean`):

Only return companies where a real company website domain could be resolved (best for CRM / lead enrichment).

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

Maximum number of company signals to return (1-2000).

## Actor input object example

```json
{
  "monthsBack": 3,
  "trendFilter": [],
  "minIntentScore": 0,
  "techFilter": [],
  "requireDomain": false,
  "maxResults": 500
}
```

# 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 = {
    "monthsBack": 3,
    "trendFilter": [],
    "minIntentScore": 0,
    "techFilter": [],
    "requireDomain": false,
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("angaba92/hiring-intent-signals-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 = {
    "monthsBack": 3,
    "trendFilter": [],
    "minIntentScore": 0,
    "techFilter": [],
    "requireDomain": False,
    "maxResults": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("angaba92/hiring-intent-signals-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "monthsBack": 3,
  "trendFilter": [],
  "minIntentScore": 0,
  "techFilter": [],
  "requireDomain": false,
  "maxResults": 500
}' |
apify call angaba92/hiring-intent-signals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=angaba92/hiring-intent-signals-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/3u3BYb9ERX9w6t6pp/builds/zCjojpj9NPXJ59vlY/openapi.json
