# Find Companies Hiring — Job Board Scraper & Signals (7 ATS) (`opensignals/ats-hiring-signals`) Actor

Find companies hiring for what you sell — no list needed: built-in directory of 8,800+ job boards (Greenhouse, Workday, Lever, Ashby +3). Scored B2B leads with tech stacks, new-tech alerts, salaries, hiring velocity, ghost-job flags. CSV-ready output, delta mode. No cookies.

- **URL**: https://apify.com/opensignals/ats-hiring-signals.md
- **Developed by:** [Andrey](https://apify.com/opensignals) (community)
- **Categories:** Lead generation, Jobs, Automation
- **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

## ATS Hiring Signals — Job Board Lead Finder (7 ATS incl. Workday)

*Job board scraper & B2B lead finder for Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Workday and Personio — company hiring signals, tech stack and scored leads.*

**Turn job postings into qualified B2B leads.** Companies that are hiring are companies that are buying — new tools, new services, new vendors. This Actor scans public **Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Workday & Personio** job boards and turns them into structured, scored **hiring signals**: which companies are growing, in which teams, how fast, and around which technologies.

No LinkedIn cookies. No anti-bot fights. No stale databases — data comes straight from each company's live job board API, so it is as fresh as the company's own careers page.

### 💥 Composite intent: hiring + funding in one score

For every company with a hiring signal, the Actor checks **SEC EDGAR**: did this company file a Form D (raise capital) in the last 12 months? The result lands in `funding_check`, and `composite_intent_score` adds +15 on top of the hiring score.

A company that is **hiring for your keywords AND recently raised money** is the hottest B2B lead there is — budget confirmed twice, from two independent official sources. Sort by `composite_intent_score` and start at the top. (Toggle: `checkFunding`, on by default.)

### 🔍 No company list? Discover companies

You don't need to bring a list at all. Enable **`discoverCompanies`** and the Actor samples companies from its **built-in directory of ~8,800 real job boards** (harvested from the Common Crawl web index) across Greenhouse, Ashby, Workable, SmartRecruiters, Personio and Lever — then scans them against your keywords and returns only the companies that are actually hiring for what you sell.

*"Find me companies hiring Python engineers right now"* becomes a single run with two input fields:

```json
{ "discoverCompanies": ["greenhouse", "ashby"], "discoverLimit": 200, "keywords": ["python"], "outputMode": "flat_leads" }
```

Every run samples randomly, so scheduled runs keep surfacing fresh companies. Combine with `rolePresets` and `locationFilter` to zero in on your exact ICP.

### Who is this for?

- **B2B sales & SDR teams** — a company hiring 5 SDRs is buying sales tooling; a company hiring DevOps engineers is buying infrastructure. Build outreach lists from *intent*, not directories.
- **Recruiting & staffing agencies** — spot companies with hiring spikes before your competitors call them.
- **Dev-tool & SaaS vendors** — filter by tech keywords (`kubernetes`, `snowflake`, `hubspot`…) to find companies whose job descriptions mention your ecosystem.
- **Investors & analysts** — headcount growth by department is one of the strongest public signals of company trajectory.

### What you get

Two record types (choose either or both in `outputMode`):

**`company_signal` — one aggregated lead record per company:**

```json
{
  "type": "company_signal",
  "company": "gitlab",
  "ats": "greenhouse",
  "board_url": "https://boards.greenhouse.io/gitlab",
  "total_open_jobs": 206,
  "matched_jobs": 56,
  "posted_last_30_days": 33,
  "newest_posting_at": "2026-08-20T17:35:39-04:00",
  "signal_score": 85,
  "top_departments": [{ "name": "AI Engineering", "jobs": 5 }],
  "top_locations": [{ "name": "Remote, United States", "jobs": 11 }],
  "keyword_hits": [{ "keyword": "kubernetes", "jobs": 21 }],
  "top_technologies": [{ "name": "Python", "jobs": 31 }, { "name": "AWS", "jobs": 24 }],
  "seniority_mix": { "senior": 21, "mid": 30, "vp_director": 2 },
  "leadership_hiring": 2,
  "remote_share_pct": 64,
  "stale_jobs": 4,
  "salary_stats": { "jobs_with_salary": 12, "min": 110000, "median": 150000, "max": 210000, "currency_hint": "$" },
  "new_technologies": ["Kafka", "Snowflake"],
  "company_domain_guess": "acme.com",
  "hiring_history": [{ "ts": "2026-08-01T00:00:00Z", "matched": 12, "total": 80 }],
  "trend": { "matched_jobs_change": 5, "total_jobs_change": 9, "previous_run_at": "…" },
  "sample_jobs": [{ "title": "Senior Backend Engineer", "url": "…" }]
}
```

**`job` — individual matched postings** with title, department, location, posting date, URL, matched keywords, plus per-job enrichment:

- `seniority` — junior / mid / senior / manager\_lead / vp\_director / c\_level (parsed from title)
- `workplace` — remote / hybrid / onsite\_or\_unspecified
- `salary_detected` — salary range found in the description text (e.g. `$152,800 - $190,000`)
- `tech_stack` — technologies detected in the posting
- `days_open` / `stale` — how long the posting has been open; `stale: true` (45+ days) flags likely evergreen/ghost jobs — a weaker buying signal
- `compensation` — publisher-provided range (Ashby boards)

#### The `signal_score` (0–100)

A transparent heuristic — no black box:

| Component | Max points | Meaning |
|---|---|---|
| Matching roles open | 40 | Volume of hiring around your keywords |
| Share of matching roles | 20 | How focused the hiring is on your niche |
| Freshness of newest posting | 20 | Recency = live budget |
| Postings in last 30 days | 20 | Hiring velocity |

Sort by `signal_score` descending and call the top of the list first. Watch two more fields: **`new_technologies`** — technologies appearing in a company's postings for the first time between runs (a company that just started mentioning Kafka is choosing Kafka tooling right now), and **`company_domain_guess`** — the likely company website extracted from posting texts, your bridge from signal to outreach. Two extra signals worth watching: `leadership_hiring` > 0 (a new VP or Head-of means new budgets and new vendor decisions) and a positive `trend.matched_jobs_change` between scheduled runs (acceleration = urgency).

### Input

| Field | Description |
|---|---|
| `discoverCompanies` + `discoverLimit` | **Zero-input discovery:** sample from the built-in ~8,800-company job-board directory and return only companies hiring for your keywords |
| `companyNames` | **Auto-discovery:** paste plain company names (`Blueground`, `Acme Corp`) — the Actor generates likely slugs and probes all five ATS providers. No need to know board URLs |
| `boards` | Board URLs (`boards.greenhouse.io/gitlab`, `jobs.lever.co/spotify`, `jobs.ashbyhq.com/ramp`, `apply.workable.com/blueground`, `careers.smartrecruiters.com/ServiceNow`) **or bare company slugs** — slugs are probed against all supported providers automatically |
| `keywords` | Match against title, department, location and full description (`golang`, `SDR`, `salesforce`…). Empty = all jobs |
| `keywordsMode` | `any` (broad) or `all` — require every keyword, e.g. `python` AND `aws` (precise targeting) |
| `searchDescriptions` | Also search inside full job descriptions — the way to detect tech stacks |
| `locationFilter` | e.g. `remote`, `berlin`, `united states` |
| `postedWithinDays` | Only jobs posted in the last N days — fresh postings are the strongest signal |
| `rolePresets` | Curated keyword bundles (Sales, Engineering, AI/ML, Leadership…) — pick roles instead of inventing keywords |
| `excludeStale` | Drop postings open 45+ days (evergreen/ghost jobs) |
| `extractTechStack` | Detect ~120 technologies (languages, clouds, SaaS tools) per job → `tech_stack` field + `top_technologies` per company. On by default, no extra cost |
| `onlyNewJobs` | **Delta mode:** remembers seen jobs between runs and outputs only NEW postings. Schedule daily → get only fresh signals into Slack/n8n/email |
| `outputMode` | `companies` (lead list), `jobs`, `both`, or `flat_leads` — one flat row per company, ready for CSV/Sheets/CRM import |

#### Where do I get board slugs?

Any company careers page hosted on `boards.greenhouse.io/<slug>`, `jobs.lever.co/<slug>`, `jobs.ashbyhq.com/<slug>`, `apply.workable.com/<slug>` or `careers.smartrecruiters.com/<Company>` — the slug is right in the URL. Quick ways to build a list:

- Google: `site:boards.greenhouse.io "backend"`, `site:jobs.lever.co "fintech"`, `site:apply.workable.com`, `site:careers.smartrecruiters.com`
- Your existing account list / CRM — paste company slugs and let the Actor probe all supported providers
- Public company directories (YC companies, industry lists) — most startups use one of these ATS

### Why this beats LinkedIn scraping

| | This Actor | LinkedIn scrapers |
|---|---|---|
| Data source | Company's own live job board API | Scraped HTML behind anti-bot |
| Freshness | Real-time | Hours–days, breaks often |
| Cookies / accounts | **None needed** | Often require session cookies |
| Full descriptions | Yes, including tech stack | Frequently truncated |
| Reliability | Stable public JSON APIs | Breaks on every layout change |

### Integrations

Works with all Apify integrations out of the box: export to **Google Sheets, Airtable, HubSpot, Zapier, Make, n8n**, or fetch results via the [Apify API](https://docs.apify.com/api/v2). Schedule it daily and diff `newest_posting_at` to catch new signals the morning they appear.

### FAQ

**Is this legal?** The Actor reads the same public job-board APIs that power the companies' own careers pages — data companies intentionally publish to attract applicants. No login, no bypassing of access controls.

**A company slug returns nothing?** The company either uses a different ATS (iCIMS, Oracle HCM — coming in future versions) or has a custom careers page. The Actor logs a warning and continues with the rest.

**How many boards can I scan per run?** Hundreds — boards are processed concurrently. For thousands, split into several runs.

**Something broken or missing a feature?** Open an issue on the Actor's Issues tab — I typically respond within 1–2 business days.

# Actor input Schema

## `boards` (type: `array`):

Company job boards to scan. Accepts full board URLs (`boards.greenhouse.io/gitlab`, `jobs.lever.co/spotify`, `jobs.ashbyhq.com/ramp`, `apply.workable.com/blueground`, `careers.smartrecruiters.com/ServiceNow`) or bare company slugs (e.g. `gitlab`). Bare slugs are probed against all five ATS providers automatically.

## `companyNames` (type: `array`):

Don't know the board slugs? Just paste plain company names (e.g. `Blueground`, `Acme Corp`) — the Actor generates likely slugs and probes all five ATS providers automatically. Use together with or instead of `boards`.

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

Case-insensitive keywords matched against job title, department, location and (optionally) full description. A job matches if ANY keyword is found. Leave empty to include all jobs. Examples: `golang`, `kubernetes`, `SDR`, `HubSpot`, `data engineer`.

## `keywordsMode` (type: `string`):

`any` = job matches if ANY keyword found (broad). `all` = job must contain ALL keywords (precise targeting, e.g. `python` AND `aws`).

## `searchDescriptions` (type: `boolean`):

Also match keywords inside full job description text (tech-stack detection). Slightly slower for Greenhouse boards.

## `locationFilter` (type: `array`):

Only include jobs whose location contains ANY of these substrings (case-insensitive), e.g. `remote`, `berlin`, `united states`. Leave empty for all locations.

## `postedWithinDays` (type: `integer`):

Only include jobs posted/updated within the last N days. 0 = no limit. Fresh postings are the strongest buying signal.

## `maxJobsPerCompany` (type: `integer`):

Cap on matched job items output per company (company signal still aggregates over all matches).

## `extractTechStack` (type: `boolean`):

Detect ~120 known technologies (languages, frameworks, clouds, SaaS tools) in each job and aggregate `top_technologies` per company. No extra cost.

## `onlyNewJobs` (type: `boolean`):

Remember which jobs were already seen in previous runs and output only NEW postings. Perfect for scheduled runs + Slack/email/n8n alerts: run daily, get only fresh signals.

## `outputMode` (type: `string`):

`companies` = one aggregated hiring-signal record per company. `jobs` = individual matched postings. `both` = both. `flat_leads` = one FLAT row per company with no nested objects — ready for CSV export, Google Sheets or CRM import.

## `rolePresets` (type: `array`):

Curated keyword bundles — pick roles instead of inventing keywords. Adds terms like `account executive`, `sdr`, `revops` (sales) or `backend`, `sre` (engineering) to your keywords.

## `excludeStale` (type: `boolean`):

Drop postings open for more than 45 days — they are often evergreen/ghost jobs and dilute the signal.

## `discoverCompanies` (type: `array`):

Don't have a company list at all? Sample companies from the built-in directory of ~8,800 job boards (collected from Common Crawl) and scan them against your keywords. Pick which ATS universes to sample from. Combine with `discoverLimit`.

## `discoverLimit` (type: `integer`):

How many companies to sample from the directory per run (random sample, spread across the selected ATS). Each scanned company that matches produces normal paid results.

## `checkFunding` (type: `boolean`):

For every company with a hiring signal, check SEC EDGAR: did it file a Form D (raise capital) in the last 12 months? Hiring + fresh money = the hottest B2B lead. Adds `funding_check` and `composite_intent_score`.

## `excludeCompanies` (type: `array`):

Skip these companies entirely (names or board slugs) — e.g. your existing customers or competitors.

## `htmlReport` (type: `boolean`):

Save a shareable `report.html` (top-25 companies by composite score) into the run's key-value store — send the link to a client or teammate.

## Actor input object example

```json
{
  "boards": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "companyNames": [],
  "keywords": [],
  "keywordsMode": "any",
  "searchDescriptions": true,
  "locationFilter": [],
  "postedWithinDays": 0,
  "maxJobsPerCompany": 100,
  "extractTechStack": true,
  "onlyNewJobs": false,
  "outputMode": "both",
  "rolePresets": [],
  "excludeStale": false,
  "discoverCompanies": [],
  "discoverLimit": 50,
  "checkFunding": true,
  "excludeCompanies": [],
  "htmlReport": true
}
```

# Actor output Schema

## `leads` (type: `string`):

One aggregated, scored hiring-signal record per company — sort by signal\_score descending

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

Individual job postings that matched your keyword/location filters, with seniority, workplace, tech stack and detected salary

## `allResults` (type: `string`):

Both record types in one dataset

## `report` (type: `string`):

Top-25 companies by composite intent score, formatted for humans

# 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 = {
    "boards": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("opensignals/ats-hiring-signals").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 = { "boards": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("opensignals/ats-hiring-signals").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 '{
  "boards": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ]
}' |
apify call opensignals/ats-hiring-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,opensignals/ats-hiring-signals"
        }
    }
}

```

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/i3JjOmYBcRBJjmEBU/builds/Ad4EsTaMU9BW2Zk1h/openapi.json
