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

# Configure PDF stamps with JavaScript

Learn how to create and customize standard and custom stamps in WebViewer. Control the appearance of stamps with APIs. Explore demo options for stamps and annotations. The Apryse Web SDK streamlines s

WebViewer supports three stamp types that you can apply to documents as annotations. All three appear in the **Stamps** panel, but each type defines a stamp's appearance differently and is managed separately, so changing one type's stamps doesn't affect the others.

The following table summarizes each type and its intended use.

| Stamp type      | Description                                                                                                                                | Preview                                                                                                                                                                                                                                                                                                                           |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Preset          | Use built-in PDF stamp designs, such as Approved, Draft, and Final. You can replace, append to, and organize these stamps into categories. | ![Preset Approved stamp](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2FnqVOtFr7GgkB08aN4i7q%2F77fc8c501762e9c443de29437b30e1e1bfb9e205-140x53.png?alt=media\&token=efb866ee-5dfc-4b52-9e6d-7cf9eedd34e2)                                                |
| Document-backed | Use pages from PDF documents as reusable vector stamp appearances.                                                                         | ![Document-backed stamp created from a PDF page showing a cartoon face](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2F6mdLmEhHB66Xo01ozA1I%2Fea4d1b8286a24bdd344c87a06e572a07ac2345fb-137x53.png?alt=media\&token=9523fe5f-7cdf-4898-a818-600084ade1a9) |
| Custom          | Generate stamps from configurable text, timestamps, colors, and font styles.                                                               | ![Custom Draft stamp with the user name and date](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2F1WF8vrNIHxpdK2MfEOOi%2F047b11c16458f4d43be5ed4a2c8928935b1dc7f8-239x53.png?alt=media\&token=9c78f129-3181-47f2-bc79-72dfb3f4e04f)                       |

## Get the Rubber Stamp tool

Use the `AnnotationCreateRubberStamp` tool to manage the stamps available in the UI.

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

```js
WebViewer(
  {
    // WebViewer configuration
  },
  viewerElement
).then((instance) => {
  const { documentViewer } = instance.Core;

  const rubberStampTool = documentViewer.getTool(
    'AnnotationCreateRubberStamp'
  );
});
```

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

## Preset stamps

WebViewer includes a set of built-in preset stamps, including the standard PDF stamps. Examples include:

* Approved
* AsIs
* Completed
* Confidential
* Departmental
* Draft
* Experimental
* Expired
* Final
* ForComment
* ForPublicRelease
* InformationOnly
* NotApproved
* NotForPublicRelease
* PreliminaryResults
* Sold
* TopSecret
* Void
* SHSignHere
* SHWitness
* SHInitialHere
* SHAccepted
* SBRejected

