ATS Job Board Monitor
Pricing
from $1.00 / 1,000 job rows
ATS Job Board Monitor
Monitor company job boards on Greenhouse, Lever (US + EU), Ashby, Workable and SmartRecruiters (Recruitee optional). Get only the new, changed and closed jobs since your last run, in one normalized format. By Steadfeed.
Pricing
from $1.00 / 1,000 job rows
Rating
0.0
(0)
Developer
Steadfeed
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Security
Limited permissionsShare
ATS Job Board Monitor: new, closed and changed jobs from company career pages
By Steadfeed. Watch the job boards of the companies you care about and get only what changed since your last run: new jobs, closed jobs, and jobs whose title, location, pay or description changed. Works with Greenhouse, Lever (US and EU), Ashby, Workable and SmartRecruiters, plus Recruitee as an option. It reads each company's own public job-board API live, so any company on a supported ATS works, not just companies in a pre-built database.
Free to start: the first check of every board you add is free, and you get 500 free job rows each month (see Pricing).
What you can use it for
- Recruiting and sales signals: see the day a target account opens (or quietly closes) roles.
- Job seekers and job boards: get an alert feed of new roles at a shortlist of companies, filtered by title, location, team or remote.
- Market research: track hiring velocity per company over time with stable first-seen and closed dates.
How it works
- You list companies as career-page URLs,
ats:slugprefixes, or bare names. - Each run fetches every board through that ATS's official public job-board endpoint and normalizes the jobs to one schema.
- In diff mode (default), the Actor compares each board with what it saw last time and outputs one row per NEW, CHANGED or CLOSED job. Its memory lives in a named key-value store in your account, so scheduled runs pick up where the last one left off.
- Each company also gets a status row (
ok,not_found,error…), so a broken board never looks like "no changes".
Run it on a schedule (for example daily or every 6 hours) and connect the dataset to email, Slack, Google Sheets or a webhook through Apify integrations.
Supported ATSs
| ATS | Example input | Notes |
|---|---|---|
| Greenhouse | https://boards.greenhouse.io/stripe, greenhouse:stripe, gh:stripe | Optional pay ranges (one extra request per job). EU-hosted Greenhouse boards are not supported yet. |
| Lever | https://jobs.lever.co/palantir, lever:palantir | EU boards: https://jobs.eu.lever.co/olx or lever-eu:olx. |
| Ashby | https://jobs.ashbyhq.com/openai, ashby:openai | Includes compensation when the company publishes it. |
| Workable | https://apply.workable.com/huggingface/, workable:huggingface | Workable rate-limits hard, so requests are spaced out more. |
| SmartRecruiters | https://careers.smartrecruiters.com/Ubisoft2, smartrecruiters:Ubisoft2 | Optional descriptions and apply links (one extra request per job). |
| Recruitee (optional) | https://bunq.recruitee.com, recruitee:bunq | Off by default; see the Recruitee section below. |
Bare names such as notion are probed in this order: Greenhouse, Lever US, Lever EU, Ashby, Workable, SmartRecruiters (then Recruitee if enabled). The first board with jobs wins. Probing costs extra requests and can match a different company that uses the same slug on another ATS, so use URLs or prefixes for anything important. The status row shows detectedBy: "probe".
Input example
{"companies": ["https://boards.greenhouse.io/stripe","lever:palantir","lever-eu:olx","https://jobs.ashbyhq.com/openai","workable:huggingface","smartrecruiters:Ubisoft2"],"mode": "diff","watchlistId": "my-targets","titleKeywords": ["engineer", "developer"],"excludeTitleKeywords": ["intern"],"locationKeywords": ["London", "Remote"],"descriptionFormat": "text"}
Main options:
- mode:
diff(changes only) orsnapshot(every current job on every run, still labelled NEW/CHANGED/UNCHANGED/CLOSED). - emitOnFirstRun (diff mode): on the first run of a watchlist, output all current jobs as NEW (default) or just record them silently. Snapshot mode ignores this setting and always outputs every current job.
- watchlistId: keeps the memory of separate watchlists apart. The same company in two watchlists is tracked independently.
- Filters: title includes/excludes, location (matches "remote" for remote jobs too), department/team, workplace type (remote / hybrid / onsite), keep-unknown-workplace.
- descriptionFormat:
text,html,bothornone. Usenonefor the smallest, cheapest-to-store output. - maxJobRowsPerRun: a hard cap on job rows per run. Rows that don't fit are not lost; they are reported on the next run.
- Politeness: parallel boards, minimum gap between requests to the same host, a separate Workable gap, and retries.
Output
Job rows (recordType: "job")
| Field | Meaning |
|---|---|
changeType | NEW, CHANGED or CLOSED. Snapshot mode also outputs UNCHANGED rows, so you get every current job plus the ones that just closed. |
changedFields, previous | For CHANGED rows: which fields changed, and their old values |
ats, region, companySlug, companyName | Where the job came from |
jobId, jobKey | The ATS's job ID and a stable global key (ats:slug:jobId, lever-eu:… for Lever EU) |
title, department, team | As published by the company |
locations, location, workplaceType | A list of locations, a joined string, and remote / hybrid / onsite / null |
employmentType, compensation | When the ATS provides them |
postedAt, updatedAt | From the ATS, when available |
firstSeenAt, lastSeenAt, closedAt | Tracked by this Actor |
jobUrl, applyUrl | Public links |
descriptionText / descriptionHtml | According to descriptionFormat |
sourceApiUrl, checkedAt | Audit trail |
Example CHANGED row (shortened):
{"recordType": "job", "changeType": "CHANGED", "changedFields": ["title", "locations"],"previous": { "title": "Software Engineer", "locations": ["Berlin"] },"ats": "lever", "region": "eu", "companySlug": "olx", "jobId": "…","title": "Senior Software Engineer", "locations": ["Berlin", "Remote"],"firstSeenAt": "2026-10-31T09:14:20.000Z", "lastSeenAt": "2026-11-01T09:14:03.000Z"}
Company status rows (recordType: "companyStatus")
One per company per run: status, message, detectedBy, jobsFound, jobRowsOutput, freeJobRows, chargedJobRows, freeBaseline, freeBaselinePending, deferred, new, changed, closed, unchanged, firstRun, durationMs. Turn them off with statusRowsInDataset: false. A run summary (SUMMARY) and all statuses (COMPANY_STATUS) are also saved to the run's key-value store.
| Status | Meaning |
|---|---|
ok | The board was read. Zero jobs is possible. |
not_found | The ATS says the board does not exist |
not_found_or_no_jobs | SmartRecruiters returns an empty result both for unknown companies and for companies with no open jobs, so the two can't be told apart |
empty_unconfirmed | A board that had jobs returned none; see the safety rules below |
auth_required | Recruitee asked for a token |
error | Network or server failure after retries. The board's memory is kept unchanged. |
invalid_input / skipped | The entry was not understood, or it was skipped because Recruitee is off. When a run reaches its row limit or spending limit, the remaining boards are skipped with deferred: true. They are checked on the next run and are not counted as needing attention. |
Dataset views
In the Output tab, Changes shows the job rows and Company status shows the health of each board.
Diff mode: the safety rules
- Failed boards never close jobs. If a board errors, its jobs stay as they were and you get an
errorstatus row. - An empty board must be empty twice. If a board that had jobs suddenly returns none, the Actor waits for a second empty run before reporting everything as CLOSED. This guards against ATS outages.
- Filters only affect output. All jobs are tracked, so changing your filters never produces fake NEW or CLOSED rows.
- Description changes are detected from a hash of the published text. They show as
descriptionHashinchangedFields(the hash is not output). - Memory is kept in the named key-value store
steadfeed-ats-monitor-state(configurable), one record per watchlist and board. To start fresh, change thewatchlistIdor delete those records.
Recruitee (optional)
From 10 February 2027, Recruitee's public Careers Site API requires a token for each company (X-Careers-Sites-Token). Until then, public boards still answer without one. Turn on Enable Recruitee and, if you have one, add a token per company (company=token, one per line). A Careers Site token has the same permissions as the Recruitee user who created it, so only use a token you are allowed to use, and store it in this secret field only. Without a token after that date, boards will return auth_required.
Privacy
This Actor only reads public job postings that companies publish for applicants. Email addresses, phone numbers and "Recruiter: / Contact: name" lines are removed from descriptions. This also removes generic company addresses such as accommodation or HR mailboxes. Recruiter and hiring-manager fields from the ATS are not output. Don't use the output to contact individuals in breach of applicable law.
Memory and run time
The default of 512 MB is plenty for typical watchlists. In platform tests, 20 boards with 7,915 jobs (including a 5,019-job board) peaked at about 250 MB and took about 37–39 s. Small watchlists run fine at 256 MB. Raise memory only for very large watchlists with full descriptions.
Rate limits and reliability
Requests are spaced per host (500 ms by default, 1,500 ms for Workable). Retries with backoff cover 408/425/429/5xx and network errors, and Retry-After is respected. Very large boards (5,000+ jobs, for example SmartRecruiters) take longer. Extra detail options (Greenhouse pay ranges, SmartRecruiters descriptions) make one request per job, capped by maxDetailRequestsPerCompany.
Pricing
Pay per event. You pay only for these events; there is no separate charge for compute or storage.
| Event | Price | When |
|---|---|---|
| Run start | $0.005 per run | Once per run (twice if you raise memory above 1 GB) |
| Company checked | $0.0005 per board | Each board checked successfully |
| Job row | $0.001 per row | Each job row output (NEW, CHANGED, CLOSED, or a snapshot row) |
Status rows and unchanged jobs are never charged.
Free tier
- Free first check of every board. The first time your Apify account checks a board, that check and its baseline rows are free. This applies to up to 100 new boards per month. If a row limit or spending limit cuts the baseline short, the board keeps its free baseline. The rows not output yet, and the checks, stay free on your next runs (for up to 14 days). Adding the same board again later (for example in a new watchlist) is charged normally.
- 500 free job rows every month (calendar month, UTC). After that, rows are charged.
- Each run's status message and
SUMMARYshow how many rows were free and how many free rows you have left. Each status row showsfreeJobRows,chargedJobRowsandfreeBaseline. - The allowance is tracked in a key-value store named
steadfeed-ats-monitor-billingin your own account. Deleting it does not refund past charges. Two runs started at exactly the same time can share the same remaining free rows.
Example costs (estimates, at the prices above)
| Use | Estimate |
|---|---|
| First run on 20 boards | $0.005 (only the run start; the baseline is free) |
| Daily diff on 20 boards with about 10 changes per day | about $0.025 per run, about $0.45 per month after the 500 free rows |
| One snapshot of a 1,000-job board, after its free baseline | $0.005 + $0.0005 + about $0.50 for rows after the free allowance |
Spending limit: set a maximum charge per run. The Actor then outputs as many changes as fit, stops cleanly, and reports the rest on the next run, so nothing is lost.
Known limits
- Lever and Ashby don't publish a company display name, so
companyNameis the board slug. - Greenhouse has no structured workplace or employment type.
workplaceTypeis inferred from location text ("Remote", "Hybrid") when possible. - EU-hosted Greenhouse boards (
*.eu.greenhouse.io) are not supported in this version. - Only Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee are supported. Workday, iCIMS and others are not.
FAQ
Can I get only new jobs? Yes. That is the default (diff mode). Filter changeType = NEW in the dataset or integration.
Do I get closed jobs without an add-on? Yes. CLOSED rows with closedAt are part of the same output.
What does the first run cost? Only the run start. The first check of each new board, and its baseline rows, are free (up to 100 new boards a month).
Why is there a steadfeed-ats-monitor-billing store in my account? It counts your free rows and free baselines. It holds board names and counters only, no job data.
My company isn't found. Open its careers page, copy the job-board URL (for example jobs.lever.co/…) and use that instead of the name.
Steadfeed is not affiliated with Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee. Trademarks belong to their owners.