Skip to content

Test your website now

Free, no card. We read only public pages.

Run free audit →

Performance · Low severity

Cache-Control Header Missing: Declare the Right Policy

Fix a missing Cache-Control header. Choose policies for HTML, versioned assets and private responses, verify revalidation, and avoid unsafe shared caching.

Published · Updated

What the check tests

Check
perf.cache-headers - Cache-Control configured
Passes when
Responses should declare Cache-Control (HTML typically no-cache/short, assets immutable).
Scope
graded on every page crawled
Severity
Low
Fix effort
small - under an hour
Impact when fixed
low

In one paragraph

A missing Cache-Control header leaves this response without an explicit policy in that header for freshness and reuse. Caches may still store it under other HTTP rules; absence does not mean nothing is cached. Choose a policy for the response's content and sensitivity, configure the actual delivery layer, and verify both browser and shared-cache behaviour before applying broad caching changes.

Why it matters

HTTP caching can reduce repeated downloads and origin work, but correctness comes first. A stale public article and another user's cached account page are very different problems. The response policy should reflect what varies and who is allowed to reuse it.

no-cache allows storage but requires validation before reuse. no-store instructs caches not to store the response. private limits storage to private caches rather than shared ones; it is not encryption and does not mean the browser cannot retain a copy. Select combinations according to the intended behaviour rather than treating these terms as interchangeable.

Validators such as ETag and Last-Modified can make revalidation cheaper when the content has not changed. Long freshness is most straightforward for assets with immutable content-hashed names, whose URL changes when the bytes change.

How WebAuditOS evaluates this finding

The supplied rule passes any present Cache-Control value and warns when it is absent. No response and statuses 401, 403, or 429 are not graded. Expires alone does not satisfy this presence check, although it remains meaningful in HTTP caching.

The rule inspects crawled page responses rather than establishing the caching policy of every asset. It does not judge whether a declared policy is appropriate. A public long-lived response containing personal data can pass while being dangerously configured.

How to fix it

  1. Classify the affected response. Separate public HTML, personalised pages, sensitive responses, versioned assets, and files whose URLs do not change when updated. Identify the CDN, origin, and browser caches involved.
  2. For public HTML that should be validated before reuse, consider:
Cache-Control: no-cache

Pair it with accurate validators where supported. This allows storage with validation; it is not an instruction to discard every response.

  1. For genuinely immutable public assets with content-hashed filenames, a common policy is:
Cache-Control: public, max-age=31536000, immutable

Do not apply it to an unversioned stylesheet or changing HTML merely because it improves a cache score. Keep old hashed assets available as required by cached documents.

  1. For content that may be stored only in a user's private cache, review private and suitable freshness or validation settings. For responses that should not be stored by caches, use an appropriate no-store policy. Never use a global public rule over authenticated content without understanding the complete design.
  2. Configure the source of the actual response. Frameworks and managed hosts may own or override cache settings on generated routes. A header added in one middleware does not necessarily apply to platform assets or edge responses.
  3. Verify cache keys, session bypass, and invalidation independently. Set-Cookie alone is not a universal guarantee that no shared cache will store a response. A CDN custom rule can also change how the origin's policy is applied.
  4. Test a first request, a repeat request, a content update, and two separate non-production user sessions where personalisation exists. Inspect freshness, validators, cache status, and response bodies. Do not test privacy isolation with real sensitive customer data.
  5. Rescan representative HTML and inspect assets separately. Track both correctness and hit rate rather than using the presence-only result as proof of a sound cache architecture.

What the fix can break

Long freshness on changing URLs can keep outdated prices, text, or JavaScript in users' caches. A later header change does not magically revoke every already-fresh stored response; plan versioning and invalidation before deployment.

A shared-cache mistake can expose one user's content to another. Treat personalisation and authorisation as primary test cases, not an afterthought to a speed change.

Overusing no-store sacrifices useful reuse, while using no-cache without workable validation may still require full transfers. Measure real behaviour instead of assuming the directive name predicts the entire performance result.

Questions

Does no-cache prevent storage?

No. It requires validation before reuse. Use no-store when the intended instruction is not to store the response.

Does private mean the response cannot be retained anywhere?

No. It excludes shared-cache storage while permitting private-cache storage under the applicable rules.

Why does an inappropriate policy still pass?

The documented rule tests presence, not suitability. Review freshness, sensitivity, and cache behaviour separately.

What should I review next?

Review compression, TTFB, and the website audit checklist.

In the report

Test this on your own site

Every scan runs perf.cache-headers on every page it crawls, on every plan. The finding carries this id, so a line in a report can be matched to the explanation above - and the free scan needs no account.