Track changes with Apryse DOCX Editor

Requirements
View Demo

Deprecation notice

With version 12.0, the namespace for tracked change APIs has moved from Core.Document.OfficeEditor to Core.Document.OfficeEditor.TrackedChangeManager. See the migration guide for details.

Tracked changes let users suggest, review, and manage edits in a DOCX document, making it easier to collaborate while preserving a clear history of what changed, who made each change, and when.

DOCX Editor with tracked changes and a sidebar showing added and deleted content.

Tracked changes in the document and review sidebar.

Tracked changes can be created by typing in reviewing mode. They may be accepted or rejected from the reviewing panel while in reviewing mode or by clicking the tracked change in editing mode.

DOCX Editor with an inserted tracked change and a pop-up to accept or reject it.

Inline tracked change in Editing mode with accept and reject controls.

TrackedChangeManager API

The Core.Document.OfficeEditor.TrackedChangeManager API provides programmatic control over tracked changes in the DOCX Editor. You can manage review workflows entirely through code, without relying on the default editor UI.

You can also use the API to build a fully custom review experience without relying on the default UI. For example, you can create a custom tracked changes panel, integrate changes into your own UI, or implement tailored review workflows using the provided methods and related events:

Get tracked changes

Tracked changes can be retrieved by using the getTrackedChanges API.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager();
5 // Retrieves a list of tracked changes ordered by their position in the document
6 const trackedChanges = await trackedChangeManager.getTrackedChanges();
7 });
8 });

Tracked changes are returned as an array of TrackedChange objects, ordered by their position in the document.

JSON

1{
2 "id": "number - The unique identifier of the object",
3 "type": "'inserted'|'deleted' | 'formatted' - The type of tracked change",
4 "author": "string - The author of the tracked change",
5 "date": "Date - The date of the tracked change",
6 "plainText": "string - The content of the tracked change to be inserted or deleted",
7 "getPagePositions": "function - Returns a promise that resolves to an array of objects containing {pageNumber: number, rect: Core.Math.Rect} for each annotation related to the tracked change"
8}

Navigate tracked changes

Jump to a tracked change by ID using the navigateToTrackedChange API. This moves the text cursor to the beginning of the change and scrolls it into view.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager();
5 const trackedChanges = await trackedChangeManager.getTrackedChanges();
6
7 // Get id of last tracked change and navigate to it
8 const lastTrackedChangeId = trackedChanges[trackedChanges.length - 1];
9 await trackedChangeManager.navigateToTrackedChange(lastTrackedChangeId);
10 });
11 });
12

Select tracked changes

You can programmatically select a tracked change by ID using the selectTrackedChange API, which highlights the change in the UI. You can also listen for selection changes using the trackedChangeSelected event, which is triggered whenever a tracked change is selected or deselected.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager;
5 const trackedChanges = await officeEditor.getTrackedChanges();
6
7 // Set up listener for tracked change selection
8 instance.Core.documentViewer.getDocument().addEventListener('trackedChangeSelected', (trackedChange, action) => {
9 // Contains tracked change object and 'selected' or 'deselected' action
10 console.log(trackedChange, action);
11 });
12
13 // Find tracked change ID to select
14 const firstChangeId = trackedChanges[0].id;
15
16 // Programatically select a tracked change with an API
17 await trackedChangeManager().selectTrackedChange(firstChangeId);
18 });
19 });
20

Modify tracked changes

You can programmatically accept or reject tracked changes by calling the appropriate APIs with the IDs obtained from the tracked changes list.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager();
5 const trackedChanges = await trackedChangeManager.getTrackedChanges();
6
7 // Accept tracked change by ID
8 await trackedChangeManager.acceptTrackedChange(trackedChanges[0].id);
9
10 // Reject tracked change by ID
11 await trackedChangeManager.rejectTrackedChange(trackedChanges[1].id);
12 });
13 });
14

Multiple tracked changes can also be programmatically accepted or rejected by using an array of tracked change IDs.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager;
5 const trackedChanges = await officeEditor.getTrackedChanges();
6 const allTrackedChangeIds = trackedChanges.map(c => c.id);
7
8 // Accept all tracked changes by their IDs
9 await trackedChangeManager.acceptTrackedChanges(allTrackedChangeIds);
10
11 // Reject all tracked changes by their IDs
12 await trackedChangeManager.rejectTrackedChanges(allTrackedChangeIds);
13 });
14 });
15

Get tracked change positions

Use the getPagePositions() method to retrieve the on-page locations of a single tracked change, including its bounding rectangles and page numbers. This shows where the tracked-change markup appears in the document when the method is called. It can be useful for positioning UI elements such as tooltips, highlights, or custom overlays.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const trackedChangeManager = instance.Core.documentViewer.getDocument().getOfficeEditor().getTrackedChangeManager();
5 const trackedChanges = await trackedChangeManager.getTrackedChanges();
6
7 // Check positions of first tracked change in document
8 const trackedChangePositions = await trackedChanges[0].getPagePositions();
9 const startRect = trackedChangePositions[0].rect; // the first rect position of the tracked change
10 const startPageNumber = trackedChangePositions[0].pageNumber; // the first page the tracked change appears
11 const endRect = trackedChangePositions[trackedChangePositions.length - 1].rect; // the last rect position of the tracked change
12 const endPageNumber = trackedChangePositions[trackedChangePositions.length - 1].pageNumber; // the last page the tracked change appears
13 });
14 });
15

Listen for change updates

Listen for tracked change updates using the trackedChangesUpdated event. This event is triggered when a tracked change is added, modified, or deleted.

JavaScript

1WebViewer(...)
2 .then(instance => {
3 instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
4 const officeEditor = instance.Core.documentViewer.getDocument().getOfficeEditor();
5 let trackedChanges = await officeEditor.getTrackedChanges();
6
7 // Set up listener to respond to updates about tracked changes
8 instance.Core.documentViewer.getDocument().addEventListener('trackedChangesUpdated', (trackedChange, action) => {
9 switch (action) {
10 case 'add':
11 trackedChanges = [...trackedChanges, trackedChange];
12 break;
13 case 'delete':
14 trackedChanges = trackedChanges.filter(tc => tc.id !== trackedChange.id);
15 break;
16 case 'modify':
17 trackedChanges = trackedChanges.map(tc => tc.id === trackedChange.id ? trackedChange : tc);
18 break;
19 }
20 });
21 });
22 });

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales