PDF Inspector: Scanned PDF Detector & Metadata Audit avatar

PDF Inspector: Scanned PDF Detector & Metadata Audit

Pricing

Pay per usage

Go to Apify Store
PDF Inspector: Scanned PDF Detector & Metadata Audit

PDF Inspector: Scanned PDF Detector & Metadata Audit

Bulk PDF audit before OCR or text extraction: which pages are scanned and need OCR, which files are encrypted, what the metadata leaks (author, local paths), embedded JavaScript and attachments, PDF/A and PDF/UA conformance, unembedded fonts, and every link inside the document.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Ai-Q Labs

Ai-Q Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 hours ago

Last modified

Share

Point it at a list of PDF URLs. It tells you, per file, whether text can be pulled out of it at all, what the file leaks about whoever made it, and whether anything inside it should stop you opening it.

This is the step before a PDF text extractor, not another one. A plain extractor hands back an empty string for a scanned page and gives you no way to tell that apart from a genuinely blank one. On a batch of a thousand documents that difference decides how much OCR you pay for.

Free to run. No API key, no proxy, no browser. Two HTTP requests per file at most: the download, and nothing else unless you turn link checking on.


The question it answers that a text extractor cannot

For every page, the Actor separates four cases that all look identical in extractor output:

Page kindWhat it meansWhat to do
text200+ characters of extractable textExtract it, you are done
sparseShort but real text - a title page, a dividerExtract it
image_with_stampAlmost no text next to images: a page number or Bates stamp burned onto a scanSend to OCR
image_onlyNo text, images presentSend to OCR
blankNo text and no images. Genuinely emptySkip it - OCR would cost money and return nothing

Those roll up into one field per document, textLayer:

  • full - every page can be read
  • partial - some pages can, some cannot. This is the dangerous one: a plain extractor returns content, so nothing looks wrong, and you silently lose the scanned pages
  • none - the whole document is a scan
  • empty - every page inspected was confirmed blank

and one number, pagesNeedingOcr, with ocrCountConfirmed telling you whether that number was measured on every page or partly inferred because the probe budget ran out.


What else comes back

Can it even be opened Encrypted-with-a-password files, damaged files, and HTML error pages served with status 200 under a .pdf URL are separated from each other rather than all failing the same way.

Permissions Which of the eight PDF permission bits are denied: printing, copying text, editing, filling forms, extracting for accessibility, assembling, high-quality printing. A file that opens fine can still be one that your extractor refuses to read.

What the file discloses Author, subject, keywords, creator, producer, creation and modification dates, XMP creator tool and document ID. Plus a byte-level search for local filesystem paths - C:\Users\..., /Users/..., \\fileserver\..., file:///... - that ended up baked into the file. Those name a person or map your internal storage.

revisions counts incremental saves. A file saved incrementally three times still contains the two earlier versions of its content; anything "removed" in the last pass may still be in there.

What it will run Document-level JavaScript, OpenAction, Launch actions (which ask the reader to execute an external file), SubmitForm actions (which post entered data to a URL), embedded file attachments with their filenames, and rich media. For inbound documents from outside your organisation, these are the fields worth a look.

Embedded XML matching a known e-invoice profile - Factur-X, ZUGFeRD, XRechnung, Order-X, UBL - is called out separately, because there the attachment is the point of the file.

Conformance and accessibility Tagged or not (from the document's own MarkInfo, not a guess), document language, title, bookmark count, PDF/A-1b-style conformance and PDF/UA-1 claims read from XMP.

Fonts Font names, and whether font programs are embedded. The warning only fires when a font outside the standard 14 is referenced without shipping the program - a file that uses only Helvetica and Times and embeds nothing is correct and portable, and is not reported as a problem.

Links inside the document Every URI link annotation, with its page number. Relative links are resolved against the location the PDF was downloaded from, exactly as a reader would. file:// links and plain http:// links are flagged. Turn checkLinks on and each one is requested, so you get the dead ones.


Status, and why ok still means something

Every row carries status, one of ok, warning, error, plus issues (machine-readable codes), issuesBySeverity, and explanations - one plain sentence per issue, so nothing needs looking up.

The severity split is deliberate:

  • error - the file could not be read, so no other field on that row can be trusted
  • warning - something that will break a downstream job or leak information
  • notice - true of most PDFs ever published: untagged, not linearised, producer string present, no document language

Notices are recorded, because if you are auditing for accessibility they are the whole point. They never change status. Untagged PDFs are the overwhelming majority of what exists; if that alone flipped every row to "warning", the twelve files that actually need work would be invisible.

onlyIssues uses the same rule, so it keeps the batch short instead of returning everything.


Output

One dataset row per PDF, plus four ready-made views in the Apify UI: Overview, OCR triage, Security and privacy, Accessibility and conformance. Export as JSON, CSV, or Excel.

A SUMMARY record in the key-value store holds the run totals: the status split, the textLayer split, how many pages out of the batch need OCR and which files are worst, the security counts, and a breakdown of every issue code by how often it fired.


Input

FieldDefaultNotes
pdfUrls-Direct links, one per line. Redirects followed
extractTextfalseAlso return the readable text
checkLinksfalseRequest every link found inside the documents
onlyIssuesfalseDrop rows whose status is ok
maxPages200Page-level inspection budget per file
maxOcrProbePages25Pages to read drawing instructions for
maxFileMb50Refused before the whole file is downloaded
maxConcurrency5Parsing holds a whole file in memory

Limits, stated plainly

  • Scanned-page detection is a measurement, not OCR. It tells you which pages need OCR and roughly what that will cost you. It does not read them.
  • Password-protected files stay closed. No password input, no cracking. They come back as encrypted_password_required and nothing else about them is claimed.
  • JavaScript, Launch and attachment detection is best-effort. From PDF 1.5 onward, objects can live in compressed streams where a byte-level search cannot see them. Every positive is real; a negative means "not found", not "definitely absent". The parser's own findings are used first and the byte scan only adds to them.
  • fontObjects counts what is visible in the clear. In a file that stores its font dictionaries in compressed object streams the count is 0 even though fonts exist. The unembedded-font warning depends on both signals, so it stays silent rather than firing wrongly.
  • Digital signatures are reported, not validated. The Actor tells you a signature field exists. It does not tell you the signature is good.
  • Only the pages inside maxPages are classified. pageCount is always the real total.

Verification

npm test runs 22 unit tests covering page classification, the PDF date format, XMP in all three encodings real tools produce (single-quoted attributes, double-quoted attributes, child elements) under both the xmpMM and xapMM prefixes, the byte scan, link classification, and the severity rules.

npm run test:live runs 45 checks against real files on the real internet: a scanned six-page document, a password-protected file, a PDF/A-1b file written by Ghostscript, a PDF/UA-1 tagged government form with an XFA layer, a file with an embedded attachment, a file containing a relative link, an HTML page served as a PDF, a 404, a real 301 redirect, the size limit, the timeout, and live link checking against known-good and known-dead URLs.