PDF Text Intake Auditor avatar

PDF Text Intake Auditor

Pricing

from $33.50 / 1,000 pdf intake checks

Go to Apify Store
PDF Text Intake Auditor

PDF Text Intake Auditor

Judges whether a PDF is ingestible before you spend on extraction: text-layer presence, page count, encryption, scan likelihood, per-page text density, metadata, a SHA-256, and a READYFORRAG / NEEDSOCR / REJECT verdict.

Pricing

from $33.50 / 1,000 pdf intake checks

Rating

0.0

(0)

Developer

NexGen Watch

NexGen Watch

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

🌐 PDF Text Intake Auditor

Judges whether a PDF is ingestible before you spend on extraction: text-layer presence, page count, encryption, scan likelihood, per-page text density, metadata, a SHA-256, and a READY_FOR_RAG / NEEDS_OCR / REJECT verdict.

Output is one pdf_intake_verdict row per result; billing is pay-per-event, the value event being one pdf intake check (a $0.02 start fee per run, then $0.05 per pdf intake check).

📊 Sample Output

PDF Text Intake Auditor sample output — a table of real pdf intake check rows (input_ref, source_type, bytes, sha256) from run nDCqwi1I4PF7enD8p on build 0.1.4

Real rows from run nDCqwi1I4PF7enD8p on build 0.1.4 (2026-09-17), the same input as the Quick start below — every value is as the source published it (emails masked, long text shortened):

input_refsource_typebytessha256metadataverdict
JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAw…base641146a25f6b496a13eb8c3643a2ba8f21b674c2f2c860de4f8bb4139cdf0ec4c61ca1{"creationdate":"D:20260915024929Z"}READY_FOR_RAG

The run finished with the status message: 1 file(s): 1 billable verdict(s), 0 unbilled (reject/unparseable/unavailable) | pdf_intake_check charged=1

✅ What you get

Each row is flat JSON with these fields (from the dataset schema and the sample run; a field the source does not publish for a given row is null):

  • input_ref (string/null) — e.g. JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAw…
  • source_type (string/null) — e.g. base64
  • bytes (integer/string/null) — e.g. 1146
  • sha256 (string/null) — e.g. a25f6b496a13eb8c3643a2ba8f21b674c2f2c860de4f8bb4139cdf0ec4c61ca1
  • page_count (integer/string/null) — e.g. 1
  • encrypted (boolean/null) — e.g. False
  • has_text_layer (boolean/null) — e.g. True
  • scan_likelihood (string/null) — e.g. low
  • per_page_text_density (string/null) — e.g. [576]
  • text_char_total (integer/string/null) — e.g. 576
  • metadata (string/null) — e.g. {"creationdate":"D:20260915024929Z"}
  • verdict (string/null) — e.g. READY_FOR_RAG
  • warnings (string/null) — e.g. contains JavaScript/auto-action objects (reported, NEVER executed)
  • faults (string/null) — null in every sample row
  • record_type (string) — e.g. pdf_intake_verdict
  • source (string/null) — e.g. buyer-supplied local PDFs (base64 / key-value-store keys)
  • outcome (string/null) — e.g. answer
  • input (string/null) — e.g. JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAw…
  • outcome_reason (string/null) — null in every sample row
  • observed_at (string/null) — null in every sample row
  • terminal (string/null) — null in every sample row

Output & billing

One row per target. A complete evidenced verdict carries outcome: answer and is the only billable outcome; blocked / unreachable / unparseable / rejected targets carry that status and are not billed (push-then-charge — failures can only undercharge).

⚙️ Sample inputs

1. Quick start — the Store example (this is what the sample above came from)

