ATS Jobs Tracker: Greenhouse, Lever, Ashby & Workable Jobs avatar

ATS Jobs Tracker: Greenhouse, Lever, Ashby & Workable Jobs

Pricing

from $1.25 / 1,000 job exporteds

Go to Apify Store
ATS Jobs Tracker: Greenhouse, Lever, Ashby & Workable Jobs

ATS Jobs Tracker: Greenhouse, Lever, Ashby & Workable Jobs

Track open jobs at any company on Greenhouse, Lever, Ashby or Workable. Paste board slugs, careers URLs or names. Only-new mode for daily monitoring, repost detection, salary, remote and department fields, plus a free per-company hiring summary. No login, no proxies. $1.75 per 1,000 jobs.

Pricing

from $1.25 / 1,000 job exporteds

Rating

0.0

(0)

Developer

Destiny Lazcano

Destiny Lazcano

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Security

Limited permissions

Share

Export every open job at the companies you care about, straight from their public Greenhouse, Lever, Ashby and Workable job boards, and track hiring over time. Paste board slugs, careers URLs or company names. You get one clean row per job with title, department, location, remote flag, employment type, posting date, salary and links. You also get a free per-company hiring summary that shows how many roles are open, in which teams and where.

Built for recruiters and sourcing teams, sales teams who treat hiring as a buying signal, investors and analysts watching headcount growth, and job seekers and job boards that need fresh postings from specific employers.

Why this tracker

  • Four ATSs, one schema. Greenhouse, Lever (global and EU), Ashby and Workable are normalized into the same columns, so a mixed list of companies becomes one table.
  • Auto-detection. Give a slug or a name (stripe, Hugging Face, stripe.com) and the Actor tries each ATS in turn until it finds a public board.
  • Only-new monitoring mode. Schedule it daily: the first run exports everything up to your Maximum jobs to export, later runs export only postings you have not received before. Jobs you already have are never charged again.
  • Repost detection. When a role disappears and comes back under a new job ID with the same title and location, it is flagged isRepost: true with repostOf pointing at the old ID.
  • Salary everywhere it exists. Structured pay from Lever and Ashby, plus pay ranges parsed from the description text (for example $150,000—$180,000 USD on Greenhouse pay-transparency postings). compensationSource tells you which.
  • Free hiring summary per company in the key-value store: open jobs by department, location, workplace type and employment type, jobs posted in the last 7 and 30 days, median days open, median USD salary, and in monitoring mode new, closed and reposted counts.

Supported job boards

ATSPaste any of theseNotes
Greenhousehttps://job-boards.greenhouse.io/stripe, https://boards.greenhouse.io/airbnb/jobs/123, embed links with ?for=figma, or greenhouse:stripeSalary comes from the description text when the posting shows a range.
Leverhttps://jobs.lever.co/palantir, https://jobs.eu.lever.co/<site>, or lever:spotifyGlobal and EU instances are both checked.
Ashbyhttps://jobs.ashbyhq.com/openai, or ashby:rampStructured compensation included. Unlisted (direct-link only) jobs are skipped.
Workablehttps://apply.workable.com/huggingface/, https://acme.workable.com, or workable:huggingfaceA /j/<code> job link does not name the company, so use the company page.

Custom careers domains (for example careers.airbnb.com) are reduced to a name guess (airbnb) and auto-detected. Careers pages hosted on a shared platform or another ATS (Notion, GitHub Pages, Workday, SmartRecruiters, BambooHR, Gusto, Wellfound, Y Combinator and similar) are rejected with a clear error instead, because their domain names the vendor, not the employer. Paste the company's board link or name for those.

Input examples

Three companies on three different ATSs (this is the prefilled example input in Console). companies is required and has no default. Without maxJobs an API or scheduled run uses 1,000.

{ "companies": ["discord", "https://jobs.ashbyhq.com/linear", "https://apply.workable.com/huggingface/"], "maxJobs": 100 }

Remote engineering roles posted in the last 14 days, with descriptions:

{
"companies": ["stripe", "figma", "https://jobs.lever.co/palantir", "ashby:ramp"],
"keywords": ["engineer", "developer"],
"excludeKeywords": ["intern"],
"remoteOnly": true,
"postedWithinDays": 14,
"includeDescription": true
}

Daily monitoring of a watch list (pair it with an Apify Schedule):

{ "companies": ["stripe", "cloudflare", "lever:spotify"], "onlyNew": true, "stateKey": "competitors" }

Filters: keywords and excludeKeywords match whole words or phrases in the job title, ignoring case. Plural, -ing, -er and -ship forms also match, so engineer matches "Engineering Manager" and intern matches "Internship" but not "Internal Audit" or "International Tax". locations match whole words in the location text. A country name or abbreviation (United States, USA, US, United Kingdom, UK, Germany, ...) also matches the job's country code, whatever form the ATS uses. Remote matches remote-flagged jobs. Greenhouse publishes no country, so there a country filter matches only when the location text names the country. departments match department or team. postedWithinDays uses Greenhouse first_published, Lever createdAt, Ashby publishedAt and Workable published_on. Jobs with no date are kept.

