Cache-Control Builder & Analyzer

Choose cache directives to compose a header, or paste an existing value for analysis. This checks header text, not a live cache.

Runs locally in your browser
This tool processes all data locally in your browser.
Response policyChoose the policy your origin response will send.
Inspect a Cache-Control valuePaste just the directive value or a complete header line.

How to build and inspect a Cache-Control header

The upper panel composes a response policy: choose a visibility, add a freshness lifetime in seconds, tick the flags you need and press Build header. The header the page would send appears in the Response header box with a three-line summary — how many directives, how fresh the response is, and which caches may keep it — followed by every conflict the combination contains. The lower panel works the other way round: paste a value copied from a response, a CDN setting or a log, press Inspect header, and read the same summary for that text. Both panels run in this browser and the page keeps working offline.

Cache-Control is the HTTP response field that tells caches how long a response may be reused and what they must check first: max-age and s-maxage set the lifetime for browsers and shared caches, no-store forbids storing, no-cache allows storing but demands validation, and immutable, stale-while-revalidate and stale-if-error refine that. This tool reads the header text against RFC 9111 and reports what a cache would make of it. It never contacts a URL, so it cannot tell you what your server, your CDN or a browser cache actually does at runtime.

  1. Pick the audience under Visibility: public for a response that shared caches may store, private when the copy is meant for one user, or no explicit visibility when the field should say nothing about it. The choice is written into the header exactly as the option reads.
  2. Fill in max-age for browsers and s-maxage when a CDN or reverse proxy needs its own lifetime. The optional windows — stale-while-revalidate and stale-if-error — and the five flags are added only when you use them. Seconds are whole digits: 3600 rather than 3600.9, which the page reports instead of rounding away.
  3. Press Build header and read the Response header box: it holds the field line as it would be sent, in the order the form lists the directives. The summary underneath counts them, names the freshness and the scope, and lists each conflict it found: public with private, no-store with a lifetime, immutable without max-age, s-maxage with private.
  4. To check a header that already exists, paste it into the second panel — the directive list on its own or the whole Cache-Control line. The quoted form is read correctly, so no-cache="Set-Cookie, Authorization" stays one directive. Unknown names, duplicates, quoted delta-seconds and values that are not digits are reported instead of being passed over.
  5. Copy takes the field line to the clipboard and Download saves it as cache-control.txt. Clear returns the form to its defaults — public with max-age=3600 — and empties both panels, so the next run starts from a known state. When a value cannot be read, the status line names the field and the reason, and the header box is emptied rather than left holding the previous result.

Conflicts, delta-seconds and what this tool cannot see

The conflicts this tool reports

public and private contradict each other: public marks the response as storable by shared caches, and private forbids exactly those caches from keeping it, so one of the two has to go. no-store is the strongest directive — nothing may be stored — which makes max-age, s-maxage and the stale windows pointless in the same header; the report says so instead of showing a lifetime that will never be applied. s-maxage is read by shared caches only, and private excludes them, so s-maxage next to private has no effect.

immutable promises that the resource will not change while it is fresh (RFC 8246); without max-age or s-maxage no freshness window is stated for the promise to cover. must-understand belongs next to no-store, and a cache that understands the status code's caching requirements ignores the no-store part (RFC 9111 section 5.2.2.3). A missing lifetime is reported as well: without max-age, s-maxage or no-cache, a cache may fall back to a heuristic — commonly a tenth of the time since Last-Modified — and reuse the response without asking the origin.

Delta-seconds: the numbers a cache accepts

max-age, s-maxage, stale-while-revalidate and stale-if-error take delta-seconds, which RFC 9111 defines as one or more digits (section 1.2.2): 0 is a valid value and means stale immediately, and a decimal point is not part of the grammar. A quoted value such as max-age="5" is reported because a sender must use the token form (section 5.2.2.1). A value above 2147483647 seconds is flagged as well: a cache that cannot represent the number must read it as 2147483648 seconds, over 68 years, which behaves like never stale.

The other argument form in this field is the quoted field-name list of no-cache and private, as in no-cache="Set-Cookie". Commas inside those quotation marks belong to the list, which is why the parser splits the field on commas outside quotes and counts such a value as one directive. Directives a cache does not recognize are ignored by that cache (section 5.2.3), and that is exactly why a misspelling such as maz-age=60 is worth reporting: the response would still be served, and the rule would simply not exist.

What this tool cannot tell you

The page never sends a request; it reads header text only. Whether a CDN, a reverse proxy or a browser honours the field depends on that system's configuration and on the status code of the response, and a cache may store a response that carries no directives at all if it considers it heuristically cacheable. Check the policy on the live response — curl -I, the cache headers your CDN reports, or the browser network panel — before trusting it.

Two neighbours of this field are deliberately out of scope: Expires gives an absolute date instead of a lifetime, and Pragma is an HTTP/1.0 request field that RFC 9111 deprecates (section 5.4). A line that starts with another field name is refused for that reason rather than relabelled as Cache-Control. And because the check is textual, a header that reads perfectly can still be wrong for the content behind it: no-store on a static asset, or a one-year max-age on a page that changes hourly, are decisions no header checker can make for you.

Recent tools: