Advanced setup
Beyond Quick setup: environment variables, self-hosted services, secure mode, AI providers, storage adapters, custom domains, and Docker.
Environment variables
Browser-side (Next.js, Vite, CRA, …)
The viewer reads these at runtime. Prefix names match your bundler's
public-env convention (NEXT_PUBLIC_ shown).
| Variable | Purpose | Required? |
|---|---|---|
NEXT_PUBLIC_TRUPDF_LICENSE | Signed license token | yes |
NEXT_PUBLIC_TRUPDF_LICENSE_BASE_URL | License-server origin (heartbeat, revocation feed) | yes |
NEXT_PUBLIC_TRUPDF_SAMPLE_URL | Sample PDF URL for the demo route | demo only |
NEXT_PUBLIC_CONVERTER_URL | Base URL of your @trupdf/converter deployment | conversion |
NEXT_PUBLIC_TRUPDF_CONVERTER_API_KEY | Converter API key (passed via converterApiKey) | conversion |
NEXT_PUBLIC_TRUPDF_DOCSERVICE_URL | Base URL of the TruPDF document service | redaction |
NEXT_PUBLIC_TRUPDF_AI_ANTHROPIC_KEY | Anthropic API key | AI |
NEXT_PUBLIC_TRUPDF_AI_GEMINI_KEY | Google Gemini key | AI |
NEXT_PUBLIC_TRUPDF_AI_OPENROUTER_KEY | OpenRouter key | AI |
NEXT_PUBLIC_TRUPDF_AI_OPENROUTER_BASE_URL | OpenRouter base URL override | AI |
NEXT_PUBLIC_TRUPDF_AI_OPENAI_COMPATIBLE_BASE_URL | Custom OpenAI-compatible LLM endpoint | AI |
NEXT_PUBLIC_TRUPDF_AI_OPENAI_COMPATIBLE_KEY | Custom LLM key | AI |
NEXT_PUBLIC_TRUPDF_AI_MODEL | Model override (e.g., claude-3-5-sonnet) | AI |
URLs must come from env vars and fail loudly when missing. No hard-coded
localhost. CORS origins must be explicit too — never wildcarded in production.
Server-side (conversion + document services)
These are read by the @trupdf/converter and document-service
processes, not the browser bundle.
Internal service wiring (engine, queue, cache) is preconfigured by the bundled
docker-compose.yml; you only set the variables below.
@trupdf/converter
| Variable | Purpose |
|---|---|
TRUPDF_LICENSE | Signed license (verified on startup) |
TRUPDF_LICENSE_DEV_MODE | 1 = synthetic enterprise (dev only; logged at WARN) |
TRUPDF_CONVERTER_API_KEY | API key clients must send (required in production) |
STORAGE_ADAPTER | local / s3 / azure / webhook |
LOCAL_STORAGE_DIR | Default /data/storage |
LOCAL_STORAGE_PUBLIC_URL | Public URL prefix for local storage |
S3_BUCKET / S3_REGION / S3_ENDPOINT / S3_KEY_PREFIX | S3 / MinIO config |
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | AWS credentials |
S3_URL_EXPIRY | Presigned URL TTL (seconds) |
S3_FORCE_PATH_STYLE | 1 for MinIO |
AZURE_ACCOUNT_NAME / AZURE_ACCOUNT_KEY / AZURE_CONTAINER / AZURE_URL_EXPIRY / AZURE_KEY_PREFIX | Azure Blob config |
WEBHOOK_STORE_URL / WEBHOOK_RETRIEVE_URL / WEBHOOK_EXISTS_URL / WEBHOOK_DELETE_URL / WEBHOOK_TOKEN / WEBHOOK_HMAC_SECRET | Webhook adapter (custom HTTP sink) |
CORS_ORIGINS | Comma list of allowed origins (required) |
CONVERSION_TIMEOUT_MS | Per-job timeout. Default 1800000 (30 min) |
MAX_UPLOAD_BYTES | Upload size cap. Default 0 (unlimited) |
CACHE_TTL_SECONDS | Result-cache TTL. Default 604800 (7 days) |
RETENTION_SWEEP_INTERVAL_MS | How often stored results are swept |
RETENTION_MAX_AGE_MS | Max age of stored results before deletion |
LOG_LEVEL | debug / info / warn / error |
PORT | Default 3002 |
The TruPDF document service (structural redaction + PDF/A validation)
| Variable | Purpose |
|---|---|
TRUPDF_CORS_ORIGINS | Comma list of allowed origins |
JAVA_OPTS | Service memory flags (-Xmx512m recommended for 50-page docs) |
DocViewer props
The main component accepts every prop the viewer exposes. See Features → Viewer for the full table; the ones you'll set most often:
<DocViewer
source="/files/sample.pdf"
licenseManager={license}
theme="system" // 'light' | 'dark' | 'system'
initialScale={1.25}
secureMode={false}
showThumbnails
showComments
modularConfig="default-ui" // or a custom JSON config
mode="view" // 'view' | 'compare'
language="en" // any of the 31 locales
converterUrl={process.env.NEXT_PUBLIC_CONVERTER_URL}
converterApiKey={process.env.NEXT_PUBLIC_TRUPDF_CONVERTER_API_KEY}
aiConfig={aiConfig}
onPasswordRequired={async () => promptUserForPassword()}
onDocumentLoaded={(doc) => analytics.track('opened', { pages: doc.numPages })}
onError={(err) => Sentry.captureException(err)}
engineRef={(engine) => {
window.__trupdf = engine;
}}
/>Self-host the conversion service
Non-PDF inputs (Office documents, HTML, images, text, markdown,
email, XPS, XOD, 2D CAD) round-trip via the TruPDF conversion
engine behind @trupdf/converter. One command brings up all three
containers:
docker-compose up -ddocker-compose.yml ships:
- the conversion engine (port 3001) — office + HTML render pipelines.
- the result cache (port 6379) — backs the job queue and dedupes repeat conversions.
- the converter orchestrator (port 3002) — the
@trupdf/converterHTTP API your app talks to.
Then point your browser bundle:
# .env.local
NEXT_PUBLIC_CONVERTER_URL=http://localhost:3002The viewer detects non-PDF input and POSTs to /convert (or
POST /convert/async + GET /convert/jobs/:id for long-running
jobs), then loads the resulting PDF stream. Trial licences do
not include the convert feature — paid tiers do by default.
See Features → Conversion for the route table and supported formats.
Self-host the TruPDF document service
Redaction is a sensitive op. The engine refuses to burn unless a structural adapter is registered — there is no visual-only fallback. The reference adapter is the document-service redaction adapter, backed by the self-hosted TruPDF document service container.
docker compose --profile phase8 up -dAt app boot, bind the document-service redaction adapter:
import { bindPdfboxRedactionAdapter } from '@trupdf/security';
bindPdfboxRedactionAdapter({
endpoint: process.env.NEXT_PUBLIC_TRUPDF_DOCSERVICE_URL!,
});See Features → Security for the full redaction flow.
The same service exposes POST /validate/pdfa — full ISO 19005
(PDF/A) validation, consumed by sdk.validatePdfA().
See Features → PDF/A & Tagged PDF.
Secure mode
secureMode: true removes the DOM text layer, blocks Ctrl+C / Cut /
Drag / right-click, adds canvas-level overlays, and lets DRM
permission checks short-circuit selection. AI features that read
text content auto-disable in secure mode.
<DocViewer source="…" licenseManager={license} secureMode />When secure mode is on:
- Text layer DOM is never mounted.
- Selection menus, search highlight overlays, and copy-text shortcuts short-circuit.
- The AI "Explain Selection" tool falls back to a page-image-only pipeline if the host enables the OCR fallback.
- Screen readers receive a live region with structural reading order
via
@trupdf/a11y.
AI provider configuration
Pass aiConfig to DocViewer. Pick one provider — Anthropic,
Gemini, OpenRouter, or any OpenAI-compatible endpoint (Ollama, vLLM,
LM Studio, on-prem MCP server, …).
import type { AIConfig } from '@trupdf/viewer';
const aiConfig: AIConfig = {
provider: 'anthropic',
apiKey: process.env.NEXT_PUBLIC_TRUPDF_AI_ANTHROPIC_KEY!,
model: 'claude-3-5-sonnet-latest',
// Optional:
secureMode: false,
cachePages: true,
abortOnUnmount: true,
};
<DocViewer source="…" licenseManager={license} aiConfig={aiConfig} />;See Features → AI for the full configuration matrix and provider notes.
Plugins
Register custom tools, toolbar buttons, sidebar panels, and menu
items via the SDK. Plugins are typed objects with optional lifecycle
hooks; one install() per plugin.
import { TruPDFSDK, type TruPDFPlugin } from '@trupdf/viewer';
const sdk = new TruPDFSDK({ licenseManager: license });
const reviewPlugin: TruPDFPlugin = {
id: 'mark-reviewed',
toolbar: [
{
id: 'mark-reviewed',
label: 'Mark reviewed',
icon: '✓',
hotkey: 'Mod+R',
handler: (api) => api.events.emit('plugin.toolbar.action', { id: 'mark-reviewed' }),
},
],
onInit: async (api) => {
/* … */
},
};
await sdk.install(reviewPlugin);See Customization → Plugins for the full surface.
Theming
Override CSS custom properties on .trupdf-viewer (or any ancestor):
.trupdf-viewer[data-theme='light'] {
--trupdf-accent: #2563eb;
--trupdf-bg: #ffffff;
--trupdf-fg: #0f172a;
}See Customization → Theming for the full token reference.
Production hardening checklist
- License token loaded from env, never source-controlled.
-
LicenseManager.destroy()called on host unmount. -
urlBase(license server) configured for staging/production separately. - Heartbeat reachable on outbound 443 from production network.
- Storage adapter set to S3 / Azure / Webhook (not
local). -
CORS_ORIGINSexplicitly set on the conversion + document services. -
TRUPDF_CONVERTER_API_KEYset on the converter and mirrored to the viewer viaconverterApiKey. - The render worker ships inside the package — no extra worker hosting or CSP entry needed.
-
secureModeenabled where the document policy demands it. - Sentry / log sink wired to
onError,LicenseExpired,LicenseRevoked,HeartbeatStale. - Audit log subscribers forwarding to your backend.
- License Server's revocation feed reachable (cached
RevocationCachefalls back to localStorage; clearing storage forces a refresh).
See also
- Licensing — full token format, heartbeat, revocation, domain matching.
- Architecture — three-layer rendering pipeline, coordinate systems.
- Compatibility — XFDF, forms, signed PDFs, browser matrix.