Job Delta — Multi-ATS Job Change Monitor
Pricing
from $4.00 / 1,000 job changes
Job Delta — Multi-ATS Job Change Monitor
Monitor public Greenhouse, Lever, Ashby, Recruitee, and Workable job boards for new, removed, reopened, and changed jobs, hiring signals, and strict cross-ATS duplicate matches. Unofficial community tool.
Pricing
from $4.00 / 1,000 job changes
Rating
0.0
(0)
Developer
Salih Can Kurnaz
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Monitor public Greenhouse, Lever, Ashby, Recruitee, and Workable job boards over time and receive only meaningful hiring changes instead of downloading the same job list on every run.
Unofficial community tool. Job Delta is not affiliated with or endorsed by Greenhouse, Lever, Ashby, Recruitee, or Workable. It reads public job-board data only.
Quick start
1. Add public board URLs or slugs
You can either select the ATS and enter its stable slug, or choose source: "auto" and paste a full supported public board URL.
| ATS | Public URL example | Explicit source | Normalized boardToken |
|---|---|---|---|
| Greenhouse | https://job-boards.greenhouse.io/acme | greenhouse | acme |
| Lever | https://jobs.lever.co/acme | lever | acme |
| Ashby | https://jobs.ashbyhq.com/acme | ashby | acme |
| Recruitee | https://acme.recruitee.com/o/platform-engineer | recruitee | acme |
| Workable | https://apply.workable.com/acme/ | workable | acme |
Full URLs are accepted only for supported allow-listed ATS hosts. Job Delta never fetches an arbitrary user-supplied host.
2. Run a silent baseline
{"monitorId": "competitor-hiring-watch","companies": [{"name": "Greenhouse","source": "auto","boardToken": "https://job-boards.greenhouse.io/greenhouse"},{"name": "Highspot","source": "auto","boardToken": "https://jobs.lever.co/highspot"},{"name": "Ashby","source": "auto","boardToken": "https://jobs.ashbyhq.com/ashby"}],"initialRunMode": "baseline_only","includeDescriptions": true,"includeSalaryDetails": false,"emitDuplicateGroups": true,"removalConfirmationRuns": 2,"hiringChangeMinJobs": 5,"hiringChangeMinPercent": 25,"rejectSuspiciousEmptyBoards": true}
The first baseline_only run records existing jobs silently. It does not report every current job as newly added.
3. Schedule repeated runs
Save the input as an Apify Task and run it every three or six hours. Keep the same monitorId; changing it creates a separate monitor with separate state.
What it detects
- New jobs (
job_added) - Confirmed removals (
job_removed) - Reopened jobs (
job_reopened) - Title, location, department and employment-type changes
- Remote-status and description changes
- Salary-range changes when public salary data is observed
- Hiring surges and slowdowns
- Strict advisory duplicate matches across different ATS sources
- A free
run_summarywith source health, request counts and billing status
Why Job Delta
Job-board scrapers normally return complete snapshots. Job Delta keeps persistent state by monitorId, compares successful runs, and emits only changes. A job must be absent from multiple successful scans before removal is confirmed, reducing false alerts from temporary source problems.
Common use cases
- Competitor hiring intelligence
- Recruiting-market monitoring
- Portfolio-company workforce monitoring
- Sales signals from hiring surges
- Remote-policy, salary, location and department-change alerts
- Event-driven job aggregation without repeated full snapshots
Supported sources
| Source | Public endpoint behavior | Authentication |
|---|---|---|
| Greenhouse | Public board jobs API; optional salary-detail requests | None |
| Lever | Public postings API | None |
| Ashby | Public Job Postings API; optional compensation payload | None |
| Recruitee | Public Careers Site /api/offers/ endpoint | None |
| Workable | Public published-jobs account endpoint | None |
No candidate data, ATS administrator account, browser automation, residential proxy, CAPTCHA solver, GPU, or LLM is required.
Example event
{"eventType": "location_changed","company": "Acme","source": "ashby","boardToken": "Acme","jobKey": "ashby:Acme:12345","detectedAt": "2026-08-03T00:00:00Z","before": {"location": "London"},"after": {"location": "Remote - Europe"},"details": {"sourceJobId": "12345","title": "Platform Engineer","applicationUrl": "https://jobs.ashbyhq.com/Acme/12345/application"}}
Reliability controls
- Persistent state separated by
monitorId, source and normalized board token - Silent baseline by default
- Configurable successful-run removal confirmation
- Suspicious-empty-board protection
- Per-company failure isolation
- HTTP retry, timeout, request and byte accounting per ATS
- Removed-job tombstones for reopening detection
- Duplicate-group replay suppression
- Allow-listed ATS URL parsing to prevent arbitrary-host requests
- Budget-aware PPE delivery: state advances only after all detected paid events are delivered
Salary behavior
- Greenhouse:
includeSalaryDetails: trueadds one optional public detail request per current job. - Ashby: the same option requests the public compensation payload.
- Lever, Recruitee, and Workable: publicly exposed salary fields are parsed without private credentials.
- A source that does not expose salary data is not treated as having a zero salary.
Billing events
Job Delta uses explicit pay-per-event value events:
board-initialized— a public board baseline is createdjob-change— a lifecycle or field-change event is deliveredhiring-signal— a surge or slowdown is deliveredduplicate-match— a new strict cross-ATS duplicate group is delivered
run_summary, failed sources, unchanged runs and replayed events are not explicitly charged. The synthetic apify-default-dataset-item event is disabled in the current Store pricing, so dataset rows are not charged separately.
API quick start
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run_input = {"monitorId": "competitor-hiring-watch","companies": [{"name": "Ashby","source": "auto","boardToken": "https://jobs.ashbyhq.com/ashby",},{"name": "TransPerfect","source": "auto","boardToken": "https://transperfect.recruitee.com/o/software-engineer",},],"initialRunMode": "baseline_only",}run = client.actor("soilair/job-delta-cross-ats-monitor").call(run_input=run_input)for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item)
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const input = {monitorId: 'competitor-hiring-watch',companies: [{ name: 'Ashby', source: 'ashby', boardToken: 'ashby' },{ name: 'TP-Link USA', source: 'workable', boardToken: 'tp-link-usa-corp' },],initialRunMode: 'baseline_only',};const run = await client.actor('soilair/job-delta-cross-ats-monitor').call(input);const { items } = await client.dataset(run.defaultDatasetId).listItems();console.dir(items, { depth: null });
Troubleshooting
- Every current job was emitted as new: use
initialRunMode: "baseline_only"on the first run. - The monitor appears to have forgotten history: keep the same
monitorIdand do not enableresetMonitor. - A board returns zero jobs unexpectedly: leave
rejectSuspiciousEmptyBoardsenabled to preserve the prior state. - A removal did not appear immediately: the default requires two successful missing scans before
job_removed. - Automatic source detection failed: use a full supported board URL, or select the ATS explicitly and provide only its slug.
- Duplicate signals are missing: enable descriptions and
emitDuplicateGroups; matching is intentionally strict and advisory.
Important behavior
- Existing Greenhouse and Lever state keys remain unchanged in v1.8.
resetMonitor: trueintentionally recreates board baselines.- Direct-link-only Ashby postings with
isListed: falseare not included. - Duplicate matching is strict and advisory; it does not delete or mutate source jobs.
- If every company source fails, the Actor fails after writing a diagnostic run summary.
- If the run budget cannot cover all detected events, Job Delta does not advance state, so unpaid changes are not silently lost.