---
title: "Revision History Plugin"
description: "A view that allows TinyMCE users to see historical snapshots of a document and an ability to restore from a snapshot"
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/revisionhistory/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/revisionhistory/index.md"
version: "latest"
last_updated: "2026-07-30T23:38:01Z"
tokens: 7782
---
# Revision History Plugin

> **Note:** This plugin is only available as a [paid add-on](/tinymce/features/revision-history/) to [a TinyMCE subscription](/pricing/).
The Revision History plugin offers users the ability to view document changes over time and restore previous revisions effortlessly.

## Interactive example

**Example**

```js
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

const fakeDelay = 200;

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-24T22:26:21.578Z',
    author: {
      id: 'james-wilson',
      name: 'James Wilson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
    },
    metadata: { source: 'ai' },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
      <h2 style="text-align: center;">Welcome to the TinyMCE editor demo!</h2>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <h2>Found a bug?</h2>
      <p>If you think you have found a bug please create an issue on the <a href="https://github.com/tinymce/tinymce/issues">GitHub repo</a> to report it to the developers.</p>
      <h2>Finally ...</h2>
      <p><s>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</s></p>
      <p>Thanks for supporting TinyMCE! We hope it helps you and your users create great content.<br>All the best from the TinyMCE team.</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    author: {
      id: 'mia.andersson',
      name: 'Mia Andersson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
      <h2 style="text-align: center;">Welcome to the TinyMCE editor demo!</h2>
      <h2>Got questions or need help?</span></h2>
      <ol>
      <li>Our <a href="../">documentation</a> is a great resource for learning how to configure TinyMCE.</li>
      <li>Have a specific question? Try the <a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code> tag at Stack Overflow</a>.</li>
      <li>We also offer enterprise grade support as part of <a href="../../../../pricing">TinyMCE premium plans</a>.</li>
      </ol>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <h2>Found a bug?</h2>
      <p>If you think you have found a bug please create an issue on the <a href="https://github.com/tinymce/tinymce/issues">GitHub repo</a> to report it to the developers.</p>
      <h2>Finally ...</h2>
      <p>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</p>
      <p>Thanks for supporting TinyMCE! We hope it helps you and your users create great content.<br>All the best from the TinyMCE team.</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-29T10:11:21.578Z',
    author: {
      id: 'mia.andersson',
      name: 'Mia Andersson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
      <h2 style="text-align: center;">Welcome to the TinyMCE editor demo!</h2>
      <h2>Got questions or need help?</h2>
      <ul>
      <li>Our <a href="../">documentation</a> is a great resource for learning how to configure TinyMCE.</li>
      <li>Have a specific question? Try the <a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code> tag at Stack Overflow</a>.</li>
      <li>We also offer enterprise grade support as part of <a href="../../../../pricing">TinyMCE premium plans</a>.</li>
      </ul>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <h2>Found a bug?</h2>
      <p>If you think you have found a bug please create an issue on the <a href="https://github.com/tinymce/tinymce/issues">GitHub repo</a> to report it to the developers.</p>
      <h2>Finally ...</h2>
      <p>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</p>
      <p>Thanks for supporting TinyMCE! We hope it helps you and your users create great content.<br>All the best from the TinyMCE team.</p>
    `,
  }
];

const revisionhistory_fetch = () => new Promise((resolve) => {
  setTimeout(() => {
    const sortedRevisions = revisions
      .sort((a, b) => new Date(a.createdAt) < new Date(b.createdAt) ? -1 : 1);
    resolve(sortedRevisions);
  }, fakeDelay);
});

const revisionhistory_fetch_revision = (_editor, revision) => new Promise((resolve, reject) => {
  setTimeout(() => {
    const revision = revisions.find((r) => r.revisionId === revision.revisionId);
    if (revision) {
      resolve(revision);
    } else {
      reject(`Revision ${revision.revisionId} is not found`);
    }
  }, fakeDelay);
});

