---
title: "Headless stamp annotations | Nutrient Web SDK"
canonical_url: "https://www.nutrient.io/guides/web/headless/stamp/"
md_url: "https://www.nutrient.io/guides/web/headless/stamp.md"
last_updated: "2026-05-15T19:10:05.084Z"
description: "Build a custom stamp picker without the default Nutrient Web SDK stamp UI, read and update the stamp template list and place StampAnnotation programmatically."
---

# Headless stamp annotations

The default stamp picker covers the common case: pick a template, and click to place. Build your own picker when you need a design system match, when the templates come from a server, or when you want a different organizational structure (for example, grouping stamps by department or project).

Looking for the visual side of this? See the [supported slots reference](https://www.nutrient.io/guides/web/user-interface/ui-customization/supported-slots.md) for replacing the bundled stamp picker. This page covers the programmatic surface you’ll call from inside that custom UI.

## When to use this

Reach for the headless stamp API when you need:

- A stamp picker that matches your host application’s design system.

- A picker that loads stamp templates from a server on document open.

- A workflow that places stamps without user interaction — for example, an “approved” stamp added on a successful API response.

- Per-organization stamp libraries layered on top of the default templates.

## API reference

| Symbol                                            | Notes                                                                                                                                                                     |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NutrientViewer.Annotations.StampAnnotation`      | The annotation class for placed stamps.                                                                                                                                   |
| `instance.stampAnnotationTemplates`               | A snapshot array of the current stamp and image annotation templates (a shallow clone, the templates themselves are immutable records). Mutating the array has no effect. |
| `instance.setStampAnnotationTemplates(stateOrFn)` | Replaces the current templates. Accepts either a new array or a callback that receives the current templates and returns a new array.                                     |
| `instance.getCustomStamps()`                      | Returns the user-defined custom stamp templates, separate from the built-in stamp set.                                                                                    |
| `instance.addCustomStamp(template)`               | Adds a single custom stamp template to the persisted custom-stamp set.                                                                                                    |
| `instance.removeCustomStamp(stampId)`             | Removes a custom stamp template by ID.                                                                                                                                    |
| `instance.createAttachment(blob)`                 | Uploads a `Blob` or `File` as an attachment and returns the attachment ID. Used by image-backed stamps via `imageAttachmentId`.                                           |

`setStampAnnotationTemplates` is the single entry point for adding, removing, or reordering the **active** template list (built-ins plus customs). For persisted user-defined customs that survive across documents, use `addCustomStamp` / `removeCustomStamp` / `getCustomStamps`.

The `stampType` field is a string. Valid values include `"Approved"`, `"NotApproved"`, `"Draft"`, `"Final"`, `"Completed"`, `"Confidential"`, `"ForPublicRelease"`, `"NotForPublicRelease"`, `"ForComment"`, `"Void"`, `"PreliminaryResults"`, `"InformationOnly"`, `"Rejected"`, `"Accepted"`, `"InitialHere"`, `"SignHere"`, `"Witness"`, `"AsIs"`, `"Departmental"`, `"Experimental"`, `"Expired"`, `"Sold"`, `"TopSecret"`, `"Revised"`, `"RejectedWithText"`, and `"Custom"` (used for image-backed or app-defined stamps). See the [built-in stamps reference](https://www.nutrient.io/guides/web/features/stamp-annotation-templates.md) for the full list.

## Example: A custom stamp picker

This example renders a picker that lists the current stamp templates. Clicking one places it on the current page:

```js

const instance = await NutrientViewer.load({
  container: "#viewer",

  document: "contract.pdf"
});

const picker = document.getElementById("stamp-picker");

function renderPicker() {
  picker.innerHTML = "";
  instance.stampAnnotationTemplates.forEach((template) => {
    const button = document.createElement("button");
    button.textContent = template.title?? template.stampType;
    button.onclick = () => placeStamp(template);
    picker.appendChild(button);
  });
}

async function placeStamp(template) {
  const pageIndex = instance.viewState.currentPageIndex;
  const stamp = template.set("pageIndex", pageIndex);
  await instance.create(stamp);
}

renderPicker();

```

Stamp templates are immutable records. Call `set()` to specialize them for the placement.

## Example: Replacing the template list from server data

`setStampAnnotationTemplates` accepts a callback so you can compose the new list from the current one:

```js

async function loadTemplatesFrom(url) {
  const response = await fetch(url);
  const data = await response.json();

  const newTemplates = data.map(
    (entry) =>
      new NutrientViewer.Annotations.StampAnnotation({
        stampType: "Custom",
        title: entry.title,
        subtitle: entry.subtitle,
        boundingBox: new NutrientViewer.Geometry.Rect({
          left: 0,
          top: 0,
          width: entry.width?? 192,
          height: entry.height?? 64
        })
      })
  );

  instance.setStampAnnotationTemplates((current) => [...current,...newTemplates
  ]);
}

```

Or pass a flat array to overwrite the list entirely:

```js

instance.setStampAnnotationTemplates(newTemplates);

```

## Example: An image-backed stamp

Image stamps reference an attachment ID. Upload the image with `createAttachment` first, and then construct the stamp:

```js

async function placeLogoStamp(file, pageIndex) {
  const attachmentId = await instance.createAttachment(file);

  const stamp = new NutrientViewer.Annotations.StampAnnotation({
    stampType: "Custom",
    pageIndex,
    boundingBox: new NutrientViewer.Geometry.Rect({
      left: 100,
      top: 100,
      width: 200,
      height: 100
    }),
    imageAttachmentId: attachmentId
  });

  await instance.create(stamp);
}

```

## Example: Place a programmatic “Approved” stamp

A common workflow is to drop a stamp in response to a server event:

```js

async function markApproved(pageIndex) {
  const stamp = new NutrientViewer.Annotations.StampAnnotation({
    stampType: "Approved",
    pageIndex,
    boundingBox: new NutrientViewer.Geometry.Rect({
      left: 50,
      top: 50,
      width: 180,
      height: 60
    })
  });

  await instance.create(stamp);
}

```

## Related

- [Built-in stamps](https://www.nutrient.io/guides/web/features/stamp-annotation-templates.md) — The default stamp templates the SDK provides.

- [Stamp configuration](https://www.nutrient.io/guides/web/annotations/stamp-annotation-configuration.md) — The broader stamp configuration reference.

- [Headless images](https://www.nutrient.io/guides/web/headless/image.md) — The underlying attachment flow used by image stamps.
---

## Related pages

- [Headless callout annotations](/guides/web/headless/callout.md)
- [Headless color presets](/guides/web/headless/color-presets.md)
- [Headless image annotations](/guides/web/headless/image.md)
- [Annotation clipboard](/guides/web/headless/clipboard.md)
- [Headless](/guides/web/headless.md)
- [Headless ink annotations](/guides/web/headless/ink.md)
- [Headless link annotations](/guides/web/headless/link.md)
- [Headless note annotations](/guides/web/headless/note.md)
- [Redactions from text selection](/guides/web/headless/redactions-from-selection.md)
- [Programmatic notes panel](/guides/web/headless/notes-panel.md)
- [Headless text annotations](/guides/web/headless/text-annotations.md)
- [Headless shape annotations](/guides/web/headless/shape.md)
- [Headless text markup](/guides/web/headless/text-markup.md)

