EmbedPDF
DocsEmbedPDF SnippetRunning Airgapped

Running Airgapped / Offline

By default, the EmbedPDF Snippet is optimized for a zero-config developer experience and pulls a handful of assets from public CDNs. For network-restricted environments, such as intranets or airgapped infrastructure, you can redirect or disable those external requests.

This guide walks through every CDN default in the snippet and shows how to redirect or disable each one.

The Three Defaults to Know

AssetDefault sourceTriggered by
pdfium.wasmcdn.jsdelivr.net/npm/@embedpdf/pdfiumViewer init
PDFium font fallback (fonts for missing glyphs)cdn.jsdelivr.net/npm/@embedpdf/fonts-*Rendering text the PDF’s embedded fonts can’t cover
Snippet UI + signature webfontsfonts.googleapis.com / fonts.gstatic.comViewer init (UI font) and opening the Create Signature modal (signature fonts)

Each of them is independently configurable via EmbedPDF.init.

1. Self-host the PDFium WebAssembly binary

Copy the wasm file out of @embedpdf/pdfium at build time and serve it from your own origin, then point wasmUrl at it.

cp node_modules/@embedpdf/pdfium/dist/pdfium.wasm public/pdfium.wasm
EmbedPDF.init({ target: document.getElementById('pdf-viewer'), src: '/document.pdf', wasmUrl: '/pdfium.wasm', });
ℹ️

The wasm file is a few MB in size. Serving it with long-lived cache headers (Cache-Control: public, max-age=31536000, immutable) alongside a versioned filename works well.

2. Replace the PDFium font fallback CDN

When a PDF references a font that isn’t embedded (common with East Asian languages, Hebrew, Arabic, etc.), PDFium needs a fallback font to render correctly. The snippet’s default downloads those fonts from jsDelivr. You have three options:

Option A — Disable fallback entirely

Set fontFallback to null. Missing glyphs will render as “tofu” boxes but no external request is made.

EmbedPDF.init({ // ... fontFallback: null, });

Option B — Self-host the fonts

Install the font packages you need and provide a custom FontFallbackConfig pointing at URLs you serve yourself. The @embedpdf/fonts-* packages ship the raw font files and ready-made font definitions you can reuse.

import { FontCharset } from '@embedpdf/models'; EmbedPDF.init({ // ... fontFallback: { fonts: { [FontCharset.SHIFTJIS]: '/fonts/NotoSansJP-Regular.otf', [FontCharset.GB2312]: '/fonts/NotoSansSC-Regular.otf', // ...add any charsets your documents need }, }, });

See the individual font package READMEs (@embedpdf/fonts-jp, @embedpdf/fonts-sc, @embedpdf/fonts-tc, @embedpdf/fonts-kr, @embedpdf/fonts-arabic, @embedpdf/fonts-hebrew, @embedpdf/fonts-latin) for the exact file names and recommended weights.

3. Configure or opt out of webfonts

The snippet uses two families of external webfonts, both configurable through the top-level fonts key:

  • fonts.ui — the UI chrome font (Open Sans by default). Loaded once at viewer init.
  • fonts.signature — the cursive fonts in the “Type” tab of the Create Signature modal (Caveat, Dancing Script, Great Vibes, Pacifico by default). Loaded lazily when the modal opens.

Both stylesheets are registered at document scope as deduped <link rel="stylesheet"> elements in document.head. That is intentional: browser support for @font-face inside shadow DOM is inconsistent, and the typed signature renderer draws text to <canvas>, which resolves fonts from the document-level font registry.

The snippet first reuses an existing matching stylesheet URL if your host page already loaded it. It can also skip injecting when document.fonts already exposes the requested family. Managed links are marked with data-embedpdf-fonts="ui" or data-embedpdf-fonts="signature" for auditing.

The high-level resolution rules are:

  • undefined (omitted) — load the Google Fonts default.
  • null — skip the managed stylesheet. Text falls back through the configured CSS font-family stack to local/system fonts.
  • custom config — use your own stylesheet URL, font family, and/or signature font list.

UI font

fonts.ui uses the same object shape as fonts.signature: stylesheetUrl controls loading, and UI adds a family field for the CSS font stack.

// Disable the UI font entirely. Viewer chrome uses the system font stack. EmbedPDF.init({ // ... fonts: { ui: null }, }); // Or point to your own stylesheet. EmbedPDF.init({ // ... fonts: { ui: { stylesheetUrl: '/fonts/open-sans.css' }, }, }); // Use a different UI font. This is useful for branding and for testing on // machines that already have Open Sans installed locally. EmbedPDF.init({ // ... fonts: { ui: { family: "'Lora', serif", stylesheetUrl: 'https://fonts.googleapis.com/css2?family=Lora:wght@400;600&display=swap', }, }, }); // Use a font that your host page already provides. No extra <link> is added. EmbedPDF.init({ // ... fonts: { ui: { family: "'Inter', system-ui, sans-serif", stylesheetUrl: null, }, }, });

Signature “Type” tab fonts

// Fully disable the signature webfonts. EmbedPDF.init({ // ... fonts: { signature: null }, }); // Self-host the stylesheet (same four families). EmbedPDF.init({ // ... fonts: { signature: { stylesheetUrl: '/fonts/signature-fonts.css' }, }, }); // Use a different font list. The fonts must already be available — // either provided by the given `stylesheetUrl`, or loaded elsewhere // in your app. Omit `stylesheetUrl` to skip the managed <link> entirely. EmbedPDF.init({ // ... fonts: { signature: { fonts: [ { name: 'Brand Script', family: "'Brand Script', cursive" }, { name: 'Mono', family: "'JetBrains Mono', monospace" }, ], }, }, });

When signature fonts are fully disabled, the Create Signature modal hides the “Type” tab. The “Draw” and “Upload” tabs remain available.

When a signature stylesheet is loaded, the snippet also calls document.fonts.load(...) for each configured family before rendering typed signatures. This prevents the hidden canvas from drawing with the generic cursive fallback while the real font file is still loading.

The four defaults (Caveat, Dancing Script, Great Vibes, Pacifico) are all licensed under the SIL Open Font License, so you can freely redistribute them alongside a self-hosted build.

Complete airgapped example

Putting it all together:

import EmbedPDF from '@embedpdf/snippet'; import { FontCharset } from '@embedpdf/models'; EmbedPDF.init({ target: document.getElementById('pdf-viewer'), src: '/document.pdf', // 1. Self-hosted wasm wasmUrl: '/assets/pdfium.wasm', // 2. Self-hosted font fallback (or set to null to disable) fontFallback: { fonts: { [FontCharset.SHIFTJIS]: '/fonts/NotoSansJP-Regular.otf', [FontCharset.GB2312]: '/fonts/NotoSansSC-Regular.otf', }, }, // 3. No external webfonts for UI or signature modal. fonts: { ui: null, signature: null, }, });

With the configuration above the snippet makes no external network requests beyond fetching your PDF document itself.

Last updated on April 28, 2026

Need Help?

Join our community for support, discussions, and to contribute to EmbedPDF's development.