tinymce.init({
  selector: 'textarea#revisionhistory',
  height: 800,
  plugins: 'revisionhistory help code link lists image',
  toolbar: 'undo redo | styles | bold italic underline | revisionhistory | link image | code',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }',
  revisionhistory_fetch,
  revisionhistory_fetch_revision,
  revisionhistory_display_author: true,
  user_id: 'kai-nakamura',
  fetch_users: (userIds) => Promise.all(userIds
    .map((userId) =>
      fetch(`${API_URL}/${userId}`)
        .then((response) => response.json())
        .catch(() => ({ id: userId })))),
});
```

> **Note:** This feature is only supported when TinyMCE is run in *classic* mode. It is not supported in *inline* mode. For more information on the differences between the editing modes, see [Classic editing mode](../use-tinymce-classic/).

## How it works

The Revision History view is accessible via either the `revisionhistory` toolbar button or menu button within the `View` menu.

The key components are:

1. In the Revision History view header, there are two buttons.

  - `Restore this version`: Sets the selected revision’s content to the editor and closes the view. Note: the button is disabled for the `initial` and `draft` revisions.
  - `Close`: Closes the **Revision History** view.
2. The readonly diff view presents the changes between the selected revision and its immediate predecessor, clearly highlighting for easy recognition. The changes are also color-coded for clarity:

  - Red: Removed content.
  - Green: New content.
  - Yellow: Content being modified. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.).
3. The revisions sidebar displays all available document revisions. When a revision is selected, the diff view is updated accordingly.

> **Note:** The default highlighting colors can be customized using the [`revisionhistory_css_url`](#revisionhistory_css_url) option.

> **Note:** The Revision History plugin processes commented HTML as valid content but disregards it during the revision comparison process. Revisions containing only commented content appear as empty in the view.

## Basic setup

To setup the Revision History plugin in the editor:

- add `revisionhistory` to the `plugins` option in the editor configuration;
- add `revisionhistory` to the `toolbar` option in the editor configuration;
- add `revisionhistory_fetch` option to the editor configuration;

For example:

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Replace this with an API request to get saved revisions
});
```

> **Note:** For information on bundling this plugin with module bundlers, see [Bundling TinyMCE - Overview](../bundling-guide/).

## Understanding revision types

The Revision History plugin offers three revision types:

1. **Initial**: This revision is generated during the TinyMCE `Loaded` event, capturing the editor’s initial content.
2. **Draft**: Generated upon opening the Revision History, this revision reflects the editor’s current content. When included, it becomes the `latest revision` in the revisions list.
3. **Saved**: These revisions are fetched from the client’s storage when opening the Revision History view, using the `revisionhistory_fetch` and `revisionhistory_fetch_revision` options.

When working with a document that has no saved revisions, the Revision History plugin typically maintains two revisions: `initial` and `draft`. If no changes have been made to the content since initialization, the `initial` revision is not displayed, as it is identical to the `draft` revision.

For documents with saved revisions, the `initial` revision is disregarded, assuming it already exists among the saved revisions. To include the initial content, add it as a revision using the `revisionhistory_fetch` option.

## Data structure

### Revision

