ATS Job Board Monitor avatar

ATS Job Board Monitor

Pricing

from $1.00 / 1,000 job rows

Go to Apify Store
ATS Job Board Monitor

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

Steadfeed

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Categories

Security

Limited permissions

Share

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

  1. You list companies as career-page URLs, ats:slug prefixes, or bare names.
  2. Each run fetches every board through that ATS's official public job-board endpoint and normalizes the jobs to one schema.
  3. 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.
  4. 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

ATSExample inputNotes
Greenhousehttps://boards.greenhouse.io/stripe, greenhouse:stripe, gh:stripeOptional pay ranges (one extra request per job). EU-hosted Greenhouse boards are not supported yet.
Leverhttps://jobs.lever.co/palantir, lever:palantirEU boards: https://jobs.eu.lever.co/olx or lever-eu:olx.
Ashbyhttps://jobs.ashbyhq.com/openai, ashby:openaiIncludes compensation when the company publishes it.
Workablehttps://apply.workable.com/huggingface/, workable:huggingfaceWorkable rate-limits hard, so requests are spaced out more.
SmartRecruitershttps://careers.smartrecruiters.com/Ubisoft2, smartrecruiters:Ubisoft2Optional descriptions and apply links (one extra request per job).
Recruitee (optional)https://bunq.recruitee.com, recruitee:bunqOff 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) or snapshot (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, both or none. Use none for 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")

FieldMeaning
changeTypeNEW, CHANGED or CLOSED. Snapshot mode also outputs UNCHANGED rows, so you get every current job plus the ones that just closed.
changedFields, previousFor CHANGED rows: which fields changed, and their old values
ats, region, companySlug, companyNameWhere the job came from
jobId, jobKeyThe ATS's job ID and a stable global key (ats:slug:jobId, lever-eu:… for Lever EU)
title, department, teamAs published by the company
locations, location, workplaceTypeA list of locations, a joined string, and remote / hybrid / onsite / null
employmentType, compensationWhen the ATS provides them
postedAt, updatedAtFrom the ATS, when available
firstSeenAt, lastSeenAt, closedAtTracked by this Actor
jobUrl, applyUrlPublic links
descriptionText / descriptionHtmlAccording to descriptionFormat
sourceApiUrl, checkedAtAudit 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.

StatusMeaning
okThe board was read. Zero jobs is possible.
not_foundThe ATS says the board does not exist
not_found_or_no_jobsSmartRecruiters returns an empty result both for unknown companies and for companies with no open jobs, so the two can't be told apart
empty_unconfirmedA board that had jobs returned none; see the safety rules below
auth_requiredRecruitee asked for a token
errorNetwork or server failure after retries. The board's memory is kept unchanged.
invalid_input / skippedThe 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 error status 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 descriptionHash in changedFields (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 the watchlistId or 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.

EventPriceWhen
Run start$0.005 per runOnce per run (twice if you raise memory above 1 GB)
Company checked$0.0005 per boardEach board checked successfully
Job row$0.001 per rowEach 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 SUMMARY show how many rows were free and how many free rows you have left. Each status row shows freeJobRows, chargedJobRows and freeBaseline.
  • The allowance is tracked in a key-value store named steadfeed-ats-monitor-billing in 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)

UseEstimate
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 dayabout $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 companyName is the board slug.
  • Greenhouse has no structured workplace or employment type. workplaceType is 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.