Skip to content
Webmaster Tools

304 Not Modified

What HTTP 304 Not Modified means, how ETag, Last-Modified, If-None-Match and If-Modified-Since work, why 304s fail, and how Googlebot uses conditional requests.

All status codes

What 304 means

The client already has a valid cached copy, so the server sends no body. 304 is defined in RFC 9110 §15.4.5 and is the answer to a conditional request (§13). A browser that cached a response with validators:

HTTP/1.1 200 OK
ETag: "33a64df5"
Last-Modified: Tue, 15 Sep 2026 08:00:00 GMT
Cache-Control: no-cache

asks again with those validators when its copy is stale or must be revalidated:

GET /styles.css HTTP/1.1
If-None-Match: "33a64df5"
If-Modified-Since: Tue, 15 Sep 2026 08:00:00 GMT

and if nothing changed the server answers:

HTTP/1.1 304 Not Modified
ETag: "33a64df5"
Cache-Control: no-cache

The client then reuses the body it already has. A 304 must not have a body, and it must include the headers a 200 would have carried among Cache-Control, Content-Location, Date, ETag, Expires and Vary, so the cache can update its stored copy.

ETag or Last-Modified

  • ETag (§8.8.3) is an opaque version tag. Strong ETags ("abc") promise byte-identical content; weak ones (W/"abc") mean equivalent content. If-None-Match uses weak comparison, so both work for 304s.
  • Last-Modified (§8.8.2) is a date with one-second resolution, checked with If-Modified-Since.
  • When a request has both, If-None-Match wins and If-Modified-Since is ignored.

Why you don't get 304s

  • No validators: dynamic pages without ETag or Last-Modified, so there's nothing to compare.
  • ETags that differ per server behind a load balancer (old Apache setups that included the file's inode), so every revalidation misses.
  • Compression changing the ETag: nginx turns strong ETags into weak ones when it gzips; Apache's mod_deflate appends -gzip, which older versions then failed to match.
  • Frameworks that rebuild the page and compare nothing. Express sends weak ETags for res.send bodies and answers 304 automatically; elsewhere you may need middleware.
  • A 304 to unconditional requests. Only answer 304 when the request had If-None-Match or If-Modified-Since; otherwise the client has no copy to reuse.

In browser DevTools, "304" means the browser asked and was told to reuse its copy; "(memory cache)" or "(disk cache)" with 200 means it didn't need to ask at all.

304 and SEO

Google's crawlers support HTTP caching: they send If-None-Match and If-Modified-Since when they have a previous copy, and Google has said it prefers ETag. Per Google's documentation, a 304 tells the indexing pipeline the content is the same as last time; signals may be recalculated, but the status otherwise has no effect on indexing. Accurate 304s save bandwidth and crawl budget on large sites. Only send them when the content really hasn't changed, or Google won't see your updates.

Send a request with your own If-None-Match header and check the status with the HTTP Request Builder.