Cross-ATS Hiring Change Feed
Under maintenancePricing
Pay per usage
Cross-ATS Hiring Change Feed
Under maintenanceTrack public job changes across Greenhouse, Ashby, Lever, Recruitee, SmartRecruiters, and Workable with company-level hiring signals and legacy Greenhouse compatibility.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
snapperwapper
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
See how a company's public hiring footprint changes across Greenhouse, Ashby, Lever, Recruitee, SmartRecruiters, and Workable in one stable feed. To try it with live data, enter a real public board such as https://boards.greenhouse.io/airbnb, run once to establish a baseline, and run the same input again to see NEW, CHANGED, CLOSED, and REOPENED events. For local adapter work, use examples/demo-fixture.json; it is a synthetic fixture and does not call real ATS endpoints.
Why use this Actor
This is a six-ATS consolidation feed, not a generic job-board scraper. It turns compatible public boards into one normalized job-change stream and rolls boards for the same company into a COMPANY_SIGNAL row. State-backed diffs, stable hashes, provenance links, and conservative fetch checks make recurring runs useful for monitoring without treating a bad response as mass hiring closures.
The Actor keeps the adopted greenhouse-hiring-change-feed name and its legacy Greenhouse mode. Existing boards inputs and legacy output fields continue to work; new users can use source-neutral companyBoards instead.
Try a real public board
In the Apify Console, create a run with this minimal cross-ATS input:
{"companyBoards": [{"boardUrl": "https://boards.greenhouse.io/airbnb","companyName": "Airbnb"}],"onlyChanges": true,"includeContent": false}
The first run normally emits the board's current jobs as NEW rows and saves the baseline. A later run with the same board compares the current public response with that saved state. A board can be replaced with any accepted canonical URL below; do not use a company career-site URL unless it is one of these ATS hosts.
Accepted board URL hosts
- Greenhouse:
boards.greenhouse.ioorjob-boards.greenhouse.io, for examplehttps://boards.greenhouse.io/<board-token>. - Ashby:
jobs.ashbyhq.com, for examplehttps://jobs.ashbyhq.com/<board-token>. - Lever:
jobs.lever.coorjobs.eu.lever.co, for examplehttps://jobs.lever.co/<board-token>. - Recruitee: a non-root
<board-token>.recruitee.comhost, for examplehttps://<board-token>.recruitee.com. - SmartRecruiters:
jobs.smartrecruiters.comorcareers.smartrecruiters.com, for examplehttps://jobs.smartrecruiters.com/<company-token>. - Workable:
apply.workable.comorwww.workable.com, for examplehttps://apply.workable.com/<account-token>.
Only canonical HTTPS URLs are accepted: no credentials, port, query string, or fragment. An optional source may be supplied, but it must match the detected host. The URL path/token is used to identify the public board; the Actor does not log in or use private ATS APIs.
Consolidate several boards for one company
Give boards from the same company the same companyName, or set an explicit companyKey:
{"companyBoards": [{ "boardUrl": "https://boards.greenhouse.io/<greenhouse-token>", "companyName": "Example Corp" },{ "boardUrl": "https://jobs.ashbyhq.com/<ashby-token>", "companyName": "Example Corp" },{ "boardUrl": "https://jobs.lever.co/<lever-token>", "companyName": "Example Corp" }],"onlyChanges": true,"includeContent": false}
The angle-bracket values above are placeholders. Replace them with the company's real public ATS board URLs; this example is not a runnable demo. The same roll-up works with any of the six supported ATSs.
Who it helps
- Recruiting operations teams tracking newly opened, changed, reopened, or closed roles across a target-account list.
- Talent-market and competitive-intelligence analysts comparing department and location hiring movement across ATSs.
- Sales and revenue-operations teams using public hiring activity as one account-research input (not as proof of purchase intent or budget).
- Workforce planners and data engineers feeding a normalized, source-linked change stream into their own warehouse or dashboard.
Input reference
Choose one input mode per run. companyBoards is the cross-ATS mode. The backward-compatible Greenhouse mode accepts tokens or canonical Greenhouse URLs:
{ "boards": ["airbnb", "https://boards.greenhouse.io/<greenhouse-token>"] }
Legacy Greenhouse rows retain fields such as companyToken, jobId, offices, contentHash, and the original summary shape. They also support the REOPENED change type and reopenedJobs summary counter. No migration is required.
The main options are:
onlyChanges(defaulttrue): In cross-ATS mode, emit job changes rather thanUNCHANGEDrows. In legacy mode, preserve the existing behavior.COMPANY_SIGNALrows are still emitted in cross-ATS mode.includeContent(defaultfalse): Opt in to cleaned employer-authored description text when a source provides it. Descriptions are never persisted in Actor state.titleContains,locationContains: Case-insensitive filters on emitted job rows. The complete validated source response still builds the persisted baseline.maxJobsPerBoard(1–500, default 500): Per-board safety cap. A capped or suspicious response is treated as partial and is not used to infer closures.maxResults(1–10,000, default 1,000): Caps emitted job-change rows after the full baseline is built. Company and error rows can accompany the capped job rows.concurrency(1–10, default 5): In cross-ATS mode, the maximum number of board fetches in flight. Legacy Greenhouse mode processes boards sequentially.maxRequestRetries(0–5, default 2): In cross-ATS mode, retries transient public-source failures. Legacy Greenhouse mode does not retry.requestTimeoutSecs(1–120, default 30): Timeout for each source request.partialFetchThreshold(0–1, default 0.25): In cross-ATS mode, suppress closures when a successful response is less than this fraction of the prior open-job baseline.
Understand the output
Cross-ATS runs can contain three record types. Stable jobKey values are SHA-256 hashes of ATS source, board token, and source job ID. Stable signalKey values are derived from companyKey, so they do not change with input ordering or run time.
JOB_CHANGE
One row for a matching job event. Common fields are companyKey, companyName, source, sourceBoardToken, sourceJobId, title, location/locations, remote, departments, employmentType, publishedAt, updatedAt, url, applyUrl, changeType, observedAt, and provenance. Source and apply links are kept only when they are HTTPS links on the expected ATS host; the board URL remains in provenance when a source supplies another career-site link.
changeType is one of:
NEW: a job not in the saved baseline.CHANGED: tracked job fields changed. In cross-ATS mode, description-only changes are ignored when content is not included.CLOSED: a previously open job is absent from a validated successful response.REOPENED: a previously closed job appears again.UNCHANGED: emitted only whenonlyChangesisfalse.
COMPANY_SIGNAL
One roll-up per companyKey in cross-ATS mode. openingCount, closureCount, changedCount, and reopenedCount summarize matched job events; openJobs is the current open baseline count. departmentDeltas and locationDeltas map labels to their change in count (positive for growth, negative for decline). status is degraded when any board for the run has an error or safety condition, and provenance.sources lists the contributing ATSs.
ERROR
An operational row for a failed board, malformed response, suspicious partial fetch, or valid-empty response. Cross-ATS errors identify the company, ATS, board token, status, and provenance without request credentials. A failed board keeps its prior state and suppresses closure inference. Legacy errors retain the legacy board token and error fields.
State and safety behavior
The Actor stores a version-3 envelope under GREENHOUSE_JOB_STATE, with separate cross-ATS jobs and legacy legacyJobs maps. State contains hashes and minimal job metadata, not descriptions. Older version-2 cross-ATS state is read without mixing it into legacy mode.
For a cross-ATS board, the prior baseline is preserved when the source is unavailable, returns malformed data, returns a valid empty list against a non-empty baseline, falls below partialFetchThreshold, exceeds the configured job cap, or reports a source total larger than the bounded fetch. These checks prevent a transient or truncated response from turning every role into CLOSED. Filters affect emitted rows only, so changing a filter does not erase or narrow the stored baseline.
Scheduling, API, and integrations
The Actor produces dataset rows; it does not send built-in hiring alerts, enrich contacts, or connect to a CRM. Use Apify platform capabilities around the run:
- Run it manually in the Apify Console, then create an Apify Schedule for recurring snapshots with the same input.
- Start runs and read the run dataset through the Apify API or CLI.
- Use Apify webhooks or integrations to hand completed-run/dataset events to your warehouse, dashboard, queue, or workflow tool.
Your downstream system decides what constitutes an alert and must handle ERROR and degraded COMPANY_SIGNAL rows.
Pricing and platform costs
The public Store listing marks this Actor Pay per usage. Apify bills compute units and other platform usage according to your subscription plan; actual cost varies with the number of boards and jobs, response sizes, retries, and run frequency. Check the Actor's current Store pricing tab and your plan for unit rates. This repository does not set a fixed per-result price or change Actor monetization.
Safety, privacy, and source rights
- Inputs are limited to canonical, unauthenticated public ATS boards. No login, credentials, applicant records, or personal-contact enrichment are used.
- Descriptions are excluded by default.
includeContent: trueemits cleaned text when available, but the text is employer-authored source content and is not saved in the baseline. - Public job postings show advertised hiring activity only. They are not proof of hiring budget, purchasing intent, company health, candidate suitability, or an employment outcome.
- Preserve the emitted provenance/source URLs and verify that your intended downstream storage, analysis, or redistribution complies with the ATS and employer's terms and applicable law. Downstream reuse rights remain your responsibility.
- This Actor is not affiliated with Greenhouse, Ashby, Lever, Recruitee, SmartRecruiters, or Workable.
Limits
- 50 boards per run
- 500 jobs per board
- 10 concurrent board fetches maximum in cross-ATS mode
- 5 retries per request maximum in cross-ATS mode; legacy Greenhouse mode does not retry
- 120-second request timeout maximum
- 10,000 emitted job-change rows maximum (company/error rows may also be emitted)
Synthetic fixture and local development
examples/demo-fixture.json contains synthetic, credential-free payloads covering all six ATS adapters. It is for tests and adapter demonstrations only: there is no demo mode, and its placeholder/acme-style URLs are not live endpoints. Repository tests use dependency injection and do not contact ATS services.
npm cinpm test
Troubleshooting and FAQ
Why did I get no job rows?
With onlyChanges: true, unchanged jobs are intentionally omitted. The first successful run establishes state; run again later to detect changes. In cross-ATS mode, a COMPANY_SIGNAL row is still produced, and an ERROR row explains a board failure or safety hold.
Why is a board URL rejected?
Use an HTTPS URL on one of the six accepted ATS hosts with no credentials, port, query, or fragment. Employer career pages and unsupported ATS hosts are not accepted.
Why did a board produce partial or valid-empty instead of closures?
The response looked truncated, exceeded a configured cap, contradicted a source total, or was empty against a non-empty baseline. The Actor preserves the prior state until a safe response arrives.
Why is contentText missing?
Set includeContent: true to request cleaned descriptions. Some sources may not provide content, and descriptions are never persisted in state.
Can I keep using my old Greenhouse input?
Yes. Pass boards with Greenhouse tokens or canonical Greenhouse URLs. Legacy rows and state remain isolated from cross-ATS state under the same Actor identity.
Can this prove an account is ready to buy, or identify candidates?
No. It reports public job-board changes only. It does not infer budget, intent, company health, candidate suitability, applicant identity, or contact details.