TPTruPDF

Conversion

The viewer renders PDFs natively. Every other format converts to PDF through the @trupdf/converter service — a self-hosted container built around the TruPDF conversion engine, with an office pipeline, an HTML render pipeline, a raster pipeline, and the TruCAD engine for 2D CAD.

Supported formats

FamilyExtensionsPipeline
PDF.pdfPassthrough — rendered natively, no server
Word processing.doc, .docx, .docm, .dot, .dotx, .dotm, .odt, .ott, .fodt, .rtf, .wps, .wpd, .pages, .abw, .sxw, .stwOffice pipeline
Spreadsheets.xls, .xlsx, .xlsm, .xlsb, .xlt, .xltx, .xltm, .xlw, .ods, .ots, .fods, .csv, .tsv, .numbers, .dif, .slk, .dbf, .sxc, .stcOffice pipeline
Presentations.ppt, .pptx, .pptm, .pot, .potx, .potm, .pps, .ppsx, .ppsm, .odp, .otp, .fodp, .key, .sxi, .stiOffice pipeline
Drawings & pub.vsd, .vsdx, .vsdm, .vdx, .pub, .odg, .otg, .fodg, .std, .sxd, .epub, .epsOffice pipeline
HTML.html, .htm, .xhtmlHTML render pipeline
Text & code.txt; Markdown (.md, .mdown, .mkd, .mkdn, .mdx); .json, .xml, .xaml, .js, .ts, .yaml, .toml, .py, .c, C++, .java, .go, Rust, Ruby, shell, .sqlText pipeline
Images.jpg, .jpeg, .jfif, .jpe, .png, .apng, .gif, .bmp, .svg, .webp, .avif, .ico, .curImage pipeline (browser-native ones also client-side)
Extended rasterTIFF (multi-page), HEIC, camera rawRaster pipeline
Email.eml, .msgParsed, then rendered
XPS.xps, .oxpsXPS pipeline
XOD.xod — legacy WebViewer XOD archivesXOD pipeline
2D CAD.dxf, .dwg (R12–R2018, CTB plot styles), .dwf, .dwfx, .dgnTruCAD engine (sidecar service)
RVT / RFA.rvt, .rfaRejected with a typed, actionable error — Revit files are 3D BIM, not 2D CAD

2D CAD — the TruCAD engine

DXF, DWG, DWF, DWFx, and DGN drawings convert through TruCADTruenoTech's own clean-room CAD engine, deployed as a separate sidecar service the converter reaches over HTTP. DWG coverage spans releases R12 through R2018, including CTB plot-style tables so line weights and plot colours reproduce faithfully.

Because TruCAD is built and maintained in-house, CAD support carries no third-party licensing constraints and evolves with the product — new releases and entity types land in the sidecar without touching your integration.

Client-only flows

Two inputs never need the server:

  • PDF — rendered natively by the viewer.
  • Browser-native images (PNG, JPEG, GIF, WebP, and any other format the browser decodes) — wrapped into a PDF client-side via imageToPdf(bytes, mime).

Everything else requires the conversion service.

Running the service

docker-compose up -d brings up the conversion engine, the result cache, and the converter orchestrator (port 3002). Internal service wiring between the containers is preconfigured by the bundled docker-compose.yml — you only set the variables documented in Advanced setup (license, API key, CORS origins, storage adapter).

Point the viewer at the converter:

NEXT_PUBLIC_CONVERTER_URL=https://convert.example.com   # your deployment — no default
<DocViewer
  source={file}
  converterUrl={process.env.NEXT_PUBLIC_CONVERTER_URL}
  converterApiKey={apiKey} // sent as X-TruPDF-API-Key

/>

The viewer auto-detects non-PDF sources, POSTs them to /convert, then loads the resulting PDF from the returned URL. Long-running conversions can use the async pair (/convert/async + /convert/jobs/:id) instead.

HTTP API

