This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/web/self-host-assets.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Self-host assets in Web SDK

When you install Nutrient Web SDK with a package manager, the SDK loads additional resources at runtime — for example, web workers, fonts, and icons. You must serve these resources from a web server. As of version 1.9.0, you can load those assets automatically from a content delivery network (CDN) by setting useCDN: true. That setup is enough for most use cases. If you need complete control over the dependencies for compliance, offline functionality, security policies, or performance optimization, you can serve the SDK assets yourself.

When to self-host assets

The table below summarizes the two asset setup modes for Web SDK and what each is for:

ModeUse forSetup
CDN (useCDN: true)Fastest integration and internet-accessible deploymentsConfigure useCDN: true in NutrientViewer.load(...).
Self-hosted (baseUrl)Compliance, offline, controlled infrastructureServe the full assets archive from your domain and configure baseUrl.

Prerequisites

This guide assumes you’ve already installed Nutrient Web SDK via a package manager. The assets archive below contains only the runtime dependencies (WebAssembly binaries, fonts, and icons) that the SDK loads. It’s not a standalone SDK distribution. Refer to the getting started guide for installation instructions.

The archive contains only the nutrient-viewer-lib/ folder. It doesn’t include the nutrient-viewer.js entry script. Keep loading the entry script from the npm package, either through your bundler or from node_modules/@nutrient-sdk/viewer/dist/nutrient-viewer.js, and use the archive as the source for nutrient-viewer-lib/.

Use the archive for the same version as the npm package. The download link below is for the latest version. For another released version, 1.9.0 or later, download https://cdn.cloud.nutrient.io/assets/pspdfkit-web-assets@<version>.zip, with <version> set to the version field in node_modules/@nutrient-sdk/viewer/package.json. With a different version, the SDK requests files the archive doesn’t have, and loading fails.

Self-hosting assets

Follow the steps below to self-host the SDK assets.

Required files — For baseUrl mode, the exact required runtime set is the entire contents of the downloaded assets archive. Serve it with the original folder structure preserved.

  1. Download the assets archive(opens in a new tab).

  2. Extract the contents of the archive directly into your application’s public directory — for example, /public/. Keep the original folder structure, including nutrient-viewer-lib/.

  3. Load the assets from your server by setting baseUrl to the URL above nutrient-viewer-lib/ when you initialize the SDK:

    NutrientViewer.load({
    container,
    document: "/nutrient-web-demo.pdf", // Place your PDF in the public directory.
    baseUrl: `${window.location.protocol}//${window.location.host}/${
    import.meta.env.PUBLIC_URL ?? "" // Usually empty for Vite, but supports custom deployments.
    }`,
    });
  4. If you use NutrientViewer.preloadWorker() to preload WebAssembly artifacts, pass the same baseUrl value:

    NutrientViewer.preloadWorker({
    baseUrl: `${window.location.protocol}//${window.location.host}/${
    import.meta.env.PUBLIC_URL ?? ""
    }`,
    });
  5. Verify self-hosting is working:

    • Start your development server.
    • Open browser DevTools and navigate to the Network tab.
    • Load a PDF in your application.
    • Confirm SDK assets are being loaded from your domain and not from cdn.cloud.nutrient.io.

Load the SDK without a bundler

Without a bundler, load nutrient-viewer.js with a <script> tag and call NutrientViewer.load(). In the example below, the application serves nutrient-viewer.js, and a separate assets server serves the extracted nutrient-viewer-lib/ folder:

<!doctype html>
<html lang="en">
<head>
<!-- Declares UTF-8, so the browser decodes nutrient-viewer.js correctly. -->
<meta charset="utf-8" />
<title>Nutrient Web SDK</title>
</head>
<body>
<div id="viewer" style="height: 100vh"></div>
<!-- Entry script copied from node_modules/@nutrient-sdk/viewer/dist/. -->
<script src="/vendor/nutrient-viewer.js"></script>
<script>
async function loadViewer() {
try {
const instance = await NutrientViewer.load({
container: "#viewer",
document: "/document.pdf",
// The folder that contains the extracted nutrient-viewer-lib/.
baseUrl: "https://assets.example.com/",
});
console.log(`Loaded ${instance.totalPageCount} page(s).`);
} catch (error) {
console.error("Failed to load the viewer:", error);
}
}
loadViewer();
</script>
</body>
</html>

