Echo Lab Tools

Echo Lab Tools › ATS jobs

Pull open jobs from Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee in one dataset

The ATS jobs scraper is an Apify Actor that fetches open job postings from the public job board APIs of Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee and returns them in one normalized JSON schema: title, department, location, remote/hybrid status, structured salary when the employer publishes it, dates and apply links.

What you get

  • One schema for six ATS job board APIs; input is greenhouse:airbnb, a board URL or a bare slug
  • Structured salary (min, max, currency, period) from Greenhouse, Lever, Ashby and Recruitee when published
  • Filters for title keywords, location, remote-only and posting date; optional plain-text descriptions

Price: $1.50 per 1,000 job postings + $0.00005 per runLogin needed: noRuns on: Apify (API, schedule, MCP)

Run the ATS jobs scraper on Apify →See real output ↓

How it works

List the job boards you want, in any of three forms: greenhouse:airbnb, a board URL such as https://jobs.lever.co/spotify, or a bare slug like ramp. A bare slug is tried on Greenhouse, then Lever, then Ashby, and the first populated board wins. Lever's EU API is tried automatically after a 404 on the global one.

The Actor calls each ATS's official, keyless job board API (boards-api.greenhouse.io, api.lever.co, api.ashbyhq.com, apply.workable.com, api.smartrecruiters.com and company recruitee.com APIs), maps every posting into the same fields, applies your filters, and pushes each job as soon as it is ready. Boards that are invalid or fail are skipped without billing and listed in a SUMMARY record with the reason. Recruiter and hiring-manager contact fields are never copied, and emails and phone numbers in descriptions are redacted.

Sample output

One row from a real run on the Apify platform (run I1xMk6IPKPAjd4QsD, build 0.1.5, 2026-11-06), which pulled 25 postings each from Airbnb's and Stripe's Greenhouse boards:

{
  "ats": "greenhouse",
  "company": "airbnb",
  "companyName": "Airbnb",
  "jobId": "8306554",
  "title": "AirCover Specialist, Claims Experience",
  "department": "Community Support",
  "team": null,
  "employmentType": null,
  "workplaceType": "remote",
  "isRemote": true,
  "location": "Canada",
  "allLocations": [
    "Canada"
  ],
  "country": null,
  "salaryMin": 58000,
  "salaryMax": 68000,
  "salaryCurrency": "CAD",
  "salaryPeriod": "year",
  "salaryText": "Canada Annual Pay Range",
  "publishedAt": "2026-10-28T14:52:05Z",
  "updatedAt": "2026-10-28T14:52:05Z",
  "jobUrl": "https://careers.airbnb.com/positions/8306554?gh_jid=8306554",
  "applyUrl": "https://careers.airbnb.com/positions/8306554?gh_jid=8306554",
  "scrapedAt": "2026-11-06T04:23:16.670356Z"
}

What the 50 rows of that run looked like:

What each ATS provides

This is the part most job scrapers skip. The six APIs expose different fields; the table shows what our normalizer can fill for each. Individual employers may still leave fields empty.

ATS Department Team Employment type Remote / hybrid Structured salary Extra locations
Greenhouse ✓ — — Only via the board's "Workplace Type" field or a "remote" location ✓ when the board publishes pay ranges —
Lever ✓ ✓ ✓ (commitment) ✓ ✓ when set ✓
Ashby ✓ ✓ ✓ ✓ (workplace type + remote flag) ✓ when published ✓
Workable if set — ✓ ✓ (telecommuting flag) — ✓
SmartRecruiters ✓ — ✓ ✓ (remote / hybrid flags) — —
Recruitee if set — ✓ ✓ (remote / hybrid / on-site) ✓ when set ✓

Output fields

