Job Board Snapshot Change Detector
Pricing
from $0.85 / 1,000 observed job-board change delivereds
Job Board Snapshot Change Detector
Compare two buyer-authorized factual job-board snapshots and report observed additions, removals and changed fields.
Compare two buyer-authorized inline job-board snapshots and receive deterministic observed ADDED, REMOVED, and CHANGED rows plus one comparison summary. The Actor never fetches a supplied URL and never interprets a difference as proof of hiring, closure, growth, or vacancy status.

What you get
- Explicit change rows. Each row identifies one stable
postingKey, the change type, selected changed fields, before/after facts when requested, and deterministic fingerprints. - One free comparison summary. Counts, snapshot metadata, truncation status, scope notices, and a report fingerprint follow the change rows.
- Reproducible output. Normalized snapshots, field selection, byte-order sorting, and fingerprints produce the same result for the same factual input.
- A closed factual contract. Descriptions, application contents, candidate data, credentials, arbitrary prose, and unknown fields are rejected.
- Delivery-first billing. The complete ordered Dataset batch is stored before one
result-foundis confirmed for each deliveredCHANGErow; the summary is not billed.
Use it to create auditable change feeds from recurring exports you are authorized to process, trigger a downstream review when selected facts change, or retain deterministic snapshot-to-snapshot evidence.
Who it is for
- Recruiting operations teams comparing authorized weekly careers exports.
- Marketplace and job-board operators monitoring their own publication snapshots.
- Analysts who need exact observed differences without a labour-market or hiring inference.
- Automation builders feeding normalized change rows into Make, Zapier, n8n, a warehouse, or an alerting rule.
Quick start
Run the public Task Job Board Snapshot Changes — Synthetic Sample (Task name compare-synthetic-job-board-snapshots, Task ID bFzRlx83jNhhRadXJ). Its explicitly synthetic snapshots deliver one added, one removed, and one changed row followed by one free summary. It performs no network request and uses no private data.
For your own comparison, replace both snapshots while keeping stable posting keys across observation times:
{"previous": {"snapshotId": "authorized-export-previous","observedAt": "2026-08-31T09:00:00.000Z","sourceLabel": "Buyer-authorized weekly export","postings": [{"postingKey": "role-101","title": "Software Engineer","department": "Engineering","location": "Tbilisi","workplaceType": "OFFICE"}]},"current": {"snapshotId": "authorized-export-current","observedAt": "2026-09-01T09:00:00.000Z","sourceLabel": "Buyer-authorized weekly export","postings": [{"postingKey": "role-101","title": "Software Engineer","department": "Engineering","location": "Remote","workplaceType": "REMOTE"}]},"changeTypes": ["ADDED", "REMOVED", "CHANGED"],"changedFields": ["title", "department", "location", "workplaceType"],"includeBeforeAfter": true,"maxChanges": 100,"inputLabel": "weekly-authorized-diff","acknowledgeObservedDiffOnly": true}
This input produces one CHANGED row because location and workplaceType differ. A posting missing from the earlier snapshot is ADDED; one missing from the later snapshot is REMOVED.
Input reference
| Field | Required | Limits | Meaning |
|---|---|---|---|
previous | Yes | Closed object | Earlier snapshot with snapshotId, observedAt, and 0–1,000 postings. |
current | Yes | Closed object | Later snapshot; its observedAt must be later and its ID must differ. |
changeTypes | Yes | Unique subset of ADDED, REMOVED, CHANGED | Select which detected rows may be delivered. |
changedFields | Yes | 0–10 unique values | Empty means every supported factual field; otherwise compare the selected fields only. |
includeBeforeAfter | Yes | Boolean | Include selected changed facts, or return only field names and fingerprints. |
maxChanges | Yes | 1–2,000 | Deterministic delivered-row ceiling; summary always discloses truncation. |
inputLabel | No | Up to 80 safe characters | Non-sensitive correlation label copied only to the summary. |
acknowledgeObservedDiffOnly | Yes | Must be true | Confirms that observed differences are not outcome or completeness claims. |
Each snapshot accepts an optional sourceLabel and closed posting rows. Every posting requires postingKey and title. Optional factual fields are department, division, location, employmentType, workplaceType, compensation, publishedAt, deadlineAt, and canonicalUrl.
Compensation, when supplied, is one complete object with integer-minor-unit minimum and maximum, uppercase three-letter currency, and period from HOUR, DAY, WEEK, MONTH, or YEAR. The Actor performs no currency, tax, purchasing-power, or period conversion. canonicalUrl is an inert HTTPS output fact and is never fetched.
How it works
- The Actor validates the entire closed input and its 2,097,152-byte ceiling before Dataset or billing access.
- It normalizes safe text and strict UTC timestamps, rejects duplicate posting keys within either snapshot, and requires the current observation time to be later.
- Exact
postingKeyidentity joins rows. Missing earlier/current keys becomeADDED/REMOVED; selected factual differences becomeCHANGED. - Change types follow the fixed order
ADDED,REMOVED,CHANGED; posting keys use deterministic byte ordering. - The Actor applies
maxChanges, builds the summary, checks the complete output against an 8,388,608-byte ceiling, and writes one ordered Dataset batch. - Only after that write succeeds does the Actor confirm one named
result-foundper deliveredCHANGErow. The summary remains free.
There is no crawler, source API, proxy, browser, geocoder, classifier, external Dataset, or model call.
Output Dataset

