304 Not Modified
What HTTP 304 Not Modified means, why it's a 3xx code but not a redirect, how ETag and Last-Modified drive it, and why it can indirectly help crawl efficiency on large sites without affecting rankings.
1 evidence signal on this page
- Related live toolHTTP Header Checker
HTTP 304 Not Modified is the response to a conditional GET or HEAD request whose condition evaluates false — one that would otherwise have gotten a 200. It's a 3xx-class response that is not a redirect — it has no Location header and, by spec, no body at all. A GET/HEAD carrying If-None-Match (matched against an ETag) or If-Modified-Since (matched against Last-Modified) is what makes a request conditional in the first place; a second visit is the typical example, not the protocol rule. When the validator still matches, the server replies 304 with no body, and the client reuses its cached copy. For SEO there's no direct ranking effect — Google already has the content, and a 304 just confirms nothing changed, though Search may still recalculate a URL's signals. The real payoff is resource savings: on large sites with many rarely-changing URLs, 304s let crawlers skip re-downloading unchanged pages, saving bandwidth and server compute, which Google says may indirectly improve crawl efficiency — it doesn't promise an automatic reallocation of crawl budget to other URLs. Google recommends ETag as the primary validator (it has no date-formatting pitfalls), supports setting both, and treats a change as significant enough to invalidate cache only when the content actually changes — not a footer copyright year. Don't confuse 304 with 301/302/307/308 (which move you to a different URL) or with 204 No Content (also bodyless, but because there's genuinely nothing to send).
TL;DR — A 304 Not ModifiedHTTP 304 Not Modified is the response to a conditional GET/HEAD whose condition evaluates false, in the 3xx class but not a redirect: it has no Location header and no body. It tells a client its cached copy is still valid. For SEO it has no direct ranking effect and no indexing effect beyond a possible signal recalculation, though it can help crawl efficiency indirectly on large sites. response is the server’s way of saying “you already have this — your copy is still good, don’t download it again.” It is not an error, and despite living in the 3xx “redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't.” family it doesn’t send anyone to a new URL. It only happens when the client (a browser or a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.) first sends a conditional request asking “has this changed since last time?” For SEO it doesn’t move your rankings, but on big sites it can help search engines use their resources more efficiently.
What a 304 actually is
Every response your server sends starts with a three-digit status code. 200 OK
means “here’s the page, body and all.” A 304 Not Modified means something more
specific: the client made a conditional request — one that says “give me this
page, but only if it changed” — and the server determined it didn’t change, so
instead of the 200 it would otherwise have sent, it replies 304 with no body at
all. That’s the actual rule: a 304 is only ever the answer to a conditional
GET/HEAD whose condition came back false.
A second visit is the typical way that happens, and it’s a useful way to picture
it: the first time a browser or crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. fetches a page, it gets a normal 200 with
the full content — plus a couple of little “fingerprint” headers. On the next
visit, the client shows the server that fingerprint and asks, “still the same?” If
nothing changed, the server answers 304 and sends no page body at all, and the
client just reuses the copy it already had. But “second visit” is the example, not
the protocol rule — what actually triggers a 304 is the conditional request itself,
however it happens to arrive. Evidence for this claim RFC 9110 defines 304 Not Modified as the response to a conditional GET or HEAD when the selected representation has not changed and says the response cannot contain content. Scope: HTTP semantics for 304 conditional responses. Confidence: high · Verified: IETF: RFC 9110 §15.4.5 — 304 Not Modified
Why it’s in the “redirect” family but isn’t a redirect
304 starts with a 3, which is the class HTTP uses for redirects. That trips people
up constantly. But a 304 has no Location header and doesn’t send you to a
different address — nobody goes anywhere. It just points the client back to its own
saved copy. So “redirect family” is a numbering quirk, not what it does.
Is a 304 a problem?
No. Seeing 304s in your browser’s network tab or in a crawl report is a sign that cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. is working — exactly what you want. A lot of the “304 error, how to fix it” advice floating around treats it like something broken on your end. It isn’t. It’s the correct, intended result of a well-behaved cache.
Does it help SEO?
Not your rankings, directly. Google already has your content from the last time it crawled the page — a 304 just confirms it hasn’t changed, so Google keeps using what it already stored (Search can still recalculate a URL’s signals, but a 304 itself isn’t a ranking or indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. bonus). Where it does help is resource efficiency: if a search engine doesn’t have to re-download pages that haven’t changed, it saves bandwidth and compute on both ends, which Google says can indirectly help crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. run more efficiently — it’s not a guarantee that the saved effort gets automatically redirected to your new or updated pages. That matters most on large sites with lots of pages that rarely change.
Evidence for this claim RFC 9111 defines validation as checking whether a stored response remains current, typically with a conditional request that can receive 304 Not Modified. Scope: HTTP cache validation; it does not create a Search ranking benefit. Confidence: high · Verified: IETF: RFC 9111 §4.3 — ValidationWant the real mechanics — ETagsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page., If-None-Match, strong vs. weak validators, how
to implement it, and what Google has actually said about it? Switch to the
Advanced tab.
TL;DR — 304 is the response to a conditional
GET/HEADwhose condition evaluates false and that would otherwise have gotten a200(RFC 9110 §15.4.5). It’s 3xx-class but not a redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't.: noLocation, no new URL, and — normatively — no body (“it cannot contain content or trailers”). The condition is carried byIf-None-Match(vs. anETag) and/orIf-Modified-Since(vs.Last-Modified); if the validator still matches, the server returns 304 and the client reuses its cache. SEO impact: no direct ranking effect — Google already has the content, though Search may still recalculate a URL’s signals — and a resource-savings win on large sites (Google says it may indirectly improve crawl efficiency; it doesn’t promise automatic reallocation of crawl budget to other URLs). Google’s crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. infrastructure supports both validators and recommendsETagas primary (it has no date-formatting pitfalls). Contrast it with 301/302/307/308 (which move the URL) and 204 (also bodyless, but because there’s genuinely nothing to send).
What 304 means in the spec
RFC 9110 (HTTP Semantics) §15.4.5 defines it precisely: “The 304 (Not Modified)
status code indicates that a conditional GET or HEAD request has been received and
would have resulted in a 200 (OK) response if it were not for the fact that the
condition evaluated to false.” That’s the actual, normative trigger — a conditional
GET/HEAD whose condition evaluates false and that otherwise would have gotten a
200. In plain terms: the client asked “give me this page, but only if it
changed,” the server determined it didn’t change, so it skips sending the body.
A “second visit” is the everyday example of how a request becomes conditional (the
client attaches a validator it saved from an earlier response), but it’s a teaching
example, not the rule itself — nothing in the spec requires a prior visit, just a
conditional request. Evidence for this claim RFC 9110 defines 304 Not Modified as the response to a conditional GET or HEAD when the selected representation has not changed and says the response cannot contain content. Scope: HTTP semantics for 304 conditional responses. Confidence: high · Verified: IETF: RFC 9110 §15.4.5 — 304 Not Modified
The spec even uses the word “redirecting” in this section — “the server is
therefore redirecting the client to make use of that stored representation as if it
were the content of a 200 (OK) response” — but read it carefully: it’s redirecting
the client back to its own cache, not to another URL. There’s no Location
header and no new address. This single sentence is the source of most of the
confusion about whether 304 “is a redirect.” It isn’t, in the HTTP sense.
Two more normative points matter:
- No body, ever. RFC 9110: “A 304 response is terminated by the end of the header section; it cannot contain content or trailers.” A 304 that ships a body is a spec violation, and some clients will mishandle it. This is a hard rule, not a style preference.
- It carries the same metadata a 200 would. The server “MUST generate any of
the following header fields that would have been sent in a 200 (OK) response to
the same request: Content-Location, Date, ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page., and Vary,” plus
Cache-ControlandExpireswhere applicable. So a 304 is the 200’s headers without the payload.
How 304 actually works: conditional requests
A server never sends a 304 out of the blue. It’s always a response to a conditional request — a request the client makes conditional by attaching a validator it saved from a previous response. There are two validators.
ETag and If-None-Match
An ETag (entity tag) is an opaque tokenA token is the smallest unit of text (or image/audio/video) an LLM processes — roughly 4 characters, or about ¾ of an English word. A context window is the maximum number of tokens (input plus output) a model can hold at once, like its short-term memory. the server attaches to a 200
response — think of it as a version fingerprint for that exact representation of
the URL. On the next request for that URL, the client sends the saved value back in
an If-None-Match header. The server compares: if the current ETag still
matches, nothing changed, so it returns 304; if it differs, it returns a fresh
200 with the new content and a new ETag.
Last-Modified and If-Modified-Since
The date-based alternative: the server sends a Last-Modified timestamp on the
200. Next time, the client sends it back in an If-Modified-Since header, and
the server compares dates — if the resource hasn’t changed since that timestamp,
it’s a 304. This is simpler but coarser (only as granular as the timestamp) and
sensitive to exact HTTP-date formatting, which is a common source of bugs. When
both validators are present, If-None-Match (the ETag) takes precedence over
If-Modified-Since.
Strong vs. weak ETags
An ETag can be strong or weak, and the difference matters. Per MDN’s
conditional-requests guidance, “strong validation consists of guaranteeing that the
resource is, byte to byte, identical to the one it is compared to.” A weak ETag
is prefixed with W/ (for example, ETag: W/"abc123") and asserts only semantic
equivalence — MDN’s example is that “a page that would differ from another only by a
different date in its footer, or different advertising, would be considered
identical to the other with weak validation.” Strong ETags (no prefix) are required
for things like range requests that need byte-exact matching; weak ETags are useful
when compressionCompression (HTTP content encoding) shrinks text-based responses — HTML, CSS, JS, JSON, SVG, XML sitemaps — before they're sent over the network, using an algorithm like Gzip, Brotli, or Zstd, so the browser or crawler downloads fewer bytes. It's not a ranking factor, but it speeds up page loads and helps pages stay under crawler fetch limits., whitespace, or trivial non-substantive differences shouldn’t force
a full re-fetch. The practical trap: if your ETag changes every time content is
gzip/Brotli-recompressed, or varies across load-balanced servers, you’ll trigger
unnecessary re-crawls — pick strong vs. weak deliberately and keep the value stable
for genuinely-unchanged content.
The full handshake, step by step
- First request → server returns
200 OKwith the content, plusETagand/orLast-Modified. - Client stores the content and those validators.
- Next request → client sends
If-None-Matchand/orIf-Modified-Sincewith the stored values. - Server decides: unchanged →
304 Not Modified, no body, the client reuses its cache; changed →200 OKwith the new body and fresh validators. Evidence for this claim RFC 9111 defines validation as checking whether a stored response remains current, typically with a conditional request that can receive 304 Not Modified. Scope: HTTP cache validation; it does not create a Search ranking benefit. Confidence: high · Verified: IETF: RFC 9111 §4.3 — Validation
If you want the deeper treatment of cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. and validators as a crawl-efficiency lever — the whole conditional requestsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. story and how it ties into crawl budgetThe number of URLs an engine will crawl in a timeframe. — that’s a companion topic; this article is the status-code-focused view.
304 and SEO: no ranking effect, real crawl-efficiency effect
Here’s the whole SEO story, and it’s narrower than a lot of blog boilerplate implies. 304 has no direct ranking effect, and Google’s own guidance on how status codes affect crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. and indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. bounds the indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. effect too: Search may still recalculate a URL’s signals, but otherwise a 304 doesn’t change how the page is indexed. Google already has the content from the previous crawl; a 304 just confirms nothing changed, so it keeps using what it has. There is no ranking bonus for returning 304s.
What 304 does buy you is resource savings that can indirectly improve crawl efficiency. In Google’s December 2024 Search Central blog post on HTTP caching, Gary Illyes put it plainly: “Especially if you have a large site with rarely-changing content under individual URLs, allowing caching locally may help your site be crawled more efficiently. Google’s crawling infrastructure supports heuristic HTTP caching as defined by the HTTP caching standard, specifically through the ETag response- and If-None-Match request header, and the Last-Modified response- and If-Modified-Since request header.”
On the exact 304 mechanism, the same post is explicit about why the empty body is the point: if the ETag the crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. sends “matches the current value the server generated, your server should return an HTTP 304 (Not modified) status code with no HTTP body,” and that “no HTTP body” part matters because “your server doesn’t have to spend compute resources on actually generating content” and “doesn’t have to transfer the HTTP body” — you save compute and bandwidth on both ends. Google’s own wording for the downstream benefit is conditional: those resource savings may indirectly improve crawl efficiency. It’s not a promise that the saved effort gets automatically reallocated to your new or updated URLs — treat it as a resource-savings mechanism with a plausible, not guaranteed, spillover benefit.
Why this matters more on large sites
If you have a few hundred pages, this is largely academic — Google will crawl your whole site comfortably regardless. The payoff scales with size: a site with hundreds of thousands or millions of URLs, many of them rarely changing, benefits materially when crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. can skip re-fetching all the unchanged ones. That’s the audience Google’s post is aimed at, and it’s the honest framing to keep — don’t oversell 304 as a small-site tactic.
ETag or Last-Modified, and what counts as “changed”
Google recommends ETag as the primary validator: “We strongly recommend using
ETag because it’s less prone to errors and mistakes (the value is not structured
unlike the Last-Modified value).” Setting both is fine and encouraged. If you do use
Last-Modified, the date “must be formatted according to the HTTP standard” — Google
recommends the format “Weekday, DD Mon YYYY HH:MM:SS Timezone,” e.g. “Fri, 4 Sep
1998 19:15:56 GMT” — or it may be silently ignored. Google also suggests setting the
max-age field of Cache-Control to help crawlers decide when to recrawl.
What counts as a change worth invalidating the cache for is your call, and Google’s advice is to reserve it for substantive changes: “Our recommendation is that you require a cache refresh on significant changes to your content; if you only updated the copyright date at the bottom of your page, that’s probably not significant.”
What Googlebot and Bingbot actually do with it
Not every crawler request is conditional. Google’s crawler documentation notes that
individual Google crawlers and fetchers vary in caching support depending on the
product they serve — GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. supports caching when re-crawling URLs for Search,
while some other Google fetchers only support it in certain conditions — so even
with headers configured correctly, don’t expect 100% of requests to carry
If-None-Match/If-Modified-Since. For Bing: conditional requests aren’t a
Google-only feature. Bing’s crawler has supported conditional GET (sending
If-Modified-Since and, when available, If-None-Match, and accepting a 304 when
content is unchanged) since at least a 2008 Live Search blog post — though Bing
hasn’t published a modern equivalent to Google’s 2024 write-up. Treat the mechanics
as generic HTTP behavior that applies to both engines.
How to implement 304 support
- Send validators on the 200. Configure your server, CDN, or app to attach an
ETag(recommended) and/or a correctly formattedLast-Modifiedheader to normal200responses. Many servers and frameworks do ETags automatically for static files; dynamic responses usually need you to opt in. - Honor the conditional headers on the way back in. When a request arrives with
If-None-Match/If-Modified-Since, compare against the current validator and return304(no body) when it still matches, or a fresh200when it doesn’t. Again, static-file servers often handle this for you; app routes and edge workers frequently don’t unless you wire it up. - Decide what “changed” means and keep the ETag stable for genuinely-unchanged content — don’t let recompression or per-server variance flip it needlessly.
- Watch for the classic misconfigurations:
- Always-200 — never emitting validators, so no request is ever conditional and you never get the efficiency benefit.
- Unstable ETags — a value that changes even when content doesn’t (load balancers, recompression), forcing constant re-fetches.
- Stale 304s — the dangerous one: a server that keeps returning
304(or an unchanged ETag) after content has genuinely changed, so crawlers and caches never pick up the update. That’s a bug to catch in log analysis, not an inherent flaw of 304.
304 vs. other status codes
304 vs. 301 / 302 / 307 / 308
Those are the actual redirects. A 301/308 (permanent) or 302/307 (temporary)
carries a Location header and moves the client to a different URL — and
301/308 also pass a canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. signal. A 304 has no Location, moves
nobody, and passes no ranking signal. Same 3xx family by number, completely
different job. The per-code redirect details live in their own articles (see the
301 redirectA 301 redirect is the HTTP status code for a permanent move: it tells browsers and search engines a URL has moved for good, and it's the strongest signal for consolidating a page's ranking signals onto the new URL. Google says permanent redirects don't cause a loss in PageRank. piece and
the redirects sub-hub).
304 vs. 204 No Content
Both are bodyless, for entirely different reasons. A 204 No Content is a 2xx
success with an intentionally empty body because the server has genuinely nothing
to send — a successful API DELETE/PUT, an analytics beacon. A 304 also sends
no body, but not because there’s nothing to send; it’s because “you already have it
and it’s still valid.” Don’t conflate them: a 204 on a page URL can be treated like
a soft 404A soft 404 is a URL that returns a success status code (usually 200 OK) even though the page is empty, missing, or shows a 'not found' message. It isn't a status code a server sends — it's a label search engines apply after comparing the response code against the rendered content, and they treat the page like a 404 for indexing. because there’s no indexable content, whereas a 304 is a validity
confirmation for content Google already has. The 204 No ContentHTTP 204 No Content is a 2xx success status meaning the server fulfilled the request but is intentionally sending back no message body. It's correct for APIs and beacons — but on a page meant to be indexed, Google treats it like a soft 404.
article covers that code in full.
Common myths about 304
- “304 is a redirect.” No
Locationheader, nobody goes anywhere. The client reuses its own cached copy. RFC 9110’s “redirecting the client to make use of that stored representation” means pointing back to the cache, not to another URL. - “304 is an error I need to fix.” It’s the correct, intended outcome of a working conditional-request setup. Seeing 304s in a crawl or DevTools is a sign caching is working — the single most common misconception in the SERP.
- “304 helps rankings.” No direct ranking effect exists, and Google bounds the indexing effect too — Search may recalculate a URL’s signals, but a 304 otherwise doesn’t change indexing. The benefit is resource savings that Google says may indirectly improve crawl efficiency on very large sites, but it’s not a ranking signal and not a guarantee that saved effort moves to other URLs.
- “If my server returns 304, Google will use stale content forever.” 304 only
fires while the validator still matches. The moment content actually changes, a
correctly implemented server returns a fresh
200with new validators. The real risk is a misconfigured server that keeps returning 304 after content changed — a bug, not a property of 304. - “ETag and Last-Modified are interchangeable.” Both are validators, but
Last-Modifiedis date-format-sensitive and only as granular as its timestamp, whileETagis opaque and precise (and can vary awkwardly across servers or after recompression if implemented carelessly). Google recommends ETag as primary, both if you can.
FAQs
Is HTTP 304 an error? No — it’s a success signal that caching is working. It means the client’s cached copy is still valid.
Is 304 Not ModifiedHTTP 304 Not Modified is the response to a conditional GET/HEAD whose condition evaluates false, in the 3xx class but not a redirect: it has no Location header and no body. It tells a client its cached copy is still valid. For SEO it has no direct ranking effect and no indexing effect beyond a possible signal recalculation, though it can help crawl efficiency indirectly on large sites. a redirect? No. It’s in the 3xx class by numbering, but it
has no Location header and doesn’t move the client to a new URL.
Does 304 help SEO or rankings? No direct ranking effect, and no indexing effect beyond Google possibly recalculating a URL’s signals. It saves bandwidth and compute by letting crawlers skip unchanged pages, which Google says may indirectly improve crawl efficiency on large sites.
What’s the difference between ETag and Last-Modified? ETag is an opaque version
fingerprint matched via If-None-Match; Last-Modified is a timestamp matched via
If-Modified-Since. Google recommends ETag as less error-prone.
What is a weak vs. a strong ETag? A strong ETag asserts byte-identical content; a
weak ETag (prefixed W/) asserts semantic equivalence, tolerating trivial
differences like compressionCompression (HTTP content encoding) shrinks text-based responses — HTML, CSS, JS, JSON, SVG, XML sitemaps — before they're sent over the network, using an algorithm like Gzip, Brotli, or Zstd, so the browser or crawler downloads fewer bytes. It's not a ranking factor, but it speeds up page loads and helps pages stay under crawler fetch limits. or a changed footer date.
Why do I see 304s in my logs or crawl reports? Because clients are making conditional requests and your server is correctly confirming content hasn’t changed. That’s expected and good.
How do I make my server return 304 correctly? Send ETag/Last-Modified on the
200, then honor If-None-Match/If-Modified-Since on the next request by
returning 304 with no body when the validator still matches.
What’s the difference between 304 and 204? Both are bodyless; 204 because there’s nothing to send, 304 because you already have a still-valid copy.
Does Googlebot send conditional headers on every request? No — caching support varies by crawler, so not every request will be conditional even with headers configured.
Can a 304 response have a body? No. Per RFC 9110, “it cannot contain content or trailers.” A 304 with a body is a spec violation.
Conditional caching depends on stable ETag or Last-Modified values and a bodyless 304 response. One ordinary header fetch does not reproduce the complete handshake.
Use my HTTP Header Checker to inspect validators and cache policy, then send a conditional request to verify the server returns 304 only while content is unchanged. HTTP Header Checker Free
- Inspect ETag, Last-Modified, Cache-Control, and Vary on the initial 200 response.
- Repeat the request with If-None-Match or If-Modified-Since and require a bodyless 304 when unchanged.
- Change substantive content and verify the server returns a fresh 200 with an updated validator.
AI summary
A condensed take on the Advanced version:
- 304 Not ModifiedHTTP 304 Not Modified is the response to a conditional GET/HEAD whose condition evaluates false, in the 3xx class but not a redirect: it has no Location header and no body. It tells a client its cached copy is still valid. For SEO it has no direct ranking effect and no indexing effect beyond a possible signal recalculation, though it can help crawl efficiency indirectly on large sites. is the response to a conditional GET/HEAD whose condition
evaluates false and that would otherwise have gotten a 200 (RFC 9110 §15.4.5).
It’s 3xx-class but NOT a redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't.: no
Locationheader, no new URL, and — normatively — no body: “it cannot contain content or trailers.” A second visit is the typical example of how a request becomes conditional, not the protocol rule. - It’s the answer to a conditional request. A
GET/HEADcarryingIf-None-Match(matched against anETag) and/orIf-Modified-Since(matched againstLast-Modified). If the validator still matches, the server returns 304 and the client reuses its cached copy. - The spec’s word “redirecting” is metaphorical — it points the client back to its own cache, not to another URL. That sentence causes most of the “is 304 a redirect” confusion.
- ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. vs. Last-Modified: ETag is an opaque version tokenA token is the smallest unit of text (or image/audio/video) an LLM processes — roughly 4 characters, or about ¾ of an English word. A context window is the maximum number of tokens (input plus output) a model can hold at once, like its short-term memory. (matched via
If-None-Match); Last-Modified is a date (matched viaIf-Modified-Since, exact HTTP-date formatting required).If-None-Matchtakes precedence when both are present. Strong ETag = byte-identical; weak ETag (W/prefix) = semantic equivalence. - No direct ranking effect, and no indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. effect beyond Google possibly recalculating a URL’s signals. Google already has the content; 304 just confirms nothing changed. As Gary Illyes framed it, cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. “may help your site be crawled more efficiently” — the benefit is resource savings that may indirectly improve crawl efficiency on large sites, not a guaranteed reallocation of crawl budget and not a rankings signal.
- Google recommends ETag as primary (“less prone to errors and mistakes”), fine
to set both;
Last-Modifiedmust use the “Weekday, DD Mon YYYY HH:MM:SS Timezone” format; invalidate cache only on significant changes (not a footer copyright date). - Caching support varies by crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. — not every GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. request is conditional.
Bing has supported conditional
GETsince a 2008 Live Search post; it’s generic HTTP behavior. - Not to be confused with 301/302/307/308 (real redirects that move the URL) or 204 No ContentHTTP 204 No Content is a 2xx success status meaning the server fulfilled the request but is intentionally sending back no message body. It's correct for APIs and beacons — but on a page meant to be indexed, Google treats it like a soft 404. (also bodyless, but because there’s genuinely nothing to send).
- The real risk isn’t 304 itself but a misconfigured server returning 304 after content actually changed — catch it in log analysis. A valid 304 can also look like an error in some client libraries or platform caching layers even when nothing is actually wrong.
Official documentation
Primary-source references for what 304 is and how search engines use it.
HTTP spec & browser reference
- RFC 9110 §15.4.5 — 304 Not Modified — the authoritative definition: conditional request, no body, required headers.
- MDN — 304 Not Modified — plain-language framing, the
If-None-Match/If-Modified-Sincetrigger, and the list of headers a 304 must carry. - MDN — HTTP conditional requests — strong vs. weak validation explained.
- MDN — ETag — the
ETagheader, including the weak (W/) vs. strong syntax.
Google Search Central
- Crawling December: HTTP caching — Gary Illyes’ Dec 9, 2024 post: how ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page./If-None-Match and Last-Modified/If-Modified-Since drive 304s and why they help crawl efficiency.
- Google Crawler (User Agent) Overview — which Google crawlersGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. support cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency., and the ETag-over-Last-Modified recommendation.
- How HTTP status codes affect Google’s crawlers — Google’s current row on 304, including the qualification that Search may recalculate a URL’s signals even though 304 otherwise has no indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. effect.
- Troubleshoot Google Search crawling errors — the source for Google’s conditional wording that resource savings from conditional requestsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. “may indirectly” improve crawl efficiency, and that Google doesn’t send conditional headers on every crawl attempt.
Bing
- Announcing crawler improvements for Live Search — the (old) Bing/Live Search post confirming conditional-GET support (
If-Modified-Since/If-None-Match→ 304) since 2008.
Quotes from the source
On-the-record statements. Each link is a deep link that jumps to the quoted passage on the source page where the source supports it.
The HTTP spec
- “The 304 (Not Modified) status code indicates that a conditional GET or HEAD request has been received and would have resulted in a 200 (OK) response if it were not for the fact that the condition evaluated to false.” — RFC 9110, HTTP Semantics, §15.4.5. Read the section
- “A 304 response is terminated by the end of the header section; it cannot contain content or trailers.” — RFC 9110, §15.4.5 (the normative “no body, ever” rule). Read the section
MDN Web Docs
- “The HTTP
304 Not Modifiedredirection response status code indicates that there is no need to retransmit the requested resources.” Jump to quote - “Strong validation consists of guaranteeing that the resource is, byte to byte, identical to the one it is compared to.” — MDN, “HTTP conditional requestsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page..” Read the guide
Gary Illyes, Google — “CrawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. December: HTTP cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency.” (Dec 9, 2024)
- “Especially if you have a large site with rarely-changing content under individual URLs, allowing caching locally may help your site be crawled more efficiently. Google’s crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. infrastructure supports heuristic HTTP caching as defined by the HTTP caching standard, specifically through the ETag response- and If-None-Match request header, and the Last-Modified response- and If-Modified-Since request header.” Read the post
- “We strongly recommend using ETag because it’s less prone to errors and mistakes (the value is not structured unlike the Last-Modified value).” Read the post
- “If the ETag value sent by the crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. matches the current value the server generated, your server should return an HTTP 304 (Not modified) status code with no HTTP body.” Read the post
- “Our recommendation is that you require a cache refresh on significant changes to your content; if you only updated the copyright date at the bottom of your page, that’s probably not significant.” Read the post
Patrick Stox — Ahrefs
- “304 Not ModifiedHTTP 304 Not Modified is the response to a conditional GET/HEAD whose condition evaluates false, in the 3xx class but not a redirect: it has no Location header and no body. It tells a client its cached copy is still valid. For SEO it has no direct ranking effect and no indexing effect beyond a possible signal recalculation, though it can help crawl efficiency indirectly on large sites. – Says the page hasn’t been modified. Typically used for caching.” — from my HTTP Status Codes & Their SEO Impact guide (this article is the deep dive that entry never got). Jump to quote
#:~:text= anchoring, so the Illyes quotes are linked to the post rather than an anchored fragment — each was verified verbatim against the live page. Bing’s conditional-request support is cited from a 2008 Live Search post, not current documentation; treat it as “supported since 2008,” not a modern statement. 304 in context: the bodyless and 3xx codes it’s confused with
304 vs. its lookalikes
| Code | Class | Body | Location header | What it actually says | Ranking/canonical signal |
|---|---|---|---|---|---|
304 Not Modified | 3xx | None (by spec) | No | ”Your cached copy is still valid — reuse it” | None (crawl efficiency only) |
301 Moved Permanently | 3xx | — | Yes | ”Moved for good — go here” | Passes canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. signal |
302 FoundA 302 (\"Found\") is a temporary redirect: it forwards users to a new URL while telling search engines the original URL should stay in the index. It's a weak canonicalization signal, not the zero-equity dead end of SEO folklore. | 3xx | — | Yes | ”Temporarily here instead” | No canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. signal |
307 Temporary RedirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. | 3xx | — | Yes | Like 302, method-preserving | No canonicalization signal |
308 Permanent RedirectA 301 redirect is the HTTP status code for a permanent move: it tells browsers and search engines a URL has moved for good, and it's the strongest signal for consolidating a page's ranking signals onto the new URL. Google says permanent redirects don't cause a loss in PageRank. | 3xx | — | Yes | Like 301, method-preserving | Passes canonicalization signal |
204 No Content | 2xx | None (nothing to send) | No | ”Success, intentionally empty” | None; on a page URL, treated like soft 404A soft 404 is a URL that returns a success status code (usually 200 OK) even though the page is empty, missing, or shows a 'not found' message. It isn't a status code a server sends — it's a label search engines apply after comparing the response code against the rendered content, and they treat the page like a 404 for indexing. |
200 OK | 2xx | Populated | No | ”Here’s the page” | Eligible for indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. |
The trap: 304 and 204 are both bodyless, and 304/301/302/307/308 are
all 3xx — but 304 is the odd one out on both axes. It’s the only 3xx that moves
nobody, and the only bodyless code that means “you already have it” rather than
“there’s nothing to send.”
The two validators
| Validator (response) | Conditional request header | Type | Notes |
|---|---|---|---|
ETag: "abc123" | If-None-Match: "abc123" | Opaque tokenA token is the smallest unit of text (or image/audio/video) an LLM processes — roughly 4 characters, or about ¾ of an English word. A context window is the maximum number of tokens (input plus output) a model can hold at once, like its short-term memory. | Google-recommended primary; strong = byte-identical |
ETag: W/"abc123" | If-None-Match: W/"abc123" | Weak token | W/ prefix = semantic equivalence (tolerates trivial diffs) |
Last-Modified: Fri, 4 Sep 1998 19:15:56 GMT | If-Modified-Since: <date> | Timestamp | Exact HTTP-date format required; coarser than ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. |
When both are present, If-None-Match takes precedence over If-Modified-Since.
Fast facts
- 304 has no body, ever — RFC 9110 makes it normative.
- 304 is a 3xx code but not a redirect (no
Location, no new URL). - No direct ranking effect, and no indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. effect beyond Google possibly recalculating a URL’s signals — the benefit is resource savings that may indirectly help crawl efficiency on large sites.
- Google recommends
ETagas primary; setting both ETag and Last-Modified is fine. Last-Modifiedmust use “Weekday, DD Mon YYYY HH:MM:SS Timezone” or it may be ignored.- Invalidate cache on significant content changes, not a footer copyright year.
- Not every crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. request is conditional — cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. support varies by crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index..
- Bing has supported conditional
GET→ 304 since 2008; it’s generic HTTP. - The real risk is a stale 304 (server returns 304 after content changed) — catch it in log analysis.
The conditional-request handshake, in raw HTTP
Concrete request/response chains showing how a 304 comes about. (Header values are illustrative.)
ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. / If-None-Match — the first fetch (200)
GET /blog/my-article/ HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "a1b2c3d4"
Cache-Control: max-age=3600
<full page body here>The client stores the body and the ETag value.
ETag / If-None-Match — the next fetch, content unchanged (304)
GET /blog/my-article/ HTTP/1.1
Host: example.com
If-None-Match: "a1b2c3d4"
HTTP/1.1 304 Not Modified
ETag: "a1b2c3d4"
Cache-Control: max-age=3600No body. The ETag matched, so the server saved the compute of generating the page and the bandwidth of sending it. The client reuses its cached copy.
Last-Modified / If-Modified-Since — the date-based equivalent
GET /blog/my-article/ HTTP/1.1
Host: example.com
If-Modified-Since: Fri, 4 Sep 1998 19:15:56 GMT
HTTP/1.1 304 Not Modified
Last-Modified: Fri, 4 Sep 1998 19:15:56 GMTNote the exact HTTP-date format — “Weekday, DD Mon YYYY HH:MM:SS Timezone” — which Google recommends to avoid parsing issues.
When content HAS changed — a fresh 200, not a 304
GET /blog/my-article/ HTTP/1.1
Host: example.com
If-None-Match: "a1b2c3d4"
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "e5f6g7h8" ← new value: content changed
<updated page body here>The stored ETag no longer matches, so the server sends the new content and a new validator. The cache updates. This is exactly why a correctly implemented 304 can’t “trap” a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. on stale content — the moment the content changes, the validator changes, and the next request gets a real 200.
Weak vs. strong ETag
ETag: "a1b2c3d4" ← strong: asserts byte-for-byte identity
ETag: W/"a1b2c3d4" ← weak: asserts semantic equivalence (the W/ prefix)Rule of thumb: if you run a large site with lots of rarely-changing URLs,
sending a stable ETag (and honoring If-None-Match) on your 200s lets crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.
confirm “still the same” with a cheap, bodyless 304 — saving bandwidth and compute
that Google says may indirectly improve how efficiently the rest of your site gets
crawled. If your ETag flips on every recompression or across load-balanced
servers, you lose that benefit.
304 mistakes that break conditional caching
Changing the ETag when the representation did not change
An ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. tied to a server instance, compressionCompression (HTTP content encoding) shrinks text-based responses — HTML, CSS, JS, JSON, SVG, XML sitemaps — before they're sent over the network, using an algorithm like Gzip, Brotli, or Zstd, so the browser or crawler downloads fewer bytes. It's not a ranking factor, but it speeds up page loads and helps pages stay under crawler fetch limits. pass, or request timestamp defeats
the validator: unchanged content keeps returning a full 200. Generate a stable
validator from the representation or deliberately use a weak ETag when byte-level
differences are not meaningful.
Returning 304 after the content changed
A stale validator can hide a real update from clients and crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.. Invalidate the
ETag or advance Last-Modified whenever the representation changes, then confirm
the old conditional request receives a fresh 200 and body.
Sending 304 without a matching conditional request
A server should not guess that a client has a cached copy. Return 304 only after
evaluating If-None-Match or If-Modified-Since; an ordinary first request needs a
complete response.
Treating 304 like a redirect or empty page
A 304 has no Location header and no response body. Do not route it through
redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. logic, and do not replace a real empty resource with 304; use the status
that describes the actual response.
Common 304 problems
The server always returns 200
Symptom: repeated requests download the full body even when nothing changed.
Likely cause: the initial response has no validator, or the application ignores
the conditional request headers. Fix: send ETag and/or a valid
Last-Modified, then implement the matching If-None-Match or
If-Modified-Since check. Confirm an unchanged request returns bodyless 304.
Different origin servers produce different ETags
Symptom: the same unchanged URL alternates between 200 and 304 behind a load
balancer. Likely cause: each node generates its own validator. Fix: derive
the ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. from shared content state, not the serving node, and repeat the same
conditional request against several responses.
Updated content still returns 304
Symptom: a browser or crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. keeps an old representation after a deployment.
Likely cause: the validator was not invalidated with the content. Fix: correct
the cache-key or deployment logic, purge the affected cache where needed, and prove
that the old ETag now receives a 200 with a new validator.
Last-Modified appears to be ignored
Symptom: If-Modified-Since never produces a 304. Likely cause: an invalid
HTTP-date, insufficient timestamp precision, or an ETag taking precedence. Fix:
inspect the raw headers, fix the date format, and test each validator separately.
A 304 looks like an error in application code
Symptom: a script or app throws an exception, or logs an “error,” on a request
that actually got a 304. Likely cause: some HTTP client libraries treat any
non-200 status — including a valid 304 — as an exception-like condition unless
you explicitly configure them to follow redirectsA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. or allow not-modified responses;
this is a client-library quirk, not a protocol or server problem. Fix: check
the client library’s handling of 304 specifically (not just its error-handling for
4xx/5xx), and confirm the raw HTTP response is a correct, bodyless 304 before
assuming the server is at fault.
A platform caching layer (e.g., IIS output caching) muddies the picture
Symptom: the origin app looks correct, but 304 behavior still seems wrong. Likely cause: a cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. layer specific to the hosting platform — IIS output caching is one documented example — sits between the app and the client and can generate or intercept 304 responses on its own. Fix: treat this as one possible layer among several (origin app, CDN, load balancer, platform cache), not the default suspect; isolate it with a controlled test that changes the validator at each layer one at a time before concluding which layer is responsible.
Prompt: audit a conditional-request trace
Paste the request and response headers from an initial fetch and a repeat fetch.
Act as an HTTP caching reviewer. I will paste two request/response header traces for
the same URL: an initial fetch and a conditional repeat. Identify the validator used,
check whether If-None-Match or If-Modified-Since was evaluated correctly, verify that
a 304 has no body or Location header, and flag unstable or stale-validator risks.
Return: observed flow, pass/fail checks, likely cause of each failure, and the exact
next request I should run. Do not infer headers that are not present.
[PASTE BOTH TRACES] Prompt: review an ETag implementation
Paste the relevant application, CDN, or server configuration.
Review this ETag/Last-Modified implementation for conditional GET correctness. Trace
the 200 -> conditional request -> 304 path, explain what causes the validator to
change, and test mentally for multiple origin nodes, compression variants, and real
content updates. Separate protocol violations from efficiency issues. Give a minimal
fix and a curl-based validation plan. Do not invent platform behavior.
[PASTE CONFIGURATION OR CODE] Shell: replay an ETag as a conditional request
Run this in a macOS/Linux terminal. Copy the ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. exactly, including quotes.
URL='https://example.com/page'
curl -sS -D - -o /dev/null "$URL"
curl -sS -D - -o /dev/null -H 'If-None-Match: "PASTE_ETAG_HERE"' "$URL"The first response should expose the validator. The second should return 304 when
the representation is unchanged and 200 when the pasted ETag is stale.
PowerShell: test Last-Modified
Run this in PowerShell after replacing the URL and timestamp.
$url = 'https://example.com/page'
$headers = @{ 'If-Modified-Since' = 'Tue, 14 Jul 2026 12:00:00 GMT' }
Invoke-WebRequest -Uri $url -Headers $headers -SkipHttpErrorCheckDevTools Console: list page resource validators
Run this in the browser Console. It reports resource timing entries; use the Network
panel to inspect the actual ETag, Last-Modified, and status headers.
console.table(performance.getEntriesByType('resource').map(r => ({name: r.name, transferSize: r.transferSize, encodedBodySize: r.encodedBodySize}))); Patrick's relevant free tools
- Website Down Checker — Check whether one URL or a small sample is reachable right now from one Cloudflare location, with response timing, redirects, DNS fallback evidence, and connection-status details.
- Googlebot Verifier — Check whether an IP claiming to be Googlebot, Bingbot, GPTBot, ClaudeBot, or another crawler is genuine — published IP ranges plus forward-confirmed reverse DNS, with the real network owner named for spoofers. IPs are checked in memory and never stored.
- Raw vs. Rendered HTML Checker — See what's in your page's initial HTML versus after JavaScript runs — headless-Chrome rendering only when the page actually needs it, a rendering-strategy verdict (SSR / prerendered / CSR / hybrid), ~15 calibrated JavaScript-SEO checks (noindex, canonicals, robots.txt blocking, links, soft 404s), a side-by-side raw-vs-rendered diff, and shareable reports.
Tools for inspecting 304 behavior
- HTTP Header Checker: inspect
ETag,Last-Modified,Cache-Control,Vary, and CDN/edge fingerprints on the normal response before replaying a validator. - Browser DevTools Network panel: disable “Disable cache,” reload, and compare the request/response headers. DevTools also makes HSTSHSTS (HTTP Strict Transport Security) is a response header that tells browsers to always connect to your site over HTTPS — even when a user types or clicks an http:// link — closing the insecure-first-request gap that a plain 301 redirect leaves open. and local-cache behavior visible, so distinguish browser behavior from what the origin sent.
- curl: send an exact
If-None-MatchorIf-Modified-Sinceheader without the browser’s cache state getting in the way. - Access logsLog file analysis is reading a web server's raw access logs to see exactly which URLs search engine crawlers actually requested, when, how often, and what status code they got. Unlike crawl tools or Search Console, logs are the unsampled, ground-truth record of what really happened.: quantify which crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. requests were conditional and whether they
ended in
304or a full200.
Prove conditional responses work after a change
Unchanged-representation test
Test to run: fetch the URL, copy its ETagA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page., then repeat with
curl -I -H 'If-None-Match: "VALUE"' URL. Expected result: 304, the matching
validator, and no body or Location. Failure interpretation: the server ignored
the condition or generated an unstable validator. Monitoring window: immediate.
Rollback trigger: the cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. change causes ordinary requests to lose their
complete 200 response.
Changed-representation test
Test to run: deploy a real content change, then replay the old ETag.
Expected result: 200 with the updated body and a new validator. Failure
interpretation: cache invalidation is stale. Monitoring window: immediately
after the deployment reaches every origin. Rollback trigger: any origin still
returns 304 for the old validator after the rollout is complete.
Multi-origin stability test
Test to run: repeat the same normal and conditional requestsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. enough times to
reach the serving pool, recording the ETag and status. Expected result: unchanged
representations use compatible validators and consistently produce 304.
Failure interpretation: validators vary by node or encoding without a matching
Vary strategy. Monitoring window: immediate, across the deployed pool.
Rollback trigger: the new validator logic serves stale content or mixes
representations between clients.
Measure conditional-cache health
Conditional revalidation success rate
Metric: conditional requestsA conditional request lets a crawler (or browser) ask a server 'has this changed since I last fetched it?' — using If-Modified-Since (checked against your Last-Modified header) and/or If-None-Match (checked against your ETag). If nothing changed, the server replies 304 Not Modified with no body, so the crawler reuses its existing copy instead of re-downloading the page. ending in 304 versus a full 200. What it tells
you: whether unchanged resources avoid unnecessary transfers. How to pull it:
group access-log requests carrying If-None-Match or If-Modified-Since by response
status and URL class. Benchmark / realistic range: establish a baseline by
content type; frequently changing pages should not be forced toward the rate of
static assets. Cadence: weekly during rollout, then monthly.
Bytes avoided on unchanged fetches
Metric: estimated response-body bytes not transferred for valid 304 responses. What it tells you: the bandwidth side of the crawl-efficiency benefit. How to pull it: join 304 log counts to the most recent complete response size for the same URL class. Benchmark / realistic range: compare against the site’s own pre-change baseline; no universal target fits every content mix. Cadence: monthly.
Stale-validator failures
Metric: changed URLs that still accept an old validator. What it tells you: whether efficiency is coming at the cost of freshness. How to pull it: run a small post-deploy sample that replays pre-deploy ETags. Benchmark / realistic range: any confirmed stale response requires investigation. Cadence: every deployment that changes cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. or validator generation.
Test yourself: 304 Not Modified
Five quick questions on what a 304 means and how it works. Pick an answer for each, then check.
304 Not Modified
HTTP 304 Not Modified is the response to a conditional GET/HEAD whose condition evaluates false, in the 3xx class but not a redirect: it has no Location header and no body. It tells a client its cached copy is still valid. For SEO it has no direct ranking effect and no indexing effect beyond a possible signal recalculation, though it can help crawl efficiency indirectly on large sites.
Related: 200 OK, 301 redirect, 204 No Content
304 Not Modified
HTTP 304 Not Modified is the response to a conditional GET or HEAD request whose condition evaluates false and that would otherwise have gotten a 200 (RFC 9110 §15.4.5). It’s in the 3xx (redirection) class by numbering, but it behaves nothing like a redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. — there’s no Location header, no new URL, and no body. The condition is carried by If-None-Match (matched against an ETag) and/or If-Modified-Since (matched against Last-Modified); a “second visit” carrying a saved validator is the typical way that happens, but the rule itself is the conditional request, not the repeat visit. A 304 tells the client, “the copy you already have is still valid — reuse it instead of me sending it again.”
The response is deliberately empty. RFC 9110 is normative on this: “A 304 response is terminated by the end of the header section; it cannot contain content or trailers.” It does still carry the metadata headers that would have accompanied the equivalent 200 OK (such as ETag, Date, Vary, Cache-Control, and Expires) — just without the payload.
For SEO, a 304 has no direct ranking effect, and Google’s own guidance bounds the indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. effect too: Search may still recalculate a URL’s signals, but a 304 otherwise doesn’t change indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.. Google already has the content from the previous crawl; a 304 simply confirms nothing changed, so Google keeps using what it has. The real benefit is resource savings that Google says may indirectly improve crawl efficiency: on large sites with many rarely-changing URLs, letting a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. skip re-downloading and re-processing unchanged pages saves bandwidth and server compute — Google doesn’t promise that saving is automatically reallocated to new or updated URLs. Google’s crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. infrastructure supports the ETag/If-None-Match and Last-Modified/If-Modified-Since mechanisms and recommends ETag as the primary validator. A 304 is not an error, not a redirect, and not something to “fix” — it’s the correct outcome of a working conditional-request setup.
Related: 200 OK, 301 redirect, 204 No Content
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Revision history
Compare the published article with an archived editorial snapshot. Added and removed words are shown only after you open a comparison.
Updated Jul 17, 2026.
Editorial summary and recorded change details.Summary
Re-anchored 304 guidance in RFC conditions and qualified indexing and crawl-efficiency effects.
Change details
-
Added a troubleshooting case for client libraries that surface a valid 304 as an exception-like error.
Try it live
This is a real endpoint on this site — not a simulation.
Hit it from the button, open it in a new tab, or
curl -i it from your terminal, and the server answers with the actual status code this article is about.