PDF Change Monitor & Diff API avatar

PDF Change Monitor & Diff API

Pricing

from $2.00 / 1,000 text pages

Go to Apify Store
PDF Change Monitor & Diff API

PDF Change Monitor & Diff API

Compare PDF revisions, extract Markdown/JSON with OCR and tables, or monitor a PDF URL for changes. Returns page-level evidence, hashes, and structured output.

Pricing

from $2.00 / 1,000 text pages

Rating

0.0

(0)

Developer

kouki ohba

kouki ohba

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

PDF Change Monitor & Diff API — OCR, Tables, Evidence

Compare two PDF revisions, run a durable change monitor for one PDF URL, or extract PDF content to Markdown and JSON. Results include page references, bounded coordinates, table-cell changes when the table is eligible, OCR provenance, and content-addressed evidence.

This Actor reports factual changes. It does not decide legal meaning, materiality, or whether a document is safe to rely on without human review.

This Actor is published on Apify Store: PDF Change Monitor & Diff API.

Why use this Actor

  • Run a PDF diff with page-level text, table, and structural evidence.
  • Keep a named baseline and use the change monitor for later checks of the same public PDF URL.
  • Extract digital or scanned PDFs with deterministic local OCR. No separate document-processing API key is required.
  • Bound work with file, page, OCR-time, and customer event-charge limits.
  • Receive typed Dataset records plus Markdown, JSON, billing, and evidence artifacts for review.

Modes and limits

  • extract accepts 1–20 PDF sources.
  • compare accepts one old and one new revision.
  • monitor accepts one stable HTTP(S) URL and a stable monitorId. It uses a dedicated named Key-value store so later scheduled runs see the same baseline.
  • Each PDF is limited to 50 MiB and 500 pages. One run downloads at most 200 MiB in total.
  • OCR is limited to 60 seconds per OCR page. Available languages are eng, jpn, deu, fra, and spa.
  • ocrMode=auto also selects a page when one raster image covers at least 30% of the page and the native layer has fewer than 128 non-whitespace characters. Use off for image-heavy documents that should remain native-only. The run must reserve the full OCR event budget before OCR starts.
  • Cell-level differences are emitted only for structurally unambiguous native text tables. OCR tables, merged cells, page-spanning tables, and ambiguous matches use a table or page fallback with a reason.
  • Compare and monitor do not publish a partial success when any required page is uncertain.

The Dataset contains typed records and one final run_summary. The default Key-value store can contain OUTPUT.json, PERSISTENCE.json, BILLING.json, document.md, diff.json, diff.md, and bounded evidence images. A link can return 404 when its mode did not produce that artifact.

Extract

curl -X POST "https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs" \
-H "authorization: Bearer <APIFY_TOKEN>" \
-H "content-type: application/json" \
-d '{"mode": "extract", "sources": [{"url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"}], "ocrMode": "auto", "ocrLanguages": ["eng"]}'
const input = {
"mode": "extract",
sources: [{ url: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" }],
ocrMode: "always",
ocrLanguages: ["eng", "jpn"],
};
const response = await fetch(
"https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs",
{ method: "POST", headers: { "authorization": "Bearer <APIFY_TOKEN>", "content-type": "application/json" }, body: JSON.stringify(input) },
);
import requests
input_data = {
"mode": "extract",
"sources": [{"url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"}],
"ocrMode": "always",
"ocrLanguages": ["eng", "jpn"],
}
requests.post(
"https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs",
headers={"Authorization": "Bearer <APIFY_TOKEN>"},
json=input_data,
timeout=30,
).raise_for_status()

Compare

curl -X POST "https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs" \
-H "authorization: Bearer <APIFY_TOKEN>" \
-H "content-type: application/json" \
-d '{"mode": "compare", "oldSource": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-old.pdf"}, "newSource": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf"}, "ocrLanguages": ["eng"]}'
const input = {
"mode": "compare",
oldSource: { url: "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-old.pdf" },
newSource: { url: "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf" },
ocrLanguages: ["eng"],
};
await fetch("https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs", {
method: "POST", headers: { "authorization": "Bearer <APIFY_TOKEN>", "content-type": "application/json" }, body: JSON.stringify(input),
});
import requests
requests.post(
"https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs",
headers={"Authorization": "Bearer <APIFY_TOKEN>"},
json={
"mode": "compare",
"oldSource": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-old.pdf"},
"newSource": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf"},
"ocrLanguages": ["eng"],
},
timeout=30,
).raise_for_status()

Monitor

Use an Apify Task and Schedule for recurring checks. Keep the monitorId, source URL, and named Key-value store unchanged between runs.

curl -X POST "https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs" \
-H "authorization: Bearer <APIFY_TOKEN>" \
-H "content-type: application/json" \
-d '{"mode": "monitor", "source": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf"}, "monitorId": "release-fixture-txt-03", "stateStore": "pdf-change-monitor-state", "ocrLanguages": ["eng"]}'
const input = {
"mode": "monitor",
source: { url: "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf" },
monitorId: "release-fixture-txt-03",
stateStore: "pdf-change-monitor-state",
ocrLanguages: ["eng"],
};
await fetch("https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs", {
method: "POST", headers: { "authorization": "Bearer <APIFY_TOKEN>", "content-type": "application/json" }, body: JSON.stringify(input),
});
import requests
requests.post(
"https://api.apify.com/v2/acts/abiding_knapweed~pdf-change-monitor-diff-api/runs",
headers={"Authorization": "Bearer <APIFY_TOKEN>"},
json={
"mode": "monitor",
"source": {"url": "https://raw.githubusercontent.com/ugin-man/pdf-change-monitor-diff-api/494b4a58dcdd18e80016623dabeb956028bb0f01/quality/fixtures/pdfs/txt-03-new.pdf"},
"monitorId": "release-fixture-txt-03",
"stateStore": "pdf-change-monitor-state",
"ocrLanguages": ["eng"],
},
timeout=30,
).raise_for_status()

Charging, errors, and data

Only completed product events are charged. Blocked URLs, validation failures, fetch failures, corrupt or unsupported PDFs, budget rejection, sandbox failure, and persistence failure have no charge. Monitor mode has one flat monitor-check event and does not also emit text-page events.

Current custom event prices are $0.002 per text-page, an additional $0.010 per ocr-page, $0.030 per revision-comparison, and $0.020 per monitor-check. The Actor uses Pay per event + usage, so Apify platform compute, storage, and network usage are billed separately. See docs/pricing.md.

Run storage follows the retention selected in your Apify account. Monitor baselines remain in the named Key-value store until you delete that store in Apify Console or with the API. Raw PDF bytes are not retained in the monitor state by default. See docs/privacy-and-retention.md.

Security design and responsible reporting are in docs/security.md. Report a problem through the public Actor Issues page.