The default Dataset contains zero or more CHANGE rows followed by exactly one COMPARISON_SUMMARY. A change example from the synthetic public Task is:
{"schemaVersion": "1.0","rowType": "CHANGE","comparisonId": "e052eae82389689eff3c1a6aca70dba5eea197dbe1499d236de75de95008e65a","position": 1,"changeType": "ADDED","postingKey": "synthetic-added","previousFingerprint": null,"currentFingerprint": "e13b4fc996a11b0881b6b2d13cd2fefe9527f4e9e8fb5a26ba7a61f053d68b20","changedFieldNames": ["title", "department", "location"],"before": null,"after": {"title": "Brand Designer","department": "Marketing","location": "Tbilisi"},"previousSnapshotId": "synthetic-jobs-previous","currentSnapshotId": "synthetic-jobs-current","observedDiffOnly": true}
The final summary reports both detected and delivered counts for all three change types, unchanged rows, selected fields/types, previous/current snapshot fingerprints, truncation, rights/scope notices, and one deterministic reportFingerprint. With no selected differences, a successful run returns only this free summary and charges zero result-found events.
Row interpretation
comparisonIdbinds both normalized snapshot identities, observation times, fingerprints, field/type selections, before/after mode, and row limit.previousFingerprintandcurrentFingerprintidentify the full normalized posting facts on each side; one isnullfor added or removed rows.changedFieldNameslists selected facts present on an added/removed row or facts whose normalized values differ on a changed row.beforeandafterinclude only those selected facts whenincludeBeforeAfter=true; fingerprints remain available when it is false.observedDiffOnly=trueis a scope statement, not a claim that a source posting opened, closed, filled, expired, or remained available.
Pricing
Pay Per Event has only the automatic Actor Start event and the primary repeatable result-found event. One result-found is one complete CHANGE row already present in the stored Dataset batch. The comparison summary is free.
| Tier | Actor Start | Each delivered change | Three-change Task total |
|---|---|---|---|
| FREE | $0.009000 | $0.001000 | $0.012000 |
| BRONZE | $0.008550 | $0.000950 | $0.011400 |
| SILVER | $0.008100 | $0.000900 | $0.010800 |
| GOLD | $0.007650 | $0.000850 | $0.010200 |
| PLATINUM | $0.007380 | $0.000820 | $0.009840 |
| DIAMOND | $0.007200 | $0.000800 | $0.009600 |
The public Task sets maxChanges=3 and caps FREE-tier spend at exactly $0.012: one start plus three changes. A valid zero-change comparison still has the automatic start charge but no result-found. Invalid input, pricing/budget mismatch, or failed Dataset delivery creates no result-found.
API and automation
Start the public synthetic Task and wait for a terminal status:
curl -X POST \'https://api.apify.com/v2/actor-tasks/bFzRlx83jNhhRadXJ/runs?token=APIFY_TOKEN&waitForFinish=180'
Read defaultDatasetId from the terminal Run, then fetch /v2/datasets/DATASET_ID/items?clean=true. In Make, Zapier, or n8n, branch on SUCCEEDED before consuming rows and route by rowType and changeType. Use the summary's comparisonId, counts, and truncated flag as the control record.
Before retrying a client timeout, inspect the original Run and Dataset. A successful batch may already have produced paid changes even if the client did not receive the terminal response.
Source rights and attribution
This Actor reads only facts supplied inline by the buyer. You must own them or have authorization to process them and remain responsible for the original source's terms, retention rules, and downstream use. sourceLabel and canonicalUrl are provenance facts only; they imply no affiliation and grant no licence to source-board or employer content.
The Actor deliberately accepts bounded publication facts rather than descriptions, requirements prose, application-routing data, candidate records, or credentials. It does not discover a source, bypass access controls, scrape a website, or validate the buyer's completeness declaration.
Security and data handling
- Runtime permission is
LIMITED_PERMISSIONS; memory is 128 MB and timeout is 180 seconds. - Input rejects unknown keys, accessors, unsafe control/format characters, malformed identifiers, invalid dates, duplicate keys, unsafe URLs, formula-leading text, non-finite numbers, and incomplete compensation ranges.
- The Actor makes zero network requests and accepts no token, cookie, proxy, external Dataset ID, Run ID, or arbitrary endpoint.
- Output uses closed Dataset schemas and contains only normalized facts, fingerprints, counts, and explicit scope/rights notices.
- Apify retains the original run INPUT in the run key-value store according to account storage and retention settings.
includeBeforeAfter=falsereduces Dataset disclosure but does not erase stored input. - No automatic retry occurs after an uncertain paid delivery. Inspect the original Run before starting another comparison.
Hard limits
| Boundary | Limit |
|---|---|
| Memory / timeout | 128 MB / 180 seconds |
| Encoded input | 2,097,152 bytes |
| Postings per snapshot | 1,000 |
| Delivered changes | 2,000 |
| Encoded complete output batch | 8,388,608 bytes |
| Network, proxy, browser, model calls | 0 |
Snapshot IDs are 1–64 safe ASCII characters; posting keys are 1–160; titles are at most 300; source labels and the optional input label are at most 80. The Actor rejects the complete run when a hard bound is exceeded instead of returning a silently incomplete claim. Only explicit maxChanges truncation succeeds, and the summary discloses it.
Limits and interpretation
- A missing posting means only that its key is absent from the supplied current snapshot. It does not prove closure, deletion, expiry, or a hiring outcome.
- An added posting is not proof of company growth, and a changed fact is not proof that a person or source intentionally edited it.
- Snapshot completeness, observation timing, identity stability, and factual accuracy remain buyer/source responsibilities.
- The Actor performs exact field comparison after normalization; it does not infer semantic equivalence, title seniority, remote status, location identity, or compensation comparability.
maxChangescan omit detected rows from delivery. Always checkselectedChangeCount,deliveredChangeCount, andtruncatedin the summary.- Fingerprints support repeatability and change detection; they are not signatures from the source or evidence of legal authenticity.
Troubleshooting
Why did the run report input_invalid?
Confirm that the snapshots have different IDs, the current observedAt is later, posting keys are unique per snapshot, required selections are present, and acknowledgeObservedDiffOnly=true. Remove unknown fields and unsafe text.
Why is an expected change missing?
Check changeTypes, changedFields, stable posting keys, and maxChanges. If a field is not selected, its difference does not create a CHANGED row. Read the summary's detected/delivered counts and truncated flag.
Why are before and after null?
They are intentionally withheld when includeBeforeAfter=false, and one side is naturally null for added or removed rows. Fingerprints and changed field names remain.
Why did the run report budget_insufficient or pricing_misconfigured?
The cap could not fund the maximum selected change rows, or active pricing did not match the closed paid-delivery contract. Increase the cap for the intended maxChanges or inspect the Actor's current event pricing.
Why is there only a summary row?
No selected difference was delivered. The summary remains useful and free; only the automatic Actor Start event applies.
FAQ
Does this Actor scrape job boards? No. It compares only the two inline snapshots supplied in the run input.
Can it prove that a vacancy closed or opened? No. It reports observed differences between supplied snapshots without interpreting the cause.
Is every Dataset row billed? No. Only CHANGE rows receive result-found; the one COMPARISON_SUMMARY row is free.
Can I compare only location and workplace mode? Yes. Put location and workplaceType in changedFields; added/removed rows still reflect the selected facts.
Are canonical URLs fetched? No. Valid HTTPS URLs remain inert factual values used only in comparison and output.
Can zero changes succeed? Yes. The Dataset contains one free summary with zero delivered changes and no result-found charge.