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

# Interact with Annotation Events in WebViewer JavaScript PDF Viewer

Discover key Annotation Events for efficient integration. Learn to track creation, modification, deletion, and selection of annotations using AnnotationManager using web. Optimize workflows with preci

There are a number of events related to annotations that can be useful to hook into. This is especially important for knowing when annotations are created in order to export them or immediately change a property. To do this you'll add a listener to the [`AnnotationManager`](/web/annotation/annotationmanager/annotationmanager.md).

{% hint style="warning" %}
**Do not add listeners in the documentLoaded event**

This will cause a new listener to be attached every time a new document is loaded.
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;

    annotationManager.addEventListener('annotationChanged', () => {
      // ...
    });
  });
```

{% endcode %}

**Related links**

* [WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html)
* [Core](https://sdk.apryse.com/api/web/Core.html)
* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
  {% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;

    annotManager.on('annotationChanged', () => {
      // ...
    });
  });
```

{% endcode %}

**Related links**

* [WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html)
* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
  {% endtab %}
  {% endtabs %}

## annotationChanged (add/modify/delete)

The [annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor) event is fired every time an annotation is added, modified, or deleted. The handler takes three parameters: an array of annotations that have changed, a string for the action (add, modify, delete), and an info object describing the event.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;

    annotationManager.addEventListener('annotationChanged', (annotations, action) => {
      if (action === 'add') {
        console.log('this is a change that added annotations');
      } else if (action === 'modify') {
        console.log('this change modified annotations');
      } else if (action === 'delete') {
        console.log('there were annotations deleted');
      }

      annotations.forEach((annot) => {
        console.log('annotation page number', annot.PageNumber);
      });
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
  {% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;

    annotManager.on('annotationChanged', (annotations, action) => {
      if (action === 'add') {
        console.log('this is a change that added annotations');
      } else if (action === 'modify') {
        console.log('this change modified annotations');
      } else if (action === 'delete') {
        console.log('there were annotations deleted');
      }

      annotations.forEach((annot) => {
        console.log('annotation page number', annot.PageNumber);
      });
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
  {% endtab %}
  {% endtabs %}

{% hint style="info" %}
The annotationChanged event will also be fired whenever annotations are imported from XFDF, even if they were not created directly by a user.
{% endhint %}

If you want to do something different in that scenario, perhaps ignore those types of events, you can use the `imported` property of the info object. For example:

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    annotationManager.addEventListener('annotationChanged', (annotations, action, { imported }) => {
      // imported indicates if the annotations were imported via a process, mainly XFDF
      if (imported) {
        return;
      }
      // do event handling
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
* [AnnotationChangedInfoObject](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#.AnnotationChangedInfoObject__anchor)
  {% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    annotManager.on('annotationChanged', (annotations, action, { imported, isUndoRedo }) => {
      if (imported) {
        return;
      }
      // do event handling
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
* [AnnotationChangedInfoObject](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#.AnnotationChangedInfoObject__anchor)
  {% endtab %}
  {% endtabs %}

One other property you might want to utilize is `isUndoRedo`, which will return true if the annotation has changed as a result of an undo or redo action.

## annotationSelected

The [annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor) event is fired any time an annotation is selected or deselected in the UI. The parameters are similar to `annotationChanged`: an array of annotations and a string for the action (selected or deselected). The preferred way to detect deselection is using the [`annotationDeselected`](#annotationdeselected) event.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    annotationManager.addEventListener('annotationSelected', (annotations, action) => {
      if (action === 'selected') {
        console.log('annotation selection');
      } else if (action === 'deselected') {
        console.log('annotation deselection');
      }

      console.log('annotation list', annotations);

      if (annotationManager.getSelectedAnnotations().length === 0 && action === 'deselected') {
        console.log('all annotations deselected');
      }
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor)
  {% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    annotManager.on('annotationSelected', (annotations, action) => {
      if (action === 'selected') {
        console.log('annotation selection');
      } else if (action === 'deselected') {
        console.log('annotation deselection');
      }

      console.log('annotation list', annotations);

      if (annotManager.getSelectedAnnotations().length === 0 && action === 'deselected') {
        console.log('all annotations deselected');
      }
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor)
  {% endtab %}
  {% endtabs %}

{% hint style="info" %}
Users can select annotations through the viewer but you can also perform selections/deselections programmatically using our [APIs ](/web/annotation/annotationmanager/annotation-selection.md).
{% endhint %}

## annotationDeselected

Using the [annotationDeselected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationDeselected__anchor) event is the recommended way to detect annotation deselection and getting the deselected annotations. You will get only the deselected annotations as a parameter to the listener.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager, Annotations } = instance.Core;
    annotationManager.addEventListener('annotationDeselected', (annotations) => {
      annotations.forEach(annot => {
        if (annot.FillColor) {
          annot.FillColor = new Annotations.Color(255, 0, 0, 1);
        }
      });
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationDeselected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationDeselected__anchor)
  {% endtab %}
  {% endtabs %}

## annotationsLoaded

The [annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor) event is fired when all the annotations internal to the document have been loaded. It is one of the [lifecycle](/web/events/loading-events.md) events in WebViewer. Since DocumentViewer is managing this process the event is fired on DocumentViewer. When working with annotations, it would be best to use this event over `documentLoaded` to ensure all annotations are available.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;
    documentViewer.addEventListener('annotationsLoaded', () => {
      // all annotations are available
      const annotations = annotationManager.getAnnotationsList();
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor)
* [AnnotationManager.getAnnotationsList](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getAnnotationsList__anchor)
  {% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { docViewer, annotManager } = instance;
    docViewer.on('annotationsLoaded', () => {
      // all annotations are available
      const annotations = annotManager.getAnnotationsList();
    });
  })
```

{% endcode %}

**Related links**

* [AnnotationManager#annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor)
* [AnnotationManager.getAnnotationsList](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getAnnotationsList__anchor)
  {% endtab %}
  {% endtabs %}

## Next steps

Look into how you can [create](/web/annotation/create-annotations.md) your own annotations!


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.apryse.com/web/events/events.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