Call [getDefaultStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#getDefaultStamps) to retrieve the complete list of built-in stamps.

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

```js
const defaultStamps = rubberStampTool.getDefaultStamps();

console.log(defaultStamps);
```

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

Call [getStandardStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#getStandardStamps__anchor) to retrieve the preset stamps currently registered with the tool.

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

```js
const currentStamps = rubberStampTool.getStandardStamps();
```

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

### Replace preset stamps

Use [registerPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#registerPresetStamps__anchor) to replace the complete list of preset stamps displayed in the **Stamps** panel.

Each entry can be:

* The name of a built-in stamp
* An absolute image URL
* A base64 data URI
* An object containing an icon and optional category

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

```js
rubberStampTool.registerPresetStamps({
  stamps: [
    'Approved',
    'Draft',
    'Final',
  ],
});
```

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

Calling [registerPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#registerPresetStamps__anchor) again replaces the previously registered list.

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

```js
rubberStampTool.registerPresetStamps({
  stamps: [
    'Confidential',
    'TopSecret',
  ],
});
```

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

To remove all preset stamps from the panel, register an empty list:

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

```js
rubberStampTool.registerPresetStamps({
  stamps: [],
});
```

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

{% hint style="warning" %}
**Deprecation notice**

[setStandardStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setStandardStamps__anchor) is deprecated as of version 12.0. Use [registerPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#registerPresetStamps__anchor) when replacing the preset stamp list, or [addPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#addPresetStamps__anchor) when appending stamps.
{% endhint %}

### Add preset stamps

Use [addPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#addPresetStamps__anchor) to append stamps to the current list.

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

```js
rubberStampTool.addPresetStamps({
  stamps: [
    'Void',
    {
      icon: 'TopSecret',
      category: 'Sensitive',
    },
  ],
});
```

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

If [registerPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#registerPresetStamps__anchor) has not been called, [addPresetStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#addPresetStamps__anchor) appends entries to the built-in default stamps.

Both methods also accept an array directly:

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

```js
rubberStampTool.addPresetStamps([
  'Approved',
  {
    icon: 'Draft',
    category: 'Review',
  },
]);
```

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

### Use images as preset stamps

The icon property for stamps can be an absolute image URL or a base64 data URI.

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

```js
rubberStampTool.addPresetStamps({
  stamps: [
    {
      icon: 'https://example.com/assets/company-seal.png',
      category: 'Company',
    },
  ],
});
```

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

When loading an image from another origin, ensure that the server permits [cross-origin access](/web/get-started/faq/cors-support.md).

<div align="left"><figure><img src="https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2FBDqumvYqIXdlhbcpt5y4%2Fc6abee4ccb32d761aab029e5103dc1f182533024-319x285.png?alt=media&amp;token=9eb86e23-9d44-42eb-a418-026dcc22b7ef" alt="Stamps panel showing an image-based SAMPLE stamp in the Company category"><figcaption><p>An image-based preset stamp in a custom category.</p></figcaption></figure></div>

### Organize preset stamps into categories

Pass a category property with a preset stamp entry to control where it appears in the **Stamps** panel.

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

```js
rubberStampTool.registerPresetStamps({
  stamps: [
    {
      icon: 'Approved',
      category: 'Review',
    },
    {
      icon: 'Draft',
      category: 'Review',
    },
    {
      icon: 'Confidential',
      category: 'Security',
    },
    'Void',
  ],
});
```

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

<div align="left"><figure><img src="https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2FNBV9qC2z7ksgJIA9S56a%2Fimage.png?alt=media&amp;token=de8478d7-e6de-4647-a763-98ad5a47fc51" alt="Stamps panel with preset stamps grouped into Review, Security, and Standard Stamps categories"><figcaption><p>Preset stamps grouped by category.</p></figcaption></figure></div>

A category can be an i18n translation key or a literal display string. Entries without a category appear in the default **Standard Stamps** category.

The configuration contains only serializable values, so you can store and restore it as JSON.

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

```js
const presetStampConfig = {
  stamps: [
    {
      icon: 'Approved',
      category: 'Review',
    },
    'Draft',
  ],
};

localStorage.setItem(
  'presetStampConfig',
  JSON.stringify(presetStampConfig)
);

const savedConfig = JSON.parse(
  localStorage.getItem('presetStampConfig')
);

rubberStampTool.registerPresetStamps(savedConfig);
```

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

## Document-backed stamps

Document-backed stamps use pages from a PDF document as stamp appearances. Each registered page becomes a selectable entry in the **Stamps** panel.

Unlike an image-based stamp, a document-backed stamp preserves the source page as a vector appearance when you place it.

Use [setDocumentStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setDocumentStamps__anchor) to register one or more PDF sources.

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

```js
const result = await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/company-seal.pdf',
    title: 'Company Seal',
  },
]);

console.log(`Registered ${result.registeredCount} stamps`);
```

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

The source can be a URL or path string, a file, a blob, or an `ArrayBuffer`. Document-backed stamps will show under the `Preset` tab in the **Stamps** panel.

<div align="left"><figure><img src="https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2FaUrTptBop27XE4qNeZAT%2Fimage.png?alt=media&amp;token=a999341a-f106-44c9-8ba4-f2a836441192" alt="Stamps panel showing document-backed stamps from a PDF in a Faces category"><figcaption><p>Each page of the source PDF appears as a separate stamp.</p></figcaption></figure></div>

### Register specific pages

By default, every page in each source document is registered as a separate stamp. Use `pages` to register specific pages. Page numbers are 1-indexed.

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

```js
const result = await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/review-stamps.pdf',
    title: 'Review',
    pages: [1, 3],
  },
]);
```

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

The panel labels include the source title and page number. For example, Review 1 and Review 3.

### Set defaults for all sources

The second argument to [setDocumentStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setDocumentStamps__anchor) provides defaults for all sources.

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

```js
const result = await rubberStampTool.setDocumentStamps(
  [
    {
      source: 'https://example.com/stamps/review.pdf',
      title: 'Review',
    },
    {
      source: 'https://example.com/stamps/legal.pdf',
      title: 'Legal',
    },
  ],
  {
    pages: [1, 2],
    cropVisibleContent: true,
  }
);
```

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

A source-level value takes precedence over the corresponding global option.

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

```js
const result = await rubberStampTool.setDocumentStamps(
  [
    {
      source: 'https://example.com/stamps/review.pdf',
      title: 'Review',
      pages: [3],
      cropVisibleContent: false,
    },
    {
      source: 'https://example.com/stamps/legal.pdf',
      title: 'Legal',
    },
  ],
  {
    pages: [1, 2],
    cropVisibleContent: true,
  }
);
```

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

In this previous example:

* Only page 3 of `review.pdf` is registered, without cropping.
* Pages 1 and 2 of `legal.pdf` are registered and cropped to their visible content.

Each source supports the following properties:

* `source`: Required PDF source. Accepts a URL string, File, Blob, or ArrayBuffer.
* `title`: Display title used in the **Stamps** panel.
* `filename`: Filename hint used while loading the source.
* `extension`: File extension override, such as `pdf`.
* `pages`: Page numbers to register. Registers all pages when omitted.
* `cropVisibleContent`: Whether to crop pages to their visible content. Defaults to `true`.
* `category`: Category in which the stamps appear.

### Organize document-backed stamps into categories

Use the category property to group document-backed stamps in the panel.

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

```js
await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/approval.pdf',
    title: 'Approval',
    category: 'Review',
  },
  {
    source: 'https://example.com/stamps/company-seal.pdf',
    title: 'Company Seal',
    pages: [1],
    category: 'Company',
  },
]);
```

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

If category is omitted, the stamps appear in the default **Standard Stamps** category.

### Handle registration results

Registration failures are isolated. A failed source or page doesn't prevent other valid pages from being registered. The [setDocumentStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setDocumentStamps__anchor) method resolves with:

* `registeredCount`: Number of pages successfully registered as stamps.
* `failures`: Sources that could not be loaded or prepared.
* `pageSuccesses`: Pages that were successfully registered.
* `pageFailures`: Individual pages that could not be registered.

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

```js
const {
  registeredCount,
  failures,
  pageSuccesses,
  pageFailures,
} = await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/review.pdf',
    title: 'Review',
    pages: [1, 2, 3],
  },
]);

console.log(`Registered ${registeredCount} stamps`);

failures.forEach(({ title, reason }) => {
  console.error(`Could not register ${title}`, reason);
});

pageFailures.forEach(({ title, pageNumber, reason }) => {
  console.error(
    `Could not register page ${pageNumber} of ${title}`,
    reason
  );
});
```

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

### Replace document-backed stamps

Each call to [setDocumentStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setDocumentStamps__anchor) replaces the previously registered document-backed stamps.

It doesn't replace preset stamps or custom stamps.

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

```js
await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/first-set.pdf',
  },
]);

// Replaces first-set.pdf with second-set.pdf.
await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/second-set.pdf',
  },
]);
```

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

### Remove document-backed stamps

Use [clearDocumentStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#clearDocumentStamps__anchor) to remove all registered document-backed stamps and release their associated document resources.

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

```js
rubberStampTool.clearDocumentStamps();
```

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

Preset stamps and custom stamps aren't affected.

## Custom stamps

Custom stamps are generated from text and styling options. They can include:

* A title
* A subtitle or formatted timestamp
* Fill and text colors
* A font family
* Bold, italic, underline, or strikethrough styling
* A category

Use [setCustomStamps()](https://sdk.apryse.com/api/web/Core.Tools.RubberStampCreateTool.html#setCustomStamps__anchor) to replace the current custom stamp list.

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

```js
WebViewer(
  {
    // WebViewer configuration
  },
  viewerElement
).then((instance) => {
  const { documentViewer, Annotations } = instance.Core;

  const rubberStampTool = documentViewer.getTool(
    'AnnotationCreateRubberStamp'
  );

  rubberStampTool.setCustomStamps([
    {
      title: 'Approved',
      subtitle: '[By $currentUser at] h:mm a, MMMM D, YYYY',
      color: new Annotations.Color('#4F9964'),
      category: 'Review',
    },
    {
      title: 'Reviewed',
      subtitle: '[By $currentUser on] MMMM Do, YYYY',
      color: new Annotations.Color('#2A85D0'),
      category: 'Review',
    },
  ]);
});
```

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

To render literal subtitle text instead of a formatted date, place the text in square brackets.

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

```javascript
rubberStampTool.setCustomStamps([
  {
    title: 'Internal',
    subtitle: '[For internal use only]',
  },
]);
```

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

Users can also create custom stamps directly from the **Custom** stamps tab of the **Stamps** panel.

![Stamps panel on the Custom tab showing an Internal custom stamp and the Add Stamp button.](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2FyYKF3TIpMzhqGMMfEOH2%2FScreenshot%202026-09-29%20at%2011.02.10%E2%80%AFAM.png?alt=media\&token=1f90525d-5735-4153-b27c-6f75ad4cdf4d)

## Combine stamp types

You can register preset, custom, and document-backed stamps independently.

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

```js
const { documentViewer, Annotations } = instance.Core;

const rubberStampTool = documentViewer.getTool(
  'AnnotationCreateRubberStamp'
);

// Replace the preset stamp list.
rubberStampTool.registerPresetStamps({
  stamps: [
    {
      icon: 'Approved',
      category: 'Review',
    },
    {
      icon: 'Confidential',
      category: 'Security',
    },
  ],
});

// Configure text-based custom stamps.
rubberStampTool.setCustomStamps([
  {
    title: 'Reviewed by legal',
    subtitle: '[By $currentUser on] MMMM D, YYYY',
    color: new Annotations.Color('#2A85D0'),
    category: 'Legal',
  },
]);

// Register PDF pages as vector document-backed stamps.
const result = await rubberStampTool.setDocumentStamps([
  {
    source: 'https://example.com/stamps/company-seals.pdf',
    title: 'Company Seal',
    pages: [1, 2],
    category: 'Company',
  },
]);

console.log(`Registered ${result.registeredCount} document-backed stamps`);
```

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


---

# 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/annotation/stamps.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.
