Nutrient Web SDK

ReferenceStandaloneConfiguration

Interface StandaloneConfiguration

Interface

Hierarchy

SharedConfigurationStandaloneConfiguration

Properties

aiAssistant

OptionalServer

Server only

This configuration describes a connection with AI Assistant service which provides AI capabilities directly in the viewer.

Example

NutrientViewer.load({
aiAssistant: {
sessionId: 'session-id',
jwt: 'xxx.xxx.xxx',
backendUrl: 'https://localhost:4000',
},
// ...
});

allowLinearizedLoading

OptionalStandalone
boolean

Standalone only

Enables or disables loading of linearized PDFs. When enabled, the SDK takes advantage of linearized (also known as "fast web view") PDFs, allowing portions of the document to be displayed while it's still being downloaded. If enabled, the PDF viewer will render the document progressively, starting with the first pages, while the rest of the file is downloaded in the background. The user interface will be in read-only mode during the download.

A indicator is displayed in the toolbar showing that the document is being downloaded.

Note: Linearized loading requires the server to support byte-range requests and the PDF document to be linearized.

Example

NutrientViewer.load({
allowLinearizedLoading: true,
// ...
});

Default Value

true

This property allows you to change a default list of annotation presets for the NutrientViewer instance. This can be used to customize the main toolbar buttons' behaviour before the application mounts.

When omitted, it will default to NutrientViewer.defaultAnnotationPresets.

Example

const annotationPresets = NutrientViewer.defaultAnnotationPresets
annotationPresets.mypreset = {
strokeWidth: 10,
};
NutrientViewer.load({
...baseOptions,
annotationPresets,
});

Default Value

Sets a custom comparator that controls the visual rendering order of non-interactive annotations on each page. When set, this comparator replaces the SDK's default type-based rendering order for annotations such as text markups, ink, images, shapes, and stamps.

Interactive annotations — widget annotations (form fields), link annotations, and signature annotations — are always rendered above all other annotations regardless of the comparator, to preserve keyboard tab order and accessibility.

The comparator receives two annotations and must return -1 if the first annotation should render below (behind) the second, or 1 if it should render above (in front of) the second. A strict total order is required.

This can also be set at runtime via NutrientViewer.Instance#setAnnotationRenderingOrderComparator.

Limitations:

  • Widget, link, and signature annotations always render on top.
  • It does not change the keyboard tab order. Hit testing follows the visual stacking the comparator produces (topmost annotation receives events first).
  • It does not affect annotation order in exported PDFs or backend storage.

Example

NutrientViewer.load({
annotationRenderingOrderComparator: (a, b) => {
const isImageA = a instanceof NutrientViewer.Annotations.ImageAnnotation;
const isImageB = b instanceof NutrientViewer.Annotations.ImageAnnotation;
if (isImageA !== isImageB) return isImageA ? -1 : 1;
if (a.createdAt < b.createdAt) return -1;
if (a.createdAt > b.createdAt) return 1;
return a.id < b.id ? -1 : 1;
},
});

You can customize the color dropdown of individual annotation properties using this callback. This callback receives the property name associated with the color dropdown and the array of default colors used by NutrientViewer.

With this API you can:

  • render a customised color pallet in each and all color dropdowns
  • control if the custom color picker UI should be rendered in the color dropdowns

Example

Customize different color dropdowns.

NutrientViewer.load({
annotationToolbarColorPresets: function ({ propertyName }) {
if (propertyName === "font-color") {
return {
presets: [
{
color: new NutrientViewer.Color({ r: 0, g: 0, b: 0 }),
localization: {
id: "brightRed",
defaultMessage: "Bright Red",
},
},
{
color: new NutrientViewer.Color({ r: 100, g: 100, b: 180 }),
localization: {
id: "deepBlue",
defaultMessage: "deepBlue",
},
},
],
};
}

if (propertyName === "stroke-color") {
return {
presets: [
{
color: new NutrientViewer.Color({ r: 0, g: 0, b: 0 }),
localization: {
id: "brightRed",
defaultMessage: "Bright Red",
},
},
{
color: new NutrientViewer.Color({ r: 100, g: 100, b: 180 }),
localization: {
id: "deepBlue",
defaultMessage: "deepBlue",
},
},
],
showColorPicker: false,
};
}
},
//...
});

You can customise the items inside the annotation toolbars by using this callback. The callback will receive the annotation which is being created or selected and based on it, you can have different annotation toolbars for different annotations.

You can do the following modifications using this API:

  • Add new annotation toolbar items
  • Remove existing annotation toolbar items
  • Change the order of the existing annotation toolbar items
  • Modify selected properties of the annotation toolbar items

You can also use the hasDesktopLayout to determine if the current UI is being rendered on mobile or desktop layout mode, which depends on the current viewport width. Based on that, you can implement different designs for Desktop and Mobile.

This callback gets called every time the annotation toolbar is mounted.

Example

Add a new annotation toolbar item

NutrientViewer.load({
annotationToolbarItems: (annotation, { defaultAnnotationToolbarItems, hasDesktopLayout }) => {
const node = document.createElement('node')
node.innerText = "Custom Item"

const icon = `<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" /></svg>`

return [{
id: "custom",
type: "custom",
node: node,
icon: icon,
className: 'Custom-Node',
onPress: () => alert("Custom item pressed!")
}, ...defaultAnnotationToolbarItems];
}
});

This callback is called whenever an annotation gets selected and can be used to define and return an array of ToolItem that will be rendered in a tooltip for the given annotation.

If the callback returns an empty array then NutrientViewer won't show any tooltip for the selected annotation.

Example

NutrientViewer.load({
annotationTooltipCallback: function(annotation) {
if (annotation instanceof NutrientViewer.Annotations.TextAnnotation) {
var toolItem = {
type: 'custom',
title: 'tooltip item for text annotations',
id: 'item-text-tooltip-annotation',
className: 'TooltipItem-Text',
onPress: function () {
console.log(annotation)
}
}
return [toolItem]
} else {
return []
}
}
// ...
});

appName

OptionalStandalone
string

When integrating NutrientViewer for Electron with context isolation enabled, this property needs to be set for the SDK to work. It will be ignored in any other case.

The value of this property needs to match the provided license key's bundle ID.

Example

NutrientViewer.load({ appName: "my-electron-app" })
number

Threshold in pixels determines when the active anchor should automatically close and snap to the origin anchor, effectively closing the shape.

Example

NutrientViewer.load({
autoCloseThreshold: 50,
});

Default Value

4px

autoSaveMode

Optional
"DISABLED" | "IMMEDIATE" | "INTELLIGENT"

This property allows you to set the auto save mode, which controls when annotations or form field values get saved.

The default is IMMEDIATE when Instant is enabled, and INTELLIGENT otherwise. On server-backed loads, Instant is enabled by instant: true, and by default when authenticating with a session without a document.

Example

NutrientViewer.load({ autoSaveMode: NutrientViewer.AutoSaveMode.INTELLIGENT })

baseCoreUrl

Optional
string

This allows you to overwrite the auto-detected URL for the Core worker NutrientViewer assets in Standalone mode. This setting may be necessary when you integrate Nutrient Web SDK in an environment that limits the size of the static assets, like Salesforce.

If your Core assets are served from a different origin, you have to include proper CORS headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

This must end with a trailing slash, and the Core assets (nutrient-viewer-[hash].wasm.js and nutrient-[hash].wasm) must be located in a nutrient-viewer-lib subfolder accessible from the baseCoreUrl.

Example

