Interactive embeds
Same id as a saved chart, different URL. /e/{id} renders an interactive HTML page – tooltips, legend toggle, responsive.
Every Pro 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 kill switch as saved charts
The embed route shares everything with /c/{id}:
- Same opaque 16-byte id.
- Same Pro-only access (the chart's creator must be on Pro for the URL to render – downgrade returns 403 for both routes).
- Same 30-day grace period on downgrade.
- Same
DELETE /api/charts/{id}to revoke a single chart. - Same per-config size limit of 50 KB.
Quota
Each fresh /e/{id} HTML response charges one render against your monthly quota – the same unified counter as /c/{id} and /chart. CDN cache hits never reach origin and never charge.
In practice, with s-maxage=86400 + stale-while-revalidate=86400, origin sees a tiny fraction of total pageviews. Each Vercel CDN region caches the response for 24h, so a chart in an article read by 10,000 viewers across regions typically generates ~20–40 origin hits per day at peak (one per region per cache cycle), regardless of viewer count; the CDN absorbs the rest.
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 charge.
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. No CSS overrides are exposed in v1; if you need a custom palette, use themeOverrides in the saved config.
Errors
| Status | Meaning |
|---|---|
308 | Request URL had a query string. Permanent redirect to the canonical bare /e/{id}; browsers and <iframe> loaders follow automatically. Cached for 1d. |
403 | Chart owner is on a paused plan (post-downgrade grace period) |
404 | Chart deleted, never existed, or grace period expired |
413 | Config too large at save time (won't surface on embed; surfaced at POST /api/charts) |
429 | Per-IP burst rate limit on origin hits (cache misses only). Includes Retry-After. CDN cache hits bypass the limiter entirely. |
503 | Storage 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
- Saved charts – the storage primitive both URLs share
- Caching & CDN – cache headers and TTLs
- Plans & Limits – Pro plan details