What is 304 Not Modified?
A 304 Not Modified response means "you already have the current version". The client asked whether a file had changed since it last fetched it, the server checked, and instead of sending the file again it returned a short header-only answer. Browsers and crawlers then reuse their stored copy.
It is a normal, healthy status. Seeing 304s in logs or developer tools is a sign that caching works, not an error to fix.
The conversation behind a 304
The first response carries a validator, either a timestamp or a fingerprint of the content:
HTTP/2 200
last-modified: Tue, 03 Nov 2026 09:12:00 GMT
etag: "5f3a-61b2c9"
On the next visit the client sends those values back as conditions:
GET /guide/ HTTP/2
if-modified-since: Tue, 03 Nov 2026 09:12:00 GMT
if-none-match: "5f3a-61b2c9"
If nothing changed, the server replies 304 with no body. If the page changed, it replies 200 with the new content and new validators. When both headers are present, the ETag comparison takes priority.
Why it matters for crawling
Google's crawlers send conditional requests and support both If-Modified-Since and If-None-Match. A 304 lets Googlebot confirm a page is unchanged without downloading it, which saves bandwidth and server work on both sides. On large sites that frees crawl capacity for pages that did change.
It has no direct effect on ranking. Google keeps using the content from its previous crawl, and the page stays indexed as it was.
Two ways it goes wrong:
- 304 for a page that has changed. If validators are not updated when content is, crawlers and browsers keep an old version. This happens when an
ETagis generated from something that ignores the content, or a cache layer answers conditional requests from a stale entry. - 304 with a body, or 304 to a first-time request. Both are server bugs. A client that has nothing stored cannot reuse it.
Checking your own server
$ curl -I https://example.com/style.css
$ curl -I -H 'If-None-Match: "5f3a-61b2c9"' https://example.com/style.css
Use the etag value from the first response in the second request. A 304 back means conditional requests work. A 200 every time means the server ignores them, and every visit downloads the file again.
On WordPress
Static files such as images, CSS and JavaScript are served by the web server, which normally handles validators and 304s without any setup. Dynamic pages are different: WordPress core sends Last-Modified and ETag headers, and answers with a 304, only for feeds. Ordinary posts and pages are generated fresh by PHP on each request and return 200 unless a page cache or CDN in front of the site adds validators.
A page cache therefore brings 304 support with it, along with the bigger win of a faster time to first byte. After enabling one, publish an edit and confirm that the next request returns the new content, so that purging works and nobody is served a stale page. That check takes a minute and catches the one failure of this kind that really costs you: visitors and crawlers being told nothing changed when it did.
Common questions
Is a 304 status code bad for SEO?
No. It tells crawlers the page has not changed, and Google keeps the version it already indexed. It only causes trouble if the server sends it for content that actually did change.
What is the difference between 200 and 304?
A 200 delivers the full content. A 304 delivers no content and tells the client to use its stored copy, so it is only valid as a reply to a conditional request.
Does Googlebot use If-Modified-Since?
Yes. Google's crawlers support If-Modified-Since and If-None-Match, and a correct 304 lets them skip downloading pages that are unchanged.