NutrientViewer.load({ baseCoreUrl: 'https://public-server.pspdfkit.com/pspdfkit-core/' });

Default Value

Auto-detected it will use the same value as baseUrl if set, or the auto-detected value from the currently executed <script> tag.

baseProcessorEngineUrl

OptionalStandalone
string

optional, Standalone only

This allows you to overwrite the auto-detected URL for the processor engine worker NutrientViewer assets in Standalone mode. This setting may be necessary when you integrate Nutrient Web SDK in an environment that limits the size of the static assets, like Salesforce.

If these assets are served from a different origin, you have to include proper CORS headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

This must end with a trailing slash, and the assets in the /nutrient-viewer-lib/gdpicture-[hash]/ folder must be directly located in the folder pointed to by baseProcessorEngineUrl.

Example

NutrientViewer.load({ baseProcessorEngineUrl: 'https://public-cdn.example.com/pspdfkit-processor-engine/' });

Default Value

Auto-detected it will use the same value as baseUrl if set, or the auto-detected value from the currently executed <script> tag.

baseUrl

Optional
string

This allows you to overwrite the auto-detected URL for all NutrientViewer assets. This setting is necessary when you load Nutrient Web SDK JavaScript from a different URL.

If your assets are served from a different origin, you have to include proper CORS headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Example

NutrientViewer.load({ baseUrl: 'https://public-server.pspdfkit.com/' });

Default Value

Auto-detected based on the currently executed <script> tag.

Note: auto-detection behavior is deprecated as of 1.9.0. Not providing baseUrl will currently trigger a warning and in future releases will lead to loading assets from CDN.

"ACCURATE" | "PURE_BLACK"

Controls how exact 100% K-only CMYK black is rendered.

This option matters for print-production documents that use CMYK color: by default, 100% K black is rendered as a dark charcoal, matching how Acrobat displays it on screen. Pure black rendering maps it to #000000 instead, which some print workflows prefer for checking black-only content. Documents that don't use CMYK color are unaffected.

In server-backed mode, this option requires Document Engine 1.18.0 or later and is ignored by older servers.

Example

NutrientViewer.load({
blackRendering: NutrientViewer.BlackRendering.PURE_BLACK,
// ...
});

Default Value

NutrientViewer.BlackRendering.ACCURATE

certificateCheckTime

OptionalStandalone
"current_time" | "signing_time"

optional, Standalone only

Determines the time used for certificate validation when verifying digital signatures.

  • 'signing_time' (default): Validates certificates against the time when the document was signed. Recommended for Long Term Validation (LTV) scenarios where certificates may have short validity windows (e.g., GlobalSign certificates with 10-minute validity).
  • 'current_time': Validates certificates against the current system time.

Example

Use signing time for certificate validation

NutrientViewer.load({
certificateCheckTime: 'signing_time',
// ...
})

Default Value

'signing_time'

container

Optional
string | HTMLElement

Selector or element where Nutrient Web SDK will be mounted.

Required unless headless: true is set.

The element must have a width and height that's greater than zero. Nutrient Web SDK adapts to the dimensions of this element. This way, applying responsive rules will work as expected.

The element can be styled using relative values as you would expect it to (CSS media queries are encouraged).

Example

// In your HTML
<div class="foo"></div>

// In your JavaScript
NutrientViewer.load({
container: '.foo',
// Other configuration options
});
// or
const element = document.getElementsByClassName('foo')[0]
NutrientViewer.load({
container: element,
// Other configuration options
});

Callback function to handle font matching during content editing operations.

This callback is invoked when the system detects a font mismatch during content editing and allows you to provide custom font substitution logic. The callback receives the system's proposed font match and metadata about the original font from the PDF.

If the callback returns a font reference, it overrides the system's choice. If it returns undefined, the system's original match is used.

Example

NutrientViewer.load({
contentEditingFontMatcher: (match, fontInfo, availableFonts) => {
console.log('System matched:', match);
console.log('Original font:', fontInfo.name, 'at', fontInfo.fontSize + 'px');
console.log('Available fonts:', availableFonts.map(f => f.family));

// For Helvetica fonts, try to find a suitable substitute
if (fontInfo.name?.includes("Helvetica")) {
// Look for Arial first, then any sans-serif font
const preferredFonts = ["Arial", "Roboto", "Open Sans", "Lato"];

for (const preferred of preferredFonts) {
const font = availableFonts.find(f => f.family.includes(preferred));
if (font) {
return { font, size: fontInfo.fontSize };
}
}

// Fallback to first available font
if (availableFonts.length > 0) {
return { font: availableFonts[0], size: fontInfo.fontSize };
}
}
return undefined; // Accept system match
}
});

customFonts

OptionalStandalone

optional, Standalone only

This property allows you to provide custom fonts you want to use when loading a Standalone instance.

From the callback defined on each NutrientViewer.Font instance you can return a promise that resolves to a Blob of the font you want to use. You are free to fetch it in whatever way you want, and optimize its loading by retrieving it from a cache using the Cache API, get it from IndexedDB, etc.

See this guide article to learn more.

Example

Fetch and use a custom set of fonts (Standalone)

const fetcher = name =>
fetch(`https://example.com/${name}`).then(r => {
if (r.status === 200) {
return r.blob();
} else {
throw new Error();
}
});

const customFonts = ["arial.ttf", "helvetica.ttf", "tahoma.ttf"]
.map(font => new NutrientViewer.Font({ name: font, callback: fetcher }));

NutrientViewer.load({
customFonts,
// ...
});

This object can include functions to be called when specific entities, like annotations, are being rendered in the viewport, and return additional or replacement DOM content for the entity instance.

Currently only annotation's rendering can be customized using the Annotation key.

If the callback returns null, the instance will be rendered normally.

Example

NutrientViewer.load({
customRenderers: {
Annotation: ({ annotation }) => ({
node: document.createElement('div').appendChild(document.createTextNode('Custom rendered!')),
append: true,
})
}
// ...
});

customUI

Optional
Partial<Record<"Sidebar", Partial<{ … }>>>

Object with callback methods to be called when different elements of the UI are being rendered. Can return DOM content to be appended to them, as well as callback functions to individually process different parts of the element (items) as they're rendered.

UI elements currently supported: sidebars.

Example

//Fully customized sidebar

NutrientViewer.load({
customUI: {
[NutrientViewer.UIElement.Sidebar]: {
[NutrientViewer.SidebarMode.CUSTOM]({ containerNode }) {
// React portals can be used as well.
// Or Vue portals, or any other framework API that allows appending components
// to arbitrary DOM nodes.
// Using vanilla JS, you can just append a node to parentNode.
const div = document.createElement("div");
div.append("My custom sidebar");
containerNode.appendChild(div);

return {
// By returning the same node that was provided, we opt-out of having the node
// appended. If we return a different node, it will be appended to the provided node.
node: containerNode,
};
}
}
}
});

//Partially customized sidebar

NutrientViewer.load({
customUI: {
[NutrientViewer.UIElement.Sidebar]: {
[NutrientViewer.SidebarMode.ANNOTATIONS]({ containerNode }) {
containerNode.style.padding = "0.5rem";

if (!containerNode.querySelector(".MyCustomSidebarComponentHeader")) {
const header = document.createElement("div");
header.classList.add("MyCustomSidebarComponentHeader");
containerNode.prepend(header);
}

return {
node: containerNode,
onRenderItem({ itemContainerNode, item: annotation }) {
const footerAuthor = itemContainerNode.querySelector(".PSPDFKit-Sidebar-Annotations-Footer span");
// Change the format of the footer text by prefixing it with "Creator: " and removing the date
footerAuthor.textContent = `Creator: ${annotation.creatorName}`;

// Add aria label to the annotation icon
const annotationIcon = itemContainerNode.querySelector(".PSPDFKit-Icon");
annotationIcon.setAttribute("aria-label", `Icon for an annotation created by ${annotation.creatorName}.`);
}
};
}
}
}
});

