Caching
Every response says how long it may be kept, in one of three classes.
| Class | Headers |
|---|---|
Data, with ?lang= | public, max-age=300, s-maxage=86400 and an ETag |
| Data, language from the header | private, max-age=300 and an ETag |
| Geo, validate | private, no-store |
The data routes are /v1/countries, /v1/countries/:country and its /states, /v1/locales/:lang and /v1/version. The per-visitor routes are /v1/geo, with or without ?include=, and POST /v1/validate, whose body is what a shopper typed.
Language and shared caches
A body whose language came from Accept-Language varies by a header its URL does not name, so a shared cache keyed on the URL would hand one visitor's language to the next. Those responses are private. A client that wants a shareable URL sends ?lang=, which the SDK always does.
Geo is never stored
A cached geo response would serve one visitor's country, city, postcode and IP address to the next, so /v1/geo is no-store and carries no ETag. A test asserts it. Because it is never cached, a form that detects its country with ?include=rules always starts with the current rules; /v1/geo?include=rules&country=XX does the same for a fixed country.
Revalidation
An ETag combines the data version, the deployed version, the language of the body and the query string, so a change to the data, to the code or to the language asked for is a new tag. If-None-Match is compared as RFC 9110 says: a list of tags, weak or strong, or *. A match gets a 304 with no body.
Browsers keep a response for 5 minutes, then revalidate with the ETag, so a deploy reaches a browser within 5 minutes and a cache outside Cloudflare that honours s-maxage within a day.
The edge
The Worker answers every request. Cloudflare runs a Worker before its cache, and this one does not put responses into it, so s-maxage is for caches outside Cloudflare. Each request costs well under a millisecond of work. The flags are the exception: they are static files, served without running the Worker and cached for a week.