# Embed an HTML Report in Your Own Site — Two Lines, Allow-listed Origins

Canonical: https://commareports.com/embed-html-report
Published: 2026-08-22

> Drop a live Comma report into your docs, intranet or customer portal with a div and a script tag. Origin-allow-listed, sandboxed, and always the current revision — no iframe of a file server, no stale export.

# Embed an HTML report in your own site

There is a specific kind of page that always ends up stale: the docs page,
intranet dashboard or customer-portal tab that shows "the latest numbers."
Someone exports an HTML file, drops it in a bucket, iframes it — and then
the numbers change and nobody re-exports it, because the export lives in a
different workflow from the report.

The fix is to embed the report itself rather than a copy of it.

## Two lines

```html
<div data-comma-report="REPORT_ID"></div>
<script src="https://commareports.com/embed.js" async></script>
```

Then add the host site's origin to that report's **allowed embed origins**.
That list is the switch: with it empty, the embed endpoint renders nothing.
With `https://docs.example.com` on it, that origin — and only that origin —
can frame the report, because `frame-ancestors` is built from the same
list. Clearing the list revokes every existing embed on the next load.

The loader builds the frame and relays the content height back out, so the
embed grows with the report instead of scrolling inside a fixed box.

## How it's isolated

The report document renders in a **nested sandboxed iframe** —
`sandbox="allow-scripts"` with no `allow-same-origin`, so it sits on an
opaque origin. Concretely:

- It cannot read your page's cookies, `localStorage` or DOM.
- It cannot reach a Comma app session either, which is why report HTML can
  keep its scripts and stay interactive.
- The only thing crossing the boundary is the height message.

Interactive reports — a Plotly figure, a filterable table, an
[interactive HTML report](/interactive-html-reports) — keep working inside
the embed for exactly that reason.

## What you get that a static iframe can't give you

- **Always current.** The embed serves the live revision, so a report
  refreshed [from CI](/docs/ci) or by a [routine](/docs/routines) updates
  everywhere it's embedded. Nobody re-exports anything.
- **Approval gating, if you want it.** With approved-only enabled, the
  embed serves the approved revision — so a customer-facing page never
  shows an unreviewed number.
- **One source of truth.** The same report has its own
  [URL](/share-html-report), its own [comment threads](/comment-on-html),
  and its own [access rules](/docs/sharing). The embed is a view of it,
  not a fork of it.

## Where teams use it

Customer-facing status and usage pages. Internal wikis and Backstage
pages, where the alternative is a screenshot with a date on it. Docs sites
that need a live example rather than a picture of one. Client portals,
where the report is the deliverable and the portal is just the frame
around it.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history. Publish one report, allow one origin, paste two lines.

**[Create your first report →](https://commareports.com/)**

### Related

- [Share an HTML report](/share-html-report) — the URL version of the same thing
- [Interactive HTML reports](/interactive-html-reports) — what survives the sandbox
- [Sharing model](/docs/sharing) · [Scheduled refreshes](/docs/routines)