Allows you to customize how to format dates displayed in the UI.

When a date is about to be rendered in specific UI elements, this function is called so the date can be formatted as desired instead of using the default date formatter.

UI elements with customizable dates currently include the annotations sidebar, and comment threads.

This function is called for each date to be formatted, and receives the corresponding Date object, the UI element to which it belongs (either the annotations sidebar or a comment thread) and the AnnotationsUnion or NutrientViewer.Comment instance to which it is associated.

Example

NutrientViewer.load({
dateTimeString: ({ dateTime, element }) => {
if(element === NutrientViewer.UIDateTimeElement.ANNOTATIONS_SIDEBAR) {
return new Intl.DateTimeFormat("en-US", {
dateStyle: "short",
timeStyle: "short",
}).format(dateTime);
} else {
return new Intl.DateTimeFormat("en-US", {
dateStyle: "full",
timeStyle: "long",
}).format(dateTime);
}
}
// ...
});

Default Value

undefined

disableForms

Optional
boolean

This property is used to force the disabling of form rendering and parsing, even if your license would permit it.

Example

NutrientViewer.load({ disableForms: true })

Default Value

false
boolean

Legacy flag for controlling DOM print quality.

Prefer printOptions.quality instead.

Example

NutrientViewer.load({ disableHighQualityPrinting: true })

Default Value

false

disableIndexedDBCaching

OptionalStandalone
boolean
boolean

Disable multi selection for annotations. Disabled by default, when enabled it doesn't allow multiple selection of annotations by calling NutrientViewer.Instance.setSelectedAnnotations, or using the multiple annotations selection UI button.

Example

NutrientViewer.load({
disableMultiSelection: true,
});

Default Value

false
boolean

By default, Nutrient Web SDK will initialize using PDF Open Parameters that are supported by our viewer. This option can be used if you want to opt-out from this behavior.

Setting a custom ViewState will overwrite these defaults. You can use NutrientViewer.viewStateFromOpenParameters to manually extract those values.

Currently, we only support the page parameter.

Example

NutrientViewer.load({
disableOpenParameters: true,
});
boolean

When this property is set to true, text in the document can not be highlighted.

Example

NutrientViewer.load({ disableTextSelection: true })

disableWebAssemblyStreaming

OptionalStandalone
boolean

Optional

When disableWebAssemblyStreaming is set to true, we force disable WebAssembly streaming instantiation. More info about this optimization can be found at: https://www.nutrient.io/blog/optimize-webassembly-startup-performance/

Example

NutrientViewer.load({
disableWebAssemblyStreaming: true,
// ...
});

document

Standalone
string | ArrayBuffer

required, Standalone only

The URL to a supported document or its content as ArrayBuffer.

NutrientViewer supports the following type of documents:

  • PDF
  • Image

Note that all the formats except for PDF require a dedicated license. Please contact sales to find out more about this.

When providing a URL keep in mind that Cross-Origin Resource Sharing (CORS) apply. To load app-provided documents with DWS Viewer API, see session.

Example

Load a PDF document from an URI

NutrientViewer.load({ document: 'https://example.com/document.pdf' });

Load a document from an ArrayBuffer

NutrientViewer.load({ document: arrayBuffer });
{ … }

An object that allows you to configure the Document Editor UI.

PropertyDescription
thumbnailDefaultSize

The default size of the thumbnail.

thumbnailMaxSize

The maximum size of the thumbnail.

thumbnailMinSize

The minimum size of the thumbnail.

Example

NutrientViewer.load({
documentEditorConfiguration: {
thumbnailDefaultSize: 500,
thumbnailMinSize: 100,
thumbnailMaxSize: 600,
}
// Other configuration options
})

This property allows you to set an initial list of document editor footer items for the NutrientViewer instance.

When omitted, it will default to NutrientViewer.defaultDocumentEditorFooterItems.

Example

const footerItems = NutrientViewer.defaultDocumentEditorFooterItems;
footerItems.reverse();
NutrientViewer.load({
documentEditorFooterItems: footerItems
// Other configuration options
});

Default Value

Errors

NutrientViewer.Error will throw an error when the supplied items array is not valid. This will also throw an error if your license does not include the Document Editor feature.

This property allows you to set an initial list of document editor toolbar items for the NutrientViewer instance.

When omitted, it will default to NutrientViewer.defaultDocumentEditorToolbarItems.

Example

const toolbarItems = NutrientViewer.defaultDocumentEditorToolbarItems;
toolbarItems.reverse();
NutrientViewer.load({
documentEditorToolbarItems: toolbarItems
// Other configuration options
});

Default Value

Errors

will throw an error when the supplied items array is not valid. This will also throw an error if your license does not include the Document Editor feature.

dynamicFonts

OptionalStandalone
string

optional, Standalone only

This property allows you to provide a URL to JSON file with fonts available for downloading, associated with specific ranges of characters and font variations.

The downloadable font files need to be in the same scope as the JSON file.

The JSON file needs to be in the following format:

type FontName = {
// The full name of the font.
fullName: string;
// The next four properties are from the `name` table in the font.
// See https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids
// Name ID 1: Font Family name
family?: string;
// Name ID 2: Font Subfamily name
subfamily?: string;
// Name ID 16: Typographic Family name
typographicFamily?: string;
// Name ID 17: Typographic Subfamily name
typographicSubfamily?: staring;
}

// Represents a font that can be downloaded.
// filePath + faceIndex should be unique.
type Font = {
name: FontName;
// Path to the font file.
filePath: string;
// If the font file is a collection, this specifies the face index.
faceIndex?: int;
// A list of all code points supported by the font.
// This can either be a range ([number, number]) or a single codepoint.
codePoints: [[number, number] | number];
// The unicode ranges from the OS/2 table: https://learn.microsoft.com/en-us/typography/opentype/spec/os2#ur
unicodeRanges?: [4 numbers];
// A sha1 of the font file. For collections, this is a SHA of the whole file, not a single font.
sha1: string;
// Specifies true if the font is allowed to be embedded, false otherwise.
// Should only be used to make a decision to download the font, proper licensing handling should be done with the downloaded font.
allowedToEmbed: boolean;
// The boldness of the font. See https://learn.microsoft.com/en-us/typography/opentype/spec/os2#wtc
weight?: number;
}

type DynamicFonts = {
availableFonts: [Font];
v: 1;
}

Example

Provide a list of downloadable font files (Standalone)
NutrientViewer.load({
dynamicFonts: "https://example.com/assets/fonts.json",
// ...
});
(new (...args: any[]) => AnnotationsUnion)[]

This property defines all annotation types that a user is able to modify. If it's not set, the user is allowed to select, create, edit or delete every annotation type. By allowing only certain annotation types for modification, you can be sure that there is no annotation type that gets introduced in the future that your user is then able to modify.

Example

Allow only the modification of ink annotations

NutrientViewer.load({
editableAnnotationTypes: [NutrientViewer.Annotations.InkAnnotation],
// ...
});

electronAppName

DeprecatedOptionalStandalone
string

When integrating NutrientViewer for Electron with context isolation enabled, this property needs to be set for the SDK to work. It will be ignored in any other case.

The value of this property needs to match the provided license key's bundle ID.

Deprecated

Example

NutrientViewer.load({ electronAppName: "my-electron-app" })

Defines specific configuration options related to the electronic signatures feature.

The creationModes key accepts an array of NutrientViewer.ElectronicSignatureCreationMode values that define which signature creation modes and in which order will be offered as part of the Electronic Signatures UI. It defaults to NutrientViewer.defaultElectronicSignatureCreationModes.

The fonts key accepts an array of Font instances that specify the name of fonts to be used as part of the 'Type' signing tab. It defaults to NutrientViewer.defaultSigningFonts.

You can specify a subset of our built-in signing fonts or specify entirely custom ones.

For using custom fonts, you need to load a custom style sheet (via Configuration#styleSheets) in which you can either specify @font-face rules for the custom font or @import other style sheets containing the fonts loading rules.

As an example of the latter, if we would wish to use the Cookie font from Google Fonts you could use the following style sheet:

@import url('https://fonts.googleapis.com/css2?family=Cookie&display=swap');

And then pass an new NutrientViewer.Font({ name: 'Cookie' }) as part of the fonts array of Configuration#electronicSignatures.

Example

NutrientViewer.load({
electronicSignatures: {
creationModes: [NutrientViewer.ElectronicSignatureCreationMode.IMAGE],
fonts: [new NutrientViewer.Font("Cookie")]
}
});
boolean

Standalone only

By default, only links that are represented as valid link annotations in the PDF will be enabled. When enableAutomaticLinkExtraction is set to true, the text of the PDF will be scanned and links will automatically be created.

To enable automatic link extraction on a Nutrient Document Engine (server-backed) deployment, check out: https://www.nutrient.io/guides/web/pspdfkit-server/configuration/overview/

Example

NutrientViewer.load({
enableAutomaticLinkExtraction: true,
// ...
});
boolean

Enable actions like cut, copy, paste and duplicate for annotations using keyboard shortcuts Cmd/Ctrl+X, Cmd/Ctrl+C, Cmd/Ctrl+V and Cmd/Ctrl+D respectively.

Example

NutrientViewer.load({
enableClipboardActions: true,
});

Default Value

false
boolean

Enable actions history for annotations. Disabled by default, when enabled it allows to undo and redo annotation actions consecutively by calling NutrientViewer.Instance#history.undo or NutrientViewer.Instance#history.redo, or using the undo and redo UI buttons, which can be optionally enabled:

Actions history tracking can be enabled and disabled at any moment by calling NutrientViewer.Instance#history.enable or NutrientViewer.Instance#history.disable.

Example

NutrientViewer.load({
enableHistory: true,
toolbarItems: NutrientViewer.defaultToolbarItems.reduce((acc, item) => {
if (item.type === "spacer") {
return acc.concat([item, { type: "undo" }, { type: "redo" }]);
}
return acc.concat([item]);
}, [])
});

Default Value

false

This call back defines which text annotations should be treated as rich text annotation. By default, all the text annotations are treated as plain text annotations, which means that when you edit them, you will see the plain text editor. You can change this behavior by returning true for the text annotations that you want to be treated as rich text annotations.

Example

NutrientViewer.load({ enableRichText: annotation => true });
boolean

When you're using a ServiceWorker, set this flag to true to be able to use Nutrient Web SDK offline. Due to a browser bug, loading CSS files would bypass service workers and we therefore load all CSS files via XHR and embed the content. Instead of loading files like SVGs by using url in your CSS, please add them as base64, otherwise these requests would bypass the service worker as well.

Example

NutrientViewer.load({
enableServiceWorkerSupport: true,
// ...
});

Allows specifying fonts that you would like to substitute in a document and the fonts you would like to use for that substitution.

Patterns are matched using the following rules:

  • * matches multiple characters.
  • ? matches a single character.

Ordering matters - As names could match multiple patterns, it's important to note that the order of the patterns matters.

Case-insensitive - Both the pattern and the target name are case-insensitive.

Example

Substitute all Noto fonts found in the document with Awesome font

NutrientViewer.load({
fontSubstitutions: [
{
pattern: "Noto*",
target: "AwesomeFont"
}
]
});
string[]

List of signature form fields names that are not allowed to store Ink Signatures.

When a signature form field name is on this list, any new ink signature for this field that is created via the UI won't be stored.

Example

NutrientViewer.load({
formFieldsNotSavingSignatures: ['signatureField1'],
// ...
});

Default Value

[]

formsConfiguration

OptionalStandalone

Standalone only

Allows configuring some behavior around forms in the viewer.

Example

NutrientViewer.load({
formsConfiguration: { },
});

Default Value

undefined

headless

Optional
boolean

Loads Nutrient Web SDK in Headless mode i.e. without a UI. Some UI-specific APIs, like the Toolbars API, are not available in this mode and, when used, will throw an error.

Example

NutrientViewer.load({
headless: true,
// ...
});

httpHeaders

OptionalStandalone
Record<string, string>

Standalone only

Custom HTTP headers to include when fetching the document from a URL. This property is only used when document is a string URL (not an ArrayBuffer).

The headers will be applied to both the initial document fetch and any subsequent range requests when using linearized loading.

Example

NutrientViewer.load({
document: 'https://example.com/document.pdf',
httpHeaders: {
'Authorization': 'Bearer token123',
'X-Custom-Header': 'custom-value'
}
});

Default Value

undefined

This property allows you to set an initial viewing state for the NutrientViewer instance.

This can be used to customize behavior before the application mounts (e.g Scroll to a specific page or use the SINGLE_PAGE mode)

It will default to a view state with its default properties (see ViewState).

If the initial view state is invalid (for example, when you define a page index that does not exist), the method will fall back to the default value for the invalid property. This means when you set the initial currentPageIndex to 5 but the document only has three pages, NutrientViewer will start on the first page but will still apply other rules defined in this initial view state.

Example

const initialViewState = new NutrientViewer.ViewState({ currentPageIndex: 2 });
NutrientViewer.load({
initialViewState,
// Other configuration options
});

Default Value

"POINT" | "STROKE"

Allows you to modify the default ink eraser behavior. By default, the eraser removes points from ink annotations. Set this to InkEraserMode.STROKE to erase whole strokes instead.

Example

NutrientViewer.load({ inkEraserMode: NutrientViewer.InkEraserMode.STROKE });

Default Value

NutrientViewer.InkEraserMode.POINT

You can customize the items inside the inline text selection toolbar that is rendered every time some text is selected on the document. The callback will receive the default items of the inline toolbar and the text that is currently selected NutrientViewer.TextSelection

You can do the following modifications using this API:

  • Add new toolbar items
  • Remove existing toolbar items
  • Change the order of the existing annotation toolbar items
  • Customise each item eg change the icon of the a default toolbar item.

You can also use the hasDesktopLayout to determine if the current UI is being rendered on mobile or desktop layout mode, which depends on the current viewport width. Based on that, you can implement different designs for Desktop and Mobile.

This callback gets called every time the inline text selection toolbar is mounted.

Example

Add a custom button and a custom node to the toolbar in desktop layout.

NutrientViewer.load({
inlineTextSelectionToolbarItems: ({ defaultItems, hasDesktopLayout }, selection) => {
console.log(selection)
if (hasDesktopLayout) {
const node = document.createElement("div");
node.innerText = "Custom Item";
return [
...defaultItems,
{
type: "custom",
id: "custom-1",
node: node,
className: "Custom-Node",
onPress: () => alert("Custom node pressed!"),
},
{
type: "custom",
id: "custom-2",
title: "custom-button-2",
onPress: () => alert("Custom item pressed!"),
},
];
}
return defaultItems
},
})
boolean

By default, we load the required Web Workers inline. That means that the Web Workers are loaded as a blob URL, which allows us to load a Worker from other domains. However, this might interfere with strict CSP policies like worker-src: 'self'. In that case, disable inline loading by setting this option to false, serve or proxy the SDK assets from the embedding application's origin, and configure baseUrl to that same-origin location. This option governs the SDK's workers in both Standalone and Document Engine deployments, with one exception: the OffscreenCanvas renderer worker used by the next page renderer (pageRendering: "next") currently always loads inline.

Note: This option is currently not supported in Salesforce environment.

Example

NutrientViewer.load({
inlineWorkers: false,
// ...
});

Default Value

true

instantJSON

OptionalStandalone

Standalone only

Instant JSON can be used to instantiate a viewer with a diff that is applied to the raw PDF. This format can be used to store annotation changes on your server and conveniently instantiate the viewer with the same content at a later time.

Instead of storing the updated PDF, this serialization only contains a diff that is applied on top of the existing PDF and thus allows you to cache the PDF and avoid transferring a potentially large PDF all the time.

You can export this format from a standalone instance by using Instance#exportInstantJSON.

annotations will follow the Instant Annotation JSON format specification.

Example

NutrientViewer.load({
instantJSON: {
format: 'https://pspdfkit.com/instant-json/v1',
skippedPdfObjectIds: [1],
annotations: [
{ id: 1, pdfObjectId: 1, type: 'pspdfkit/text', content: 'Hello World' },
{ id: -1, type: 'pspdfkit/text', content: 'Hello Universe' },
],
},
// ...
});

By implementing this callback you have a fine grained control over which annotations are read-only. This callback will receive the Annotation a user wants to modify and by returning true or false you can define if the annotation should be read-only (false) or modifiable (true).

This API will not disable ToolbarButtons for you, but will not allow the user to create a new Annotation with the UI.

Example

Only allow the modification of annotations from the same author

NutrientViewer.load({
isEditableAnnotation: function(annotation) {
return annotation.creatorName === myCurrentUser.name;
},
});

Do not allow changing the value of a specific form field

NutrientViewer.load({
isEditableAnnotation: function(annotation) {
// Check if the annotation is associated with a specific form field
if (
annotation instanceof NutrientViewer.Annotations.WidgetAnnotation &&
annotation.formFieldName === "MyFormField"
) {
// If it is, disallow editing it
return false;
}
// Otherwise, allow editing
return true;
},
});

By implementing this callback you have a fine grained control over which comments are read-only. This callback will receive the Comment a user wants to modify and by returning true or false you can define if the comment should be read-only (false) or modifiable (true).

To learn more check this guide article.

Example

Only allow the modification of comment from the same author.

NutrientViewer.load({
isEditableComment: function(comment) {
return comment.creatorName === myCurrentUser.name;
},
});

Controls which SDK keyboard shortcuts the SDK intercepts globally, and which it restricts to "the user is interacting with the viewer."

  • { scope: 'viewer' } (default) — No shortcuts are captured globally. Every shortcut fires only when the user has interacted with the viewer. The host page's own input fields keep native browser shortcuts (Cmd+F opens browser Find, Cmd+P opens browser Print, etc.). Recommended for most applications.
  • { scope: 'global', interceptedActions: KeyboardShortcutActions[] } — The listed actions fire from anywhere on the page, including when the user is focused on a host-page element. Actions NOT in the list fall back to viewer-scope behavior. To restore the pre-2026 default of "every shortcut globally captured," pass every value of NutrientViewer.KeyboardShortcutActions.

Markup-toolbar shortcuts (highlight, strikeout, underline, etc.) are always viewer-scoped — they cannot be intercepted globally. In iframe mode, pagination keystrokes only fire from within the iframe.

Example

// Default: viewer scope (no shortcuts captured globally).
await NutrientViewer.load({
// ...
keyboardShortcutScope: { scope: 'viewer' },
})
// Pre-2026 behavior: every action captured globally.
await NutrientViewer.load({
// ...
keyboardShortcutScope: {
scope: 'global',
interceptedActions: [
NutrientViewer.KeyboardShortcutActions.SEARCH,
NutrientViewer.KeyboardShortcutActions.PRINT,
NutrientViewer.KeyboardShortcutActions.ZOOM,
NutrientViewer.KeyboardShortcutActions.UNDO,
NutrientViewer.KeyboardShortcutActions.REDO,
NutrientViewer.KeyboardShortcutActions.PAGINATION,
],
},
})
// Global capture for everything EXCEPT search — preserves browser Find.
await NutrientViewer.load({
// ...
keyboardShortcutScope: {
scope: 'global',
interceptedActions: [
NutrientViewer.KeyboardShortcutActions.PRINT,
NutrientViewer.KeyboardShortcutActions.ZOOM,
NutrientViewer.KeyboardShortcutActions.UNDO,
NutrientViewer.KeyboardShortcutActions.REDO,
NutrientViewer.KeyboardShortcutActions.PAGINATION,
],
},
})

Default Value

{ scope: 'viewer' }

licenseKey

OptionalStandalone
string

Standalone only

Nutrient Web SDK license key from https://my.nutrient.io/.

This isn't used for DWS Viewer API app-provided document loading; see session.

If neither licenseKey nor a DWS Viewer API session is provided, the instance will run in trial mode for a limited time and then request the user to visit https://www.nutrient.io/try/ to request a trial license.

Example

Activate with a license key

NutrientViewer.load({ licenseKey: "YOUR_LICENSE_KEY_GOES_HERE", document: 'https://example.com/document.pdf' });

locale

Optional
Locale | string & {}

The initial locale (language) for the application. All the available locales are defined in NutrientViewer.I18n.locales. When a locale is not provided Nutrient Web SDK tries to autodetect the locale using window.navigator.language. If the detected locale is not supported then the en locale is used instead.

Example

NutrientViewer.load({
locale: 'de',
// ...
});

logLevel

Optional
"none" | "debug"

Verbosity of SDK initialization logging. Currently 'none' (default) and 'debug'; more levels may be added in future releases.

Setting 'debug' emits tagged console.log lines at each init stage, useful for diagnosing where a load stalls or fails. Can also be enabled globally by setting globalThis.NUTRIENT_LOG_LEVEL = 'debug' before the SDK module evaluates.

Example

NutrientViewer.load({
document: '/example.pdf',
container: '.viewer',
logLevel: NutrientViewer.LogLevel.DEBUG,
});

Default Value

NutrientViewer.LogLevel.NONE
number

This property allows you to configure the maximum zoom level. The largest zoom level at a given time will be calculated based on the page proportions and this option. This is not necessarily a hard limit. For example, in order to satisfy the 'fit to width' and 'fit to page' zoom modes, the actual maximum zoom may be higher.

When omitted, the default is 10.

Example

NutrientViewer.load({ maxDefaultZoomLevel: 20 })

Default Value

10
number

Defines how often the password modal is presented after a wrong password has been entered. By default, there won't be a limit for a regular Nutrient Web SDK installation.

When running in the headless mode, this option is ignored as we don't have an interface where we could request a password (This is the same as setting maxPasswordRetries to 0).

Example

NutrientViewer.load({
maxPasswordRetries: 3,
// ...
});

    | "whole"
    | "oneDp"
    | "twoDp"
    | "threeDp"
    | "fourDp"
    | "1/2"
    | "1/4"
    | "1/8"
    | "1/16"

Set the precision value of all the newly created measurement annotations.

Example

NutrientViewer.load({ measurementPrecision: NutrientViewer.MeasurementPrecision.THREE });

Default Value

NutrientViewer.MeasurementPrecision.TWO

Set the default value of scale for all newly created measurement annotations.

Example

NutrientViewer.load(new NutrientViewer.MeasurementScale({
unitFrom: NutrientViewer.MeasurementScaleUnitFrom.CENTIMETERS,
unitTo: NutrientViewer.MeasurementScaleUnitTo.INCHES,
fromValue: 1,
toValue: 2,
}));

Default Value

1 inch = 1 inch
boolean

Allows the user to toggle the snapping behavior while creation of measurement annotations. The snapping points are the points are a combination of endpoints, midpoints and intersections.

Example

NutrientViewer.load({ measurementSnapping: false });

Default Value

false
number

This property allows you to configure the minimum zoom level. The smallest zoom level at a given time will be calculated based on the page proportions and this option. This is not necessarily a hard limit. For example, in order to zoom out to show the entire page, the actual minimum zoom may be lower.

When omitted, the default is 0.5.

Example

NutrientViewer.load({ minDefaultZoomLevel: 0.1 })

Default Value

0.5

nonce

Optional
string

A CSP nonce to apply to dynamically created <style> and <script> elements.

When your Content Security Policy uses nonce-based rules (e.g. style-src 'nonce-...') instead of 'unsafe-inline', provide the nonce value here so that all elements injected by the SDK are permitted by the browser.

The nonce must match the value in your CSP header or <meta> tag for the current page load.

Example

NutrientViewer.load({
nonce: "abc123",
// ...
});

officeConversionSettings

OptionalStandalone

Standalone only

Configures how Office documents (e.g. DOCX, XLSX) are converted to PDF when loaded. This is the load-time equivalent of the settings accepted by NutrientViewer.convertToPDF — for example, controlling how tracked changes (revisions) in a DOCX are rendered via documentMarkupMode.

Example

NutrientViewer.load({
document: 'https://example.com/document.docx',
officeConversionSettings: {
documentMarkupMode: 'simpleMarkup',
},
// ...
});

Default Value

{ splitExcelSheetsIntoPages: false, spreadsheetRenderOnlyPrintArea: true, documentMarkupMode: 'noMarkup' }

Allows to modify the default behavior when annotations are resized using the selection corner handles by returning an object. This provides more control over whether annotations should keep their aspect ratio when resized, for example.

Example

Unlock aspect ratio for the top left resize anchor

NutrientViewer.load({
onAnnotationResizeStart: event => {
return {
maintainAspectRatio: event.resizeAnchor === 'TOP_LEFT',
}
}
});

onAuthFailed

Optional
() => void | Promise<void>

optional, Server only

Callback invoked when JWT tokens expire and soft refresh fails. Implement this to fetch a new JWT and call setSession(newJwt) within 30 seconds. If not called in time, the SDK throws and does not recover.

Example

NutrientViewer.load({
documentId: 'doc',
authPayload: { jwt: initialJwt },
onAuthFailed: async () => {
const newJwt = await fetchNewJwtFromBackend();
instance.setSession(newJwt);
},
});

You can programmatically modify the properties of the comment just before it is created.

Example

NutrientViewer.load({ onCommentCreationStart: comment => comment.set('text', { format: 'xhtml', value: '<p>Default text</p>' }) });

This callback is called once for each page, the first time that page renders. It is registered before rendering starts, so it also observes the first page render, which makes it the supported way to measure the time to the first rendered page.

See OnInitialPageRenderCallback for when exactly it is called and what it guarantees.

Example

The first call reports whichever page renders first, which is not page 0 when the viewer starts on another page.

const startedAt = performance.now();
let reported = false;

NutrientViewer.load({
onInitialPageRender: function({ pageIndex }) {
if (reported) return;

reported = true;
console.log(`page ${pageIndex} rendered after ${performance.now() - startedAt}ms`);
},
// ...
});

onOpenURI

Optional

By default, all the URLs on which the user clicks explicitly open as expected but the URLs which open due to a result of JavaScript action are not opened due to security reasons. You can override this behaviour using this callback. If this callback returns true, the URL will open.

Example

NutrientViewer.load({
onOpenURI: (url, isUserInitiated) => {
if (url.startsWith('https://abc.com') && isUserInitiated) {
return true
}

return false;
}
// ...
});

Default Value

undefined
(info: PasswordRequiredInfo) => Promise<string | null | undefined>

Called when the SDK needs a password to open an encrypted document. The callback receives { filter, metadata } describing the encryption used:

  • For standard password-protected files, filter is 'Standard' and metadata is null.
  • For files using a custom encryption filter that resolves to a standard PDF password (e.g. Dedicon), filter is the filter name as encoded in the PDF (e.g. 'Dedicon') and metadata carries the filter-specific payload (for Dedicon, the embedded XML blob you can use to look up the actual password).

Resolve the returned promise to a password string to use it for the next attempt; resolve to null/undefined to fall back to the built-in UI password prompt; reject to abort opening the document. The callback is fired before the UI prompt on every password failure (including retries), so it can centralise password resolution. As a safety net, if the callback returns the same password that just failed, the SDK gives up and rejects with the underlying password error instead of retrying indefinitely.

Example

NutrientViewer.load({
onPasswordRequired: async ({ filter, metadata }) => {
if (filter === 'Dedicon') {
return await resolveDediconPassword(metadata)
}
return null // fall back to the default password prompt UI
},
// ...
});

optional

You can programmatically modify the properties of the widget annotation and the associated form field just before it is created via the Form Creator UI.

Example

Set the opacity of all widget annotations.

NutrientViewer.load({
onWidgetAnnotationCreationStart: (annotation, formField) => {
return { annotation: annotation.set('opacity', 0.7) };
}
// ...
});

Default Value

undefined
"AUTO" | "OFF"

Controls whether the renderer simulates overprinting used by the document.

Overprinting is a print-production technique where overlapping inks are printed on top of each other instead of knocking each other out. This option matters for prepress and soft-proofing workflows where the on-screen preview should match the printed output; typical screen-oriented documents are unaffected.

In server-backed mode, this option requires Document Engine 1.18.0 or later and is ignored by older servers.

Example

NutrientViewer.load({
overprintPreview: NutrientViewer.OverprintPreview.OFF,
// ...
});

Default Value

NutrientViewer.OverprintPreview.AUTO

overrideMemoryLimit

OptionalStandalone
number

Overrides the allocable maximum memory when using Nutrient Web SDK Standalone. Only set this if you know that your users have web browsers with enough memory available.

This can improve rendering of documents with large images.

Example

NutrientViewer.load({
overrideMemoryLimit: 4096, // 4 GB
// ...
});

pageCacheSizeInBytes

OptionalStandalone
number

Limits the estimated memory, in bytes, retained by Core's page cache when using Nutrient Web SDK Standalone. The currently active page may exceed this limit when it alone requires more memory.

Example

NutrientViewer.load({
pageCacheSizeInBytes: 256 * 1024 * 1024, // 256 MiB
// ...
});

Default Value

268435456
"next" | "legacy"

Configures the page rendering engine.

Use "legacy" to keep the existing rendering pipeline. Use "next" to opt in to the next-generation page rendering pipeline.

If left undefined, NutrientViewer currently defaults to "legacy".

Example

NutrientViewer.load({ pageRendering: "next" })

Default Value

undefined

password

Optional
string

If set, it will try to unlock the PDF with the provided password when loading it. PDFs which do not require a password won't open if this property is set.

Example

NutrientViewer.load({
password: 'secr3t',
// ...
});

populateInkSignatures

DeprecatedOptional

Loads Ink Signatures when the UI displays them for the first time.

Ink Signatures are special Ink Annotations whose pageIndex and boundingBox are defined at creation time. They can be converted to serializable objects with NutrientViewer.Annotations.toSerializableObject and stored as JSON using their InstantJSON format. Serialized JSON annotations can be deserialized with JSON.parse and then converted to annotations with NutrientViewer.Annotations.fromSerializableObject.

Example

Populate Ink Signatures on demand.

NutrientViewer.load({
populateInkSignatures: () => {
return fetch('/signatures')
.then(r => r.json())
.then(a => (
NutrientViewer.Immutable.List(
a.map(NutrientViewer.Annotations.fromSerializableObject))
)
);
},
// ...
});

Default Value

() => Promise.resolve(NutrientViewer.Immutable.List())

Loads signatures when the UI displays them for the first time.

Signatures can be added as special Ink Annotations or Image Annotations whose pageIndex and boundingBox are defined at creation time. They can be converted to serializable objects with NutrientViewer.Annotations.toSerializableObject and stored as JSON using their InstantJSON format. Serialized JSON annotations can be deserialized with JSON.parse and then converted to annotations with NutrientViewer.Annotations.fromSerializableObject.

Example

Populate Signatures on demand.

NutrientViewer.load({
populateStoredSignatures: () => {
return fetch('/signatures')
.then(r => r.json())
.then(a => (
NutrientViewer.Immutable.List(
a.map(NutrientViewer.Annotations.fromSerializableObject))
)
);
},
// ...
});

Default Value

() => Promise.resolve(NutrientViewer.Immutable.List())
boolean

When copying of text is disabled, it's still possible to select text but copying either using the shortcut or a context menu will have no effect.

This is implemented internally by listening to the copy event and prevent the default implementation.

Please note that preventing text copying only provides limited security since the text will still be transmitted to the client.

Example

NutrientViewer.load({
preventTextCopy: true,
// ...
});

printMode

DeprecatedOptional
"DOM" | "EXPORT_PDF"

This property allows you to set the NutrientViewer.PrintMode to use.

Example

NutrientViewer.load({ printMode: NutrientViewer.PrintMode.DOM })

Default Value

NutrientViewer.PrintMode.DOM

printOptions

Optional
{ mode?: "DOM" | "EXPORT_PDF"; quality?: "LOW" | "MEDIUM" | "HIGH" }

The printing mode and quality.

Determines whether printing a document renders each page as a bitmap image or prints a PDF directly.

PropertyDescription
mode

NutrientViewer.PrintMode mode to use for printing.

quality

NutrientViewer.PrintQuality option to control bitmap quality used by PrintMode.DOM.

Default Value

{ mode: NutrientViewer.PrintMode.DOM, quality: NutrientViewer.PrintQuality.LOW }

processorEngine

OptionalStandalone
string

optional, Standalone only

Document processing can be a time-consuming task, especially when working with large documents. In order to improve the user experience it is possible to choose between two different processor engines with different optimizations applied: either one with a smaller bundle size (the default), but slower overall performance, or one with a larger bundle size, but faster processing time.

Either case it's recommended to enable asset compression on your Server to improve loading time.

Example

NutrientViewer.load({ processorEngine: NutrientViewer.ProcessorEngine.fasterProcessing });

Default Value

NutrientViewer.ProcessorEngine.fasterProcessing

productId

OptionalStandalone
string

optional, Standalone only

Allows specifying the environment in which the SDK is running.

Example

NutrientViewer.load({ productId: NutrientViewer.ProductId.SharePoint });

This callback is called whenever a page is rendered or printed (only for NutrientViewer.PrintMode.DOM). You can use it to render watermarks on the page.

Example

NutrientViewer.load({
renderPageCallback: function(ctx, pageIndex, pageSize) {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(pageSize.width, pageSize.height);
ctx.stroke();

ctx.font = "30px Comic Sans MS";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(
`This is page ${pageIndex + 1}`,
pageSize.width / 2,
pageSize.height / 2
);
}
// ...
});
boolean

This property allows you to restrict the movement of annotations to the page boundary. This is set to true by default. If you want to disable this, you can set it to false.

Default Value

true

serverUrl

Optional
string

This allows you to overwrite the auto-detected Nutrient Document Engine URL. This setting is necessary when your Nutrient Document Engine is located under a different URL.

Example

NutrientViewer.load({ serverUrl: 'https://public-server.pspdfkit.com/' })

Default Value

Auto-detected based on the currently executed <script> tag.

session

Optional
string

Server and DWS Viewer API only

The session token or publishable key used to authenticate a DWS Viewer API or Document Engine session.

When provided by itself, session opens the DWS-hosted document authorized by the token. When provided together with document, session authorizes DWS Viewer API loading for an app-provided document, such as a URL or ArrayBuffer. For that flow, use a publishable DWS Viewer API key or create a documentless DWS Viewer API session by omitting document_id and allowed_documents, and omit licenseKey.

Existing DWS Viewer API frontend sessions can also authorize app-provided document loading for compatibility, but browser-only integrations should use a publishable key.

Example

Load a DWS-hosted document

NutrientViewer.load({ session: 'xxx.xxx.xxx' });

Load an app-provided document with DWS Viewer API

NutrientViewer.load({
session: 'pdf_pub_live_...',
document: 'https://example.com/document.pdf',
});

signal

Optional

An optional AbortSignal that can be used to cancel the operation.

When the signal is aborted, the returned promise rejects with a DOMException with name set to 'AbortError'. Any resources allocated during the operation (backend, UI) are cleaned up.

For HTTP-based operations (document fetch, authentication), the underlying network request is cancelled. For WASM/worker operations, the promise rejects immediately but the underlying operation may run to completion in the background.

Example

const controller = new AbortController();
const loadPromise = NutrientViewer.load({
document: '/example.pdf',
container: '.viewer',
signal: controller.signal,
});

// Cancel loading after 5 seconds
setTimeout(() => controller.abort(), 5000);

try {
const instance = await loadPromise;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Loading was cancelled');
}
}