Field Type Example Meaning
ats, company, companyName string greenhouse, airbnb Source ATS, input slug, company name if supplied
jobId, title string 8306554 Source ID and job title
department, team, employmentType string / null Community Support As classified by the source, never guessed
workplaceType, isRemote string / boolean / null remote, true remote, hybrid, onsite or null; remote eligibility
location, allLocations, country string / array Canada Primary and additional locations
salaryMin, salaryMax, salaryCurrency, salaryPeriod, salaryText number / string / null 58000, 68000, CAD Structured pay range and source label
publishedAt, updatedAt, scrapedAt string 2026-10-28T14:52:05Z ISO 8601 UTC
jobUrl, applyUrl string — Public posting and application links
description string — Only with includeDescription; plain text, max 20,000 characters

How much does it cost to scrape job postings?

Pricing is per result: $1.50 per 1,000 job postings ($0.0015 per job) plus $0.00005 per run, platform usage included. Failed boards are not billed.

Worked examples: the sample run above saved 50 postings, $0.075. A weekly pull of every opening at 20 companies that average 150 postings each is 3,000 rows, $4.50 per week. A daily alert with postedWithinDays: 1 only bills for postings published in the last day that match (undated postings always pass the filter), so watching 100 boards that post 60 matching jobs a day costs about $0.09 a day. Use maxJobs and maxJobsPerCompany to cap any run. Apify's free plan includes $5 a month for Store tools (apify.com/pricing, checked 2026-11-06).

Limits you should know about

  1. Six ATS only. Workday, iCIMS, Taleo, LinkedIn and Indeed are not supported: they do not offer the public, keyless job board APIs this tool relies on.
  2. You need the board slug. The tool reads boards you name; it does not discover which companies use which ATS. Bare slugs are only tried on Greenhouse, Lever and Ashby.
  3. Salaries come only from structured fields. Nothing is guessed from description text, currencies and periods are not converted, and a Greenhouse period is only set when the range title names it.
  4. Completeness depends on each employer. Missing departments, dates or salaries are null. Workable's widget API can return an empty board even when the company's other careers page shows openings.
  5. No cross-run memory. Each run returns the current postings; there is no stored diff between runs. postedWithinDays filters by publish date, which is the practical way to get "new since yesterday".

API: call it from code

curl -X POST "https://api.apify.com/v2/acts/echolab~ats-jobs-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companies": ["greenhouse:airbnb", "lever:spotify", "ashby:ramp"], "keywords": ["engineer"], "remoteOnly": true, "maxJobsPerCompany": 10}'

Python, keeping only postings with a published salary:

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("echolab/ats-jobs-scraper").call(run_input={
    "companies": ["greenhouse:airbnb", "lever:spotify", "ashby:ramp"],
    "postedWithinDays": 7,
    "maxJobsPerCompany": 0,      # 0 = no per-board cap
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    if job["salaryMin"] is not None:
        print(job["companyName"] or job["company"], job["title"], job["salaryMin"], job["salaryMax"], job["salaryCurrency"])

ATS jobs scraper vs. alternatives

Option Good for Trade-off
This Actor A known list of companies on these six ATS, normalized into one schema, paid per job No company discovery; no Workday/iCIMS/Taleo
Calling each ATS API yourself Free and well documented, fine for one ATS Six schemas, pagination styles and salary formats to map and maintain
LinkedIn / Indeed scrapers Companies without a public ATS board Behind logins and anti-bot systems; more fragile; terms-of-service risk
Commercial job-data feeds Millions of pre-indexed companies, history, company discovery Subscription or contract pricing

When not to use it: if your target companies run Workday or iCIMS, or you need to find every company hiring for a role across the web, use a commercial job-data feed. If you only follow one Greenhouse board, its API is free and simple. This tool fits when you track tens or hundreds of named companies across several ATS and want one clean table.

Open the ATS jobs scraper on Apify for the full input schema.

Changelog

  • 2026-11-06 — build 0.1.5: boards that send "metadata": null (Stripe's Greenhouse board does) no longer lose every posting; a board whose postings all fail to parse now counts as failed instead of OK.
  • 2026-11-05 — first public release on the Apify Store with pay-per-result pricing ($1.50 per 1,000 jobs).

Run the ATS jobs scraper on Apify →