VeriPDF Examples
Practical examples covering common use cases. Each example is self-contained and can be copied directly into your project.
Table of Contents
- Basic React Viewer
- Headless Verification (Node.js)
- Vanilla JS Drop-in
- Custom Trust Store
- Online Revocation Checking
- Metadata Extraction
- Certificate Inspection
- Theme Customization
- Plugin Development
- Next.js Integration
- Error Handling Patterns
Basic React Viewer
Full-featured viewer with all plugins enabled, drag-and-drop file loading, and verification display.
import { useState, useCallback, useRef } from 'react'
import {
VeriPdfProvider,
Viewer,
WelcomeScreen,
useVerification,
defaultLayoutPlugin,
type ViewerHandle,
} from '@trexolab/verifykit-react'
import '@trexolab/verifykit-react/styles.css'
function App() {
return (
<VeriPdfProvider config={{ theme: { mode: 'system' } }}>
<div style={{ height: '100vh' }}>
<PdfApp />
</div>
</VeriPdfProvider>
)
}
function PdfApp() {
const verification = useVerification()
const viewerRef = useRef<ViewerHandle>(null)
const [layout] = useState(() => defaultLayoutPlugin())
const handleFile = useCallback(
async (file: File) => {
try {
await verification.load(file)
} catch (err) {
console.error('Failed to load PDF:', err)
}
},
[verification],
)
if (!verification.fileBuffer) {
return (
<WelcomeScreen
onOpenFile={handleFile}
title="My PDF Viewer"
subtitle="Drag and drop a PDF here, or click to browse"
/>
)
}
return (
<Viewer
ref={viewerRef}
fileBuffer={verification.fileBuffer}
fileName={verification.fileName}
plugins={[layout.plugin]}
onOpenFile={handleFile}
initialState={{
signatures: verification.signatures,
unsignedFields: verification.unsignedFields,
verificationStatus: verification.status ?? undefined,
}}
/>
)
}What you get: toolbar, sidebar (thumbnails/bookmarks/attachments), search, zoom, page navigation, rotation, print, download, fullscreen, theme toggle, signature panel, keyboard shortcuts, context menu, and drag-and-drop file loading.
To disable specific features:
const [layout] = useState(() =>
defaultLayoutPlugin({
disable: {
print: true,
download: true,
openFile: true,
contextMenu: true,
},
})
)Headless Verification (Node.js)
Server-side signature verification with no UI. Prints all 8 check results and certificate details.
import { createVerifier } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
async function main() {
// createVerifier() is async -- initializes the WASM module
const verifier = await createVerifier()
try {
const buffer = await readFile('signed-contract.pdf')
const result = await verifier.verify(buffer, 'signed-contract.pdf')
console.log(`File: ${result.fileName}`)
console.log(`Size: ${result.fileSize} bytes`)
console.log(`Hash: ${result.fileHash}`)
console.log(`Signatures: ${result.signatures.length}`)
console.log()
for (const sig of result.signatures) {
console.log(`--- Signature: ${sig.name} ---`)
console.log(` Status: ${sig.overallStatus}`)
console.log(` Message: ${sig.overallMessage}`)
console.log(` PAdES Level: ${sig.padesLevel}`)
console.log(` Integrity: ${sig.integrityCheck.status} -- ${sig.integrityCheck.detail}`)
console.log(` Signature: ${sig.signatureCheck.status} -- ${sig.signatureCheck.detail}`)
console.log(` Chain: ${sig.certificateChainCheck.status} -- ${sig.certificateChainCheck.detail}`)
console.log(` Expiry: ${sig.expiryCheck.status} -- ${sig.expiryCheck.detail}`)
console.log(` Timestamp: ${sig.timestampCheck.status} -- ${sig.timestampCheck.detail}`)
console.log(` Revocation: ${sig.revocationCheck.status} -- ${sig.revocationCheck.detail}`)
console.log(` Algorithm: ${sig.algorithmCheck.status} -- ${sig.algorithmCheck.detail}`)
console.log(` EKU: ${sig.ekuCheck.status} -- ${sig.ekuCheck.detail}`)
if (sig.signerCertificate) {
console.log(` Signer: ${sig.signerCertificate.subject}`)
console.log(` Issuer: ${sig.signerCertificate.issuer}`)
console.log(` Valid: ${sig.signerCertificate.notBefore.toISOString()} to ${sig.signerCertificate.notAfter.toISOString()}`)
console.log(` Fingerprint: ${sig.signerCertificate.fingerprint}`)
console.log(` Key: ${sig.signerCertificate.keyAlgorithm} ${sig.signerCertificate.keySize ?? ''}`)
}
if (sig.timestamp) {
console.log(` TSA: ${sig.timestamp.tsaName}`)
console.log(` TSA Time: ${sig.timestamp.time.toISOString()}`)
}
console.log()
}
} catch (err) {
console.error('Verification failed:', err instanceof Error ? err.message : err)
process.exitCode = 1
} finally {
verifier.dispose()
}
}
main()For one-shot verification without managing a verifier instance:
import { verifyPdf } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
const buffer = await readFile('document.pdf')
const result = await verifyPdf(buffer, 'document.pdf')
for (const sig of result.signatures) {
console.log(`${sig.name}: ${sig.overallStatus}`)
}Vanilla JS Drop-in
CDN (No Build Tools)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/@trexolab/verifykit-vanilla/dist/veripdf.css">
<style>
html, body { height: 100%; margin: 0; padding: 0; }
</style>
</head>
<body>
<div id="viewer" style="width: 100%; height: 100vh;"></div>
<script src="https://unpkg.com/@trexolab/verifykit-vanilla/dist/veripdf.umd.js"></script>
<script>
var viewer = VeriPdf.create(document.getElementById('viewer'), {
theme: { mode: 'system' },
features: {
signatures: true,
print: true,
download: true,
search: true,
fullscreen: true,
themeToggle: true,
},
onError: function (errMsg) {
console.error('VeriPdf error:', errMsg)
},
})
fetch('/document.pdf')
.then(function (r) { return r.arrayBuffer() })
.then(function (buf) { return viewer.load(buf, 'document.pdf') })
.then(function (result) {
console.log('Signatures:', result.signatures.length)
for (var i = 0; i < result.signatures.length; i++) {
console.log(result.signatures[i].name + ': ' + result.signatures[i].overallStatus)
}
})
.catch(function (err) {
console.error('Failed to load PDF:', err)
})
</script>
</body>
</html>With File Input
<input type="file" id="file-input" accept=".pdf" />
<div id="viewer" style="width: 100%; height: 80vh;"></div>
<script src="https://unpkg.com/@trexolab/verifykit-vanilla/dist/veripdf.umd.js"></script>
<script>
var viewer = VeriPdf.create(document.getElementById('viewer'), {
onError: function (errMsg) { alert('Error: ' + errMsg) },
})
document.getElementById('file-input').addEventListener('change', function (e) {
var file = e.target.files[0]
if (!file) return
file.arrayBuffer()
.then(function (buf) { return viewer.load(buf, file.name) })
.then(function (result) {
console.log('Loaded:', result.signatures.length, 'signatures')
})
.catch(function (err) {
console.error('Failed to load file:', err)
})
})
</script>ESM Import with Programmatic API
import { create } from '@trexolab/verifykit-vanilla'
import '@trexolab/verifykit-vanilla/veripdf.css'
const viewer = create(document.getElementById('viewer')!, {
theme: { mode: 'dark' },
features: { signatures: true, print: true, download: true },
})
// Load a document
const result = await viewer.load(pdfArrayBuffer, 'report.pdf')
console.log(`Verified ${result.signatures.length} signatures`)
// Navigate
viewer.goToPage(5)
viewer.goToNextPage()
console.log('Page:', viewer.getCurrentPage(), '/', viewer.getPageCount())
// Zoom
viewer.zoomIn()
viewer.zoomTo(2.0)
viewer.setFitMode('width')
// Subscribe to events
const unsubPage = viewer.on('pageChange', (page) => {
console.log('Now on page:', page)
})
const unsubVerified = viewer.on('verified', (result) => {
console.log('Verification complete:', result)
})
// Unsubscribe when done
unsubPage()
unsubVerified()
// Clean up when removing
viewer.destroy()Custom Trust Store
Add Enterprise Root CAs (Merge with Built-in)
The @trexolab/verifykit-core engine ships with 119 embedded AATL root certificates. You can add your own:
import { createVerifier } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
const enterpriseRootPem = await readFile('enterprise-root-ca.pem', 'utf-8')
// 'merge' adds your cert alongside the built-in 119 AATL certificates
const verifier = await createVerifier({
trustStore: {
certificates: [enterpriseRootPem],
mode: 'merge',
},
})
try {
const pdfBuffer = await readFile('document.pdf')
const result = await verifier.verify(pdfBuffer, 'document.pdf')
for (const sig of result.signatures) {
console.log(`${sig.name}: ${sig.overallStatus}`)
}
} finally {
verifier.dispose()
}Replace the Built-in Store Entirely
// Only your certificate is trusted -- built-in AATL store is ignored
const verifier = await createVerifier({
trustStore: {
certificates: [enterpriseRootPem],
mode: 'replace',
},
})Custom Trust Store in React
<VeriPdfProvider config={{
trustStore: {
certificates: [myCompanyRootCaPem],
mode: 'merge',
},
}}>
<PdfApp />
</VeriPdfProvider>Custom Trust Store in Vanilla
const viewer = VeriPdf.create(document.getElementById('viewer'), {
trustStore: {
certificates: [enterpriseRootPem],
mode: 'merge',
},
})Online Revocation Checking
Node.js
import { createVerifier } from '@trexolab/verifykit-core'
import { revocationPlugin } from '@trexolab/verifykit-plugin-revocation'
import { readFile } from 'node:fs/promises'
async function main() {
const verifier = await createVerifier({
plugins: [revocationPlugin({ timeout: 15_000 })],
})
try {
const buffer = await readFile('document.pdf')
const result = await verifier.verify(buffer, 'document.pdf')
for (const sig of result.signatures) {
// Without the plugin: "Not checked (offline)"
// With the plugin: live CRL/OCSP lookup result
console.log(`Revocation: ${sig.revocationCheck.status} -- ${sig.revocationCheck.detail}`)
}
} finally {
verifier.dispose()
}
}
main()Disable CRL (OCSP Only)
const verifier = await createVerifier({
plugins: [revocationPlugin({ ocsp: true, crl: false })],
})Vanilla API with Revocation
import { create } from '@trexolab/verifykit-vanilla'
import { revocationPlugin } from '@trexolab/verifykit-plugin-revocation'
import '@trexolab/verifykit-vanilla/veripdf.css'
const viewer = create(document.getElementById('viewer')!, {
plugins: [revocationPlugin()],
trustStore: {
certificates: [enterpriseRootPem],
mode: 'merge',
},
})
const result = await viewer.load(buffer, 'contract.pdf')
for (const sig of result.signatures) {
console.log(`Revocation: ${sig.revocationCheck.status} -- ${sig.revocationCheck.detail}`)
}Metadata Extraction
Node.js
Extract document properties without performing signature verification:
import { createVerifier } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
async function main() {
const verifier = await createVerifier()
try {
const buffer = await readFile('document.pdf')
const { metadata, permissions } = await verifier.extractMetadata(buffer)
console.log('Title:', metadata.title)
console.log('Author:', metadata.author)
console.log('Creator:', metadata.creator)
console.log('Producer:', metadata.producer)
console.log('Pages:', metadata.pageCount)
console.log('PDF Version:', metadata.pdfVersion)
console.log('Created:', metadata.creationDate?.toISOString())
console.log('Modified:', metadata.modDate?.toISOString())
console.log('\nPermissions:')
console.log(' Encrypted:', permissions.encrypted)
console.log(' Printing:', permissions.printing)
console.log(' Copying:', permissions.copying)
console.log(' Annotations:', permissions.annotations)
console.log(' Form filling:', permissions.formFilling)
} finally {
verifier.dispose()
}
}
main()One-Shot Metadata Extraction
import { extractPdfMetadata } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
const buffer = await readFile('document.pdf')
const { metadata, permissions } = await extractPdfMetadata(buffer)
console.log(`${metadata.title} by ${metadata.author} (${metadata.pageCount} pages)`)React Metadata Display
import { useVerification } from '@trexolab/verifykit-react'
function MetadataPanel() {
const verification = useVerification()
if (!verification.metadata) return null
const { metadata, permissions } = verification
return (
<div>
<h3>Document Properties</h3>
<p>Title: {metadata.title || '(none)'}</p>
<p>Author: {metadata.author || '(none)'}</p>
<p>Pages: {metadata.pageCount}</p>
<p>PDF Version: {metadata.pdfVersion}</p>
<p>Encrypted: {permissions?.encrypted ? 'Yes' : 'No'}</p>
</div>
)
}Certificate Inspection
Print Full Certificate Chain
import { createVerifier, oidToName, parseDn } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
const verifier = await createVerifier()
try {
const buffer = await readFile('signed.pdf')
const result = await verifier.verify(buffer, 'signed.pdf')
for (const sig of result.signatures) {
console.log(`\n=== ${sig.name} ===`)
console.log(`Certificate chain depth: ${sig.certificateChain.length}`)
for (let i = 0; i < sig.certificateChain.length; i++) {
const cert = sig.certificateChain[i]
const indent = ' '.repeat(i)
console.log(`${indent}[${i}] ${parseDn(cert.subject)}`)
console.log(`${indent} Issuer: ${parseDn(cert.issuer)}`)
console.log(`${indent} Serial: ${cert.serialNumber}`)
console.log(`${indent} Valid: ${cert.notBefore.toISOString()} to ${cert.notAfter.toISOString()}`)
console.log(`${indent} Expired: ${cert.isExpired}`)
console.log(`${indent} CA: ${cert.isCA}`)
console.log(`${indent} Key: ${cert.keyAlgorithm} ${cert.keySize ?? ''}`)
console.log(`${indent} Sig Alg: ${oidToName(cert.signatureAlgorithm)}`)
console.log(`${indent} Fingerprint (SHA-256): ${cert.fingerprint}`)
if (cert.keyUsage?.length) {
console.log(`${indent} Key Usage: ${cert.keyUsage.join(', ')}`)
}
if (cert.extKeyUsage?.length) {
console.log(`${indent} Ext Key Usage: ${cert.extKeyUsage.join(', ')}`)
}
if (cert.crlDistributionPoints?.length) {
console.log(`${indent} CRL URLs: ${cert.crlDistributionPoints.join(', ')}`)
}
if (cert.ocspUrls?.length) {
console.log(`${indent} OCSP URLs: ${cert.ocspUrls.join(', ')}`)
}
}
}
} finally {
verifier.dispose()
}Export Certificates in React
import {
useVerification,
exportCertAsPem,
exportCertAsDer,
downloadBlob,
type PdfSignature,
} from '@trexolab/verifykit-react'
function CertExporter() {
const verification = useVerification()
function exportPem(sig: PdfSignature) {
if (!sig.signerCertificate?.rawDer) return
try {
const pem = exportCertAsPem(sig.signerCertificate)
const blob = new Blob([pem], { type: 'application/x-pem-file' })
downloadBlob(blob, `${sig.name}.pem`)
} catch (err) {
console.error('PEM export failed:', err)
}
}
function exportDer(sig: PdfSignature) {
if (!sig.signerCertificate?.rawDer) return
try {
const der = exportCertAsDer(sig.signerCertificate)
const blob = new Blob([der], { type: 'application/x-x509-ca-cert' })
downloadBlob(blob, `${sig.name}.cer`)
} catch (err) {
console.error('DER export failed:', err)
}
}
return (
<div>
{verification.signatures.map((sig, i) => (
<div key={i}>
<span>{sig.name}</span>
<button onClick={() => exportPem(sig)}>Export PEM</button>
<button onClick={() => exportDer(sig)}>Export DER</button>
</div>
))}
</div>
)
}Theme Customization
Set Theme Mode
// 'system' follows the OS preference, or pick 'light' / 'dark' explicitly
<VeriPdfProvider config={{
theme: { mode: 'dark' },
}}>Override CSS Variables
<VeriPdfProvider config={{
theme: {
mode: 'light',
overrides: {
'--primary': '#6366f1',
'--primary-hover': '#4f46e5',
'--bg': '#fefefe',
'--toolbar-bg': '#f8f8f8',
},
},
}}>Toggle Theme at Runtime (Plugin API)
const [layout] = useState(() => defaultLayoutPlugin())
// Toggle between light and dark
layout.theme.toggleTheme()
// Set a specific theme
layout.theme.setTheme('dark')
// Get current theme
const current = layout.theme.getTheme() // 'light' | 'dark'Toggle Theme at Runtime (Vanilla API)
const viewer = VeriPdf.create(container, { theme: { mode: 'system' } })
// Change theme after creation
viewer.setTheme('dark')
viewer.setTheme('light')
viewer.setTheme('system')Vanilla Theme Change Events
viewer.on('themeChange', (mode) => {
document.body.className = String(mode)
})Required CSS Reset
Your app needs this so the viewer fills the viewport:
html, body, #root {
height: 100%;
margin: 0;
padding: 0;
}Plugin Development
Writing a Custom Viewer Plugin
This example creates a plugin that counts words across all pages and exposes the count via a toolbar slot and keyboard shortcut.
import { useState } from 'react'
import type { ViewerPlugin, PluginContext } from '@trexolab/verifykit-react'
interface WordCountPluginApi {
getWordCount(): number
}
function wordCountPlugin(): { plugin: ViewerPlugin; api: WordCountPluginApi } {
let ctx: PluginContext
let wordCount = 0
const plugin: ViewerPlugin = {
name: 'word-count',
install(c) {
ctx = c
// Register a keyboard shortcut
ctx.registerShortcut({
id: 'word-count-show',
key: 'w',
ctrl: true,
shift: true,
description: 'Show word count',
handler(e) {
e.preventDefault()
alert(`Approximate word count: ${wordCount}`)
},
})
},
async onDocumentLoad({ document, numPages }) {
wordCount = 0
try {
for (let i = 1; i <= numPages; i++) {
const page = await document.getPage(i)
const textContent = await page.getTextContent()
for (const item of textContent.items) {
if ('str' in item) {
wordCount += item.str.split(/\s+/).filter(Boolean).length
}
}
}
} catch (err) {
console.error('Word count failed:', err)
}
},
// Add a toolbar slot
renderToolbarSlot: {
WordCount: () => (
<span style={{ fontSize: 11, padding: '0 8px', opacity: 0.7 }}>
~{wordCount.toLocaleString()} words
</span>
),
},
destroy() {
wordCount = 0
},
}
const api: WordCountPluginApi = {
getWordCount: () => wordCount,
}
return { plugin, api }
}
// Usage:
function App() {
const [wc] = useState(() => wordCountPlugin())
const [layout] = useState(() => defaultLayoutPlugin())
return (
<Viewer
fileBuffer={buffer}
plugins={[layout.plugin, wc.plugin]}
/>
)
}Plugin Lifecycle
1. Factory called: const wc = wordCountPlugin()
2. Passed to Viewer: <Viewer plugins={[wc.plugin]} />
3. install() called: plugin receives PluginContext (store, shortcuts, etc.)
4. Document loads: onDocumentLoad({ document, numPages })
5. User interacts: toolbar slots render, shortcuts fire
6. Document unloads: onDocumentUnload()
7. Viewer unmounts: destroy() called for cleanup
Writing a Core Verification Plugin
Core plugins extend the verification engine (not the viewer UI):
import type { VeriPdfPlugin, CertificateInfo, RevocationCheckResult } from '@trexolab/verifykit-core'
function myRevocationPlugin(): VeriPdfPlugin {
return {
name: 'my-revocation',
revocation: {
async checkOCSP(cert: CertificateInfo, issuer: CertificateInfo, urls: string[]): Promise<RevocationCheckResult> {
// Your custom OCSP logic here
for (const url of urls) {
try {
const response = await fetch(url, { method: 'POST', body: buildOcspRequest(cert) })
// Parse response...
return { status: 'good', source: `custom OCSP (${url})` }
} catch {
continue
}
}
return { status: 'unknown', source: 'custom OCSP (all failed)' }
},
},
}
}Next.js Integration
Client Component Wrapper
// components/PdfViewer.tsx
'use client'
import { useState, useCallback, useRef } from 'react'
import {
VeriPdfProvider,
Viewer,
WelcomeScreen,
useVerification,
defaultLayoutPlugin,
type ViewerHandle,
} from '@trexolab/verifykit-react'
import '@trexolab/verifykit-react/styles.css'
export function PdfViewerApp() {
return (
<VeriPdfProvider config={{ theme: { mode: 'system' } }}>
<PdfViewerInner />
</VeriPdfProvider>
)
}
function PdfViewerInner() {
const verification = useVerification()
const viewerRef = useRef<ViewerHandle>(null)
const [layout] = useState(() => defaultLayoutPlugin())
const handleFile = useCallback(
async (file: File) => {
await verification.load(file)
},
[verification],
)
if (!verification.fileBuffer) {
return <WelcomeScreen onOpenFile={handleFile} />
}
return (
<Viewer
ref={viewerRef}
fileBuffer={verification.fileBuffer}
fileName={verification.fileName}
plugins={[layout.plugin]}
onOpenFile={handleFile}
initialState={{
signatures: verification.signatures,
verificationStatus: verification.status ?? undefined,
}}
/>
)
}Dynamic Import in Page
// app/pdf/page.tsx
import dynamic from 'next/dynamic'
const PdfViewerApp = dynamic(
() => import('@/components/PdfViewer').then(m => m.PdfViewerApp),
{ ssr: false, loading: () => <p>Loading viewer...</p> }
)
export default function PdfPage() {
return (
<div style={{ height: '100vh' }}>
<PdfViewerApp />
</div>
)
}Next.js WASM Configuration
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config) => {
config.experiments = { ...config.experiments, asyncWebAssembly: true }
return config
},
}
module.exports = nextConfigServer-Side Verification (Route Handler)
You can also use @trexolab/verifykit-core in a Next.js API route for server-side verification:
// app/api/verify/route.ts
import { createVerifier } from '@trexolab/verifykit-core'
export async function POST(request: Request) {
const formData = await request.formData()
const file = formData.get('pdf') as File
if (!file) {
return Response.json({ error: 'No file provided' }, { status: 400 })
}
const verifier = await createVerifier()
try {
const buffer = await file.arrayBuffer()
const result = await verifier.verify(buffer, file.name)
return Response.json(result)
} finally {
verifier.dispose()
}
}Error Handling Patterns
React Error Handling
import { VeriPdfProvider, useVerification } from '@trexolab/verifykit-react'
import '@trexolab/verifykit-react/styles.css'
function PdfApp() {
const verification = useVerification()
async function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]
if (!file) return
try {
await verification.load(file)
} catch (err) {
// This catches errors during PDF loading and WASM initialization
console.error('Load failed:', err instanceof Error ? err.message : err)
}
}
return (
<div>
<input type="file" accept=".pdf" onChange={handleFile} />
{/* Loading state */}
{verification.isLoading && <p>Verifying signatures...</p>}
{/* Error state -- set by the hook after load() fails */}
{verification.error && (
<div style={{ color: 'red', padding: 16 }}>
<strong>Error:</strong> {verification.error}
</div>
)}
{/* Success state */}
{verification.signatures.map((sig, i) => (
<div key={i}>
<strong>{sig.name}:</strong> {sig.overallStatus} -- {sig.overallMessage}
</div>
))}
</div>
)
}Node.js Error Handling
import { createVerifier } from '@trexolab/verifykit-core'
import { readFile } from 'node:fs/promises'
async function verifyWithRetry(path: string, maxRetries = 2) {
let verifier = await createVerifier()
let lastError: Error | null = null
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const buffer = await readFile(path)
const result = await verifier.verify(buffer, path)
return result
} catch (err) {
lastError = err instanceof Error ? err : new Error(String(err))
console.warn(`Attempt ${attempt + 1} failed: ${lastError.message}`)
// Dispose and recreate verifier on failure
verifier.dispose()
if (attempt < maxRetries) {
verifier = await createVerifier()
}
}
}
throw lastError
}Vanilla Error Handling
const viewer = VeriPdf.create(container, {
onError: (errMsg) => {
// Called for any error during the viewer lifecycle
showErrorBanner(errMsg)
},
})
// load() returns a Promise -- handle both async and sync errors
try {
const result = await viewer.load(buffer, 'doc.pdf')
console.log('Verified successfully:', result.signatures.length, 'signatures')
} catch (err) {
// Catches load-time errors (bad PDF, WASM failure, network errors)
console.error('Load failed:', err instanceof Error ? err.message : err)
}
// Subscribe to error events
viewer.on('error', (errMsg) => {
console.error('Viewer error event:', errMsg)
})Common Error Scenarios
| Error | Cause | Recovery |
|---|---|---|
Failed to fetch PDF: HTTP 404 | URL input returned a 404 | Check the URL, ensure CORS headers are set |
Unsupported input type | Invalid argument to load() or verify() | Pass ArrayBuffer, Uint8Array, File, or URL string |
WASM module not initialized | Synchronous function called before WASM loaded | Await createVerifier() or initWasm() first |
VeriPdf viewer failed to initialize within 10 seconds | Container not in DOM or WASM load failed | Ensure container is attached and visible; check network for .wasm file |
CompileError: WebAssembly.instantiate() | Corrupted or missing .wasm binary | Verify the .wasm file is served with application/wasm MIME type |