This property allows you to set an initial list of stamp and image annotation templates for the NutrientViewer instance. This can be used to customize the list of available stamp and image annotation templates that will be available in the stamps picker UI before the application mounts.

When omitted, it will default to NutrientViewer.defaultStampAnnotationTemplates.

Example

const stampAnnotationTemplates = NutrientViewer.defaultStampAnnotationTemplates
stampAnnotationTemplates.push(new NutrientViewer.Annotations.StampAnnotation({
stampType: "Custom",
title: "My custom text",
boundingBox: new NutrientViewer.Geometry.Rect({
left: 0,
top: 0,
width: 300,
height: 100
})
}));
NutrientViewer.load({
stampAnnotationTemplates,
// Other configuration options
});

Default Value

standaloneInstancesPoolSize

OptionalStandalone
number

Standalone only

Nutrient Web SDK uses an object pool to keep disposed instances in memory for fast reuse. Since this process can be memory inefficient, by default we only keep one instance in memory.

With this configuration option you can tune in the number of instances to keep in memory, or disable object pooling by setting this parameter to 0.

More about this feature: https://www.nutrient.io/blog/optimize-webassembly-startup-performance/

Example

NutrientViewer.load({
standaloneInstancesPoolSize: 2,
// ...
});

Default Value

1

styleSheets

