HiringSignal — Hiring & Buying Intent Signals
Pricing
from $10.00 / 1,000 company comparisons
HiringSignal — Hiring & Buying Intent Signals
Track hiring changes across companies and turn them into evidence-backed B2B buying signals. Detect team expansion, executive hiring, hiring surges and slowdowns across Greenhouse, Lever, Ashby and Workday.
Pricing
from $10.00 / 1,000 company comparisons
Rating
0.0
(0)
Developer
Daniel Coldibeli
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a month ago
Last modified
Categories
Security
Limited permissionsShare
HiringSignal — Turn Hiring Changes Into B2B Buying Signals
Don't just scrape jobs. Monitor what changed.
Track companies over time and discover meaningful hiring changes — team expansion, executive hiring, hiring surges and slowdowns — with evidence from the original job postings.
Give HiringSignal a list of company domains. The first run establishes a free baseline. Run them again later and get the changes that matter.
Companies → Free baseline → Compare later → Hiring Signals → Buying Intent
Why HiringSignal?
Most job scrapers tell you what jobs exist right now.
HiringSignal tells you what changed since the last run — and turns those changes into structured signals you can use for prospecting, account research, recruiting intelligence, market monitoring, and automated workflows.
- Team and function expansion — security, data, AI, sales, and engineering
- Executive hiring — new leadership roles opening at a company
- Hiring surges — overall posting volume jumping sharply
- Confirmed hiring slowdowns — closures jumping sharply, not just a quiet week
- Rule-based buying-intent categories — a plausible purchase need implied by the hiring pattern
- Evidence linking every signal back to the underlying postings — no black box, nothing to take on faith
Example signal
Illustrative example for explanation only — not a claim about a real company.
- Company:
example.com - Change: 4 new jobs, 1 confirmed closed
- Signal:
SECURITY_TEAM_EXPANSION - Buying intent:
SECURITY_TOOLING_NEED - Evidence: "Senior Security Engineer"; "Application Security Lead"
Who it's for
- Sales intelligence and prospecting: see which accounts are building a security, data, AI, or sales team right now.
- Recruiting and talent intelligence: track hiring activity by function at target or competitor companies.
- Market research and competitive intelligence: follow expansion, executive hires, and slowdowns across a watchlist.
- Agents and automated workflows: consistent, typed records with clear statuses that can be consumed through the Apify API or MCP.
How it works
- Resolve. Each company domain is resolved to its public careers page, and the applicant tracking system (ATS) behind it is identified.
- Collect. The current job postings are collected from that ATS and normalized to one shape.
- Compare. The collection is compared with the company's previous one: which postings are new, still open, or confirmed closed.
- Signal. Confirmed changes become deterministic Hiring Signals, and selected signals become Buying Intent events.
The first run for a company establishes its baseline. There is nothing to compare against yet, so it produces no signals. That is expected, and it is free. From the second run on, every run reports what changed.
Quick start
- Enter one or more company domains under Company domains (for example
stripe.com), up to 50 per run. - Click Start. Each new company shows
baseline_establishedwith the message "Baseline established — monitoring started. Run this company again later to detect hiring changes." - Run it again later with the same domains, or set up an Apify Schedule (daily or weekly works well for most watchlists). Now each company shows
compared, with what changed and any signals detected. - Open the Output tab to see one row per company. Switch to the Hiring signals or Buying intent view to see one row per signal or event, with evidence.
What you get
Company monitoring results (Output tab)
One record per company per run:
| Field | Meaning |
|---|---|
companyDomain | The monitored company |
status | baseline_established, compared, rebaselined, suspicious_zero, collection_failed, or processing_error |
message | Plain-language explanation of the result |
atsProvider | Where the postings came from (greenhouse, lever, ashby, workday, generic) |
previousTotal, currentTotal, newJobsCount, closedJobsCount, netChange | What changed since the previous run (set when status is compared). A posting is reported in closedJobsCount once, in the run where it's first confirmed closed — never again in later runs. |
truncated | True when this company's postings hit Max jobs per company — the real total may be higher than collected. While true, newJobsCount/closedJobsCount are reported as 0 instead of risking a false signal from an incomplete window; see maxJobsPerCompany under Input. |
signals | Hiring Signals, each with strength, confidence, metrics, and evidence |
buyingIntents | Buying Intent events, each with an explanation and evidence |
billable | Whether this company counted as a billable event in this run |
The Output tab has three views: Company overview, Hiring signals (one row per signal), and Buying intent (one row per event).
Illustrative record (the structure matches real output; the values are made up):
{"companyDomain": "example.com","status": "compared","message": "Compared with the previous run: 4 new, 1 closed, net +3 open postings. 1 hiring signal and 1 buying-intent event detected.","atsProvider": "greenhouse","previousTotal": 38,"currentTotal": 41,"newJobsCount": 4,"closedJobsCount": 1,"netChange": 3,"truncated": false,"signalsCount": 1,"signals": [{"signalType": "SECURITY_TEAM_EXPANSION","strength": "medium","confidence": 0.8,"evidence": [{ "jobId": "…", "title": "Senior Security Engineer", "reason": "SECURITY_TEAM_EXPANSION: title/description matched \"security engineer\" (SECURITY, via title)" },{ "jobId": "…", "title": "Application Security Lead", "reason": "SECURITY_TEAM_EXPANSION: title/description matched \"application security\" (SECURITY, via title)" }],"metrics": { "previousActiveJobs": 38, "currentActiveJobs": 41, "newJobsCount": 4, "closedJobsCount": 1, "categoryNewJobsCount": 2 }}],"buyingIntentsCount": 1,"buyingIntents": [{"category": "SECURITY_TOOLING_NEED","strength": "medium","confidence": 0.8,"sourceSignalTypes": ["SECURITY_TEAM_EXPANSION"],"explanation": "SECURITY_TOOLING_NEED inferred from SECURITY_TEAM_EXPANSION (2 new SECURITY-tagged job(s))."}],"billable": true}
Raw job postings
Every normalized posting collected in the run is in the run's jobs dataset: title, department or team, location, remote and employment type, salary when the source exposes it, description (optional), apply URL, and ATS. Fields a source doesn't expose are left out, never guessed.
History across runs
Three named datasets in your account keep the full history across runs: hiring-signals, buying-intent-events, and temporal-summaries (one change record per company per run). For API consumers, each run also writes SIGNALS, BUYING-INTENTS, and summary records to its key-value store.
Hiring Signals
| Signal | Meaning |
|---|---|
AI_TEAM_EXPANSION | New AI/ML roles opened, past a threshold |
SECURITY_TEAM_EXPANSION | New security roles opened |
DATA_TEAM_EXPANSION | New data roles opened |
SALES_TEAM_EXPANSION | New sales/GTM roles opened |
ENGINEERING_EXPANSION | New engineering roles opened |
EXECUTIVE_HIRING | New executive-level roles opened |
HIRING_SURGE | Overall new-posting volume jumped sharply |
HIRING_SLOWDOWN | Confirmed closures jumped sharply |
Signals are deterministic and rule-based. Roles are classified by function using keyword and phrase rules, not a black-box model, so every signal can be traced to its postings.
Buying Intent
| Hiring Signal | Buying Intent category |
|---|---|
AI_TEAM_EXPANSION | AI_ML_TOOLING_NEED |
SECURITY_TEAM_EXPANSION | SECURITY_TOOLING_NEED |
DATA_TEAM_EXPANSION | DATA_INFRASTRUCTURE_NEED |
SALES_TEAM_EXPANSION | SALES_GTM_TOOLING_NEED |
A Buying Intent event is a rule-based inference: a plausible category of purchase need implied by the hiring pattern. EXECUTIVE_HIRING and HIRING_SURGE can appear as corroborating context but never raise an event's strength or confidence. HiringSignal does not score, rank, or prioritize companies. It gives you the evidence, and the judgment stays with you.
Pricing
HiringSignal uses pay-per-event pricing with one billable event, Company comparison (company-monitored): you're charged once for each company comparison it completes against that company's previous run. The current price is shown in this Actor's pricing section.
You are not charged for:
- a company's first baseline (
baseline_established); - a re-baseline after the comparison basis changes — the detected job source, or the job-collection window (
rebaselined); - a collection that failed or looked unreliable (
collection_failed,suspicious_zero); the previous state is kept unchanged; - a company whose results could not be fully saved (
processing_error, orcomparedwithbillable: false).
Each record's billable field shows exactly which companies were charged in a run. If you set a maximum cost per run, HiringSignal stops before starting a company that would exceed it, and the run log says how many were skipped.
Input
| Field | Default | Description |
|---|---|---|
companyDomains (required) | — | Domains or URLs to monitor, normalized to bare hostnames and deduplicated. Up to 50 per run. An entry that isn't a usable domain is skipped with a warning in the run log — the rest of the batch still runs. If none of the entries are usable, the run fails (nothing to process). |
maxJobsPerCompany | 100 | Maximum postings collected per company (hard cap 500). Comparisons (new/closed postings, and the signals built from them) are computed only on this collected window, not the company's true total — a company with more open postings than this cap is marked truncated (see Company monitoring results) and newJobsCount/closedJobsCount are reported as 0 rather than risking a false signal from a window that doesn't cover every posting. Raising or lowering this value for an already-truncated company triggers one free re-baseline instead of reporting a false mass of new or closed postings. |
includeDescription | true | Include each posting's full description in the jobs dataset. |
closeConfirmationRuns (advanced, hidden from the form) | 2 | Consecutive runs a posting must be missing before it counts as closed. This protects against a single failed collection looking like a mass closure. The default is the protective setting for almost every use case; still available to API callers. Hard cap 10. |
validationMode (advanced, hidden from the form) | false | Adds a detailed report to the log and the VALIDATION-REPORT record, showing which job source was detected for each company. Still available to API callers; for normal use, the default dataset's atsProvider, careersUrl, status, and message columns already cover this. |
Supported job sources
- Greenhouse, Lever, Ashby: public job board APIs. Ashby also covers a company-hosted proxy pattern, observed working in limited validation.
- Workday: the public Candidate Experience Site API for careers sites on
*.myworkdayjobs.com. Verified against real tenants, though accuracy has not yet been measured as broadly as for Greenhouse, Lever, and Ashby. - Generic fallback: best-effort extraction of job links from other careers pages' HTML.
Coverage depends on how each company publishes its jobs. Companies on Greenhouse, Lever, Ashby, or Workday work best. A careers page that only renders jobs with client-side JavaScript, with no static HTML or public API behind it, may return few or no jobs. No domain is guaranteed to produce jobs or signals.
Limitations
- The first run for a company never produces signals. That is the baseline, and it is free.
- Generic-fallback job identity is URL-based. If a careers site reissues a posting under a new URL, it can look like one job closing and another opening. Treat new/closed activity from generic-fallback companies with that in mind. Greenhouse, Lever, Ashby, and Workday use the source's own stable IDs and aren't affected.
- The careers-page resolver looks at the homepage's links and common careers paths. It can miss a careers page reachable only through JavaScript navigation or an unusual URL.
- Posting dates are a proxy. Some sources only expose a "last updated" time.
- Country is included only when the source provides it as a field. It is never guessed from a location string.
- Classification is keyword/phrase-based, not NLP. A vague title and description produce no category rather than a guess.
- Companies are processed one at a time, to stay polite to the sites being read. A full 50-company run takes longer than a small one. The default timeout is one hour at 1 GB of memory.
- History datasets grow over time. The named history datasets are never pruned by this Actor. Their retention follows your Apify account's storage settings, so export or clear old data as needed.
Security & compliance
- Only public, unauthenticated pages and public ATS API endpoints are read, the same data any visitor to a careers page can see.
- No logins, session cookies, CAPTCHA solving, or anti-bot evasion.
- No data about job applicants is collected, and no application is ever submitted.
- Runs with Apify's limited permissions.
Troubleshooting
- All companies show
baseline_established. That's the first run. Run again later to get comparisons. - A company shows
collection_failedor has 0 jobs. Its careers page may not be on a supported ATS, or may render jobs only with JavaScript. The default output'satsProvider,careersUrl, andmessagecolumns show what was detected for each company; API callers can also passvalidationMode: truefor an additional detailed report in the run log and under theVALIDATION-REPORTkey-value record. comparedbut no signals. Nothing changed enough to qualify as a signal since the previous run. The message says so explicitly.comparedbutnewJobsCount/closedJobsCountare always 0. Checktruncated— if true, this company has more postings thanmaxJobsPerCompany, so change detection is suppressed rather than risking a false signal. RaisemaxJobsPerCompany(see Input) if you need full coverage for this company.- "must contain at most 50 entries." Split your list across several runs or Schedules.
- One company didn't run, but the rest did. A domain that isn't a usable domain is skipped with a warning in the run log; every other domain in the same input is still processed.