> 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/appian/customization/working-with-apis.md).

# Working with WebViewer APIs in Appian

Learn how to enhance your Appian experience with the WebViewer Appian component. Explore high and low-level features, leverage APIs, config files, and event handling for a customized solution. Dive in

Users may have needs not yet supported by the current Appian component. The WebViewer Appian component offers some high and low-level features of the WebViewer SDK. However, it only exposes a fraction of the SDK's capabilities, requiring mapping to reveal more. Rather than waiting for developers to enable these features, you can work directly with the APIs to create a solution that works for you.

{% hint style="warning" %}
This may be considered an advanced topic for those who may not know how to code, as this is considered high code territory. However, you can leverage our guides, code samples, and support to help in your journey and mastery!
{% endhint %}

## Config files

WebViewer actually runs in an [iframe](/web/what-is-webviewer/wv-inside.md) where all the namespaces and APIs are accessible. To access these APIs, you can leverage a [config](/web/advanced/config-files.md) file for WebViewer. Despite its name, it is actually a JavaScript file that is executed within the iframe.

You can upload this config file to Appian, and provide the [document ID](/appian/get-started/component-properties.md#configfileid) of the file to WebViewer.

![](https://1373770520-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQBPkEFulYTrl1g37jENZ%2Fuploads%2Fgit-blob-3731291c5760d89c77a5c85845cf644a61db8717%2F1608e6dd9a194401ae13b75298ffb0eeb0d0dc70-192x82.png?alt=media)

Check out our [repository with example config files for Appian](https://github.com/PDFTron/appian-config-file-samples/).

## Hooking into events

All of the [events](/web/events/loading-events.md) found in WebViewer are accessible. The most important being when the viewer is loaded as that is one of the earliest opportunities to setup WebViewer related settings or document preload actions (ex. fetching XFDF, notifying an external service, etc).

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

```js
instance.UI.addEventListener(instance.UI.Events.VIEWER_LOADED, () => {
  console.log("WebViewer Ready");
  // Perform some preload actions or more WebViewer configuration
  // Example - Disable UI elements on load. This is just an example and this functionality is actually a property of the component already.
  // instance.UI.disableElements(['toggleNotesButton']);
});
```

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

[UI#viewerLoaded](https://sdk.apryse.com/api/web/UI.html#event:viewerLoaded__anchor) [UI.disableElements](https://sdk.apryse.com/api/web/UI.html#disableElements__anchor)

Other important events include [`documentLoaded`](/web/events/loading-events.md#document-loaded) and [`annotationsLoaded`](/web/events/events.md#annotationsloaded).

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

```js
// Listening for when a document is loaded.
// You can hook into this directly or when the viewer is ready.
instance.UI.addEventListener(instance.UI.Events.DOCUMENT_LOADED, () => {
  // Document is loaded and you can work with the document related APIs
});
```

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

[UI#documentLoaded](https://sdk.apryse.com/api/web/UI.html#event:documentLoaded__anchor)

## Passing data to the config file

In most cases, you want to provide some data from Appian to WebViewer to use for a particular use case. For example, you need to create a certain type of annotation at a specific location when a document is loaded. You can communicate this through the [`customData`](/appian/get-started/component-properties.md#customdata) property of the component. It takes a JSON object which will be stringified and parsed, so only values and simple objects with values can be passed through this.

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

```js
instance.UI.addEventListener(instance.UI.Events.VIEWER_LOADED, () => {
  // Setup actions
});

instance.UI.addEventListener(instance.UI.Events.DOCUMENT_LOADED, () => {
  // Get the Annotations namespace and the annotation manager from Core
  const { annotationManager, Annotations } = instance.Core;
  // Get the custom data assembled by WebViewer
  const custom = JSON.parse(instance.UI.getCustomData());
  // Get the custom data mapped to the property (provided by user)
  const { customData } = custom;
  // Create a rectangle annotation if user specified 'rect'
  if (customData.type === "rect") {
    const rectangleAnnotation = new Annotations.RectangleAnnotation({
      PageNumber: 1,
      X: 100,
      Y: 100,
      Width: 250,
      Height: 250,
    });
    annotationManager.addAnnotation(rectangleAnnotation);
    annotationManager.redrawAnnotation(rectangleAnnotation);
  }
});
```

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

[Annotations](https://sdk.apryse.com/api/web/Core.Annotations.html) [AnnotationManager](https://sdk.apryse.com/api/web/Core.AnnotationManager.html) [UI.getCustomData](https://sdk.apryse.com/api/web/UI.html#.getCustomData__anchor) [RectangleAnnotation](https://sdk.apryse.com/api/web/Core.Annotations.RectangleAnnotation.html) [AnnotationManager.addAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#addAnnotation__anchor) [AnnotationManager.redrawAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#redrawAnnotation__anchor)

## `customData` object (WebViewer assembled)

It can be kind of confusing having two custom data objects, one embedded in the other. The parent custom data object is actually the object WebViewer assembles underneath with useful properties. Most of which are properties that were passed into the component at the very beginning. For example, if you had [`mentionableUsers`](/appian/get-started/component-properties.md#mentionableUsers) set in the Appian component, you could find them here as well.

The [`customData`](/appian/get-started/component-properties.md#customdata) property of that custom data object is the actual object that maps to the one provided to the component in Appian.

The following are some other properties found on the parent custom data object (subject to change):

* appainDocId
* automaticSemanticComparison
* customData
* customSubstituteFontUrl
* darkMode
* defaultLanguageCode
* disabledElements
* docAccessConnectedSystem
* documentFolder
* enableAnnotations
* enableDocumentGeneration
* enableExtractPagesToAppian
* enableMeasurement
* enableMultiTabMode
* enableOfficeEditing
* enablePdfEditing
* enableRedaction
* enableSemanticCompareMode
* enableSignatureEncryption
* enableSignatureRequests
* enabledElements
* loadAsPDF
* mentionableUsers
* notesInLeftPanel
* searchTerm
* serviceAPIKey
* templateData
* url
* userDisplayName
* watermarkOptions
* xfdfAnnotationData
* xfdfDocumentFolder

You can checkout the full list of the [Appian component properties](/appian/get-started/component-properties.md).

## Passing data back to Appian (appianManager)

Now that we've looked at how to get data from Appian, we can take a look at how to send some data back to Appian. This is done through an object called the `appianManager`. This object manages the interaction between WebViewer and Appian through various APIs.

## Triggering an event

To trigger events on the Appian side, you will need to call the `saveValue` function on the `appianManager` object. This function takes two parameters: the event name and the data to send back to Appian. The data can be any type of value, including objects and arrays. You can refer to our [component properties](/appian/get-started/component-properties.md) to see what kind of events are available. However, triggering an existing event by yourself can cause unexpected behavior, so it's best to stick to the [`onCustomEvent`](/appian/get-started/component-properties.md#onCustomEvent) event for your own custom events, and using a `type` property to differentiate between different events.

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

```js
instance.UI.addEventListener(instance.UI.Events.DOCUMENT_LOADED, () => {
  appianManager.saveValue('onCustomEvent', { type: 'myCustomEvent', data: 'some data' });
});
```

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

## Next steps

Look into what APIs exist within [WebViewer](/web/get-started/guides/features/annotation.md) to create a solution that works for you!


---

# 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/appian/customization/working-with-apis.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.
