> 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/html/load-html.md).

# Load and Annotate HTML

Load and annotate HTML pages directly with WebViewer-HTML. An addon for WebViewer enabling live HTML page annotation. Learn how to integrate and use this feature seamlessly using web. The Apryse Web S

{% hint style="info" %}
New licenses for WebViewer HTML are no longer offered.
{% endhint %}

## Loading HTML directly (dynamic)

You can load HTML pages directly by importing [webviewer-html module](https://www.npmjs.com/package/@pdftron/webviewer-html/) completely client-side.

This is an addon for WebViewer that allows loading HTML web pages so that live HTML pages can be annotated.

Let me know how you are planning to use WebViewer HTML or if you have any feedback on any feature missing. [Let us know](https://apryse.com/form/feature-request).

Please make sure to check [the CHANGELOG](/web/html/changelog.md) to ensure versions of WebViewer and WebViewer-HTML are compatible.

## Sample Integration

Try out the [react sample](https://github.com/ApryseSDK/webviewer-html-annotate-proxy/). It shows how to integrate WebViewer and WebViewer-HTML with webviewer-html-proxy-server, a server component for proxying web pages.

### Initial setup

Before you begin, make sure your development environment includes [Node.js and npm](https://www.npmjs.com/get-npm/).

### Install

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

```sh
npm install @pdftron/webviewer-html
```

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

### How to use

WebViewer-HTML requires the server component, [@pdftron/webviewer-html-proxy-server](https://www.npmjs.com/package/@pdftron/webviewer-html-proxy-server/). This proxy server solves CORS issues. It will also parse the page for text and links, allowing you to use text annotations and page navigation.

Call the `createServer` function in your server component and pass in an object that includes `SERVER_ROOT` and `PORT`, see [API docs for more](https://sdk.apryse.com/api/html-proxy-server/#toc3__anchor).

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

```js
const HTMLProxyServer = require('@pdftron/webviewer-html-proxy-server');
HTMLProxyServer.createServer({
  SERVER_ROOT: `http://localhost`,
  PORT: 3100
});
```

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

When making the request to the proxy-server, make sure to pass along `{ credentials: 'include' }` to be able to [send cookies in cross-origin requests](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch/).

You can either load HTML pages from URLs, or static resources using the relative path. This API is available to load an HTML page by calling `loadHTMLPage`.

<pre class="language-js" data-line-numbers><code class="lang-js">import WebViewer from '@pdftron/webviewer';
import { initializeHTMLViewer } from '@pdftron/webviewer-html';

WebViewer(
  {
    path: 'lib',
  },
  document.getElementById('viewer')
).then(async (instance) => {
  const url = 'https://apryse.com/';
  const htmlProxyServerUrl = 'http://localhost:3100';

  // Tell webviewer-html-proxy-server that you want to proxy this URL
  const proxyUrlRes =
    await fetch(
      `${htmlProxyServerUrl}/pdftron-proxy?url=${url}`, 
      { credentials: 'include' },
    );

  const { validUrl } = await proxyUrlRes.json();
  const { href, origin, pathname } = new URL(validUrl);
  const hrefWithoutOrigin = href.split(origin)[1] || pathname;

  const license = `<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>`;

  // Extends WebViewer to allow loading HTML5 files from URL or static folder.
  const { loadHTMLPage } = await initializeHTMLViewer(instance, { license });

  loadHTMLPage({
    iframeUrl: `${htmlProxyServerUrl}${hrefWithoutOrigin}`,
    // URL that is being proxied
    urlToProxy: validUrl,
    width: 1440,
    height: 770,
  });
});
</code></pre>

New versions of [WebViewer v8.5](/web/changelogs/version-8/v8-5/v8-5-0.md) and above requires the `disableVirtualDisplayMode: true` constructor option. See [documentation](https://sdk.apryse.com/api/web/global.html#WebViewerOptions__anchor).

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

```js
WebViewer(
  {
    path: 'lib',
    disableVirtualDisplayMode: true,
  },
  document.getElementById('viewer')
).then(async (instance) => {
  // ...
});
```

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

### Detecting when the proxy is loaded

You can add a `proxyLoaded` event listener to detect when the proxy iframe is fully loaded. This event comes from the `DOMContentLoaded` event attached to the proxy website.

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

```js
import WebViewer from '@pdftron/webviewer';

WebViewer(
  {
    path: 'lib',
  },
  document.getElementById('viewer')
).then((instance) => {
  const { documentViewer } = instance.Core;
  documentViewer.addEventListener('proxyLoaded', listener);
});
```

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

### Version 3.x

Older versions 3.x of WebViewer-HTML used website scraping to save the website as a snapshot in time, without the need for a separate server component. Please refer to [this sample](https://github.com/ApryseSDK/webviewer-html-annotate/) that scrapes the content of a live website and allows you to annotate. This sample along with WebViewer-HTML v3.x are no longer maintained, as the proxy solution allows to better capture accurately the content of a live website. Read more in our [blog about scraping](https://apryse.com/blog/webviewer/webviewer-annotate-html-via-proxy-vs-scraping).

### Adding a license key

Beginning with version 3.x, we have added a watermark on all HTML pages being viewed in the demo mode. Version 3.x introduces quite a number of feature additions including text tools like highlighting and strikeout, as well as searching capabilities. To remove the `Apryse Demo` watermark, please pass the license key to the function. The license key can be obtained on [Apryse's website](https://apryse.com/form/contact-sales).

<pre class="language-js" data-line-numbers><code class="lang-js">WebViewer(
  {
    path: 'lib',
  },
  document.getElementById('viewer')
).then(async (instance) => {
  // Insert your demo or commercial license key here
  const license = `<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>`;
  const { loadHTMLPage } = await initializeHTMLViewer(instance, { license });
});
</code></pre>

For versions v4.5x and below, please pass the licence key to `loadHTMLPage`.

<pre class="language-js" data-line-numbers><code class="lang-js">loadHTMLPage({
  // Your webviewer-html-proxy-server url
  iframeUrl: 'http://localhost:3100',
  // Original url that is being proxied
  urlToProxy: 'https://apryse.com/',
  width: 500,
  height: 500,
  // Insert your demo or commercial license key here
  license: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
});
</code></pre>

### Documentation

[Client API documentation](https://sdk.apryse.com/api/html/)

[Server API documentation](https://sdk.apryse.com/api/html-proxy-server/)


---

# 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/html/load-html.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.
