Caching & CDN

How szum's CDN serves cached charts instantly – and why audience-facing loads are free.

szum's GET endpoints are CDN-cached. The reason that matters is latency: a cache hit returns in tens of milliseconds without waiting on origin render, font loading, or theme application. For a chart in an article that gets 10,000 page views, origin render runs once per region per cache cycle (~20–40 times a day); every other load comes back from the edge instantly.

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

EndpointCache hitCache miss
GET /c/{id} (saved image)free+1 render
GET /e/{id} (interactive embed)free+1 render

Example. A chart embedded in an article seen 2M times in a month: the CDN serves nearly all of those loads for free. The origin only re-renders ~20–40 times per region per day per cache cycle – a few thousand renders total, typically well within a Pro plan's included allotment. Your cost stays flat no matter how large the audience grows, because audience-facing loads are absorbed by the CDN.

How a render gets charged

Two things have to happen for one render to be charged:

  1. The request reaches origin (cache miss, cache expiry, or Cache-Control: no-cache from the client).
  2. The origin actually produces an image (passes validation, isn't rate-limited, isn't refused for plan reasons).

If either fails, the bucket isn't incremented. On render error after a successful origin hit, the bucket is refunded.

Cache headers per endpoint

EndpointCache-ControlNotes
POST /chartprivate, no-storeAuthenticated; response carries X-Usage-* headers, must not be reused across keys
GET /chartpublic, max-age=86400, s-maxage=604800, stale-while-revalidate=864001d browser, 7d CDN, 1d SWR
GET /c/{id} (saved image)public, max-age=86400, s-maxage=86400, stale-while-revalidate=864001d browser, 1d CDN, 1d SWR – long TTL absorbs popularity bursts; staleness after an unpublish/delete is bounded to ≤1d (no immutable)
GET /e/{id} (interactive embed)public, max-age=86400, s-maxage=86400, stale-while-revalidate=86400Same as /c/{id} – HTML shell, identical kill-switch semantics
GET /r/{id} (transient, MCP)public, max-age=3600, immutable1h CDN cache, never revalidates – the id is single-use (10 min TTL); a rendered image harmlessly outlives its config

Error responses on cacheable routes (404, 403, 429, 500) are returned with private, no-store, so a transient failure can't poison the edge cache.

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/abc123 and https://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 bytes-identical for every recipient, so cache hit rates approach 100% and the average viewer gets the chart back instantly from the nearest edge.

See also

On this page