Job Delta — Multi-ATS Job Change Monitor avatar

Job Delta — Multi-ATS Job Change Monitor

Pricing

from $4.00 / 1,000 job changes

Go to Apify Store
Job Delta — Multi-ATS Job Change Monitor

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

Salih Can Kurnaz

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

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.

ATSPublic URL exampleExplicit sourceNormalized boardToken
Greenhousehttps://job-boards.greenhouse.io/acmegreenhouseacme
Leverhttps://jobs.lever.co/acmeleveracme
Ashbyhttps://jobs.ashbyhq.com/acmeashbyacme
Recruiteehttps://acme.recruitee.com/o/platform-engineerrecruiteeacme
Workablehttps://apply.workable.com/acme/workableacme

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_summary with 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

SourcePublic endpoint behaviorAuthentication
GreenhousePublic board jobs API; optional salary-detail requestsNone
LeverPublic postings APINone
AshbyPublic Job Postings API; optional compensation payloadNone
RecruiteePublic Careers Site /api/offers/ endpointNone
WorkablePublic published-jobs account endpointNone

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: true adds 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 created
  • job-change — a lifecycle or field-change event is delivered
  • hiring-signal — a surge or slowdown is delivered
  • duplicate-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 ApifyClient
client = 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 monitorId and do not enable resetMonitor.
  • A board returns zero jobs unexpectedly: leave rejectSuspiciousEmptyBoards enabled 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: true intentionally recreates board baselines.
  • Direct-link-only Ashby postings with isListed: false are 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.