> AI agents: this is one page from Mammoth Analytics documentation. The index of all pages as Markdown is https://docs.mammoth.io/llms.txt. Append `.md` to any docs URL, or send `Accept: text/markdown`, to get Markdown.

# Mammoth board embedding

> Embed a Mammoth board in your own page. Covers the three embed modes, the origin allowlist, the workspace signing secret and the nine REST operations.

A Mammoth board inside a page you control, scoped to a viewer who has no Mammoth account and never signs in.

> **Eight of the nine operations have a command**
>
> Every operation below except the workspace-wide usage read has a `mammoth dashboard embed` command and a matching `client.dashboards.embed_*` SDK method. The workspace-wide usage read is REST only.

> **Embedding on your own website is being rolled out**
>
> Embedding a board on your own website, as an iframe on another domain, is being rolled out. Until then, the public link and opening the embed URL directly work, while the browser blocks framing from another domain.

## The three modes

**Every published board embeds.** The mode is not a switch that turns embedding on. It decides what a board *without* a public link demands from the page framing it.

| Mode | The board | Viewer is | Sees |
| --- | --- | --- | --- |
| `public` | has a public link | anyone | the whole board |
| `key` | no public link; the page presents the board's embed key | anonymous, no viewer identity | every row |
| `signed` | no public link; every viewer needs a host-signed token | whoever your token says | the rows your claims allow |

All three modes are available regardless of plan. Availability of the attribution mark—whether a "Built with Mammoth" footer appears—depends on your plan; check with your admin. A board with a public link embeds over that link whatever `mode` is saved.

## Who can change what

Two different permissions, and mixing them up is the first thing to get wrong. Board settings are an editor's. The workspace signing secret and the session lifetime are an owner's or admin's.

## The nine operations

The commands take the board id as the first argument, or the workspace id for the two workspace commands. `config set`, `key rotate`, `origin revoke` and `secret rotate` need `--yes --confirm ID`, repeating that id. `lifetime set` and `preview-token create` need no confirmation. `mammoth schema get <command.id>` shows each command's input.

### Per board

| Operation | What it does | CLI |
| --- | --- | --- |
| `GET /dashboards/{id}/embed/config` | Read a board's embed settings. | `mammoth dashboard embed config get` |
| `PUT /dashboards/{id}/embed/config` | Save them: mode, origin policy, appearance, snippet shape. | `mammoth dashboard embed config set` |
| `POST /dashboards/{id}/embed/key` | Create or rotate the board's embed key. Editor only. | `mammoth dashboard embed key rotate` |
| `POST /dashboards/{id}/embed/preview-token` | Mint a preview token for the simulator. Editor only. | `mammoth dashboard embed preview-token create` |
| `DELETE /dashboards/{id}/embed/origin` | Revoke one origin from the allowlist. | `mammoth dashboard embed origin revoke` |
| `GET /dashboards/{id}/embed/usage` | Where this board has been loaded from. | `mammoth dashboard embed usage get` |

### Per workspace

| Operation | What it does | CLI |
| --- | --- | --- |
| `POST /workspaces/{id}/embed/secret` | Create or rotate the signing secret. Owners and admins only. | `mammoth dashboard embed secret rotate` |
| `PUT /workspaces/{id}/embed/lifetime` | How long an embed viewer session lives, 60 to 3600 seconds. | `mammoth dashboard embed lifetime set` |
| `GET /workspaces/{id}/dashboards/embed-usage` | Distinct origins per board over the last 90 days. | REST only |

## The signing secret is returned once

> **No read route ever includes the secret**
>
> `POST /workspaces/{id}/embed/secret` returns the plaintext secret **once**. Nothing reads it back, and the route is excluded from the request log. Store it the way you store `MAMMOTH_API_TOKEN`: in the environment, never in a prompt, a script or a repository file.

Rotating keeps the previous secret valid for **24 hours**, so a rotation does not invalidate every live token at once. The board-level embed key behaves the same way and for the same reason; send `keep_previous: false` to end the old one immediately.

## Framing is open until you close it

`allow_any_origin` defaults to **true**. Any site may frame the board until you set it false, and only then does `allowed_origins` restrict anything.

- Patterns are `https://host[:port]`, with one leading `*.` label allowed.
- Normalised and de-duplicated, at most 20 per board.
- `DELETE .../embed/origin` returns **400** while the board is open to any site. There is no list to take a site off.

## A page opened from a file cannot frame a board

A page opened straight from disk (a `file://` address) cannot frame an embed. The embed response allows framing with `frame-ancestors *`, and that rule matches only `http` and `https` pages. This is a browser rule, so no board setting changes it. Serve the test page over `http://localhost` or from your real site instead.

## Signed mode, and the preview token

In `signed` mode your server mints a token per viewer, carrying `claims` keyed by the board's row-level-security rules. A signed token may not outlive the workspace session lifetime, so the 60–3600 second setting caps both.

`POST .../embed/preview-token` exists so an author can see the board under a given scope *without ever holding the secret*: it signs server-side with the workspace secret and is editor-only. Use it to check a scope before you build the signing into your backend.

## What usage data can and cannot tell you

`GET .../embed/usage` returns one row per origin and tile, with rolling render counts, health, and whether the origin is still on the allowlist.

> **Observed, not known**
>
> The registry is built from render beacons. It records where a board **has been loaded from**, which is not the same as where it has been embedded: a snippet pasted into a page nobody has opened does not appear. Read it as a floor, never a count.

## Snippet shape

`snippet.height` is `auto` (the SDK grows the frame), `aspect` (16:9), or a pixel count from 240 to 2400. `appearance` carries the saved look applied on load, including `tile` to embed one chart instead of the whole board.

## Order of operations

1. Publish the board. An unpublished board has nothing to frame.
2. Decide the mode. Leave it `key` unless a viewer must see only their own rows.
3. For `signed`: rotate the workspace secret, store the plaintext, set the session lifetime.
4. Close the origin policy if you need it closed: `allow_any_origin: false` plus `allowed_origins`.
5. Check a scope with a preview token before writing the signing into your backend.
6. Read usage after the page is live, as a floor.

> **Verify against your workspace**
>
> Generated from the v2 OpenAPI spec as read on September 20, 2026. The spec your workspace serves is authoritative where this page is a copy: `GET /api/v2/docs/openapi.json`.

## Next up

- [Authentication](https://docs.mammoth.io/build/auth): API tokens, and where credentials belong.
- [Command contract](https://docs.mammoth.io/build/): every command, with its blast radius and endpoint.

---
Source: https://docs.mammoth.io/build/embedding.md · Updated: 2026-10-13