Hiring Pulse avatar

Hiring Pulse

Pricing

from $4.00 / 1,000 company snapshots

Go to Apify Store
Hiring Pulse

Hiring Pulse

Monitors company ATS job boards over time and emits hiring-signal deltas: net role growth, new senior hires, first sales hire, function-mix shifts.

Pricing

from $4.00 / 1,000 company snapshots

Rating

0.0

(0)

Developer

Elliot Rose

Elliot Rose

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Categories

Share

hiring-pulse

Company hiring-signal monitor. Give it a list of company domains; it finds each company's applicant-tracking-system (ATS) job board, snapshots the currently open roles, and diffs that snapshot against the previous run (stored in a named key-value store so scheduled runs stay stateful). It sells the change — net growth, new senior hires, a first sales hire, function-mix shifts — not the job list itself.

Input

FieldTypeDefaultDescription
domainsstring[]— (required)Company website domains, e.g. "acme.com". No protocol/path.
atsOverridesarray[][{domain, ats, token}] — skip discovery for a domain by declaring its ATS and board token directly.
emitJobsbooleanfalseAlso push one dataset row per currently open job.
onlyChangedbooleanfalseAfter a company's first snapshot, skip pushing its signal row when nothing changed (delta 0, no new/closed roles).
stateStoreNamestring"hiring-pulse-state"Named key-value store used to persist ATS discovery cache (ats:{domain}) and job snapshots (snap:{domain}).
maxConcurrencyinteger5Max domains processed concurrently.

Output

One signal row per domain per run in the default dataset, e.g.:

{
"domain": "acme.com",
"ats": "greenhouse",
"token": "acme",
"open_roles": 24,
"prev_open_roles": 19,
"delta": 5,
"new_roles": [
{ "id": "4006", "title": "Director of Sales", "department": "Sales",
"location": "Remote", "remote": true,
"url": "https://boards.greenhouse.io/acme/jobs/4006",
"posted_at": "2026-08-10T15:00:00-05:00", "seniority": "lead",
"function": "sales" }
],
"closed_roles": [],
"new_titles": ["Director of Sales", "Senior Backend Engineer"],
"senior_hires": [ /* Job objects with seniority in lead/exec/senior */ ],
"first_sales_hire": true,
"function_counts": { "engineering": 12, "sales": 3, "design": 2, "other": 7 },
"function_deltas": { "engineering": 2, "sales": 1 },
"remote_share": 0.58,
"score": 27,
"first_snapshot": false,
"snapshot_at": "2026-08-29T09:00:00+00:00",
"prev_snapshot_at": "2026-08-15T09:00:00+00:00",
"urls": {
"board_url": "https://boards.greenhouse.io/acme",
"career_page": "https://acme.com/careers"
}
}

With emitJobs: true, one additional row per currently open job is pushed (the Job object plus domain/ats).

Companies whose ATS could not be identified still get a row, with "ats": null, "open_roles": null, and "first_snapshot": true (see Limitations).

Pricing events

Pay-per-event; wrap every charge in try/except so local runs (no PPE config) never crash.

EventPriceWhen
company-snapshot$0.004Once per pushed signal row.
signal-event$0.02Per changed role (new + closed), only after the first snapshot — i.e. you're charged for detected changes, not for the baseline.
job-row$0.0005Per pushed job row, only when emitJobs: true.

MCP tools

This Actor is designed to back two MCP tools for agent/LLM callers:

  • get_hiring_signals(domain) — returns the latest signal row (and, if requested, recent history) for one company, backed by the snap:{domain} and dataset rows this Actor produces.
  • find_companies_hiring(role, stage) — surfaces companies whose latest signal shows growth in a given function (role, e.g. "engineering", "sales") and/or a first_sales_hire/senior_hires pattern matching an early go-to-market stage. Implement as a query over accumulated company-snapshot rows across runs of this Actor.

Limitations

  • Unknown/custom ATS: companies that don't use Greenhouse, Lever, Ashby, SmartRecruiters, or Workable (or host a heavily customized/JS-only careers page we can't parse without a browser) return "ats": null. Use atsOverrides if you already know a company's board token, or extend src/ats.py with a new adapter.
  • Discovery is a two-step heuristic (crawl known careers-page paths for a board link, then probe each ATS API with the domain's second-level label as a guessed token) — it can miss boards on non-obvious paths or under a token that doesn't match the domain name.
  • remote is null (not false) whenever the source location text has no clear remote/on-site signal — we never guess.
  • No Playwright/browser rendering: careers pages that only render job listings via client-side JS (no server-rendered link/iframe to the ATS) won't be discovered by the crawl step, only by the probe-by-token fallback.
  • Seniority/function classification is keyword-based (see src/classify.py) and works from the title/department strings alone — it will occasionally miscategorize unconventional title formats.