Optional
string[]

This will load your custom CSS as a <link rel="stylesheet"> inside the NutrientViewer component. This is necessary to isolate styling of the viewer from the outside application and avoid external stylesheets overwriting important viewer attributes.

An array is allowed to load multiple stylesheets. The order in the array will also be the order in which the stylesheets get loaded.

The array will be copied by us on start up time, which means that you can not mutate it after the viewer has started.

More information on how to style Nutrient Web SDK can be found in our guides.

Example

NutrientViewer.load({
styleSheets: [
'https://example.com/my-stylesheet.css',
'https://example.com/other-stylesheet.css'
]
})

Default Value

[]

tempStorage

OptionalStandalone
"auto" | "memory" | "opfs" | { minFileSize?: number; mode: "opfs" }

Standalone only

Controls where the SDK temporarily keeps document data while loading a document from a URL in standalone mode.

By default, the SDK manages this automatically. For larger eligible documents loaded from a URL, it prefers the browser's Origin Private File System (OPFS) to reduce peak memory usage. Documents that do not benefit from OPFS, or documents loaded through a different processing path, continue to use the in-memory path.

If OPFS is unavailable or initialization fails, the SDK falls back to the in-memory path. In that case, the document may be requested again.

For whole-document URL downloads, the OPFS path requires a valid Content-Length response header so the SDK can pre-allocate storage. If that header is missing or invalid, the SDK falls back to the in-memory path.

  • "auto" (default): Let the SDK manage temporary storage automatically. For larger eligible URL-loaded documents, the SDK prefers OPFS.
  • "memory": Always keep temporary document data in memory.
  • "opfs" or { mode: 'opfs' }: Prefer OPFS for eligible URL-loaded documents regardless of file size.
  • { mode: 'opfs', minFileSize }: Prefer OPFS only when the file size is known and is at least minFileSize bytes.

