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:
- The request reaches origin (cache miss, cache expiry, or
Cache-Control: no-cachefrom the client). - 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
| 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) | public, max-age=300, s-maxage=600, stale-while-revalidate=86400 | 5m 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, immutable | 1h, 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
- 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