{
"files": [
"JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAwIFJdCi9NZWRpYUJveCBbMCAwIDU5NS4yOCA4NDEuODldCi9UeXBlIC9QYWdlcwo+PgplbmRvYmoKMiAwIG9iago8PAovT3BlbkFjdGlvbiBbMyAwIFIgL0ZpdEggbnVsbF0KL1BhZ2VMYXlvdXQgL09uZUNvbHVtbgovUGFnZXMgMSAwIFIKL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL0NvbnRlbnRzIDQgMCBSCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyA2IDAgUgovVHlwZSAvUGFnZQo+PgplbmRvYmoKNCAwIG9iago8PAovRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDI0MAo+PgpzdHJlYW0KeJy10sFOwzAMBuD7nuI/MomFJG2ajtsQbAIhhFAlzqHxtkCXoTaD8fZk1VB34LhIPlm2P0u2xMOIM6XxPbqpcDUXEDnjHNUSd9UhlQkmSuipYkKjsrh4ov2C/KsJ9RrPt3Pc+2A+CLOddWHbYoLObD4bAn05S74m2G2925APbIzq/Ti1h8R/kI7bFD306DxBXCOsXYcYBi2Z5hIdNVQH8xaNQPuAxvxQi2W0X2aLSayxsbGL9YeNnF+dukck16wsB0QmQaRikg9IlgThkqlsQPIUSKGnrFQDopIgSv99WI8USZAsZ+rkJvqMyC/VYgHPCmVuZHN0cmVhbQplbmRvYmoKNSAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYQovRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZwovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjYgMCBvYmoKPDwKL0ZvbnQgPDwvRjEgNSAwIFI+PgovUHJvY1NldCBbL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSV0KPj4KZW5kb2JqCjcgMCBvYmoKPDwKL0NyZWF0aW9uRGF0ZSAoRDoyMDI2MDkxNTAyNDkyOVopCj4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDEwMiAwMDAwMCBuIAowMDAwMDAwMjA1IDAwMDAwIG4gCjAwMDAwMDAyODUgMDAwMDAgbiAKMDAwMDAwMDU5NyAwMDAwMCBuIAowMDAwMDAwNjk0IDAwMDAwIG4gCjAwMDAwMDA3ODEgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSA4Ci9Sb290IDIgMCBSCi9JbmZvIDcgMCBSCi9JRCBbPEYxMjc2NkZDNDlCRjQ1MTIzQUIxMzNDNTY2NTA5MDBDPjxGMTI3NjZGQzQ5QkY0NTEyM0FCMTMzQzU2NjUwOTAwQz5dCj4+CnN0YXJ0eHJlZgo4MzYKJSVFT0YK"
],
"maxBytes": 26214400,
"maxPages": 300
}

The sample run charged exactly: 1 × $0.02 apify-actor-start + 1 × $0.05 pdf_intake_check = $0.07 on the Free tier — every delivered row was billed.

2. A smaller, narrowed run

{
"files": [
"JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAwIFJdCi9NZWRpYUJveCBbMCAwIDU5NS4yOCA4NDEuODldCi9UeXBlIC9QYWdlcwo+PgplbmRvYmoKMiAwIG9iago8PAovT3BlbkFjdGlvbiBbMyAwIFIgL0ZpdEggbnVsbF0KL1BhZ2VMYXlvdXQgL09uZUNvbHVtbgovUGFnZXMgMSAwIFIKL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL0NvbnRlbnRzIDQgMCBSCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyA2IDAgUgovVHlwZSAvUGFnZQo+PgplbmRvYmoKNCAwIG9iago8PAovRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDI0MAo+PgpzdHJlYW0KeJy10sFOwzAMBuD7nuI/MomFJG2ajtsQbAIhhFAlzqHxtkCXoTaD8fZk1VB34LhIPlm2P0u2xMOIM6XxPbqpcDUXEDnjHNUSd9UhlQkmSuipYkKjsrh4ov2C/KsJ9RrPt3Pc+2A+CLOddWHbYoLObD4bAn05S74m2G2925APbIzq/Ti1h8R/kI7bFD306DxBXCOsXYcYBi2Z5hIdNVQH8xaNQPuAxvxQi2W0X2aLSayxsbGL9YeNnF+dukck16wsB0QmQaRikg9IlgThkqlsQPIUSKGnrFQDopIgSv99WI8USZAsZ+rkJvqMyC/VYgHPCmVuZHN0cmVhbQplbmRvYmoKNSAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYQovRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZwovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjYgMCBvYmoKPDwKL0ZvbnQgPDwvRjEgNSAwIFI+PgovUHJvY1NldCBbL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSV0KPj4KZW5kb2JqCjcgMCBvYmoKPDwKL0NyZWF0aW9uRGF0ZSAoRDoyMDI2MDkxNTAyNDkyOVopCj4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDEwMiAwMDAwMCBuIAowMDAwMDAwMjA1IDAwMDAwIG4gCjAwMDAwMDAyODUgMDAwMDAgbiAKMDAwMDAwMDU5NyAwMDAwMCBuIAowMDAwMDAwNjk0IDAwMDAwIG4gCjAwMDAwMDA3ODEgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSA4Ci9Sb290IDIgMCBSCi9JbmZvIDcgMCBSCi9JRCBbPEYxMjc2NkZDNDlCRjQ1MTIzQUIxMzNDNTY2NTA5MDBDPjxGMTI3NjZGQzQ5QkY0NTEyM0FCMTMzQzU2NjUwOTAwQz5dCj4+CnN0YXJ0eHJlZgo4MzYKJSVFT0YK"
],
"maxBytes": 26214400,
"maxPages": 300,
"userAgent": "Mozilla/5.0 (compatible; NexGenWatchBot/1.0; +https://apify.com/nexgenwatch)"
}

A bounded run for checking the field shape before scheduling. userAgent narrows what the source is asked for.

3. A full-size run