Example

NutrientViewer.load({
tempStorage: 'auto',
document: 'https://example.com/large-document.pdf',
// ...
});

Default Value

"auto"

theme

Optional
"AUTO" | "LIGHT" | "DARK" | "HIGH_CONTRAST_LIGHT" | "HIGH_CONTRAST_DARK" | { … }

This property allows you to set theme to use for the UI. See NutrientViewer.Theme

Note: You can customize the appearance of the UI using our public CSS classes. Please refer to this guide article for information on how to customize the appearance.

Example

NutrientViewer.load({ theme: NutrientViewer.Theme.DARK })

Default Value

NutrientViewer.Theme.LIGHT

tileSize

Optional
number

This property allows you to change the size of the tiles used to render the document, in pixels. The bigger the tile, the fewer requests is made, but each tile will take longer to render.

This is useful for situations where you want to reduce the number of requests made to the server.

By default, the tile size is set to 512px in Nutrient Document Engine (server-backed) deployment, and 1536px in Standalone deployment.

Example

NutrientViewer.load({
tileSize: 1024
})

Default Value

512 in Nutrient Document Engine (server-backed), 1536 in Standalone

toolbarItems

Optional

This property allows you to set an initial list of toolbar items for the NutrientViewer instance. This can be used to customize the main toolbar before the application mounts.

