TPTruPDF

PDF/A & Tagged PDF

Archival conformance (ISO 19005) and logical document structure (Tagged PDF). Claim detection runs instantly in the browser; full validation runs on the TruPDF document service — the same self-hosted container that powers structural redaction.

PDF/A claim detection (instant, offline)

Every PDF/A producer stamps the conformance level into XMP metadata (pdfaid:part / pdfaid:conformance). Reading the claim is instant and needs no server:

const claim = await sdk.getPdfAClaim();
// { part: 2, conformance: 'B', label: 'PDF/A-2B' } — or null
 
if (claim) badge.textContent = claim.label;

Returns null when the document makes no PDF/A claim. A claim is not proof — any tool can write the XMP entry. For proof, run full validation.

Full ISO 19005 validation

sdk.validatePdfA() posts the loaded document to the document service's POST /validate/pdfa endpoint, runs the full ISO 19005 rule set through the validation engine, and returns a typed report with per-clause failures:

import { PdfAValidationError } from '@trupdf/viewer';
 
try {
  const report = await sdk.validatePdfA({
    endpoint: process.env.NEXT_PUBLIC_TRUPDF_DOCSERVICE_URL!, // your deployment — required, no default
    secret: process.env.NEXT_PUBLIC_TRUPDF_DOCSERVICE_SECRET,
    flavour: 'auto', // default — the validation engine picks from the document's claim
  });
 
  if (report.compliant) {
    console.log(`Valid PDF/A-${report.flavour} — ${report.totalChecks} checks passed`);
  } else {
    for (const rule of report.failedRules) {
      console.warn(
        `§${rule.clause} test ${rule.testNumber}: ${rule.description} (${rule.failedChecks}×)`,
      );
    }
  }
} catch (e) {
  if (e instanceof PdfAValidationError) console.error(e.code, e.message);
}

Result shape

FieldMeaning
complianttrue when every ISO 19005 rule check passed
flavourFlavour validated against, e.g. 2B (after auto-detection)
statementHuman-readable compliance statement from the validation engine
totalChecksNumber of rule checks executed
failedRules{ clause, testNumber, description, failedChecks }[] — ISO 19005 clause per failure
truncatedtrue when failedRules was capped server-side

Flavours

auto (default), 1a, 1b, 2a, 2b, 2u, 3a, 3b, 3u. With auto, the validation engine detects the flavour from the document's own claim.

Errors

All failures throw PdfAValidationError with a typed code:

CodeWhen
NETWORKRequest never reached the service (or no endpoint)
HTTPNon-2xx response without a more specific cause
UNPARSEABLE_PDFThe service could not parse the PDF binary
INVALID_FLAVOURThe service rejected the requested flavour
BAD_RESPONSEResponse was not JSON / unexpected shape

Endpoint configuration

The endpoint URL must come from your own config/env — TruPDF never ships a default URL. When the service enforces a shared secret (TRUPDF_INTERNAL_SECRET on the service side), pass it as secret and it is sent as the X-TruPDF-Internal-Secret header.

The endpoint lives in the same self-hosted TruPDF document service that powers structural redaction:

docker compose --profile phase8 up -d

See Advanced setup for service env vars.

Tagged PDF

Tagged PDF is the logical structure tree screen readers and PDF/UA workflows consume. Two read APIs:

const { isTagged, suspects } = await sdk.getTaggedPdfInfo();
// Catalog /MarkInfo: isTagged = /Marked true; suspects = /Suspects true
// (Acrobat shows the latter as "tagged, with suspects")
 
const tree = await sdk.getStructureTree(1); // 1-based page number
// StructureNode | null (null on untagged documents)

Each StructureNode is normalised for hosts:

interface StructureNode {
  role: string; // after role-mapping: 'Document', 'H1', 'P', 'Table', 'Figure', …
  alt?: string; // /Alt alternate description (figures)
  lang?: string; // /Lang override
  children: StructureNode[];
  contentItems: number; // marked-content leaves under this node
}

Walk it to extract headings, table semantics, or figure alt text — the same data a PDF/UA checker inspects:

function headings(node: StructureNode, out: string[] = []): string[] {
  if (/^H[1-6]$/.test(node.role)) out.push(node.role);
  node.children.forEach((c) => headings(c, out));
  return out;
}

Reading is v1 — tag authoring is on the roadmap. See Accessibility for how the viewer itself exposes content to screen readers.

Engine-level APIs (non-SDK hosts)

The same capabilities exist as standalone functions, exported from @trupdf/viewer / @trupdf/core, for hosts that work with the render engine directly:

import {
  detectPdfAClaim,
  validatePdfA,
  readTaggedPdfInfo,
  readStructureTree,
} from '@trupdf/viewer';
 
const claim = await detectPdfAClaim(pdf); // the loaded document handle
const info = await readTaggedPdfInfo(pdf);
const tree = await readStructureTree(pdf, 1);
 
const report = await validatePdfA(await pdf.getData(), {
  endpoint: process.env.NEXT_PUBLIC_TRUPDF_DOCSERVICE_URL!,
});