RouteMethodPurpose
/healthGETLiveness probe; reports whether the async queue is enabled
/convertPOSTMultipart file; blocks until done, returns { url, hash, strategy, fromCache, durationMs, bytes }
/convert/asyncPOSTMultipart file; returns 202 { jobId } immediately (503 when the queue is disabled)
/convert/jobs/:idGETJob snapshot { id, status, progress, result, error, attemptsMade }
/convert/jobs/:idDELETECancel / remove the job (204)
/docgenPOSTMultipart template + data JSON → rendered PDF (same response shape as /convert)
/bookmarks/readPOSTRead user bookmarks stored as a PDF attachment
/bookmarks/writePOSTWrite the bookmark tree back into the PDF attachment
/fetch-urlPOST{ url } — SSRF-guarded server-side fetch for CORS-blocked remote files; original filename surfaced via X-TruPDF-Original-Name

Authentication — set TRUPDF_CONVERTER_API_KEY on the service (required in production); callers send it as the X-TruPDF-API-Key header. The viewer does this automatically from the converterApiKey prop.

Password-protected documents — supply the open password as a multipart password field or the X-Document-Password header on /convert and /convert/async. Encrypted files without a valid password fail with PASSWORD_REQUIRED.

Error codes

Failures return a typed JSON body { code, message }:

CodeHTTPWhen
INVALID_INPUT400Missing / malformed field, bad URL, invalid JSON
UNSUPPORTED_FORMAT400No pipeline claims the file's format
PASSWORD_REQUIRED401Encrypted document; no or wrong password supplied
NOT_FOUND404Unknown job id
FILE_TOO_LARGE413Upload exceeds MAX_UPLOAD_BYTES
QUEUE_DISABLED503Async endpoints called without a queue configured
UPSTREAM_ERROR502/fetch-url upstream failure
TIMEOUT504Conversion exceeded CONVERSION_TIMEOUT_MS
INTERNAL500Everything else

A conversion pipeline that is unreachable returns 503, and one that rejects the input returns 502 — both with a typed code identifying which pipeline failed (e.g. CAD_CONVERTER_UNAVAILABLE / CAD_CONVERTER_FAILED for the TruCAD sidecar).

Strategy router

Each format family maps to a typed strategy:

  • PassthroughStrategy — PDF
  • OfficeStrategy — word processing / spreadsheets / presentations / drawings
  • HTMLStrategy — HTML / XHTML / HTM
  • TextStrategy — plain text, Markdown, code files
  • ImageStrategy — browser-common raster images
  • RasterImageStrategy — multi-page TIFF
  • MagickImageStrategy — extended raster (HEIC, SVG rasterisation, camera raw)
  • EmailStrategy — EML / MSG
  • XpsStrategy — XPS / OXPS
  • XodStrategy — legacy WebViewer XOD archives
  • TruCadStrategy — 2D CAD via the TruCAD sidecar
  • RvtStrategy — typed rejection for Revit 3D BIM files

Adding a new format = adding a new strategy. No parallel pipelines.

Storage adapters

The converter persists results via a pluggable backend:

AdapterEnv STORAGE_ADAPTERUse case
LocalStorageAdapterlocalDev / single-node
S3StorageAdapters3AWS S3 / MinIO / Cloudflare R2
AzureBlobStorageAdapterazureAzure Blob Storage
WebhookStorageAdapterwebhookCustom HTTP sink (HMAC-signed)

See Advanced setup for the env-var matrix per adapter.

Result cache

Converted output lands in the result cache (7-day TTL by default, CACHE_TTL_SECONDS). The cache key is sha256(input), so re-uploading the same file returns the cached result instantly — across users. fromCache: true in the response marks a hit.

Set LOG_LEVEL=debug to see cache hits / misses.

License gating

The converter constructor calls gate.require('convert'). The viewer silently skips conversion endpoints when the bound license is missing the feature. Trial tokens do not include convert; pro and enterprise include it by default.