RFC 9111 • deterministic calculator
HTTP Cache Freshness Calculator
Change a response, then inspect private and shared cache decisions side by side.
Response and timing
Parsed headers: Date, Age, Cache-Control, ETag, Vary
Invalid values must be non-negative whole numbers.
Shared cache
Freshness timeline
Not a CDN predictor
Real CDNs diverge from the spec. Cloudflare does not cache HTML by default in all cases, and a configured Browser Cache TTL can rewrite max-age.
What this HTTP cache freshness calculator does
Build a response with Cache-Control fields, timing values, validators, and other response headers—or paste raw response headers. The calculator recomputes in your browser as you edit the inputs and shows private-cache and shared-cache outcomes side by side.
It reports apparent age, corrected initial age, current age, freshness lifetime, fresh or stale status, the fresh-boundary epoch, stale-while-revalidate and stale-if-error status, and the next conditional request. Results cite the rule used, including RFC 9111 sections for age and freshness calculations and RFC 9110 §13.1.2 for validator selection.
How to use it
- Enter Date, upstream request time, response time, request instant, and Age in epoch seconds. Add max-age, s-maxage, stale-while-revalidate, stale-if-error, or Expires values.
- Add Cache-Control directives, ETag, Last-Modified, Vary, or paste raw response headers. You can also use the no-store, no-cache, must-revalidate, proxy-revalidate, private, public, and immutable toggles.
- Read the private and shared results, then compare the fresh boundary and stale-window status in the timeline. Change any value to recompute the result immediately.
How the calculation works
The calculator uses integer epoch seconds. Date, upstream request time, response time, request instant, and Age are required for an RFC-exact age result. Non-negative whole-number inputs are accepted; invalid values and values outside JavaScript’s safe whole-number range produce a diagnostic instead of a numeric result. If the request instant is earlier than the response time, the timeline is marked invalid rather than calculating a negative resident time.
Current age
The implementation follows RFC 9111 §4.2.3:
apparent_age = max(0, response_time - Date) response_delay = response_time - upstream_request_time corrected_age_value = Age + response_delay corrected_initial_age = max(apparent_age, corrected_age_value) resident_time = request_instant - response_time current_age = corrected_initial_age + resident_time
The result displays apparent age, corrected initial age, and current age, each labeled with RFC 9111 §4.2.3.
Freshness lifetime
For a shared cache, a supplied s-maxage value is selected first and is labeled RFC 9111 §5.2.2.10. Otherwise, the calculator uses max-age; if no applicable max-age is present, it uses max(0, Expires - Date) when both values are supplied. For a private cache, s-maxage is not selected; the calculator uses max-age, then the Expires and Date difference. When no lifetime can be calculated, it displays “unknown / heuristic not calculated.”
The freshness test is the strict RFC 9111 §4.2 comparison:
freshness_lifetime > current_age
At the exact boundary, the response is stale. The displayed fresh boundary is response_time + freshness_lifetime, labeled RFC 9111 §4.2.1.
no-cache makes the result stale because it requires validation before use. no-store blocks storage or reuse. A shared cache also blocks a response marked private. The calculator recognizes public, must-revalidate, proxy-revalidate, immutable, stale-while-revalidate, stale-if-error, Vary, Date, Age, Expires, ETag, and Last-Modified as part of the response input model. Vary is displayed as supplied header data; it does not change the freshness lifetime in this calculation.
Stale windows and validation
After freshness ends, the result reports whether stale-while-revalidate is available while revalidating under RFC 9111 §5.2.2.4, or whether stale-if-error is available only on an error under RFC 9111 §5.2.2.3. These are reported as statuses, not as a guarantee that stale content will be served. must-revalidate applies a blocked-by-must-revalidate status to those stale windows; proxy-revalidate does the same for shared-cache handling.
For a fresh result, the next conditional request is none. For a stale or validation-required result, an ETag produces If-None-Match: <ETag>. Without an ETag, Last-Modified produces If-Modified-Since: <Last-Modified>. Without either validator, the result is none (full fetch; no validator). This selection is labeled RFC 9110 §13.1.2.
Private and shared caches are different
The two result panels always use the same supplied response and timing values but apply different cache rules. A shared cache uses s-maxage when present, while a private cache ignores it and uses max-age or Expires. A response marked private is blocked for a shared cache, and no-store blocks storage or reuse in either result. This side-by-side comparison makes the s-maxage versus max-age difference visible instead of treating every cache as the same.
Frequently asked questions
How is HTTP freshness calculated?
The calculator compares freshness lifetime with current age using freshness_lifetime > current_age, as specified by RFC 9111 §4.2. The equality case is stale.
Does Age mean the seconds since Date?
Not always. RFC 9111 §4.2.3 also accounts for apparent age, the delay between the upstream request and response, and resident time in the cache. The calculator displays those intermediate age values.
What is the difference between max-age and s-maxage?
s-maxage applies to shared caches and takes priority there. Private-cache results ignore s-maxage and use max-age when available, as described by RFC 9111 §5.2.2.10 and §4.2.1.
Is max-age=0 the same as no-store?
No. max-age=0 makes the response immediately stale. no-store blocks the response from being stored or reused, so the calculator reports a blocked outcome.
When does a cache send If-None-Match or If-Modified-Since?
When the result is not directly fresh or requires validation, the calculator prefers If-None-Match when an ETag is present. If there is no ETag, it uses If-Modified-Since when Last-Modified is present. With neither validator, it reports a full fetch with no validator.
Can stale-while-revalidate serve stale content?
It can make a stale response available while revalidation is happening during the reported window. It is not a permanent guarantee, and must-revalidate can block the stale-window status shown by the calculator.
What does Vary change?
Vary identifies request-header information that belongs to the cache variant key. It does not directly change the freshness lifetime calculated here; the supplied Vary value remains part of the parsed response-header input.
Does this predict Cloudflare or another CDN?
No. This is an RFC-based calculation from the headers and times you provide, not a prediction of a particular CDN. Real CDNs can diverge from the specification: Cloudflare may apply its own caching defaults, and a configured Browser Cache TTL can rewrite max-age. Check the CDN’s configuration and actual response headers.
Not a URL fetcher
Everything is computed in your browser from the values or raw headers you enter. Nothing is uploaded, and there is no backend.