ATS Jobs Scraper (All In One)
Pricing
from $0.56 / 1,000 results
ATS Jobs Scraper (All In One)
Scrapes live jobs from four ATS platforms — Ashby, BambooHR, Breezy HR and SmartRecruiters — into one unified schema. Paste mixed career page URLs and each is routed automatically. Split city/state/country, ISO 8601 UTC dates, and descriptions as clean Markdown for LLM use.
Pricing
from $0.56 / 1,000 results
Rating
0.0
(0)
Developer
Ibnu Adzim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Share
All-in-One ATS Jobs Scraper
Scrapes live job postings from four applicant tracking systems — Ashby, BambooHR, Breezy HR and SmartRecruiters — and returns them in one unified schema.
Paste a mixed list of career page URLs. The Actor works out which ATS each one belongs to from the URL and routes it automatically, so you never have to sort your list by platform or run four different scrapers and reconcile the output yourself.
Public data only. No login, no cookies, no browser, and no bot challenge on any of the four — every one of 8 TLS fingerprints tested returned a clean 200 from an ordinary residential connection.
Why one Actor instead of four
The four platforms differ in transport — how they paginate, whether descriptions arrive with the listing or need a second request, what they do when a company does not exist. They do not differ in purpose: each is a company-scoped public job board.
Which ATS a company runs is an implementation detail its candidates never chose and should not have to care about. If you are tracking 200 companies, some are on Ashby and some are on BambooHR, and what you want is one table. Reconciling four location shapes, four employment-type vocabularies and four timestamp formats is the hard part of this job — so the Actor does it, once, rather than handing you the same problem four times.
Supported URL forms
| ATS | Career page URL | Single job URL |
|---|---|---|
| Ashby | https://jobs.ashbyhq.com/posthog | https://jobs.ashbyhq.com/posthog/<uuid> |
| BambooHR | https://nectar.bamboohr.com/careers | https://nectar.bamboohr.com/careers/157 |
| Breezy HR | https://boldare.breezy.hr | https://boldare.breezy.hr/p/<id> |
| SmartRecruiters | https://jobs.smartrecruiters.com/BoschGroup | https://jobs.smartrecruiters.com/BoschGroup/<id> |
A URL naming one job scrapes just that posting. The shorthand
platform:company works too — ashby:posthog, bamboohr:nectar,
breezy:boldare, smartrecruiters:BoschGroup.
If a company's careers page is on its own domain (careers.acme.com), it is
usually just embedding one of these four. Use the ATS URL its Apply button
points at.
What you get
Three record types share one dataset, told apart by recordType.
JOB — one row per posting
Every job row has the same fields regardless of which ATS it came from:
{"atsPlatform": "ashby","companySlug": "vanta","companyName": "Vanta","jobId": "f8af3807-3595-4580-a65c-dad2e268ace5","title": "Technical Account Executive - EMEA","jobUrl": "https://jobs.ashbyhq.com/vanta/f8af3807-…","applyUrl": "https://jobs.ashbyhq.com/vanta/f8af3807-…/application","department": "Sales & Customer Success","team": "New Business Sales","employmentType": "FULL_TIME", // FULL_TIME | PART_TIME | CONTRACT// | INTERNSHIP | TEMPORARY// | VOLUNTEER | OTHER"workplaceType": "REMOTE", // REMOTE | HYBRID | ONSITE"location": {"raw": "Remote U.S.","city": null,"state": null,"country": "United States","countryCode": "US", // ISO 3166-1 alpha-2"postalCode": null,"latitude": null,"longitude": null,"isRemote": true},"secondaryLocations": [ /* same shape */ ],"publishedAt": "2026-06-12T09:30:02Z", // ISO 8601, always UTC"updatedAt": null,"compensation": { "raw": "…", "minimum": 150000, "maximum": 190000,"currency": "USD", "interval": "YEARLY" },"descriptionHtml": "<h2>About…","descriptionMarkdown": "## About…", // clean Markdown, for LLM/RAG use"descriptionText": "About…","isListed": true,"raw": { /* upstream's object, verbatim */ }}
raw keeps the untouched upstream object, so nothing is lost to
normalisation and you can always reach a platform-specific field the unified
schema does not model.
BOARD_SUMMARY — one row per career page
The board's own job count, how many rows this run took, how many requests it cost, and the honesty flags below.
ERROR — one row per input that failed
Every input URL produces at least one row, so a board that 404s or a URL that is not an ATS at all is visible in the dataset rather than silently missing.
Descriptions as Markdown
ATS job descriptions are HTML written in rich-text editors: inline styles,
spacer paragraphs, nested lists. descriptionMarkdown is that HTML converted
to clean Markdown with ATX headings, which is what makes this dataset directly
usable as LLM input without a second cleaning pass.
On SmartRecruiters the description arrives as four separate blocks — company description, job description, qualifications, additional information. They are concatenated in the order the real job page shows them, each under its own heading, rather than being flattened into one undifferentiated wall of text.
Cost: the includeDescription switch
This is the Actor's main cost lever, and it behaves differently per platform:
| ATS | Requests with descriptions | Requests without |
|---|---|---|
| Ashby | 2 per board, any number of jobs | 1 per board |
| BambooHR | 1 + 1 per job | 1 per board |
| Breezy HR | 1 + 1 per job | 1 per board |
| SmartRecruiters | 1 per 100 jobs + 1 per job | 1 per 100 jobs |
Ashby ships the full description inside the board response, so descriptions there are effectively free.
One caveat: turning descriptions off on BambooHR also drops
location.country and publishedAt, because that platform only returns them
on the per-job response.
Known limits and honest flags
A nonexistent SmartRecruiters company looks exactly like a real one with no
open jobs. It answers totalFound: 0 either way, and no other endpoint
distinguishes them — jobs.smartrecruiters.com/<company> and
careers.smartrecruiters.com/<company> redirect identically for a real-but-empty
company and a misspelt one. Rather than report a confident "0 jobs", the
summary row sets companyExistenceUnverified: true and the run logs a
warning. The other three platforms are honest: Ashby and Breezy return 404,
BambooHR redirects away.
workplaceType is left null rather than guessed. Some Ashby postings
carry no workplace field at all; where the location text does not clearly say
remote or hybrid, the Actor emits null instead of assuming on-site.
BambooHR exposes no company display name. Its API has no such field and
every tenant's careers page is titled "BambooHR", so companyName falls back
to the URL slug there. Ashby's name is read from the board page and falls back
to the slug on the minority of tenants that serve an un-rendered page.
pageSize only affects SmartRecruiters. It is the only one of the four
that paginates; the others return their whole board in a single response. It is
capped at 100 because SmartRecruiters silently clamps anything higher back to
100 while still reporting success.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
startUrls | array | — | Required. Mixed career page URLs. |
includeDescription | boolean | true | Full descriptions + Markdown. |
maxItems | integer | 0 | Jobs per board; 0 = all. |
pageSize | integer | 100 | SmartRecruiters only. Max 100. |
maxConcurrency | integer | 6 | Total requests in flight. |
minRequestInterval | integer | 0 | Seconds between request starts. |
proxyConfiguration | object | Residential | Not needed to get past a bot wall — there isn't one. |
Notes on politeness
None of these platforms rate-limited during testing, but many of these boards
belong to small companies rather than enterprises. The defaults are modest on
purpose, and minRequestInterval — not maxConcurrency — is the honest speed
control: once a rate cap binds, extra concurrency buys nothing.
See CRAWLING_METHOD.md for the full recon trail, the endpoints, and every trap found while building this.