Interactive embeds

Same id as a saved chart, different URL. /e/{id} renders an interactive HTML page – tooltips, legend toggle, responsive.

Every chart you save via POST /api/charts mints two URLs from one id:

  • /c/{id} – the static image you embed in emails and Markdown.
  • /e/{id} – an interactive HTML page you drop into an <iframe>.

Same config, same visual quality, different medium. Use the embed when the chart lives in a web product or dashboard and your readers expect to hover, scan series, and toggle legend items.

Embedding

The embed URL works inside any iframe on any origin:

<iframe
  src="https://szum.io/e/abc123"
  loading="lazy"
  scrolling="no"
  style="width: 100%; aspect-ratio: 16/10; border: 0"
></iframe>

Set aspect-ratio to the dimensions your saved chart was sized to. The runtime is container-driven – it re-renders to match the iframe at any width.

What's interactive

  • Hover. A tooltip follows the pointer. For lines and stacked areas the tooltip is x-aggregated – one tooltip per unique x, with all visible series listed at that x. A 1px vertical indicator marks the active x. For bars, dots, and pies the tooltip names the datum directly under the cursor.
  • Legend toggle. Click any legend item to hide its series. The chart re-packs immediately – stacked bars rearrange as if the hidden series wasn't there. Click again to bring it back.
  • Responsive. The runtime watches the iframe with a ResizeObserver and re-lays out on every change. Drag the parent window and the chart follows.
  • Touch. Tap and drag to scrub the chart; the tooltip follows the touch. Lift to dismiss. Vertical page scrolling is preserved – the chart only captures horizontal gestures.

Same primitive as saved charts

The embed route shares everything with /c/{id}:

  • Same opaque 16-byte id.
  • Same storage and ownership. Available on Free and Pro.
  • Same 30-day grace period when a Pro account downgrades to Free – URLs return 403 during the grace window, then 404 after deletion. Free-from-the-start accounts serve normally.
  • Same DELETE /api/charts/{id} to revoke a single chart.
  • Same per-config size limit of 50 KB.

Quota

Only cache-miss loads of /e/{id} count – one render against the creator's monthly quota, the same meter that covers /c/{id}. CDN cache hits are served from the edge for free; there is no separate per-view charge.

In practice, with s-maxage=86400 + stale-while-revalidate=86400, render runs only on the first hit per cache window per region. A chart in an article read by 10,000 viewers across regions typically generates only ~20–40 renders per day at peak (one per region per cache cycle); the CDN absorbs the rest at no cost.

Once the page loads in a viewer's browser, every subsequent local interaction (hover, resize, legend toggle) runs entirely on the client and never reaches origin – no extra cost.

Theming

The embed inherits the chart's theme. editorial looks like editorial; dark looks like dark – page background, tooltip surface, legend swatches, and the x-indicator all derive from the resolved theme. If you need a custom palette, use themeOverrides in the saved config.

Attribution

Free embeds carry the same small "made with szum" credit as the static image – rendered inside the chart by the same pipeline, so the band and spacing match exactly. In the embed it's also a real link: the credit group is wrapped in an <a>, so clicking it opens szum.io (in the static image it's just pixels). Pro embeds omit it by default (set attribution: true in the saved config to keep it).

Errors

StatusMeaning
308Request URL had a query string. Permanent redirect to the canonical bare /e/{id}; browsers and <iframe> loaders follow automatically. Cached for 1d.
403Chart owner is on a paused plan (post-downgrade grace period)
404Chart deleted, never existed, or grace period expired
413Config too large at save time (won't surface on embed; surfaced at POST /api/charts)
429Per-IP burst rate limit on origin hits (cache misses only). Includes Retry-After. CDN cache hits bypass the limiter entirely.
503Storage temporarily unavailable – retry after Retry-After: 2

All error responses set Cache-Control: private, no-store, so a transient blob outage or post-downgrade 403 isn't edge-cached.

See also

On this page