When omitted, it will default to NutrientViewer.defaultToolbarItems.

Example

const toolbarItems = NutrientViewer.defaultToolbarItems;
toolbarItems.reverse();
NutrientViewer.load({
toolbarItems,
// Other configuration options
});

Default Value

"TOP" | "BOTTOM"

This property allows you to configure where the toolbar is placed. If nothing is configured, it will default to the top.

Example

NutrientViewer.load({ toolbarPlacement: NutrientViewer.ToolbarPlacement.TOP })

Default Value

NutrientViewer.ToolbarPlacement.TOP

trustedCAsCallback

OptionalStandalone

required, Standalone only

By implementing this callback you have a fine grained control over which certificates are going to be used for digital signatures validation.

The callback must return an Array of ArrayBuffer (DER) or string (PEM) containing X.509 certificates.

See this guide article to learn more.

Example

Fetch and use custom set of certificates (Standalone)

NutrientViewer.load({
trustedCAsCallback: function() {
return new Promise((resolve, reject) => {
fetch("/your-certificate.cer")
.then(res => res.arrayBuffer())
.then(cert => resolve([cert]))
.catch(reject)
});
},
// ...
})

ui

Optional

In-place UI customization API for the supported components using slots. Refer to this guide to get started.

Can be used to:

  • fully replace the default component UI with a custom one
  • insert a custom UI at a predefined slot in an existing component
  • replace an existing slot in a component with your own custom UI

See the list of supported slots here.

Example

NutrientViewer.load({
ui: {
commentThread: {
header: (getInstance, id) => {
const header = document.createElement('div');
header.innerText = 'Custom Comment Thread Header';

return {
render: (params) => header,
onMount: (id) => {
console.log(`Comment thread header mounted`);
},
onUnmount: (id) => {
console.log(`Comment thread header unmounted`);
}
};
}
}
}
});

unstable_inkEraserMode

DeprecatedOptional
"POINT" | "STROKE"

Allows to modify the default ink eraser behavior, which removes ink annotation points by default, changes it to make it remove entire strokes instead.

Deprecated

Use inkEraserMode instead.

Example

NutrientViewer.load({ unstable_inkEraserMode: NutrientViewer.unstable_InkEraserMode.STROKE });

Default Value

NutrientViewer.unstable_InkEraserMode.POINT

useCDN

Optional
boolean

This property is a temporary flag to explicitly enable loading assets from the CDN when baseUrl is not provided. This flag will be removed in future releases once loading from CDN is the default behavior when baseUrl is not set.

Has no effect when baseUrl is provided.

Default Value

false

useIframe

DeprecatedOptional
boolean

XFDF

OptionalStandalone
string

Standalone only

XFDF can be used to instantiate a viewer with a diff that is applied to the raw PDF. This format can be used to store annotation and form fields changes on your server and conveniently instantiate the viewer with the same content at a later time.

Instead of storing the updated PDF, this serialization only contains a diff that is applied on top of the existing PDF and thus allows you to cache the PDF and avoid transferring a potentially large PDF all the time.

You can export this format from a standalone instance by using Instance#exportXFDF.

Example

NutrientViewer.load({
XFDF: xfdfString,
// ...
});

XFDFIgnorePageRotation

OptionalStandalone
boolean

Standalone only

Whether the imported XFDF should ignore the page rotation.

The default import behavior will take the page rotation into account.

This is useful when you have PDF pages that look the same, but have different underlying page rotations. Use in connection with Instance#exportXFDF ignorePageRotation parameter.

Example

NutrientViewer.load({
XFDF: xfdfString,
XFDFIgnorePageRotation: true,
// ...
});

Default Value

false

XFDFKeepCurrentAnnotations

OptionalStandalone
boolean

Standalone only

Whether the annotations embedded in the PDF document should be kept instead of replaced importing XFDF.

The default import behavior will replace all annotations.

Example

NutrientViewer.load({
XFDF: xfdfString,
XFDFKeepCurrentAnnotations: true,
// ...
});

Default Value

false

XFDFRichTextEnabled

OptionalStandalone
boolean

Standalone only

Whether the imported XFDF should have rich text annotations or not.

The default import behavior will convert rich text annotations to plain text annotations. If set to true, rich text annotations will be supported and plain text annotations will be converted to rich text annotations.

Example

NutrientViewer.load({
XFDF: xfdfString,
XFDFRichTextEnabled: true,
// ...
});

Default Value

false