Docs & Code Guide

Embed diagrams in Backstage TechDocs: what DOMPurify strips and what passes

TechDocs renders your MkDocs-built pages inside Backstage, and between the build and the reader sits a sanitizer: DOMPurify processes the rendered HTML and strips iframes and scripts by default. External images pass through untouched, which makes the image form of a live diagram work with zero configuration, while the iframe form needs one explicit allowlist entry. Here is the pipeline, the config, and the attribute-stripping quirk that catches teams after the allowlist works.

7 min readFor platform teams running Backstage with TechDocs

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

171/20003 credits left
Try:

No account needed · Editable canvas, not a picture

The pipeline: MkDocs builds, DOMPurify decides

TechDocs takes the docs folder of a component, builds it with MkDocs and the techdocs-core plugin, and serves the result inside the Backstage frontend. Before rendering, the HTML is sanitized with DOMPurify. That split matters when debugging: markup can be perfectly valid in the MkDocs output and still vanish in Backstage, because the sanitizer removed it at view time.

The default posture is strict: iframes and scripts are stripped. Plain images, including ones pointing at external URLs, are not. Knowing which side of that line each embed form falls on saves the usual hour of confusion.

The image form works with zero configuration

Standard Markdown image syntax with an absolute URL survives the whole pipeline: MkDocs emits the img tag, DOMPurify allows it, and the reader's browser fetches the image from the source at view time. Nothing is copied at build time, so the docs page shows the diagram as it currently is, not as it was when CI last ran.

Datadef serves the image with an ETag from the diagram's last edit and a five minute cache lifetime, so an edited diagram appears in TechDocs within minutes, independent of your docs build cadence. That independence is the point: TechDocs pages rebuild when the repo changes, but the diagram updates when the diagram changes.

<!-- In docs/architecture.md, no config needed -->
![Service architecture](https://datadef.io/api/embed/my-platform-a1b2c3d4)

<!-- Sized render for wide pages (params optional) -->
![Service architecture](https://datadef.io/api/embed/my-platform-a1b2c3d4?width=2400&height=1400&scale=2)

Iframes need allowedIframeHosts, and attributes get trimmed

The interactive form goes through the sanitizer's allowlist: hosts listed under techdocs.sanitizer.allowedIframeHosts in app-config.yaml keep their iframes, everything else is stripped. Add the diagram host once and every component's docs can embed interactive diagrams.

The quirk that follows: even for allowlisted hosts, DOMPurify strips most iframe attributes, teams have reported everything beyond basics like src, id, and width being removed. Keep the tag minimal and set the size through the attributes that survive rather than inline styles. If the frame still fights the layout, the image form above needs no allowlist and no attribute negotiation.

# app-config.yaml
techdocs:
  sanitizer:
    allowedIframeHosts:
      - datadef.io

# docs/architecture.md
# <iframe src="https://datadef.io/embed/my-platform-a1b2c3d4"
#         width="100%" height="480"></iframe>

Previewing locally before it hits the catalog

Two workflow details round this out. techdocs-cli serve builds and serves the docs locally inside a Backstage-like preview, so you can check that an embed renders before pushing; remember the sanitizer runs in the Backstage frontend, so the authoritative test for iframes is a Backstage instance with your app-config. And the catalog finds the docs through the backstage.io/techdocs-ref annotation in catalog-info.yaml, typically dir:. for docs living beside the code.

Since the diagram arrives by URL, no mkdocs.yml plugin is involved, nothing new in requirements.txt, and the embed works identically across every component that references it.

Keeping the diagram current, and the honest limits

TechDocs teams already run docs through CI, and the diagram fits the same pipeline: one extra stage where an MCP-connected agent, speaking to the Datadef server at registry name io.datadef/mcp, reads the component repository and updates the diagram alongside the TechDocs publish. The trigger is your pipeline, not Datadef, which has no eyes on the repository and never acts on its own; the stage authenticates with an agent API key, part of the paid plans.

The limits: embed URLs exist only for projects shared public, which internal platform teams should weigh honestly; confidential architectures belong in committed static exports with accepted staleness. For diagrams of many services and their dependencies, the wider practice is covered in keeping microservices docs in sync, and deciding who owns which diagram is its own problem, covered in documentation ownership models.

FAQ

Why is my iframe not showing in Backstage TechDocs?

The Backstage frontend sanitizes rendered TechDocs HTML with DOMPurify, which strips iframes by default. Add the iframe host to techdocs.sanitizer.allowedIframeHosts in app-config.yaml. Note that even allowlisted iframes lose most attributes beyond basics such as src, id, and width.

Do external images work in TechDocs?

Yes, with no configuration. Standard Markdown image syntax with an absolute URL passes the MkDocs build and the DOMPurify sanitizer, and the browser fetches the image from the source at view time, so an externally hosted diagram stays current between docs builds.

Does an embedded diagram update without rebuilding TechDocs?

Yes. The page references a URL rather than a file baked in at build time, and Datadef serves it with a five minute cache lifetime, so an edited diagram appears within minutes regardless of when the docs last built. The diagram edit itself is made by a person or an MCP-connected agent.

How do I preview a TechDocs embed locally?

Run techdocs-cli serve in the component repo to build with MkDocs and preview in a Backstage-like shell. For iframes, verify in a real Backstage instance too, because the DOMPurify sanitizer and the allowedIframeHosts config act in the Backstage frontend, not in the MkDocs build.

Where does TechDocs find the docs for a catalog component?

Through the backstage.io/techdocs-ref annotation in catalog-info.yaml, most commonly dir:. meaning the docs folder and mkdocs.yml live in the same repository as the component. The TechDocs pipeline builds from that reference.