Multi-ATS Hiring Intent Monitor avatar

Multi-ATS Hiring Intent Monitor

Under maintenance

Pricing

Pay per usage

Go to Apify Store
Multi-ATS Hiring Intent Monitor

Multi-ATS Hiring Intent Monitor

Under maintenance

Monitor public career pages and ATS job boards across Greenhouse, Lever, Ashby, SmartRecruiters, Workday, and generic career pages. Detect new, changed, and removed jobs, generate hiring intent signals, and export normalized job records with company summaries.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Вадим Захаров

Вадим Захаров

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Monitor public company career pages and ATS boards for new, changed, and removed jobs. Extract normalized job records, detect hiring intent signals, create company summaries, and track changes over time.

This Actor works as a Greenhouse jobs scraper, Lever jobs scraper, Ashby jobs scraper, SmartRecruiters jobs scraper, Workday jobs scraper, ATS jobs scraper, career page scraper, hiring intent monitor, and job change monitor for public hiring data.

It is built for recruiting intelligence, sales intelligence, account monitoring, market research, and company hiring signals.

What this Actor does

  • Accepts company domains and direct career URLs.
  • Discovers public career pages from company domains.
  • Detects supported ATS platforms automatically.
  • Extracts public job postings from supported ATS sources.
  • Normalizes titles, locations, departments, descriptions, seniority, remote type, skills, and compensation fields.
  • Tracks new, changed, unchanged, and removed jobs across recurring runs.
  • Emits optional company_summary records with hiring signals.
  • Saves a user-facing run summary in key-value store record OUTPUT.

The Actor uses public career pages and public ATS endpoints only. It does not use LinkedIn, private ATS APIs, login-only systems, cookies, candidate systems, or hidden/private endpoints.

Supported ATS sources

SourceBehavior
GreenhouseUses public Greenhouse job board APIs where available.
LeverUses public Lever postings APIs, including EU host detection.
AshbyUses public Ashby posting APIs and requests compensation when available.
SmartRecruitersUses public SmartRecruiters company postings pagination.
WorkdayBest-effort extraction from public visible HTML and JSON-LD.
Generic career pagesBest-effort JSON-LD and visible job-link extraction.

Supported platform input values:

["auto", "greenhouse", "lever", "ashby", "workday", "smartrecruiters", "generic"]

Use auto for normal runs.

What data you get

The default dataset contains job records and, when enabled, company_summary records.

Job records include:

  • company and source metadata
  • ATS platform and ATS job ID
  • stable job identity fields
  • fingerprint and contentHash
  • title and normalized title
  • location and normalized location
  • department, team, and employment type
  • remote type
  • seniority
  • extracted skills
  • matched keywords and locations
  • text description
  • optional HTML description
  • salary and compensation fields
  • posting and apply URLs
  • change status
  • first seen, last seen, removed timestamps
  • warnings and errors arrays

Compensation fields are always present and nullable:

salaryMin
salaryMax
salaryCurrency
salaryPeriod
compensationText

descriptionText is always present on job records and is "" when an ATS listing does not expose description text. descriptionHtml is emitted only when includeDescriptionHtml is true. rawSource is emitted only when includeRawSource is true.

After a normal run, the Actor also writes a KVS OUTPUT record in the run's default key-value store. OUTPUT is a user-facing run summary, not persistent state.

OUTPUT includes:

  • actorName
  • runId
  • scrapedAt
  • datasetId
  • keyValueStoreId
  • stateKey
  • summary
  • byAtsPlatform
  • byCompany
  • topHiringSignals
  • warnings
  • errors

The summary counters include discovered targets, detected targets, successful and failed targets, parser success/failure by ATS, zero-job boards, blocked updates, updated/preserved state counts, emitted records, and job status totals.

Input examples

Company domain baseline

Use this for the first run of a monitor.

{
"companyDomains": ["example.com", "acme.com"],
"atsPlatforms": ["auto"],
"onlyChangesSinceLastRun": false,
"stateKey": "baseline-monitor",
"includeCompanySummary": true,
"maxJobsPerCompany": 500
}

Scheduled delta run

Use the same stateKey for recurring monitoring.

{
"companyDomains": ["example.com", "acme.com"],
"atsPlatforms": ["auto"],
"onlyChangesSinceLastRun": true,
"stateKey": "baseline-monitor",
"includeCompanySummary": true,
"maxJobsPerCompany": 500
}

Direct career URLs

Use direct URLs when you already know the ATS board or career page.

{
"careerUrls": [
"https://boards.greenhouse.io/acme",
"https://jobs.lever.co/example",
"https://jobs.ashbyhq.com/example",
"https://careers.smartrecruiters.com/example"
],
"atsPlatforms": ["auto"],
"stateKey": "direct-boards-monitor",
"includeCompanySummary": true
}

Keyword and location matching

Keywords and locations enrich output. They do not filter jobs out.

{
"companyDomains": ["example.com"],
"keywords": ["AI", "LLM", "RevOps", "security"],
"locations": ["London", "Berlin", "Remote"],
"stateKey": "keyword-location-monitor",
"includeCompanySummary": true
}

proxyConfiguration can be provided when you want Apify Proxy settings for HTTP requests.

Debug output

Use only when inspecting parser behavior.

{
"careerUrls": ["https://boards.greenhouse.io/example"],
"includeRawSource": true,
"includeDescriptionHtml": true,
"stateKey": "debug-monitor"
}

Output examples

Job record

{
"recordType": "job",
"runId": "abc123",
"scrapedAt": "2026-06-06T10:00:00.000Z",
"companyDomain": "example.com",
"companyName": "Example",
"sourceUrl": "https://boards.greenhouse.io/example",
"careerUrl": "https://boards.greenhouse.io/example",
"atsPlatform": "greenhouse",
"atsJobId": "job-2",
"stableJobKey": "example.com|greenhouse|job-2",
"fingerprint": "0adcd377d1d9b02d5ba4a6ea09cc2dcfe2e2c0f169e0d4c132e750894f0cb71c",
"contentHash": "3bf383d76d0d8b659100d07983e99b9debf179791994401e63d47d6462179c6e",
"title": "LLM Engineer",
"normalizedTitle": "llm engineer",
"location": "London",
"normalizedLocation": "london",
"department": "AI",
"team": "AI",
"remoteType": "onsite",
"seniority": "unknown",
"skills": ["AI", "LLM"],
"matchedKeywords": ["LLM"],
"matchedLocations": ["London"],
"descriptionText": "Build LLM systems in London.",
"salaryMin": null,
"salaryMax": null,
"salaryCurrency": null,
"salaryPeriod": null,
"compensationText": null,
"postingUrl": "https://boards.greenhouse.io/example/jobs/job-2",
"applyUrl": null,
"changeStatus": "new",
"firstSeenAt": "2026-06-06T10:00:00.000Z",
"lastSeenAt": "2026-06-06T10:00:00.000Z",
"removedAt": null,
"isCurrent": true,
"warnings": [],
"errors": []
}

Company summary

{
"recordType": "company_summary",
"runId": "abc123",
"scrapedAt": "2026-06-06T10:00:00.000Z",
"companyDomain": "example.com",
"companyName": "Example",
"processedSourceUrls": ["https://boards.greenhouse.io/example"],
"atsPlatformsDetected": ["greenhouse"],
"totalCurrentJobs": 25,
"emittedJobRecords": 3,
"newJobs": 2,
"changedJobs": 1,
"removedJobs": 0,
"unchangedJobs": 22,
"topDepartments": [{ "name": "Engineering", "count": 12 }],
"topLocations": [{ "name": "London", "count": 5 }],
"newLocations": ["London"],
"topSkills": [{ "name": "AI", "count": 4 }],
"matchedKeywords": [{ "keyword": "AI", "count": 4 }],
"matchedLocations": [{ "location": "London", "count": 5 }],
"hiringSignals": [
{
"signalType": "ai_team_expansion",
"label": "AI team expansion",
"confidence": "medium",
"score": 45,
"evidenceJobFingerprints": ["0adcd377d1d9b02d5ba4a6ea09cc2dcfe2e2c0f169e0d4c132e750894f0cb71c"],
"evidenceTitles": ["LLM Engineer"],
"evidenceLocations": ["London"],
"explanation": "1 new or changed jobs matched AI team expansion."
}
],
"warnings": [],
"errors": []
}

OUTPUT summary

{
"actorName": "multi-ats-hiring-intent-monitor",
"runId": "abc123",
"scrapedAt": "2026-06-06T10:00:00.000Z",
"datasetId": "defaultDatasetId",
"keyValueStoreId": "defaultKeyValueStoreId",
"stateKey": "baseline-monitor",
"summary": {
"targetsDiscovered": 2,
"targetsDetected": 2,
"targetsSucceeded": 2,
"targetsFailed": 0,
"parserSuccessByAts": { "greenhouse": 1, "lever": 1 },
"parserFailureByAts": {},
"companiesStateUpdated": 2,
"companiesStatePreserved": 0,
"newJobs": 2,
"changedJobs": 1,
"removedJobs": 0,
"unchangedJobs": 22
},
"byAtsPlatform": {},
"byCompany": {},
"topHiringSignals": [],
"warnings": [],
"errors": []
}

