Web SDKv1.0.0

Initialization

Kernstra.init(options?) initializes the SDK: it verifies the license and loads the engine binary. Call it before creating any viewer; it resolves when the SDK is ready. It is idempotent: a second call with the same options gets the same promise (React's StrictMode needs no guard), one with other options rejects with INVALID_ARGUMENT, and a failed call starts over on the next.

The engine, pdf-engine.bin (~4.4 MB), is not in the package: init() downloads it from the asset store your license names, verifies it against the digest built into the SDK and keeps the verified copy in the browser's Cache Storage, so the next load downloads nothing. The same goes for the text-shaping binary, the font-subsetting binary and every bundled font. The minimal, and usual, initialization passes only the license.

init() rejects with LICENSE_REQUIRED (no valid license, or not a secure context), FEATURE_NOT_LICENSED (engineUrl / shaperUrl / subsetterUrl without self-hosting), ENGINE_LOAD_FAILED (binary not downloaded, not verified, or not started) or INVALID_ARGUMENT (a second call with other options, a styleNonce that is not base64 or base64url, or a licensePopup part that is not a string). See Kernstra for the rest of the static API.

SDKInitOptions

Example

TypeScript
import { Kernstra, PDFDocument, PDFViewer } from '@kernstra/pdf-web-sdk';

await Kernstra.init({ license: import.meta.env.KERNSTRA_LICENSE });

console.log(Kernstra.isInitialized()); // true
console.log(Kernstra.version); // matches the installed package

const doc = await PDFDocument.fromUrl('/form.pdf');
new PDFViewer(container, doc);

Options 7

licensestring

Your license token. A valid license — development or production — is required: Kernstra.init() verifies it before anything else happens; without one it shows a "License required" popup, rejects with LICENSE_REQUIRED, and never downloads the engine.

Pass the token to init, typically from your build's own variable, or set it where the SDK looks when none is passed: a globalThis.KERNSTRA_LICENSE string, a <meta name="kernstra-license" content="…"> tag, or, in Node, process.env.KERNSTRA_LICENSE. The SDK ships prebuilt, so a bundler cannot substitute an environment variable into it; read the variable in your code. An empty or missing value means "no license given"; only Kernstra.setLicense('') signs out and forgets the cached token.

Development tokens watermark every rendered, printed and exported page with the Kernstra mark, so development output can never ship as production; they may name * and run on any host, or be bound to your local and staging origins. Production tokens are bound to your origins and render clean output.

Secure context. The SDK runs only where the browser provides the Web Crypto API — over HTTPS or on localhost. On a plain-HTTP origin it refuses to start (LICENSE_REQUIRED, reason insecure-context). This holds for offline (air-gapped) licenses too: an intranet deployment needs HTTPS, a self-signed certificate is enough. There is deliberately no fallback for plain HTTP. See Licensing for origins, status checks, outages and what a stopped license means.

licenseTypeScript
await Kernstra.init({ license: import.meta.env.KERNSTRA_LICENSE });
engineUrlstring

A self-hosted copy of pdf-engine.bin — self-hosting licenses only. Online licenses download the engine from the asset store the license names, and there is nothing to configure. A license that includes self-hosting may serve the binaries and the bundled fonts from its own infrastructure; today that is an offline license, which names no store and always self-hosts. Fetch the file once from the store — the path is its digest under the engine folder, as Kernstra.assetDigests.engine names it — and pass where you put it.

Without self-hosting in the license, engineUrl, shaperUrl and subsetterUrl are refused by Kernstra.init() with FEATURE_NOT_LICENSED before anything is fetched. Every load is verified: an engine binary that is not this version's fails with ENGINE_LOAD_FAILED and never executes. A self-hosted copy is not kept in Cache Storage: it is fetched from your URL on each load, so serve it with your own HTTP caching headers. See Engine, binaries and fonts.

engineUrlTypeScript
await Kernstra.init({
  license: import.meta.env.KERNSTRA_LICENSE,
  engineUrl: '/assets/pdf-engine.bin',
  shaperUrl: '/assets/pdf-shaper.bin',
  subsetterUrl: '/assets/pdf-subset.bin',
});
shaperUrlstring
A self-hosted copy of pdf-shaper.bin (~0.4 MB), the text-shaping binary — self-hosting licenses only, likewise refused with FEATURE_NOT_LICENSED without self-hosting. It is downloaded on the first use of a text tool (Edit Text, Add Text, Text box), which shape the text they write with it: kerning, ligatures and complex scripts (Arabic, Hebrew, Indic). Fetch it once from the store under the shaper folder by Kernstra.assetDigests.shaper. A tool that cannot load it falls back to the font's own character map: the text is still written, without kerning, ligatures or complex-script shaping, and the next use tries the download again; a Text box whose words need a bundled face logs a console warning and is drawn with the standard fonts.
subsetterUrlstring
A self-hosted copy of pdf-subset.bin (~0.6 MB), the font-subsetting binary — self-hosting licenses only, likewise refused with FEATURE_NOT_LICENSED without self-hosting. It is downloaded on first use when fonts.subset is on, so an exported document embeds only the glyphs it uses. Fetch it once from the store under the subsetter folder by Kernstra.assetDigests.subset. It is optional: if it cannot be loaded, the SDK warns once in the console and embeds full fonts, as it does with subsetting off.
workerUrlstring

URL to render.worker.js, the prebuilt, self-contained worker bundle the package ships at dist/render.worker.js and exposes via the ./render-worker export subpath. It is an ES module and must be served as a same-origin URL — Web Workers cannot be loaded from bare package specifiers at runtime. Either copy it to your static assets (works with every bundler) or, in Vite, import it with the ?url suffix. The worker takes the engine's bytes from the page and makes no request of its own. Unlike engineUrl, it is not a self-hosting option: any license may set it, since the file is your own copy of one the package ships.

When a workerUrl is provided, page rendering moves off the main thread with no viewer configuration change; performance.workerEnabled: false disables it. The worker renders from a copy of the document: under a production license that includes export with clean output it holds the document as edited; under any other license it holds only the bytes you handed over and is stopped at the first change to the document, after which every page renders on the main thread (see Web worker rendering). Without a workerUrl the worker is never created. Enabling it keeps the engine (~4.4 MB) in memory twice, once on each thread, though it is downloaded only once; the worker also holds its own copy of the document. See Web worker rendering.

workerUrlTypeScript
// Option B: Vite ?url import (Vite emits the file and returns its URL)
import RenderWorkerUrl from '@kernstra/pdf-web-sdk/render-worker?url';

await Kernstra.init({
  license: import.meta.env.KERNSTRA_LICENSE,
  workerUrl: RenderWorkerUrl,
});

// Option A: copy dist/render.worker.js to your static assets instead
// cp node_modules/@kernstra/pdf-web-sdk/dist/render.worker.js public/assets/render.worker.js
// await Kernstra.init({ license: import.meta.env.KERNSTRA_LICENSE, workerUrl: '/assets/render.worker.js' });
styleNoncestring

The page's CSP nonce, carried by every stylesheet the SDK injects — the print frame's included. A style-src without 'unsafe-inline' refuses every <style> the SDK adds unless it carries the page's nonce; pass that nonce once. When styleNonce is not given, the SDK reads the nonce a page declares for its tooling as <meta property="csp-nonce" nonce="…">, the convention Vite and others follow. With a nonce in force the Google Fonts link (tools.sign.webFonts) carries it too, so style-src needs no Google origin. The SDK styles its elements through the CSSOM, never with style="…" markup, so style-src-attr needs nothing.

A value that is not base64 or base64url is refused with INVALID_ARGUMENT. A policy that enforces Trusted Types (require-trusted-types-for 'script') is not supported in 1.0. See Installation and support for the full policy.

styleNonceTypeScript
await Kernstra.init({
  license: import.meta.env.KERNSTRA_LICENSE,
  styleNonce: nonceFromYourServer,
});
licensePopupLicensePopupOptions
The "License required" popup in your own words: its title (default "License required"), its text (the body, in place of the SDK's sentence naming the reason) and its closeLabel (default "Close"). Each part replaces the SDK's own, and what you leave out stays; a part that is not a string rejects init with INVALID_ARGUMENT. The link is not yours to change: it goes to kernstra.com, where a license is bought. See Licensing.
licensePopupTypeScript
await Kernstra.init({
  license,
  licensePopup: {
    title: 'Editing is unavailable',
    text: 'The editor is temporarily unavailable. Please try again later.',
  },
});

A content security policy that covers the SDK

DirectiveValueWhy
script-src'self' 'wasm-unsafe-eval''wasm-unsafe-eval' lets the browser compile the engine; it is narrower than 'unsafe-eval' and every supported browser has it.
worker-src'self'Where render.worker.js is served, when workerUrl is set. Serve the worker with a Content-Security-Policy of its own that has script-src 'self' 'wasm-unsafe-eval', since the SDK's engine is compiled inside the worker too.
connect-src'self' https://<assets store> https://<licensing api>The two origins the license token carries: the first serves the engine, the shaping and subsetting binaries and the bundled fonts, the second answers the status check on each load. An offline license names neither; a self-hosted deployment replaces the store with your own origin.
img-src'self' data:Stamps, signatures, thumbnails and print pages are data: images.
style-src'self' 'nonce-<nonce>' (or 'unsafe-inline')Pass the nonce as styleNonce. With tools.sign.webFonts: true add https://fonts.googleapis.com here and https://fonts.gstatic.com to font-src; nothing else is loaded from a third party.

Notes

Anything you point the SDK at yourself — a document URL, customFonts URLs, an uploadTo() destination, a stamp image url — needs its origin in connect-src or img-src as well.

Any bundler that reads package.json exports builds the SDK as is — the Angular CLI, esbuild and Rollup included. The package's only file beside the JavaScript is the render worker, which is SDK code.

The ?url suffix is Vite's: TypeScript knows it once vite/client is in your tsconfig.json types, or referenced from a .d.ts your program includes (/// <reference types="vite/client" />). A bundler without the suffix — webpack 5, the Angular CLI, esbuild, Rollup — serves the file as a static asset instead; see Integrations.

Kernstra.destroy() tears down the SDK and frees its resources. Destroy your viewers and close your documents first: with a document still open it throws INVALID_STATE rather than free them from under it.