Output

One row per job, de-duplicated by ATS + company + job ID:

ColumnExample
ats, company, companyNamegreenhouse, discord, Discord
jobId, jobKey, title8917177002, greenhouse:discord:8917177002, Associate Commercial Counsel
department, teamLegal
location, allLocations, countrySan Francisco Bay Area or Remote (U.S.), ..., US (ISO code when the ATS gives a country)
isRemote, workplaceTypetrue, remote / hybrid / onsite / empty. Hybrid jobs are isRemote: false unless one of their locations is remote.
employmentTypeFull-time, Part-time, Contract, Internship, ...
postedAt, updatedAt, daysOpen2026-11-03T16:27:16Z, 2
compensation, salaryMin, salaryMax, salaryCurrency, salaryInterval, compensationSource$200,000—$225,000 USD, 200000, 225000, USD, year, description
jobUrl, applyUrl, boardUrllinks to the employer's own posting
descriptionplain text, only with Include job description
isNew, isRepost, repostOf, firstSeenAtonly-new mode only
scrapedAtwhen the board was read

Dates are ISO 8601 in UTC. Workable publishes dates without a time, so its postedAt is a plain date. Lever and Ashby publish no update time, and Lever's date is when the posting was created. companyName is filled where the ATS publishes it (Greenhouse and Workable).

The key-value store also holds HIRING_SUMMARY (free, one entry per company, computed over the whole board before your filters) and RUN_REPORT (what was read, what was found, what failed and why).

Pricing

Pay per job delivered to your dataset. The summary, the report, closed-job notices and skipped already-seen jobs are free.

Apify planPrice per jobPer 1,000 jobs
Free and Bronze$0.00175$1.75
Silver$0.00150$1.50
Gold and above$0.00125$1.25

Apify's standard run-start fee ($0.00005) applies. Your run's Maximum cost per run is respected: at $1.75 per 1,000 jobs a $1.00 cap allows 571 jobs, and the run stops cleanly with a status message saying so. Maximum jobs to export caps a run too.

Monitoring with Apify Schedules

  1. Turn on Only new jobs and give your list a Monitoring list name.
  2. Raise Maximum jobs to export for the first run (the Console prefill is 100) so it covers every open job on your list. Run once. Everything currently open is exported and remembered, up to that maximum.
  3. In Console, create a Schedule (for example daily at 07:00) that runs this Actor with the same input.
  4. Each later run exports only new postings and updates HIRING_SUMMARY with new, closed and reposted counts. Connect a webhook, Slack or Google Sheets integration to get the new rows automatically.

If a run stops at the maximum, the jobs it did not reach come in later runs as isNew: false rows, and companies after the cut are not checked (no HIRING_SUMMARY entry) in that run.

The memory lives in your own account, in the named key-value store ats-jobs-tracker-state-<name>. Delete that store to start over. A job that was filtered out earlier is exported the first time it matches your filters.

Limits and good citizenship

  • Reads only the public, unauthenticated job-board endpoints each ATS documents for careers pages and widgets. It never logs in, never submits applications and never touches candidate data.
  • One honest User-Agent, no proxies, no cookies, at most one request per second per host. When an ATS answers 401, 403, 429, 451, 503 or a bot check, that answer is recorded as refused and the Actor sends no further requests to that ATS for the rest of the run. Every later company on it is reported as refused too. A name being auto-detected is then also reported as refused instead of being matched on another ATS, so it never resolves to the wrong company's board. Network errors and other 5xx are retried once.
  • One company failing (wrong slug, 404, timeout) never stops the run. The status message names the failures and RUN_REPORT gives the details.
  • Up to 500 companies and 100,000 jobs per run. Large boards (several MB) take a few seconds each.
  • Job-board content belongs to each employer. Link back with jobUrl and respect each employer's terms when you republish. Workable marks its pages as not for AI training.

FAQ

A company was "not found". It may use another ATS, a different slug, or no public board at all. Open its careers page, copy the link to its job board and paste that instead of the name.

Why is the salary empty? The employer did not publish one. Ranges are read from structured fields first and from the description text second. Single numbers are ignored on purpose to avoid false matches.

Do I get duplicate rows across runs? Not in only-new mode. Without it, each run is a full snapshot.

Why does Greenhouse not show workplaceType? Greenhouse has no standard field. It is read from a custom "Workplace Type" field when the company has one. Some boards (Cloudflare, for example) put "Hybrid", "In-Office" or "Distributed" where the location should be. That value becomes workplaceType, and the location is taken from a location custom field or the offices. Otherwise isRemote falls back to "remote" in the location or title.

Something looks wrong. Open an issue on the Issues tab with your input JSON. Issues are answered within two business days.