{
"files": [
"JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAwIFJdCi9NZWRpYUJveCBbMCAwIDU5NS4yOCA4NDEuODldCi9UeXBlIC9QYWdlcwo+PgplbmRvYmoKMiAwIG9iago8PAovT3BlbkFjdGlvbiBbMyAwIFIgL0ZpdEggbnVsbF0KL1BhZ2VMYXlvdXQgL09uZUNvbHVtbgovUGFnZXMgMSAwIFIKL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL0NvbnRlbnRzIDQgMCBSCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyA2IDAgUgovVHlwZSAvUGFnZQo+PgplbmRvYmoKNCAwIG9iago8PAovRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDI0MAo+PgpzdHJlYW0KeJy10sFOwzAMBuD7nuI/MomFJG2ajtsQbAIhhFAlzqHxtkCXoTaD8fZk1VB34LhIPlm2P0u2xMOIM6XxPbqpcDUXEDnjHNUSd9UhlQkmSuipYkKjsrh4ov2C/KsJ9RrPt3Pc+2A+CLOddWHbYoLObD4bAn05S74m2G2925APbIzq/Ti1h8R/kI7bFD306DxBXCOsXYcYBi2Z5hIdNVQH8xaNQPuAxvxQi2W0X2aLSayxsbGL9YeNnF+dukck16wsB0QmQaRikg9IlgThkqlsQPIUSKGnrFQDopIgSv99WI8USZAsZ+rkJvqMyC/VYgHPCmVuZHN0cmVhbQplbmRvYmoKNSAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYQovRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZwovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjYgMCBvYmoKPDwKL0ZvbnQgPDwvRjEgNSAwIFI+PgovUHJvY1NldCBbL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSV0KPj4KZW5kb2JqCjcgMCBvYmoKPDwKL0NyZWF0aW9uRGF0ZSAoRDoyMDI2MDkxNTAyNDkyOVopCj4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDEwMiAwMDAwMCBuIAowMDAwMDAwMjA1IDAwMDAwIG4gCjAwMDAwMDAyODUgMDAwMDAgbiAKMDAwMDAwMDU5NyAwMDAwMCBuIAowMDAwMDAwNjk0IDAwMDAwIG4gCjAwMDAwMDA3ODEgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSA4Ci9Sb290IDIgMCBSCi9JbmZvIDcgMCBSCi9JRCBbPEYxMjc2NkZDNDlCRjQ1MTIzQUIxMzNDNTY2NTA5MDBDPjxGMTI3NjZGQzQ5QkY0NTEyM0FCMTMzQzU2NjUwOTAwQz5dCj4+CnN0YXJ0eHJlZgo4MzYKJSVFT0YK"
],
"maxBytes": 26214400,
"maxPages": 300
}

The same input run on a schedule; each run is billed only for what it delivers.

🧾 JSON sample record

One real record from run nDCqwi1I4PF7enD8p, exactly as it lands in the dataset (emails masked, long text shortened):

{
"input_ref": "JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAw…",
"source_type": "base64",
"bytes": 1146,
"sha256": "a25f6b496a13eb8c3643a2ba8f21b674c2f2c860de4f8bb4139cdf0ec4c61ca1",
"page_count": 1,
"encrypted": false,
"has_text_layer": true,
"scan_likelihood": "low",
"per_page_text_density": "[576]",
"text_char_total": 576,
"metadata": "{\"creationdate\":\"D:20260915024929Z\"}",
"verdict": "READY_FOR_RAG",
"warnings": "contains JavaScript/auto-action objects (reported, NEVER executed)",
"faults": null,
"record_type": "pdf_intake_verdict",
"source": "buyer-supplied local PDFs (base64 / key-value-store keys)",
"outcome": "answer",
"input": "JVBERi0xLjMKJenr8b8KMSAwIG9iago8PAovQ291bnQgMQovS2lkcyBbMyAw…",
"outcome_reason": null
}

🔧 How it works

Transport. Plain HTTPS from the Apify platform, no proxy. robots.txt is read first and a disallowed path is never fetched. Every request carries an identified contact User-Agent.

Terminal states. A run ends NORMAL, CAPPED (your cap was reached), PARTIAL (something was withheld and the message says what), GENUINE_EMPTY (the source was read and truly had nothing in scope) or BLOCKED (the source refused or changed shape — the run FAILS loud and bills nothing). A zero-row run is never reported as a silent success.

Charging. Each pdf intake check is charged at the moment it is pushed (pdf_intake_check); a row that fails to charge is not delivered, so the dataset count always equals the charged count.

What you submit

files — pdf files (base64 or key-value-store keys). Locally-supplied PDFs — each item is a base64 data string (optionally a data: URL) or a key naming an entry in the run's key-value store. Per file: text-layer presence, page count, encryption, scan likelihood, per-page text density, document metadata, SHA-256, warnings, and a READY_FOR_RAG / NEEDS_OCR / REJECT verdict. A completed verdict bills; an unreadable/oversized/rejected file is delivered unbilled. Untrusted-file guards: size + page caps, decompression-bomb guard, no macro/JS execution.