Incremental monitoring

Use stateKey to keep independent monitors separate. The Actor stores previous snapshots in the named key-value store multi-ats-hiring-intent-monitor-state-store under that key. The run OUTPUT summary remains in the run's default key-value store and is separate from state.

Recommended scheduled workflow:

  1. Run a baseline with onlyChangesSinceLastRun: false.
  2. Schedule recurring runs with the same stateKey.
  3. Set onlyChangesSinceLastRun: true for recurring delta runs.
  4. Consume dataset job records for new, changed, and removed.
  5. Read KVS OUTPUT for run-level warnings, errors, and counters.

onlyNewSinceLastRun is a legacy name. It still works, but the behavior is not only new jobs. The mode emits new, changed, and removed records, and excludes unchanged jobs. New users should use onlyChangesSinceLastRun.

When testing locally with Apify CLI, use --no-purge so local storage keeps state between runs.

Hiring intent signals

Hiring signals are derived from new and changed job records.

Current signal types:

  • ai_team_expansion
  • sales_expansion
  • security_investment
  • new_geo_expansion
  • revops_investment
  • customer_support_scaling

Signals include confidence, score, evidence job fingerprints, titles, locations, and an explanation. They are intended for sales intelligence, recruiting intelligence, account prioritization, and market research workflows.

Company summaries

When includeCompanySummary is true, the Actor emits one company_summary record per processed company.

Company summaries include:

  • processed source URLs
  • detected ATS platforms
  • current job totals
  • emitted job totals
  • new/changed/removed/unchanged counts
  • top departments
  • top locations
  • newly seen locations
  • top skills
  • matched keywords
  • matched locations
  • hiring signals
  • company-level warnings and errors

Workday/generic limitations

Workday support is best-effort. Many Workday boards are JavaScript-rendered, tenant-specific, or expose jobs only through client-side APIs. This Actor does not run Playwright or browser rendering by default in V1. There is no JavaScript rendering by default in V1, so some Workday pages may return warnings or zero records.

Generic career page support is also best-effort. Custom career pages vary widely, so the generic parser looks for JSON-LD JobPosting data and visible public job links. There is no guarantee for every custom career page.

State safety behavior:

  • Failed source updates preserve previous state.
  • Invalid JSON responses preserve previous state.
  • Suspicious zero-job generic extraction preserves previous state.
  • This avoids false removed-job records when a page temporarily fails or cannot be parsed safely.

Interpreting warnings

Common warning meanings:

  • invalid JSON response: a public JSON endpoint returned a body that was not parseable JSON.
  • HTTP 4xx/5xx: the public career page or ATS endpoint failed.
  • No allowed ATS parser detected: a source URL did not match enabled parsers.
  • No jobs extracted from generic career page: generic extraction could not safely identify jobs.
  • Workday page appears JS-rendered: server HTML did not expose enough job data.
  • Partial source failure: successful sources can update while failed-source state is preserved.

Warnings are surfaced in dataset records and in the KVS OUTPUT run summary.

Local usage

Install dependencies:

$npm install

Run full local verification:

$npm run verify

Run fixture smoke:

$npm run smoke

Run manual live smoke after building:

npm run build
SMOKE_GREENHOUSE_URL=https://boards.greenhouse.io/example npm run smoke:live

Run with Apify CLI:

npm install -g apify-cli
mkdir -p storage/key_value_stores/default
cp input.json storage/key_value_stores/default/INPUT.json
apify run --no-purge

FAQ

Does this scrape LinkedIn?

No. This Actor does not scrape LinkedIn.

Does this use private ATS APIs?

No. It uses public career pages and public ATS endpoints only. It does not use login-only APIs, cookies, private candidate systems, or private ATS data.

Does this run Playwright or browser rendering?

No. V1 does not use Playwright or JavaScript rendering by default. This keeps the Actor lighter, but it means some JavaScript-only Workday or custom pages may not expose jobs.

Can it monitor changes over time?

Yes. Use the same stateKey across scheduled runs and set onlyChangesSinceLastRun to true for delta output.

What happens when a board temporarily fails?

The Actor preserves previous state for failed or suspicious sources so a temporary parser, HTTP, invalid JSON, Workday, or generic extraction issue does not create false removals.

Are compensation fields guaranteed?

No. Compensation parsing is best-effort. When a board exposes clear salary or compensation data, the Actor maps it. Missing or unparseable compensation is represented as null.

Is every custom career page supported?

No. Generic career pages are best-effort. Pages with JSON-LD or visible job links work best.