Ats Job Scraper Change Tracker
Pricing
Pay per usage
Ats Job Scraper Change Tracker
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Maximilian Waibel
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
ATS Job Scraper with Change Tracking
Scrape company job boards on Workday, Greenhouse, Lever, Ashby, SmartRecruiters and Personio — then run it on a schedule and get only what moved: roles opened, edited, closed, or re-listed.
Every closed role tells you how many days it was open. That is time-to-fill, per company, per team — and it is a number no plain job scraper can give you, because it only exists if something remembered yesterday.
Why not just re-scrape the board every day?
You can. Every other ATS job scraper in the store will hand you all 4,000 roles every morning for about $6, and leave you to work out which two of them changed.
This one does the diff, and charges accordingly:
| This Actor | Plain ATS scraper | |
|---|---|---|
| 20 companies, first run | $2.11 | ~$6.00 |
| 20 companies, every day after | $0.41 | ~$6.00 |
| Per month, on a daily schedule | ~$12 | ~$180 |
| Rows you have to read | ~30/day | 4,000/day |
| Roles that closed | reported, with tenure | not reported |
| What changed in an edited role | named, with before/after | work it out yourself |
Watching is cheap because watching is cheap. Reading a board that has not moved costs half a cent, and unchanged roles are never billed at all.
Quick start
1. Type company names. One per line, into Companies to watch. Up to 100.
stripelinearBosch Group
You do not need to find their job board — the Actor probes Greenhouse, Lever, Ashby, SmartRecruiters and Personio, works out which one hosts them, and remembers the answer so it never looks again.
2. Workday is the exception. Paste the careers page URL:
https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite
A Workday board is identified by a tenant, a shard number (wd5) and a site name
that the company chose. None of the three can be guessed from "nvidia", so there
is nothing to probe. Every other provider also accepts greenhouse:stripe if you
already know the board.
3. Leave Only report movement on and run it.
The first run on each company returns every open role, because nothing is known yet. That is the baseline, and it is priced like the plain list it is — $0.50 per 1,000 roles, below the going rate in this store. Every run after that returns only what changed.
4. Put it on a schedule. Daily is the sweet spot for hiring. In Apify Console: Actor → Schedules → Create. That is the whole product — a scheduled run that stays quiet until something happens.
What you get back
One row per role that moved. _change tells you what happened:
_change | Means |
|---|---|
new | the role was posted since your last run |
changed | title, location, team, salary or another detail was edited |
closed | the role is gone from the board — filled or pulled |
reopened | a role that had disappeared is listed again |
unchanged | only on full-dump runs, where every open role is returned |
An edited role names what moved, so you do not have to diff it yourself:
{"_change": "changed","_changed_fields": "location, title","_changed": {"title": { "from": "Senior Backend Engineer", "to": "Staff Backend Engineer" },"location": { "from": "Berlin, Germany", "to": "Munich, Germany" }},"title": "Staff Backend Engineer","company": "acme","url": "https://boards.greenhouse.io/acme/jobs/4001"}
A closed role names itself and says how long it took:
{"_change": "closed","title": "Director, Compounding Operations","company": "ro","ats": "lever","location": "Romeoville, IL","department": "Pharmacy","url": "https://jobs.lever.co/ro/c7f3d544-0899-4f8f-a319-c645e3928d08","posted_at": "2026-08-13T22:35:07.762000+00:00","_days_open": 17.3,"id": "lever:ro:c7f3d544-0899-4f8f-a319-c645e3928d08"}
Every row carries title, company, ats, location, department,
employment_type, remote, url, apply_url and posted_at. Where the
provider publishes them you also get salary_min / salary_max /
salary_currency, hybrid, seniority and reference. Turn on Include full
posting text to add description.
posted_at is a full UTC timestamp wherever the provider gives one. On Workday
roles older than 30 days it is empty: the board only says "30+ Days Ago", which
names no date, and a guess would be worse than nothing.
What people use it for
Competitive hiring intelligence. A rival's role closes after 9 days — they hired fast, in that function. Six engineering roles open in a week — they raised, or they are scaling. Watch 20 competitors for the price of a coffee a month and read the pattern.
Recruiting and sourcing. Know within a day when a target company opens a role you can fill, instead of finding it in week three.
Your own funnel. Your posting has been open 60 days while comparable roles elsewhere close in 20. That is your process, not the market.
Market research. Track remote policies, salary bands and location mix across a sector over months, without re-downloading the whole sector every night.
Cost
You pay per event, not per month:
| $0.01 | per run |
| $0.005 | per company watched — an unreachable board is free |
| $0.0005 | per role on that company's first run, when there is nothing to compare against yet |
| $0.01 | per change delivered — only roles that actually moved |
Worked examples, using real board sizes:
| Roles | Cost | |
|---|---|---|
| First run, the three prefilled companies | 130 | $0.09 once |
| A quiet day on those three | 0 moved | $0.025 |
| A normal day, a few roles move | ~4 moved | $0.065 |
| First run, 20 companies | ~4,000 | $2.11 once |
| A normal day across 20 companies | ~30 moved | $0.41 |
| Adding a 21st company later | ~200 | $0.105 once |
Two things worth knowing about that table:
The first run is cheap on purpose. It is the run you judge this Actor on before you trust it, so it is priced below every plain job scraper in the store rather than above them. Stripe alone is 575 roles — about $0.30 to take a complete snapshot of.
Growing your watchlist costs one company. Adding a company pays that company's baseline and nothing else; the twenty you were already watching keep their history and are not re-reported. The same is true of editing a filter, or reordering the list.
Want a hard ceiling? Set a maximum cost per run when you start it. The run
stops delivering at your cap instead of quietly working for free, records in
RUN_SUMMARY how many rows it withheld, and reports those rows on the next run
rather than losing them — still at the baseline price if that is what they were.
Setting a limit delays data; it never makes it cost more.
Getting the data out
Every run writes to a dataset you can export as JSON, CSV or Excel from the Console, or pull through the API:
https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=csv
On a schedule you usually want the last run endpoint, which always points at the newest results:
https://api.apify.com/v2/acts/<USERNAME>~ats-job-scraper-change-tracker/runs/last/dataset/items?token=<TOKEN>
For alerting, add a webhook under Actor → Integrations on Run succeeded and point it at Slack, Make, Zapier or your own endpoint. Because quiet runs deliver nothing, a webhook that arrives with rows in it means something actually happened — no filtering on your side.
The dataset ships two table views: What moved for the daily read, and Time to fill for the closures, sorted by how long each role was open.
Use it from an AI agent
The same Actor runs as an MCP server, so Claude, Cursor or Codex can query it directly. Enable Standby in the Actor's settings and point your client at its Standby URL. Three tools:
| Tool | |
|---|---|
watch_feed | what moved since your last call |
read_feed | every open role right now |
feed_status | how many roles are tracked and still open |
Then ask things like "has anyone on my watchlist opened a staff engineer role this week?" and the agent polls it itself.
Settings worth knowing
Only report movement — on by default, and the reason to use this Actor. Turn it off to get every open role on every run, billed at the cheaper baseline rate.
Include full posting text — off by default. Adds the description field and
makes results much larger. On Workday it costs one extra request per role, so
runs there get noticeably slower, and it stops after the first 300 roles of a
board. Changing it changes what a role's record contains, so it starts a fresh
comparison on purpose.
Location filter / Title filter — deliver only roles whose location or title contains your text, case-insensitive. The board is still read and compared in full, so closures are still reported and changing a filter does not reset your history — you are simply billed for fewer rows.
Limits, stated plainly
- The first run on each company returns everything. Nothing is known yet.
- A company name is found by probing, so a company whose board is empty on
one provider and live on another resolves to the live one — but a company on
none of the five is reported as unresolvable rather than guessed at. Paste the
URL if you know it. Two consequences worth knowing: a name resolves only when
all five providers actually answered, so a rate limit fails that name for the
run rather than settling it wrongly and remembering it; and a SmartRecruiters
board with nothing open at all cannot be found by name, because their API
answers the same way for a company with no roles as for a name that was never
a company. Watch that one as
smartrecruiters:tokenor by URL. - Workday needs the full URL, and caps a board at 2,000 roles. Bigger boards are read up to that ceiling and reported, but closures are not reported for them, because the full set was never visible. The run says so in its notes.
- An unreachable board is skipped, noted, and not charged for. Transient failures (429, 503, timeouts) are retried with backoff first. The rest of your watchlist runs normally, and no closure is invented for the roles on the board that failed — a board that times out is not a board where everyone got hired.
- A very large watchlist has a ceiling. Tracking state is checkpointed into a single platform record with an 8 MB limit; compressed, that holds roughly 150,000 tracked roles. Past it, closed roles are dropped first and the run tells you in the dataset if it still does not fit. Roles that are still open are never dropped to make room.
Where the data comes from
Only the public job-board endpoints these six providers publish for third-party use. No authentication, no login-walled data, no personal data. Recruiter names are never requested. Descriptions are employer-authored posting text and are truncated rather than republished in full. Unlisted Ashby postings are excluded.
Troubleshooting
"No public job board found for X" — the company is on Workday (paste the careers URL), on an ATS this Actor does not read, or spells its board slug unusually. Open the careers page in a browser and paste the URL you land on.
"Board not found" — the token in the URL is wrong, or the company moved boards. Open the careers page in a browser: if it redirects somewhere else, use the URL you land on.
Everything came back as new on the second run — check whether you changed
Include full posting text between runs; that changes what a role's record
contains, so it starts a fresh comparison on purpose. Changing the companies
or the filters does not. If neither applies, open RUN_SUMMARY and check
state_durable — a failed checkpoint is reported there and as a warning row in
the dataset.
A run returned nothing at all — that is the normal result on a quiet day, and
it costs a couple of cents. Open RUN_SUMMARY in the run's key-value store:
unchanged tells you how many roles were checked and found untouched.
Closures never appear — they cannot on a company's first run, and they will not appear for a Workday board over 2,000 roles. They do appear on filtered runs, unlike most scrapers.
A department or salary field is empty — not every provider publishes every
field, and not every employer fills in the ones that exist. Salary bands come
from Lever and Ashby where the company entered them; hybrid, seniority and
reference come from SmartRecruiters; seniority also from Personio.
Working on the code? See [DEVELOPMENT.md].