> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/npm.md).

# Build a JavaScript PDF viewer with Apryse WebViewer SDK and npm

Get started with the Apryse WebViewer SDK. Install a Java PDF viewer in a vanilla JavaScript app using Node Package Manager (npm) without a bundler, then render your first document in the WebViewer UI

This guide demonstrates how to integrate the Apryse [WebViewer SDK](/web/what-is-webviewer/overview.md) into a vanilla JavaScript application using Node Package Manager (npm), without a bundler. You’ll install the SDK, serve its assets, and load it directly in the browser using a script tag. The examples use a simple HTML‑based project to focus on the core integration steps. By the end, you’ll initialize WebViewer and render a PDF document in the UI.

You can also download our ready-to-use [GitHub samples](https://github.com/ApryseSDK/webviewer-samples) to get started quickly, or explore the interactive [Showcase demo](https://showcase.apryse.com/) to see WebViewer's full capabilities in action.

## Prerequisites

Before you start:

* Install [Node.js](https://nodejs.org/en/download) and npm. We recommend using the latest active LTS release.
* Install [Visual Studio Code](https://code.visualstudio.com/Download) or another code editor to develop and debug your code.
* Get your Apryse trial key.

{% @apryse-license-key/apryse-license-key platform="WEB\_VIEWER" variant="full" %}

## 1. Create your project

Set up your project by creating a folder and preparing a workspace for your WebViewer application.

1. In your terminal, go to the directory where you want to create the project.
2. Create a new project folder and move to it so you can start working with it:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
mkdir webviewer-npm-integration
cd webviewer-npm-integration
```

{% endcode %}
{% endtab %}
{% endtabs %}

3. Initialize your project and generate a default `package.json` file:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npm init -y
```

{% endcode %}
{% endtab %}
{% endtabs %}

## 2. Install WebViewer

Next, install the Apryse WebViewer SDK using npm. This command adds the [WebViewer package](https://www.npmjs.com/package/@pdftron/webviewer) to your project, allowing you to integrate the PDF viewer and editor into your application.

After navigating to your `webviewer-npm-integration` project directory, run the following command to install WebViewer:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npm i @pdftron/webviewer
```

{% endcode %}
{% endtab %}
{% endtabs %}

## 3. Copy WebViewer assets

WebViewer needs access to its static assets at runtime, including WebAssembly modules, HTML, and CSS files. You must copy these assets into the `public` directory so they can be served correctly. For more, see [Copying WebViewer static assets](/web/get-started/copy-assets.md).

1. From your project root, create the `public/lib/webviewer` directory if it doesn't already exist:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npx --yes shx mkdir -p public/lib/webviewer
```

{% endcode %}
{% endtab %}
{% endtabs %}

2. Copy all WebViewer static assets from `node_modules/@pdftron/webviewer/public` into the new `public/lib/webviewer` directory:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npx --yes cpy-cli "node_modules/@pdftron/webviewer/public/**/*" public/lib/webviewer
```

{% endcode %}
{% endtab %}
{% endtabs %}

3. Copy the `webviewer.min.js` library file from `node_modules` to the `public` directory:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npx --yes cpy-cli node_modules/@pdftron/webviewer/webviewer.min.js public/lib/webviewer --flat 
```

{% endcode %}
{% endtab %}
{% endtabs %}

Your project should now include a similar structure:

{% code lineNumbers="true" %}

```
webviewer-npm-integration/
├── node_modules/
│   └── @pdftron/
│       └── webviewer/
├── public/
│   └── lib/
│       └── webviewer/
│           ├── core/
│           ├── ui/
│           └── webviewer.min.js
├── package.json
└── package-lock.json
```

{% endcode %}

{% hint style="info" %}
**Info**

You can optionally [automate asset copying](/web/get-started/copy-assets.md). This is recommended for larger projects. It ensures the WebViewer runtime files are updated consistently as part of your build process.
{% endhint %}

## 4. Create PDF viewer

In this section, you'll create an HTML page for your WebViewer application, add the WebViewer script, define a container for the viewer, and initialize WebViewer so it can load and display a document.

1. Open the `webviewer-npm-integration` folder in Visual Studio Code.
2. Create a new `index.html` file in the `webviewer-npm-integration/public` folder.
3. Add the following HTML to the `index.html` file:

{% tabs %}
{% tab title="HTML" %}
{% code title="index.html" lineNumbers="true" %}

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Basic WebViewer</title>
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />
    
    
    <!-- Import WebViewer as a script
         The src path must point to the webviewer.min.js file
         inside your project's WebViewer/lib folder -->
    <script src="/lib/webviewer/webviewer.min.js"></script>
  </head>

  <body>
    <!-- Container where WebViewer is rendered -->
    <div id="viewer" style="width: 100%; height: 100vh; margin: 0 auto;"></div>
  </body>
</html>
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Info**

This guide uses a `<script>` tag to load WebViewer. To learn about other approaches, see framework compatibility and [Importing](/web/get-started/libraries-and-frameworks/frameworks.md#importing) sections.
{% endhint %}

4. Add the following JavaScript to your `index.html` file, placing it after the `<div id="viewer">` element and before the closing `</body>` tag:

{% tabs %}
{% tab title="Web Component" %}

<pre class="language-js" data-line-numbers><code class="lang-js">&#x3C;script>
  WebViewer({
    // Add path to Apryse 'lib' folder on your server
    path: '/lib/webviewer',
    // Replace with your license key, key signup at https://dev.apryse.com
    licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
    // Specify an initial document to load on startup
    initialDoc: 'https://apryse.s3.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf',
    // You can also use documents on your server
    // initialDoc: '/path/to/my/file.pdf',
  // Provide id of HTML element where WebViewer should be mounted
  }, document.getElementById('viewer'))
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;

    // Call methods from instance, documentViewer, and annotationManager as needed

    // You can also access major namespaces from the instance as follows:
    // const Tools = instance.Core.Tools;
    // const Annotations = instance.Core.Annotations;
 
    documentViewer.addEventListener('documentLoaded', () => {
      // Call methods relating to the loaded document
    });
  });
&#x3C;/script>
</code></pre>

[WebViewer()](https://sdk.apryse.com/api/web/global.html#WebViewer__anchor) [WebComponent()](https://sdk.apryse.com/api/web/global.html?#WebComponent__anchor) [WebViewerOptions](https://sdk.apryse.com/api/web/global.html#WebViewerOptions__anchor) [DocumentViewer.documentLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:documentLoaded)
{% endtab %}

{% tab title="Iframe" %}

<pre class="language-js" data-line-numbers><code class="lang-js">&#x3C;script>
  // Uses iframe-based WebViewer, which was default through version 10

  WebViewer.Iframe({
    // Add path to Apryse 'lib' folder on your server
    path: '/lib/webviewer',
    // Replace with your license key, key signup at https://dev.apryse.com
    licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
// Provide id of HTML element where WebViewer should be mounted
}, document.getElementById('viewer'))
  .then(instance => {
    const { UI, Core } = instance;
    const { documentViewer, annotationManager, Tools, Annotations } = Core;

    // Call methods from UI, Core, instance, documentViewer, and annotationManager as needed

    documentViewer.addEventListener('documentLoaded', () => {
      // Call methods relating to loaded document
    });

    instance.UI.loadDocument('https://apryse.s3.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf');
  });
&#x3C;/script>
</code></pre>

[WebViewer()](https://sdk.apryse.com/api/web/global.html#WebViewer__anchor) [WebComponent()](https://sdk.apryse.com/api/web/global.html?#WebComponent__anchor) [WebViewerOptions](https://sdk.apryse.com/api/web/global.html#WebViewerOptions__anchor) [DocumentViewer.documentLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:documentLoaded) [UI.loadDocument()](https://sdk.apryse.com/api/web/UI.html#.loadDocument)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Info**

* If you're signed in with an Apryse account, your license key is automatically prepopulated in all code snippets.
* Starting in version 11, WebViewer instantiates using a web component instead of an iframe by default; however, both methods are available. See [this guide](/web/ui-customization/web-component-vs-iframe.md) for more information.
  {% endhint %}

5. Save the `index.html` file.

## 5. Verify your output

Once your project files are in place, serve the webpage so that WebViewer can load its UI and display the PDF you added as the initial document in `index.html`. We use [http-server](https://www.npmjs.com/package/http-server) to preview the page locally in your browser.

1. From your project directory, run the following command to start a local web server:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npx http-server -a localhost
```

{% endcode %}
{% endtab %}
{% endtabs %}

If prompted, press `y` to install `http-server`. A successful output looks similar to:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
Starting up http-server, serving ./public

http-server version: 14.1.1

http-server settings: 
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none

Available on:
  http://localhost:8080
```

{% endcode %}
{% endtab %}
{% endtabs %}

2. Open the localhost URL from your terminal to view the WebViewer UI and PDF document.

## Get started video

In this 4-minute video, learn how to install WebViewer in a simple HTML-based project using npm.

{% embed url="<https://www.youtube.com/embed/siJASVtD-S0?si=zNmu6tLv9dP6yJyf>" %}
Install the Apryse WebViewer SDK in an HTML-based project using npm.
{% endembed %}

## Next Steps

<a href="/web/what-is-webviewer/usage.md" class="button primary">Usage</a><a href="/web/get-started/guides.md" class="button primary">Guides</a><a href="/web/get-started/samples.md" class="button primary">Samples</a><a href="https://sdk.apryse.com/api/web/index.html" class="button primary">API docs</a>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/npm.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