The revision is an `Object` that contains the following fields:

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `revisionId` | `string` | required | The unique string ID of the revision. |
| `createdAt` | `string` | required | A UTC datetime string in ISO-8061 format. |
| `content` | `string` | optional | HTML string of the revision content. Empty string is considered as valid content. |
| `author` | [Author](#author) `Object` | optional | The author of the revision. |
| `metadata` | [Metadata](#metadata) `Object` | optional | Additional information about the revision, such as whether it was AI-assisted. |

### Author

The author is an `Object` that represents the author or creator of a revision. It contains the following fields:

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `id` | `string` | required | The unique string ID of the author. |
| `name` | `string` | optional | The name of the revision author. If not provided, the default value is `Anonymous`. |
| `avatar` | `string` | optional | The URL of the author’s avatar image. If not provided or invalid, the Revision History will use a generated avatar using the author’s initials. |

### Metadata

The metadata is an `Object` that holds additional information about a revision. It contains the following fields:

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `source` | `string` | optional | The origin of the revision’s content. A value of `'ai'` marks the revision as AI-assisted and displays an AI badge on the revision card by default. Set [`revisionhistory_ai_attribution`](#revisionhistory_ai_attribution) to `false` to hide the badge. |

## Attributing AI-assisted revisions

A revision is identified as AI-assisted through the `source` field of its [`metadata`](#metadata) object. When `metadata.source` is `'ai'`, an AI badge appears on that revision card by default. Set [`revisionhistory_ai_attribution`](#revisionhistory_ai_attribution) to `false` to hide the badge.

The Revision History plugin does not set this marker automatically. Instead, the application must listen for content events and save each revision with the marker attached. The [TinyMCE AI](../tinymceai/) plugin sets `ai` to `true` on both the `BeforeSetContent` and `SetContent` events for any content it inserts, so either event can signal AI involvement:

- `BeforeSetContent` fires immediately before the AI content is inserted. Calling `editor.getContent()` at this point returns the content as it stood before the AI edit.
- `SetContent` fires immediately after the AI content is inserted. Calling `editor.getContent()` at this point returns the AI-generated result.

Either event can drive attribution, and both can be used together. Which to listen for depends on the granularity the application requires. A revision covers everything that changed since the previous revision, so listening for a single event produces revisions that can hold both AI-generated and human content:

- Listening for `BeforeSetContent` alone saves the human edits made since the last revision, together with the AI edit that preceded them.
- Listening for `SetContent` alone saves the AI edit, together with the human edits that preceded it.
- Listening for both separates the two, saving the content as it stood before each AI edit and the AI-generated result as distinct revisions.

Where the aim is to save a revision whenever content changes, either event is suitable. Where AI-generated and human content must be distinguished, listen for both. There are three steps to keep attribution accurate:

1. **Detect**: Listen for `BeforeSetContent`, `SetContent`, or both, and check whether the `ai` property is `true`. Both events also fire for content changes that the AI plugin did not make, so this check keeps unrelated changes out of the attributed revisions.
2. **Save**: When the check passes, save a revision, setting `metadata.source` to `'ai'` for the AI-generated content.
3. **Restore**: When a revision is restored, save it with its marker preserved so the restored content remains correctly attributed.

> **Note:** The AI badge appears only on `saved` revisions. The `draft` and `initial` revisions are generated from the editor’s current content and do not carry `metadata`, so they never display the badge, even when that content was AI-assisted. See [Understanding revision types](#understanding-revision-types).

### Saving an AI-assisted revision

The application is responsible for saving revisions and returns them through the [`revisionhistory_fetch`](#revisionhistory_fetch) option. The following example listens for both events, sharing a single helper that snapshots the current content and marks the revision as AI-assisted when its `aiAssisted` parameter is `true`. `BeforeSetContent` saves the content that preceded each AI edit as its own revision, and `SetContent` saves the AI-generated result:

```js
// Call this when saving a snapshot of the current content as a revision.
const saveRevision = (aiAssisted) => {
  const revision = {
    revisionId: createRevisionId(), // Replace with your ID generation
    createdAt: new Date().toISOString(),
    content: editor.getContent(),
    // Mark the revision as AI-assisted when the content came from the AI plugin.
    ...(aiAssisted ? { metadata: { source: 'ai' } } : {})
  };

  saveToStorage(revision); // Replace with your storage call
};

// Save the pre-AI (human) content before the TinyMCE AI plugin inserts its edit.
editor.on('BeforeSetContent', (e) => {
  if (e.ai) {
    saveRevision(false);
  }
});

// Save the post-AI content and mark it as AI-assisted.
editor.on('SetContent', (e) => {
  if (e.ai) {
    saveRevision(true);
  }
});
```
To drive attribution from a single event, keep only the listener required. The revisions this produces combine AI-generated and human content, as described in [Attributing AI-assisted revisions](#attributing-ai-assisted-revisions).

### Restoring an AI-assisted revision

Restoring a revision sets its content back into the editor and fires the `VersionRestored` event. The restored content is not flagged as AI-assisted, so look up the revision that was restored and save it with its marker preserved, using the `saveRevision()` helper shown in [Saving an AI-assisted revision](#saving-an-ai-assisted-revision):

```js
editor.on('VersionRestored', (e) => {
  const restored = getFromStorage(e.revisionId); // Replace with your storage lookup
  // Preserve attribution so the restored content keeps its marker.
  saveRevision(restored?.metadata?.source === 'ai');
});
```

## Options

The following configuration options affect the behavior of the Revision History plugin.

### `revisionhistory_fetch`

The `revisionhistory_fetch` function retrieves saved revisions and is called when the user opens the Revision History view.

> **Important:** The `revisionhistory_fetch` function is required for the Revision History plugin to function.
It expects an asynchronous function that returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which resolves to an array of revisions.

> **Note:** The Revision History plugin does not sort results before displaying them, allowing integrators to sort the results according to their preference. Tiny recommends to sort the results in reverse chronological order, as this makes it easier for users to identify revisions by date.
**Type:** `Function` (Returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))

**Input parameters:** None

**Return data:** `Array` of [Revision](#revision) `Objects`

#### Example of `revisionhistory_fetch` response

```js
const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>Welcome to TinyMCE Docs!</h2>
      <p>Here is some content that is <strong>bold</strong> and <em>italic</em>.</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>Welcome to TinyMCE Docs!</p>
      <p>Here is some content that is bold and italic.</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>Welcome to Tinymce!</p>
    `,
  }
];
```

#### Example: Using `revisionhistory_fetch`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () =>
    fetch('<API URL>')  // Update the URL and response handling code according to your API
    .then((response) => response.json())
    .then((data) => data)
    .catch((error) => console.log('Failed to get revisions\n' + error))
});
```

### `revisionhistory_fetch_revision`

When a revision is selected, the plugin uses this option to update the selected or closest revision that has no content. The function is expected to return a Promise that resolves with an updated revision.

**Type:** `Function` (Returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))

**Input parameters:**

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `editor` | `Editor` | required | The current editor instance (useful if there are multiple editors on the page). |
| `revision` | [Revision](#revision) `Object` | required | The targeted revision. |

**Return data:** [Revision](#revision) `Object`

#### Example: Using `revisionhistory_fetch_revision`

```js
const lightRevisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
  }
];

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>Welcome to TinyMCE Docs!</h2>
      <p>Here is some content that is <strong>bold</strong> and <em>italic</em>.</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>Welcome to TinyMCE Docs!</p>
      <p>Here is some content that is bold and italic.</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>Welcome to Tinymce!</p>
    `,
  }
];

tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve(lightRevisions),
  revisionhistory_fetch_revision: (_editor, revision) => new Promise((resolve) => {
    let newRevision = null;
    for (let i = 0; i < revisions.length; i++) {
      const temp = revisions[i];
      if (temp.revisionId === revision.revisionId) {
        newRevision = temp;
        break;
      }
    }
    resolve(newRevision);
  })
});
```

### `revisionhistory_allow_restore`

The `revisionhistory_allow_restore` option enables or disables the ability to restore a revision.

**Type:** `Boolean`

**Default vale:** `true`

**Possible values:** `true`, `false`

#### Example: Using `revisionhistory_allow_restore`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_allow_restore: false
  });
```

### `user_id`

This option sets the unique identifier for the current user in the editor. It is used in the the [`UserLookup`](../userlookup/) API.

**Type:** `String`

**Default value:** `'Anonymous'`

Example: using `user_id` option
```javascript
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  user_id: 'james-wilson' // replace this with a unique string to identify the user
});
```

### `fetch_users`

A **required callback function** that fetches user data. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the [`UserLookup`](../userlookup/) API. If the returned array does not include all requested user IDs, promises for the missing users will be rejected with a "User {id} not found" error.

**Type:** `Function`

**Parameters:** - `ids` (`Array<string>`): An array of user IDs to fetch.

**Returns:** - `Promise<Array<Object>>`: A promise that resolves to an array of user objects.

Example: using `fetch_users` option
```javascript
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

tinymce.init({
  selector: 'textarea',
  user_id: 'james-wilson',
  fetch_users: (userIds) => Promise.all(userIds
    .map((userId) =>
      fetch(`${API_URL}/${userId}`)
        .then((response) => response.json())
        .catch(() => ({ id: userId })))),
});
```
Example: returning user array with validation
```javascript
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

tinymce.init({
  selector: 'textarea',
  user_id: 'james-wilson',
  fetch_users: async (userIds) => {
    const users = await Promise.all(userIds
        .map((userId) =>
        fetch(`${API_URL}/${userId}`)
            .then((response) => response.json())
            .catch(() => ({ id: userId }))));

    return userIds.map(
      (userId) =>
        users.find((user) => user.id === userId)
        || ({ id: userId }) // Still returns a valid user even if it wasn't returned from the server
    );
  },
});
```

### `revisionhistory_author`

> **Important:** This option has been deprecated in TinyMCE 8 and may be removed in a future major TinyMCE release. Use a combination of `user_id` and `fetch_users` instead. | `User Lookup API`
This option configures the author for the `initial` and `draft` revisions.

**Type:** [Author](#author) `Object`

#### Example: using `revisionhistory_author`

```js
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true,
  revisionhistory_author: {
    id: 'john.doe',
    name: 'John Doe',
    avatar: 'https://example.com/avatar.jpg'
  }
});
```

### `revisionhistory_display_author`

This option configures the display of the revision’s author. When set to `true`, the author’s name appears in each revision within the Revision History sidebar. If the author’s name is not provided, it defaults to `Anonymous`.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

#### Example: using `revisionhistory_display_author`

```js
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true
});
```

### `revisionhistory_ai_attribution`

This option controls the display of the AI badge on revision cards. An AI badge appears on each revision whose [`metadata`](#metadata) has `source` set to `'ai'` by default. Set this option to `false` to hide the badge. For details on attributing revisions to AI, see [Attributing AI-assisted revisions](#attributing-ai-assisted-revisions).

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

#### Example: using `revisionhistory_ai_attribution`

```js
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_ai_attribution: false
});
```

### `revisionhistory_css_url`

This option sets the location where a CSS file containing the styles for change annotations should be loaded from. It can be used along with `revisionhistory_diff_classes` to override the default CSS classes.

> **Note:** Ensure that the file includes all CSS classes expected by [`revisionhistory_diff_classes`](#revisionhistory_diff_classes).
**Type:** `String`

**Default value:** `'${pluginUrl}/css/revisionhistory.css'`

#### Example: using `revisionhistory_css_url`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_css_url: './revisionhistory.css'
});
```

### `revisionhistory_diff_classes`

This option configures the CSS classes being applied to the change annotations. This option can be used in combination with the `revisionhistory_css_url` to provide custom styles to the change annotations.

> **Note:** The CSS class names must exist in the [`revisionhistory_css_url`](#revisionhistory_css_url).
**Type:** `Object`

**Default value:** `addition`, `removal`, `modification`

```js
{
  addition: 'tox-revisionhistory__annotation--added',
  removal: 'tox-revisionhistory__annotation--removed',
  modification: 'tox-revisionhistory__annotation--modified'
}
```

#### Example: using `revisionhistory_diff_classes`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_css_url: './revisionhistory.css',
  revisionhistory_diff_classes: {
    addition: 'added',
    removal: 'removed',
    modification: 'modified'
  }
});
```

## Show view on editor load

The [`view_show`](../custom-view/#view_show) option can be used to show the Revision History view when the editor is loaded.

For example:
```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  view_show: 'revision',
  revisionhistory_fetch: () => Promise.resolve([]), // Replace with API request to get saved revisions
});
```

## Toolbar buttons

The Revision History plugin provides the following toolbar buttons:

| Toolbar button identifier | Description |
| --- | --- |
| `revisionhistory` | Opens the Revision History view. |

These toolbar buttons can be added to the editor using:

- The [`toolbar`](../toolbar-configuration-options/#toolbar) configuration option.
- The [`quickbars_insert_toolbar`](../quickbars/#quickbars_insert_toolbar) configuration option.
- [Custom Context toolbars](../contexttoolbar/).

## Menu items

The Revision History plugin provides the following menu items:

| Menu item identifier | [Default Menu Location](../menus-configuration-options/#example-the-tinymce-default-menu-items) | Description |
| --- | --- | --- |
| `revisionhistory` | View | Opens the Revision History view. |

These menu items can be added to the editor using:

- The [`menu`](../menus-configuration-options/#menu) configuration option.
- The [`contextmenu`](../menus-configuration-options/#contextmenu) configuration option.
- [Custom Menu toolbar buttons](../custom-menu-toolbar-button/).

## Commands

The Revision History plugin provides the following TinyMCE commands.

| Command | Description |
| --- | --- |
| revisionHistory | Toggle the Revision History view |

Examples
```js
tinymce.activeEditor.execCommand('revisionHistory');
```

## Events

The Revision History plugin provides the following events.

The following events are provided by the [Revision History plugin](#).

| Name | Data | Description |
| --- | --- | --- |
| VersionRestored | `{ revisionId: string }` | Fired when a version is restored. |

## APIs

The Revision History plugin provide the following APIs.

```ts
interface PluginAPI {
  diff: (originalHTML: string, changedHTML: string) => string
}
```

### `diff`

Returns a HTML string with annotations indicating the changes in `originalHTML` relative to `changedHTML`. The styling of annotations can be customized via [`revisionhistory_diff_classes`](#revisionhistory_diff_classes) option.

Example
```js
const input1 = `<p>The banner is <span style="color: rgb(224, 62, 45);">red</span></p>`;
const input2 = `<p>The flag is <span style="color: rgb(22, 145, 121);">red</span></p>`;
tinymce.activeEditor.plugins.revisionhistory.diff(input1, input2);
/*
Expected output:
<p>The
 <del class="tox-revisionhistory__annotation--removed">banner</del><ins class="tox-revisionhistory__annotation--added">flag</ins>
 is
<ins class="tox-revisionhistory__annotation--modified"><span style="color: rgb(22, 145, 121);">red</span></ins>
</p>
*/
```
