CDN and caching
How Szum's CDN serves cached charts quickly – and why cache hits are free.
Szum's public chart-delivery GET endpoints are CDN-cached. The reason that matters is latency: a cache hit avoids origin work such as rendering an image or preparing an embed response. An origin render is generally needed only on the first request to each active cache location after expiry, but the exact count depends on traffic geography and cache behavior.
Cost-wise, only renders are billed, and only on cache misses. A CDN cache hit on /c/{id} or /e/{id} is served entirely from the edge, never reaches Szum, and costs nothing – there is no separate per-view charge.
What each cache hit costs your plan
| Endpoint | Cache hit | Cache miss |
|---|---|---|
GET /c/{id} (saved image) | free | +1 render |
GET /e/{id} (interactive embed) | free | +1 render |
Example. For a chart embedded in an article seen 2M times in a month, requests that reuse the same URL can be served from cache instead of rerendering at origin. Billed renders scale with cache misses rather than raw page views, so they usually grow much more slowly than the audience. The exact total depends on active cache locations, expiry, revalidation, and client cache bypasses.
How a render gets charged
Two things have to happen for one render to count:
- The request reaches origin (cache miss, cache expiry, or
Cache-Control: no-cachefrom the client). - Szum successfully produces the requested chart output (the request passes validation, rate limits, and plan policy).
If either fails, the render is not committed. Failed work releases its temporary capacity reservation without entering usage.
Cache headers per endpoint
| Endpoint | Cache-Control | Notes |
|---|---|---|
POST /chart | private, no-store | Authenticated; response carries X-Usage-* headers, must not be reused across keys |
GET /chart | public, max-age=86400, s-maxage=604800, stale-while-revalidate=86400 | 1d browser, 7d CDN, 1d SWR |
GET /c/{id} (saved image) | public, max-age=86400, s-maxage=86400, stale-while-revalidate=86400 | 1d browser, 1d CDN, 1d SWR – update, unpublish, and delete request a CDN purge; browser caches and purge failures fall back to ≤1d |
GET /e/{id} (interactive embed) | public, max-age=86400, s-maxage=86400, stale-while-revalidate=86400 | Same as /c/{id} – HTML shell, identical kill-switch semantics |
GET /r/{id}[.png|.svg] (MCP) | public, max-age=3600, immutable | 1 hour response cache; the preview config lives for 1 hour, and bare, PNG, and SVG URLs are distinct immutable cache keys |
The public chart-delivery routes (/chart, /c, /e, and /r) return handled non-redirect errors with private, no-store, so a transient failure can't poison their edge caches.
Cache keys
The CDN keys on the full URL including query string. That means:
https://szum.io/chart?config={...}– two clients sending the same byte-identical config share the same cache entry. Reorder a JSON key and you get a fresh render. The query string IS the input here, so unique query strings produce different renders, which is intentional.https://szum.io/c/abc123andhttps://szum.io/e/abc123– stable; everyone who fetches the same id hits the same cache entry.
Use /c/{id} (saved charts) or /e/{id} (interactive embeds) when many recipients will fetch the same chart – emails, dashboards, Slack, iframes. The opaque short URL is byte-identical for every recipient, which gives repeated requests the best chance of being served from edge cache.
See also
- API → Response – full header reference for
POST /chart - Saved charts → Rate limits – how
GET /c/{id}interacts with the creator's plan - Plans & Limits – what counts toward the monthly bucket