Career Site Jobs Scraper - $0.55/1k, 10 ATS
Pricing
from $0.55 / 1,000 job scrapeds
Career Site Jobs Scraper - $0.55/1k, 10 ATS
Paste a company career page URL or company name and get every open job: title, location, department, employment type, posted date, apply link and the ATS detected for you. 10 ATS families. $0.55 per 1,000 jobs, flat on every plan — the cheapest career-site job scraper on the market.
Pricing
from $0.55 / 1,000 job scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Career Site Jobs Scraper
Give it a company career page — or just a company name — and get back every open job on it: title, location, department, employment type, posted date, a direct apply link, and which applicant tracking system the page is actually running on. It reads the public job-board feed that the company's own careers widget reads, across Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, Breezy HR and Workday. No account, no cookies, no login, no browser rendering.
- Paste a careers URL, a bare domain, a board URL you already know, or a plain company name — all four work.
- The applicant tracking system is detected for you and reported on every row, so you never have to look it up first.
- Ten ATS families supported, covering the large majority of company career pages that publish an open job feed.
- Many companies resolve in a single request, because the board is identified before anything heavy is fetched.
- Runs with empty input return a labelled sample row, free, so you can see the shape first.
- Jobs are deduplicated per company, so the same posting is never charged twice in one run.
Price
$0.55 per 1,000 jobs, plus a $0.001 start fee per run (billed per gigabyte of run memory, so exactly that on the default 1 GB).
This is the cheapest company career page jobs scraper on the market, and it is the same rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.
| Jobs | Total cost |
|---|---|
| 100 | $0.056 |
| 1,000 | $0.551 |
| 10,000 | $5.501 |
| 100,000 | $55.001 |
What is actually charged
- One
job-scrapedevent per job row written to the dataset. Nothing else is metered per row. - Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a search that matched nothing. Those rows all carry
"charged": false. - Companies whose career page does not expose a supported job feed cost you nothing — they produce an uncharged diagnostic row, not a billed one.
- Companies whose board exists but currently lists no open roles are free for the same reason.
- Duplicate postings inside one company are dropped before they are charged.
- Everything the run does to work out which system a company uses is free. You are billed for jobs, not for lookups.
- A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one, so there is no price quietly attached to
apify-default-dataset-item— the trick that makes some scrapers bill you for their own error messages.
Input
{"companies": ["https://www.figma.com/careers","https://jobs.ashbyhq.com/ramp","notion.com","Databricks"],"maxItems": 100}
| Field | What it does |
|---|---|
companies | One entry per company, up to 50 per run. A careers page URL, a bare domain, a board URL, or a company name. The run works out the rest. |
maxItems | Total jobs across all companies. The budget is split evenly, so five companies and 50 jobs gives you ten each. Default 50, hard ceiling 5,000. Keep it low while testing — you pay per job. |
fullDetails | Off by default. Adds a plain-text description to every row, and fills in the posted date on Ashby rows. Slower and much heavier, because description feeds are many times larger than listing feeds. |
proxyUrls | Leave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port. |
Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.
Output
One row per job. A real row from a real run:
{"ok": true,"charged": true,"recordType": "job","inputUrl": "https://www.figma.com/careers","company": "figma","ats": "greenhouse","atsName": "Greenhouse","boardToken": "figma","title": "Software Engineer, Design Systems","location": "San Francisco, CA • New York, NY","remote": null,"department": "Engineering","employmentType": null,"postedAt": "2026-06-30T18:11:04.000Z","applyUrl": "https://job-boards.greenhouse.io/figma/jobs/5561234004","jobUrl": "https://job-boards.greenhouse.io/figma/jobs/5561234004","jobId": "5561234004","salary": null,"detectedVia": "token","scrapedAt": "2026-08-15T16:42:08.911Z"}
Field notes
inputUrl— the exact string you supplied for this company, so you can join the rows back onto your input list.ats— the applicant tracking system detected, lower-case and stable:greenhouse,lever,ashby,workable,smartrecruiters,recruitee,personio,teamtailor,breezy,workday.atsNameis the same thing spelled for humans.boardToken— the company's identifier on that system. Handy if you want to hit the same board again later without re-detecting it.location— as the company wrote it. Some boards give one city, some give a list, some give a region like "Europe". Multiple locations are joined with commas.department— the team or department the board files the job under. A few systems do not expose it — see Limitations.employmentType— full-time, part-time, contract, intern and so on, in the wording the board uses. Null where the board does not record it.postedAt— when the posting was published, normalised to ISO 8601 in UTC. Null where the board does not publish a date.applyUrl— the page that starts an application. On some systems that is the posting page itself.jobUrl— the public posting page, suitable for sharing.jobId— the posting's id on its board. Stable, and the right key to diff on when you re-run.remote— true or false where the board records it explicitly, otherwise inferred from the location text, otherwise null.salary— only where the board publishes a range. Most do not.detectedVia— how the board was found:url(your input already named it),token(matched from the company domain or name), orhtml(read off the careers page).
Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.
How it works
- Nearly every company careers page is a thin front end over an applicant tracking system, and those systems publish an unauthenticated JSON feed of open roles so the company's own page can render them. This Actor reads that feed directly.
- Working out which system a company uses is the real work, and it is done cheapest-first. If the URL you gave already names a board, that is free. Otherwise the run derives a likely board identifier from the domain or company name and asks the boards directly — a miss is a tiny 404, far cheaper than downloading a corporate web page.
- Only if both of those fail does it fetch the careers page itself and look for an embedded board. There is no page rendering anywhere in the chain, because the pages in question are themselves just calling the feeds we already read.
- Each feed is requested in its lightest documented form. Where a system offers both a listing feed and a much larger feed with every job description inlined, the listing feed is used unless you ask for descriptions.
- Requests leave through a large pool of rotating datacenter addresses, so a per-address rate limit is answered by moving rather than by waiting.
What people use it for
- Watching a list of target companies for new openings: run the same list on a schedule and diff on
jobIdto see only what appeared since last time. - Building a niche job board or newsletter from a curated set of employers, without signing up to an aggregator feed.
- Recruiting and talent mapping — see which departments a chosen set of employers is growing, and where.
- Sales and hiring-signal research: a burst of postings in one function is a strong buying signal, and
departmentpluspostedAtgives you that directly. - Market research on remote policy, employment types or salary disclosure across an industry, using flat typed columns instead of scraped page text.
- Enriching a CRM or spreadsheet of companies with a live open-roles count and the system each one hires through.
What "the ATS is detected for you" means in practice
Most tools in this space make you supply the applicant tracking system and the board identifier yourself — you have to already know that Figma hires through Greenhouse under the token figma, and that Ramp uses Ashby. That is fine for three companies and unusable for three hundred.
Here you give the thing you actually have — a careers URL off the company website, a domain out of your CRM, or a company name out of a spreadsheet — and the run resolves it. Every row comes back stamped with the ats and boardToken it resolved to, so the first run doubles as a way to build that mapping for yourself.
Detection is cheapest-first and never renders a page, so on the common case it costs a single small request before any job data is read.
Reading the output
Every run writes three kinds of row, and they are easy to tell apart:
- Real rows carry
"charged": trueand"recordType": "job". These are the rows you paid for, one billed event each. - The sample row carries
"_sample": trueand"charged": false. There is exactly one, it only appears when the input had no companies in it, and it exists so you can look at the output shape before you spend anything. - Diagnostic rows carry
"_diagnostic": true,"charged": falseand anerrorCodeyou can switch on:NO_RESULTSwhen a company has no supported feed or no open roles,NOT_FOUNDwhen a board id turned out not to exist,RATE_LIMITEDwhen a board throttled the run,SERVER_ERRORwhen a board was briefly down,NETWORKwhen it could not be reached at all, andTIME_BUDGETwhen the run ran out of time before reaching a company. Each one carries theinputUrlit belongs to and a plain-English explanation.
If you only want the data, filter on charged == true. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.
Getting the best coverage
If a company comes back as NO_RESULTS and you believe it does publish jobs, the fastest fix is to give the board URL directly. Open the company careers page, click through to any single job, and look at the address bar — if it lands on a job-board host, paste that URL in instead of the marketing page and the run will use it verbatim.
Workday boards must always be supplied as a URL, because a Workday address contains a tenant, a datacenter and a site name that cannot be guessed from a company name. Any Workday careers URL works — the run pulls the three parts out of it.
Limitations
- Only career pages running on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, Breezy HR and Workday are supported. Large enterprises frequently use systems that publish no open job feed at all; those companies return an uncharged diagnostic row rather than data.
- A company is only found if its board identifier can be derived from its domain or name, or is present on its careers page, or you supplied the board URL yourself. A company whose board id bears no relation to its name and who does not embed the board on a fetchable page will not resolve.
- Workday needs a full careers URL, not a company name — the address contains a tenant and site id that cannot be guessed.
- Posted dates are not universal. Ashby only exposes them on the heavier feed, so they arrive null unless you turn on full details; Personio does not publish them at all; Workday reports them as relative text ("Posted 30+ Days Ago") which is converted to an approximate date, not an exact one.
- Department is not universal either. Workday and Teamtailor listing feeds do not carry it at all, SmartRecruiters carries it on roughly a third of postings, and Personio boards that do not categorise their roles leave it empty.
- Employment type is null on Greenhouse and Workday, which do not carry it in their public listing feeds.
- Salary appears only where the board publishes a range. The large majority do not.
- Job descriptions are off by default. Turning them on makes runs slower and much heavier, and the text is flattened to plain text with the HTML stripped.
- Results are the boards' current open roles. There is no history and no closed-job archive; a posting that was filled yesterday is simply absent today.
- Boards rate-limit by address under heavy use. The run rotates addresses and retries, but a very large company list in a single run can still hit a throttle and return diagnostic rows for the tail.
- The time spent working out which system a company uses is paid for by the jobs the run finds, so a run that finds nothing gives up quickly: if the first companies in your list cannot be resolved, the rest come back as uncharged
TIME_BUDGETrows within a few seconds rather than the run grinding through all fifty. That keeps a list of dead URLs from eating your run time, and it never happens once jobs start coming back. Putting a board URL first, or supplying board URLs throughout, sidesteps it entirely — a board URL needs no lookup at all. - Location is whatever the board recorded, which is not normalised across systems — one company writes "Remote - US", another writes "San Francisco, California, United States".
- The hard ceilings are 50 companies and 5,000 jobs per run. Split larger jobs across runs.
Questions
What do I actually paste in?
Whatever you have. A careers page URL, a bare domain like figma.com, a board URL like https://jobs.lever.co/matchgroup, or just Figma. All four resolve to the same board. A URL is more reliable than a name, and a board URL is the most reliable of all.
How do I know which system a company uses?
You do not need to — that is the point. Every row tells you, in the ats and boardToken fields. Run your list once and you have the mapping for good.
What happens if a company is not supported?
You get one uncharged diagnostic row for it with errorCode: "NO_RESULTS" explaining what was tried, and the run carries on to your other companies. You are never billed for a company that returned no jobs.
Why is postedAt sometimes null?
Because the board does not publish it. Different systems expose different fields, and inventing a date would be worse than leaving it empty. The Limitations section lists exactly which systems omit it.
Can I get the full job description?
Yes — turn on full details. It is off by default because the description feeds are many times larger than the listing feeds, so leaving it on makes every run slower for data most callers do not use.
Do I need a proxy?
No. The run brings its own egress and the cost of it is already inside the price you see. The proxyUrls field exists only for callers who specifically want traffic to leave through servers they already own.
Will the run fail if one company breaks?
No. A blocked, empty or unsupported company produces an uncharged diagnostic row and the run carries on and still finishes as succeeded. A failed run would still bill you the start fee, which would mean paying to be told something went wrong.
Can I run this on a schedule?
Yes. Nothing in the run holds state between runs, so a schedule with the same company list is safe. Diff on jobId to see which postings are new since last time.
How do I get exactly the rows I paid for?
Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.