Configure the assets server as follows:

  • When it’s on a different origin from your application, send an Access-Control-Allow-Origin header for your application’s origin. Without it, the viewer doesn’t finish loading, and NutrientViewer.load() neither resolves nor rejects. In that case, check the browser console and the Network tab for a blocked .wasm request. For more information, see cross-origin resource sharing (CORS) issues.
  • A separate assets origin requires the default inlineWorkers: true. With inlineWorkers: false, serve the assets from your application’s origin.
  • Serve .wasm files with the application/wasm Multipurpose Internet Mail Extensions (MIME) type. With a different MIME type, the viewer still loads, but it logs errors in the console and falls back to classic WebAssembly instantiation.

Common 404 troubleshooting checks

Use the checks below to identify the most common asset-loading misconfigurations:

  • baseUrl points to the actual public URL root where assets are served.
  • Asset archive contents were extracted completely (no nested extra folder level).
  • Development/proxy/CDN configuration doesn’t rewrite asset requests away from the asset root.
  • Network tab shows runtime assets loaded from expected host/path.

If you use NutrientViewer.preloadWorker(...), make sure it uses the same baseUrl.

Deprecation warning in the console

The console warning Copying assets from the npm package is deprecated means Nutrient Web SDK loaded nutrient-viewer-lib/ from the npm package. The npm package keeps that copy in node_modules/@nutrient-sdk/viewer/dist/nutrient-viewer-lib/. The viewer still works with the npm copy, but that source is deprecated. To remove the warning, serve nutrient-viewer-lib/ from the assets archive instead, and set baseUrl to the URL of the folder that contains it. Remove any build step that copies nutrient-viewer-lib/ from node_modules; it overwrites the archive’s files.

The two folders contain the same file names. Nutrient Web SDK tells them apart by loading npm-assets-deprecated.js from the nutrient-viewer-lib/ folder it uses. The npm package’s copy marks the assets as deprecated, and the archive’s copy doesn’t.

Integration checklist

Use the checklist below to validate your setup before moving to production:

  • Verify asset mode/path (useCDN or baseUrl).
  • Confirm entrypoint import and viewer mount container.
  • Unload before reload when switching documents.
  • Reapply toolbar/custom UI configuration after each load.
  • Confirm export behavior matches your workflow.

For a full embedded integration flow, refer to the embedding Web SDK in a dashboard/app shell guide.

Why this change?

Starting with version 1.9.0, we changed how we distribute runtime assets. This shift addresses challenges developers encountered with modern build tools and deployment workflows. It also makes the SDK more flexible for different use cases.

Cleaner assets for self-hosting

Build tools like Vite and Webpack often struggled to locate large binary files buried deep within node_modules hierarchies. The self-host ZIP provides a stable source for these assets that doesn’t depend on npm’s folder structure or on how build tools resolve paths. The archive works the same way in every environment.

Smaller package size

Separating large binary assets from the core package keeps installations lean. This means faster npm installs, quicker continuous integration and continuous delivery (CI/CD) pipelines, and less bandwidth consumption. That’s especially valuable for teams working with constrained network conditions or deploying frequently. Your project downloads only what it needs.

Easier for most, flexible for you

Setting useCDN: true without a baseUrl loads the assets from the CDN, which is the simplest setup. Most teams can start immediately without managing assets. But if you need strict control — whether for compliance requirements, air-gapped environments, offline functionality, or security policies — the self-hosting path remains supported.

Looking ahead

The old approach still works during this transition period, which gives everyone time to migrate. The deprecation warning points you to the new method before we eventually phase out the old files. We’re also exploring package manager integration to simplify self-hosting. Feedback from teams that need that level of control informs this work.

Deprecation warning: Before version 1.9.0, the recommended way to self-host assets was by using the files inside node_modules/@nutrient-sdk/viewer/dist/nutrient-viewer-lib. This is no longer recommended and will result in a warning in the console. Use the method described above instead. This change gives you more flexibility in how you manage and deploy assets.