Untrusted-file guards

Inputs are treated as untrusted: a byte-size cap (decompression-bomb guard) rejects oversized files before parsing, a page cap bounds inspection, and embedded JavaScript / auto-actions are reported as warnings, never executed. Files are inspected, not run.

Why this and not the obvious alternative

a per-file RAG-readiness intake VERDICT with a content hash and OCR-need call — not a PDF-to-text dump; it judges whether a document is ingestible before you spend on extraction.

What is not done. No login, no cookie or CAPTCHA bypass, no private or personal-account data, no browser automation.

💰 Pricing example

EventFreeBronzeSilverGold
Actor Start (apify-actor-start)$0.02$0.02$0.02$0.02
Pdf Intake Check (pdf_intake_check)$0.05$0.04$0.04$0.03

Worked at the live Free-tier price:

  • 1 pdf intake checks: $0.02 start + 1 × $0.05 = $0.07
  • 25 pdf intake checks: $0.02 start + 25 × $0.05 = $1.27
  • 100 pdf intake checks: $0.02 start + 100 × $0.05 = $5.02

A run that delivers zero rows charges the $0.02 start fee only. A BLOCKED run (source refused) fails loud and charges no value event. The start fee is charged once per GB of run memory; the default run memory is 1024 MB.

Yield on the sample run: 1 file(s): 1 billable verdict(s), 0 unbilled (reject/unparseable/unavailable) | pdf_intake_check charged=1.

This actor reads public data only. It collects only what the source publishes to any visitor, keeps to the source's robots rules (checked on every run), identifies itself with a contact User-Agent, and does not access accounts, private data or anything behind authentication. Use the output in line with the source's terms and your local law; the intended use is B2B research and monitoring.

❓ FAQ

Q: Do I need an API key or a login?
A: No. the input schema has no key field and the actor carries no secrets.

Q: Why did my run return 0 rows?
A: Read the run's status message. GENUINE_EMPTY means the source was read and had nothing in scope for your input; BLOCKED means the source refused and the run failed without billing a value event — retry later or narrow the input. A zero-row run bills the start fee only.

Q: How fresh is the data?
A: Every run reads the source live at run time; nothing is cached between runs. Put it on a schedule for a continuous feed.

Q: What formats can I export?
A: The dataset downloads as JSON, CSV, Excel, XML or RSS from the run's Dataset tab or the Apify API, and any run can push to a webhook or integration.

Q: How is this different from the other web QA and enrichment tools actors?
A: Same output shape and billing model; this one covers PDF Text Intake Auditor. The siblings under Related Actors cover the other sources or slices — run several on one schedule for a combined feed.

Q: Are there rate limits?
A: The actor paces itself against the source and honours its robots rules; there is no per-buyer limit beyond your Apify plan's concurrency.

🆘 Troubleshooting

  • Run FAILED with BLOCKED → the source refused the request or changed its page shape → nothing was billed beyond the start fee; retry after a while, and if it persists open an Issue with the run id.
  • Fewer rows than expected → the source had fewer items in scope → widen the input.
  • Input validation error on start → a field is outside the schema's allowed values → start from the Quick start block and change one field at a time.
  • Run TIMED-OUT → a very wide request on a slow day → raise the run timeout in Run options or narrow the input; what was delivered before the timeout is still in the dataset.
  • HTML to PDF Evidence Renderer — Renders each HTML document or permitted public URL to a hashed, print-pinned PDF evidence artifact: page count, resource-failure ledger, input+output…
  • Internal Link Architecture Verifier — Runs a bounded same-origin crawl unioned with your sitemap, builds the internal link graph, and returns one evidenced verdict per page: orphan-from-s…
  • Marketing Stack Enricher — Give it a list of company domains; it returns one CRM-ready record per domain describing
  • Responsive Visual QA Matrix — Runs a headless-Chromium responsive QA pass on each URL across desktop/tablet/mobile and returns one verdict per URL: per-viewport layout metrics, a…
  • 🧠 Review Sentiment Analyzer — Themes, Trends & Complaints — Turn any review set into themes, complaints, sentiment % and trends
  • RSS Feed Contract Monitor — Checks a feed's health and contract: RSS/Atom/RDF shape validation, item canonicalization, a freshness score, duplicate GUID/link detection, ETag/Las…
  • 🏢 About NexGenData — NexGen Watch is NexGenData's fleet of 256 public monitoring and lookup actors built on official sources, pay-per-result. Browse the catalog at apify.com/nexgenwatch.

⭐ Found this useful?

If this actor saved you a manual check, a quick review on the Apify Store helps other teams find it. Feature request or a source that changed? Open it from the Issues tab — every one is read.