szum

Caching & CDN

Why repeated fetches of the same chart URL don't burn renders – and exactly how aggressive each endpoint is.

szum's GET endpoints are CDN-cached. Fetches that hit the edge cache never reach the origin, so they never increment your render counter. This is what makes embedding in emails, Markdown, and dashboards economical: a chart linked in a newsletter that goes to 10,000 inboxes renders once at origin, then serves from the edge.

What "didn't count as a render" means

Every render endpoint instruments origin renders, not edge fetches. 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)public, max-age=300, s-maxage=600, stale-while-revalidate=864005m browser, 10m CDN, 1d SWR – short TTL keeps the surface fresh after the creator updates settings
GET /r/{id} (transient, MCP)public, max-age=3600, immutable1h, never revalidates – the id is single-use anyway (1h Redis TTL)

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.
  • https://szum.io/c/abc123 – stable; everyone who fetches the same id hits the same cache entry.

Use https://szum.io/c/{id} (saved charts) when many recipients will fetch the same chart – emails, dashboards, Slack. The opaque short URL is bytes-identical for every recipient, so cache hit rates approach 100%.

Forcing a fresh render

Append a unique query parameter (e.g. ?v=2) to bust the cache. The origin rebuilds and counts as one render. This is intended for development; don't do it in production embeds or your render bucket will track viewer count instead of unique chart count.

See also

On this page