Cloudflare Workers SEO
How to make technical SEO changes on Cloudflare Workers — the fetch handler, HTMLRewriter for canonical/hreflang/JSON-LD injection, KV-backed redirects, the Cache API vs edge cache vs Cache-Control, the cloaking boundary, and how Bot Fight Mode can block Googlebot.
1 evidence signal on this page
- Linked source datagooglebot.json
Cloudflare Workers SEO is doing technical SEO on Cloudflare's serverless runtime: a Worker only sees requests its route matches, and every one of those enters one fetch handler where you rewrite the request, the response headers, and the response body. Body rewriting runs through HTMLRewriter — the actual mechanism for injecting a canonical tag, fixing hreflang, or adding JSON-LD without a CMS deploy — and it needs to be idempotent against missing, duplicate, and non-HTML cases. Redirects at scale belong in KV or D1; Bulk Redirects/Rules are simpler for small sets, but pick one owner per URL so systems don't conflict. Three separate things share the word cache — the Workers Cache API, the Cloudflare edge cache, and origin Cache-Control — and conflating them is why an injected tag seems to not show up; diagnose by cache key, layer, TTL, and invalidation. The hard rule is cloaking: apply identical logic for Googlebot and users. The most Workers-specific self-inflicted wound is Bot Fight Mode blocking Googlebot on a pipeline your WAF allow-rules don't even reach. Ship every SEO-affecting change with recorded version metadata and a tested rollback, then verify with GSC URL Inspection and the CF-Cache-Status header. See the Edge SEO hub for the general concept.
TL;DR — Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user. are little programs that run on Cloudflare’s network, in front of your real website. A Worker can add 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., fix a meta tag, or inject a canonical tagA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content. as the page flies past — without touching your CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. or waiting on developers. This page is the hands-on, code-level version of the broader Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. idea: how you actually do it on Workers specifically. The one rule you can’t break: whatever a Worker changes, it has to change for Google and real visitors the same way. Showing Google something different is cloaking.
What a Cloudflare Worker is, in plain terms
If your site is on Cloudflare, every request from a visitor (or from 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.) passes through Cloudflare’s network before it reaches your actual server. A Worker is a small script you can run at that point in the path. It sees the request coming in and the response going out, and it can change either one. Evidence for this claim Cloudflare Workers run code on Cloudflare's network and can inspect or modify requests and responses. Scope: Cloudflare Workers request handling. Confidence: high · Verified: Cloudflare Workers: How Workers works
That’s the whole appeal for SEO: you get to fix things on pages you can’t otherwise edit. Stuck on a locked-down platform? Waiting weeks for a developer to add a canonical tag? A Worker can do it in minutes, live, without a deploy to the site itself.
What people use Workers for in SEO
- Redirects — send old URLs to new ones at the edge, even thousands of them.
- Fixing or adding tags — inject a canonical tagA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content., correct a title, add hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., drop in structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. — all without editing the page’s source.
- Rewriting headers — add or fix things like
X-Robots-Tag.
The rule you cannot break
Whatever your Worker does, it has to do it for everyone. If you show 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. a different page than a real person sees — to game rankings — that’s cloaking, and it’s against Google’s rules. Evidence for this claim Google defines serving materially different content to search engines and users to manipulate rankings as cloaking and a spam-policy violation. Scope: Google Search spam policy; legitimate personalization is context-dependent. Confidence: high · Verified: Google: Spam policies — cloaking The safe pattern is simple: apply the same logic to every request, no matter who’s asking. (The Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. hub covers this rule in depth — this page assumes you already get the concept and want the Cloudflare-specific how-to.)
The two ways to hurt yourself
Most “Cloudflare hurt my SEO” stories aren’t the Worker code at all:
- A botA 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.-blocking setting. Cloudflare’s Bot Fight Mode can accidentally block or challenge Googlebot. If Google can’t fetch your pages, nothing else matters.
- 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. confusion. Cloudflare has more than one kind of cache, and if you don’t know which one you’re touching, a change you shipped can seem to “not show up.”
Want the actual code — a fetch handler, an HTMLRewriter example, a KV redirect
table — plus the caching and bot-blocking details? Switch to the Advanced tab.
TL;DR — A Cloudflare WorkerA serverless function that runs at Cloudflare's global edge, close to every user. only sees requests matched by its configured route, and it intercepts each one in a single
fetchhandler, where you do three things in sequence: rewrite the request, rewrite the response headers, and rewrite the response body viaHTMLRewriter. That’s the real mechanism behind “inject a canonical” or “fix a title” — and it needs to be idempotent, tested against missing, duplicate, and non-HTML responses, not just the happy path. 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. at scale live in KV (fast key lookup) or D1 (relational); Bulk Redirects/Rules cover small sets more simply, and I generally prefer edge-level redirects over server-level — but pick one owner per URL, since a Worker redirect, a Bulk Redirect, and an origin redirect can all fire on the same path. Three different things share the word “cache” — the Workers Cache API (caches.default), the Cloudflare edge cache, and originCache-Control— and confusing them is the usual cause of “my tag didn’t show up”; diagnose staleness by cache key, layer, TTL, and invalidation rather than guessing. Google’s own 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 / 304 guidance is directly actionable for a Worker that owns the response. The cloaking line: identical logic for every requester. The most Workers-specific self-inflicted wound is BotA 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. Fight Mode, which runs outside the WAF Ruleset Engine, so ordinary “allow” rules don’t reach it. Ship every SEO-affecting change with recorded version metadata, a tested rollback, and a stop condition — then verify with GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. andCF-Cache-Status.
What this article is (and isn’t)
This is the practitioner, code-level companion to the Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS.
hub. The hub owns the general definition, the platform comparison table (Workers,
Akamai, Fastly, Lambda@Edge, Vercel, Netlify), the Snippets-vs-Workers decision, and
the full treatment of the cloaking rule. I’m not re-deriving any of that here. This page
goes one level deeper into Cloudflare Workers specifically — the runtime this very site’s
own worker runs on, wired in through run_worker_first in wrangler.toml — with real
APIs rather than “edge compute can inject tags” hand-waving.
A note before the code: Google has no Cloudflare-Workers-specific documentation. The official guidance that governs this (cloaking policy, 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., CDN 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.) is general and applies to any edge implementation. I’d rather say that plainly than imply a Google doc exists that doesn’t.
How a Worker sits in the request/response path
A Worker is a serverless script running on V8 isolates. Every request it’s routed to
enters through a fetch handler. Evidence for this claim A Cloudflare Worker receives HTTP requests through a fetch handler. Scope: Cloudflare Workers handlers. Confidence: high · Verified: Cloudflare Workers: Fetch handler “Routed to” is doing real work in that sentence: a
Worker only sees requests that match its configured
route or custom domain —
everything else never reaches the fetch handler at all. Where two routes could both match
the same URL, the more specific pattern takes precedence, so before you trust a Worker’s
behavior for a given URL, confirm the route actually matches it and check which deployed
version is live on that route (Wrangler environments and gradual rollouts mean the version
serving traffic isn’t always the one in your editor). Inside the handler you can do three
distinct things, in order:
- Rewrite the request before it goes to your origin.
- Rewrite the response headers on the way back out.
- Rewrite the response body — via
HTMLRewriter.
Here’s the minimal shape:
export default {
async fetch(request, env, ctx) {
// 1. (optionally) inspect/modify the request
const response = await fetch(request); // hit the origin
// 2. rewrite headers
const headers = new Headers(response.headers);
headers.set("X-Robots-Tag", "index, follow");
// 3. rewrite the body with HTMLRewriter (see next section)
return new Response(response.body, { ...response, headers });
},
};The SALT.agency team, who coined “edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS.” off Cloudflare Workers research, built their tooling as a filter chain — a request filter, a response filter, and a body filter. That’s the same three-phase pattern; they just named it. Keeping those three phases separate in your head keeps a Worker legible.
Rewriting HTML with HTMLRewriter
HTMLRewriter is Cloudflare’s streaming HTML parser, and it’s the actual API behind every
“inject a tag” trick. Evidence for this claim Cloudflare HTMLRewriter provides selector-based handlers that can transform streamed HTML elements. Scope: Cloudflare Workers HTMLRewriter API. Confidence: high · Verified: Cloudflare Workers: HTMLRewriter You register .on(selector, handler) element
handlers, and the handler gets getAttribute / setAttribute, prepend / append,
setInnerContent, and replace. Because it streams, you’re not buffering the whole
document in memory.
Injecting or fixing a canonical tag
class CanonicalHandler {
constructor(url) { this.url = url; }
element(el) { el.setAttribute("href", this.url); }
}
const rewriter = new HTMLRewriter()
.on('link[rel="canonical"]', new CanonicalHandler("https://example.com/preferred/"));
return rewriter.transform(response);If the page has no canonical at all, you attach a handler to head and append one
instead of editing an existing tag. Either way, remember the lesson from the
canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. side of this:
rel=canonical is a hint, not a command — a Worker lets you set it consistently across a
whole platform, but Google still decides.
The CanonicalHandler above assumes a tag already exists and the response is HTML. Neither
is guaranteed in production, and getting it wrong is how you end up with two canonical tagsA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content.
on one page instead of one. Before you ship a rewrite like this, make it idempotent and test
it against:
- No existing canonical — your handler needs to detect the missing case and
appendone tohead, not silently no-op onlink[rel="canonical"]matching nothing. - A duplicate or malformed canonical already present — decide whether you remove the stray tag or leave your rewrite to add a second one (the latter is a real bug, not an edge case — duplicate canonicals are a common self-inflicted issue).
- A non-HTML response — an API route, an image, or a redirect response passed through the
same Worker shouldn’t be run through
HTMLRewriterat all; scope the transform to routes and content types you’ve actually checked. - Running the transform twice on the same response (a retry, a nested
fetch) — confirm it doesn’t re-append a second tag.
Adding or correcting hreflang alternates
Same mechanism, driven off config. You append one link[rel="alternate"] per locale to
head. If your alternates are per-locale and relational, that config belongs in D1; if it’s
a flat lookup, KV is fine. The point is that HTMLRewriter injects them identically for every
requester — you’re not branching on user agentA user agent is the HTTP request header a client (browser, crawler, or bot) sends to identify itself. For crawlers, a short user-agent token — a substring of that string — is what robots.txt rules actually target..
Injecting JSON-LD structured data
new HTMLRewriter().on("head", {
element(head) {
head.append(
`<script type="application/ld+json">${JSON.stringify(schema)}</script>`,
{ html: true }
);
},
});CPU limits that bite at scale
One competitor claim I’d push back on is “sub-millisecond, no constraints.” The real ceiling
is CPU time: 10 ms on the free plan, 30 ms on paid (wall-clock time waiting on fetch
doesn’t count — CPU time does). For typical rewrites you’ll never notice. For heavy
HTMLRewriter passes over very large pages, it’s a real constraint to design around, not
scaremongering.
Redirects at the edge: KV vs D1 vs Rules
I typically prefer to have redirects on the edge (CDN level) over having them on the server — it offloads the work from your origin and applies before the page is ever generated. On Cloudflare specifically, in my Ahrefs guide to redirects for SEO I laid out that you’ve got several options: single or bulk redirects, redirect rules, page rules, or Workers with key-value pairs — or a Worker that modifies headers to add a redirect.
For a Worker-driven table, KV is the natural home: a fast, eventually-consistent key lookup keyed by URL.
export default {
async fetch(request, env) {
const url = new URL(request.url);
const target = await env.REDIRECTS.get(url.pathname); // KV namespace
if (target) return Response.redirect(target, 301);
return fetch(request);
},
};Reach for D1 when redirects are relational (per-locale, per-segment SQL you want to query). And know when a Worker is overkill: for a small, static set of redirects, Cloudflare’s Bulk Redirects or Redirect Rules are simpler and need no code at all. Don’t hand-roll a KV Worker for fifty redirects.
Pick one owner for a given URL and don’t let a Worker redirect, a Bulk Redirect, a Redirect Rule, and an origin redirect all apply to the same path — they’re separate systems that can each fire on the same request, and when more than one matches, you’re debugging precedence instead of a clean redirect. Before you add a redirect anywhere, check whether one already exists for that path in the other systems, and pick the layer based on match complexity (simple 1:1 vs. pattern-based), scale, and who needs to observe or roll it back — a Worker redirect lives in your code and logs; a Bulk Redirect or Rule lives in the dashboard and is easier for a non-developer to audit or revert.
Caching: three different things, one confusing name
This is the section competitor pages skip, and it’s the one that generates the most “why didn’t my change show up” confusion. Three separate layers share the word cache:
- The Workers Cache API —
caches.defaultandcaches.open(). This is a Worker-scoped programmable cache you read and write in code. - The Cloudflare edge cache — the CDN cache that serves your assets. Distinct from the Cache API.
- Origin
Cache-Control— the headers your origin (or your Worker) sets, which influence both of the above and what 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. does.
Conflate them and you’ll swear a change didn’t deploy when it’s just being served from a layer you didn’t purge.
When a change genuinely isn’t showing up, don’t guess — diagnose it layer by layer:
- Cache key. What request attributes determine whether two requests hit the same cached entry (URL, and sometimes headers or cookies if your cache key includes them)? A rewrite that varies by something not in the cache key can serve the wrong variant.
- Which layer served the response. Check
CF-Cache-Status(HIT/MISS/EXPIRED/DYNAMIC) to see whether the edge cache answered at all, or the request reached your Worker. - Location/state. Cloudflare’s cache is distributed across data centers — a purge or a fresh deploy doesn’t necessarily invalidate every edge location instantly.
- TTL and the rule that set it. Confirm whether a cache rule, a
Cache-Controlheader from your origin, or a header your Worker itself set is controlling the TTL. - Invalidation. Did you purge the specific URL, purge everything, or rely on TTL expiry?
A Worker-owned Cache API entry (
caches.default) needs its own explicitdelete()— purging the CDN cache doesn’t touch it.
What Googlebot does with ETag / If-None-Match / 304
If your Worker generates or rewrites the response, it owns the caching headers — which means
Google’s December 2024 HTTP caching guidance is directly actionable for you. Google supports
heuristic HTTP caching through ETag/If-None-Match and Last-Modified/If-Modified-Since,
strongly recommends ETag
because it’s less error-prone, and says that when 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.’s ETag matches, your server
should return 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. with no body. A response-generating Worker can implement
exactly that: compute an ETag, compare it against If-None-Match, and short-circuit to a 304
itself — saving compute and giving Googlebot a fast, cacheable signal.
The max-age recrawl tradeoff
Google also says to consider setting Cache-Control: max-age to help crawlers decide when to
recrawl. The catch for a Worker that rewrites HTML: an aggressive max-age on a page whose
Worker-injected tags just changed can delay Googlebot from seeing the update you just shipped.
Don’t slap a long cache lifetime on rewritten HTML and forget about it.
The cloaking boundary, applied to Workers
The hard rule, in Workers terms: run the same logic for every requester. Google’s spam policy defines cloaking as presenting different content to users and search engines to manipulate rankings, and specifically calls out inserting text or keywords only when the requester is a search engine.
A couple of clarifications, because people over-correct here:
- Inspecting the User-Agent isn’t automatically cloaking. Logging bot traffic, or serving a cached response faster to any client, is fine. The line is a content difference by requester identity, done to manipulate rankings.
- Page-split A/B testing on Workers is fine. Splitting users by URL and treating every requester the same is legitimate. Splitting by who’s asking — bot vs. human — is not.
A worked example of the safe pattern: this site’s own preview gate is a Worker that 404s any
/preview/ path unless a cookie matches a secret. It returns that 404 to everyone without
the cookie — Googlebot included. That’s precisely the safe shape: it isn’t hiding one thing from
bots and showing another to users; it applies one rule uniformly.
And don’t lean on a bot-only pre-render step even if you build it cleanly on Workers. Google has called dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. a workaround and not a long-term solution; a Worker that pre-renders only for bots inherits that deprecation.
How a Worker can accidentally block or slow Googlebot
This is the most Workers-specific way to shoot yourself in the foot, and it’s usually not in your Worker code.
Bot Fight Mode runs outside the Ruleset Engine
Bot Fight Mode (and Super Bot Fight Mode) can produce false positives against legitimate crawlers, Googlebot included. The trap: Bot Fight Mode is evaluated on a separate pipeline from the WAF Ruleset Engine, so your ordinary WAF “allow” or “skip” custom rules don’t override it. If Bot Fight Mode is challenging Googlebot, you don’t fix it with an allow-rule — you have to change or disable the mode itself. (Confirm the current mechanics against Cloudflare’s Bot Fight Mode and Super Bot Fight Mode docs before you rely on it — bot products change.)
The verified-bots custom rule pattern
Cloudflare exposes a cf.client.bot field and a
verified-bots allow pattern
so you can permit known-good crawlers in your custom rules — useful for the WAF side, though (per
above) it does not reach Bot Fight Mode.
A crawler user-agent string is only a claim. Match the source to the operator's published ranges before granting or denying special treatment.
Spot-check the source IP with my free Googlebot Verifier Free
- Copy the claimed user-agent and source IP from the edge log.
- Compare the IP with the crawler operator’s published ranges instead of trusting the header.
- Apply the verified-bot rule consistently, then compare the final response seen by users and the crawler.
The Googlebot Verifier row lists IP 203.0.113.9, a Googlebot user-agent claim, and a published-range mismatch marked for spot-checking.
The CDN itself is neutral-to-positive
To be clear about the myth: Cloudflare-the-CDN doesn’t hurt SEO. Google’s own 2024
Crawling December
work notes that Google increases crawl rateCrawl rate is how fast a search engine crawler fetches pages from your site — the number of simultaneous requests it makes and the delay between them. Google sets it automatically based on your server's health; it's the supply side of crawl budget, not a ranking factor. when it detects a CDN — but that a CDN can also
accidentally block Googlebot via WAF/bot rules, and that a 503 is better than a bot-verification
interstitial. The risk is a misconfigured Worker or bot setting, not the infrastructure.
Verifying what Googlebot actually received
After any Worker deploy, confirm what a crawler actually got — don’t assume:
- GSC URL Inspection → Test Live URL. Fetches the page as Google and shows the rendered HTML, so you can confirm your injected canonical/hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others./JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. is actually present.
- Check
CF-Cache-Statusalongside the HTML.HIT/MISS/EXPIREDtells you whether you’re looking at a fresh Worker response or a cached one — the fastest way to catch a “change didn’t show up” that’s really a cache-layer issue. - Fetch as Googlebot directly. Request with Googlebot’s user agent and compare — but remember matching the string proves nothing about identity; verify real Googlebot with reverse + forward DNS against Google’s published ranges (see the Scripts tab).
Deployment hygiene specific to Workers
A successful wrangler deploy tells you the script shipped — it doesn’t tell you Googlebot is
getting the right rendered output. Treat every SEO-affecting Worker change as a release with a
record, not just a push:
- Scope your routes. Don’t run a Worker on
/*by default. Match it to the paths it needs in yourwrangler.tomlroute patterns so a bug can’t take down your whole site. - Check current limits before you promise scale. CPU time, subrequest counts, and script size limits vary by plan and change over time — confirm against Cloudflare’s current limits page before you design a rewrite around a specific ceiling, rather than relying on a remembered number.
- Record version metadata for the release. Cloudflare’s versions and deployments model tracks the source version, compatibility date, bindings, and routes for each deploy — note which version is live on which route so a “the Worker is doing X” claim is checkable against what’s actually deployed, not what’s in your editor.
- Version and roll back with Wrangler environments. Ship to a staging environment, gradually roll out by percentage, and keep the ability to revert to the prior version instantly.
- Use scoped logs to monitor the rollout — with their limits in mind. Cloudflare’s Workers Logs and log tailing can support debugging a gradual rollout, but logs are sampled and retained for a limited window — treat them as scoped evidence for the requests they captured, not a complete record of every crawler visit.
- Set a stop condition and test the rollback before you need it. Decide up front what observed behavior (error rate, a wrong response on a spot-check, a crawl-rate drop) halts the rollout, and confirm the rollback path actually works rather than assuming it will.
- Purge cache as part of the deploy. Since three cache layers are in play, make cache purge/invalidation an explicit step of shipping a rewrite, not an afterthought.
A Bing note, and one forward-looking thing
Bing has no Cloudflare/edge-specific guidance either. But because a Worker deploy is instant while crawls aren’t, IndexNow is the natural pairing — fire it the moment a Worker-driven redirect table or tag change ships so Bing (and other participating engines) re-crawl promptly. And worth a glance: Cloudflare shipped edge-enforced canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. as a product feature (“Redirects for AI Training”) — verified AI-training crawlers get a 301 to your canonical URL with one toggle. It’s a useful contrast to hand-rolling canonical logic in your own Worker, and a reminder that “serving crawlers something different from users” is a pattern Microsoft has publicly been skeptical of on Cloudflare’s other AI-crawler features — a good gut check on any bot-conditional Worker.
For the broader picture — the platform comparison, Snippets vs. Workers, the dev-queue and governance angles — head back to the Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. hub.
AI summary
A condensed take on the Advanced version:
- Cloudflare Workers SEOCloudflare Workers SEO is using Cloudflare's serverless V8-isolate runtime — the fetch handler, the HTMLRewriter streaming parser, KV/D1 storage, and the Cache API — to make technical SEO changes (redirects, header and meta-tag rewriting, canonical/hreflang/structured-data injection) at the CDN edge, before a response reaches Googlebot or a user, without deploying to the origin or CMS. = doing technical SEOTechnical SEO is the practice of making a site easy for search engines to crawl, render, index, and (now) be eligible for AI answers. It's the foundation that lets your content and links rank — not a ranking trick of its own. on Cloudflare’s V8-isolate runtime. It’s the code-level, Workers-specific implementation of the general Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. concept — see that hub for the definition, platform comparison, and cloaking depth.
- A Worker only sees what its route matches. Route/domain configuration and precedence decide
which requests reach the
fetchhandler at all — confirm the route and the deployed version before trusting a Worker’s behavior for a URL. - One
fetchhandler, three phases: rewrite the request, rewrite the response headers, rewrite the response body. Body rewriting runs throughHTMLRewriter— the real mechanism for injecting a canonical, fixing hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., or adding JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal.. Make the rewrite idempotent and test it against missing, duplicate, malformed, and non-HTML responses, not just the happy path. - 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.: KV for fast key lookups, D1 for relational config, Bulk Redirects/Rules for small static sets. Patrick prefers edge-level redirects over server-level — but pick one owner per URL; a Worker redirect, Bulk Redirect, Redirect Rule, and origin redirect can all fire on the same path.
- Three caches share one word: the Workers Cache API (
caches.default), the Cloudflare edge cache, and originCache-Control— conflating them causes “my change didn’t show up.” Diagnose it by cache key, layer, TTL, and invalidation rather than guessing. - Google’s 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/304 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. guidance (Dec 2024) is directly actionable: a
response-owning Worker can short-circuit to a 304 itself; but an aggressive
max-agecan delay recrawlCrawl frequency is how often a search engine comes back to re-fetch a page it already knows about. Popular pages that change often get refreshed many times a day; stable pages can go weeks or months between crawls — and you influence it indirectly, not by setting a dial. of a just-changed page. - Cloaking rule: identical logic for every requester. Inspecting the UA isn’t automatically cloaking; a content difference by requester identity to manipulate rankings is.
- Biggest self-inflicted risk: BotA 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. Fight Mode runs outside the WAF Ruleset Engine, so normal allow-rules don’t reach it — you must change the mode itself.
- Ship deliberately: check current plan limits before promising scale, record version metadata (compatibility date, bindings, routes) per release, use scoped logs (sampled, not a complete record) to watch a rollout, and set a stop condition with a tested rollback before you need it.
- Verify with GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL Inspection (Test Live URL) and the
CF-Cache-Statusheader; watch CPU limits (10 ms free / 30 ms paid) on heavy rewrites.
Official documentation
There is no Cloudflare-Workers-specific SEO doc from Google or Bing — the governing guidance is general. The most useful primary sources are split between the search engines (policy/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 Cloudflare (the runtime APIs).
Google (applies to any edge implementation)
- Spam policies — cloaking — the hard boundary any Worker logic must respect.
- Crawling December: HTTP caching (2024) — 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 / 304 / max-age, directly actionable for a response-owning Worker.
- Crawling December: CDNs and crawling (2024) — how a CDN affects crawl rateCrawl rate is how fast a search engine crawler fetches pages from your site — the number of simultaneous requests it makes and the delay between them. Google sets it automatically based on your server's health; it's the supply side of crawl budget, not a ranking factor. and how botA 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. rules can block 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..
- Dynamic rendering (deprecated) — why a bot-only pre-render Worker inherits a deprecated pattern.
- Overview of Google crawlers and fetchers — user agentsA user agent is the HTTP request header a client (browser, crawler, or bot) sends to identify itself. For crawlers, a short user-agent token — a substring of that string — is what robots.txt rules actually target. and published IP ranges for verification.
Cloudflare (the runtime)
- HTMLRewriter — the streaming HTML parser API.
- Cache API —
caches.default/caches.open(). - How the cache works — the Cache API vs. the edge cache.
- Routes and domains — route matching, precedence, and which requests actually invoke a Worker.
- Bulk Redirects — the no-code 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. system a Worker redirect can conflict or overlap with.
- Workers limits — current CPU, subrequest, and script-size ceilings; plan- and date-sensitive, so check it directly rather than trusting a remembered number.
- Versions and deployments — versioned/gradual deploys and rollback.
- Workers Logs — invocation logs, tailing, and their sampling/retention limits.
- Bot Fight Mode / Super Bot Fight Mode — the bot settings that can block 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..
- Allow traffic from verified bots — the
cf.client.botcustom-rule pattern.
Bing — no edge/Workers page exists; IndexNow is the relevant pairing for instant post-deploy re-crawl.
Quotes from the source
On-the-record statements. Each Google link is a deep link that jumps to the quoted passage.
Google — the cloaking boundary
- “Cloaking refers to the practice of presenting different content to users and search engines with the intent to manipulate search rankings and mislead users.” — Google Search Central, Spam policies for Google web search. Jump to quote
- “Inserting text or keywords into a page only when the user agentA user agent is the HTTP request header a client (browser, crawler, or bot) sends to identify itself. For crawlers, a short user-agent token — a substring of that string — is what robots.txt rules actually target. that is requesting the page is a search engine, not a human visitor” — listed as an example of cloaking. Jump to quote
Google — 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. (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, 2024)
- “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 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. response- and If-None-Match request header, and the Last-Modified response- and If-Modified-Since request header.” Jump to quote
- “We strongly recommend using ETag because it’s less prone to errors and mistakes (the value is not structured unlike the Last-Modified value).” Jump to quote
- “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 304HTTP 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. (Not modified) status code with no HTTP body.” Jump to quote
- “While not required, consider also setting the max-age field of the Cache-Control header to help 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. determine when to recrawlCrawl frequency is how often a search engine comes back to re-fetch a page it already knows about. Popular pages that change often get refreshed many times a day; stable pages can go weeks or months between crawls — and you influence it indirectly, not by setting a dial. the specific URL.” Jump to quote
Google — dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. (deprecated)
- “Dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” Jump to quote
Me — on edge-level 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.
- “I typically prefer to have redirects on the edge (CDN-level) over having them on the server.” — from my Ahrefs guide, 11 Types of Redirects & Their SEO Impact. Relayed from my own published article; wording is mine but confirm the exact phrasing against the live page before treating it as a hard quote.
Cloudflare / SALT.agency — why Workers for redirects
- “we needed to implement simple redirects, which should be easy to create on the majority of platforms but wasn’t supported” — Igor Krestov & Dan Taylor, Diving into Technical SEO using Cloudflare Workers (Cloudflare blog). Relayed via summarization of the Cloudflare blog post, not confirmed as an exact substring — re-verify against the live page before using as a hard blockquote.
Which tool for the job?
“I need to add 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..”
- A small, static set (a few dozen, no logic)? → Cloudflare Bulk Redirects or Redirect Rules. No Worker, no code.
- Thousands of URL-keyed redirects? → A Worker + KV lookup.
- Relational (per-locale, per-segment, queried) redirects? → A Worker + D1.
- Need to redirect and rewrite headers in the same pass? → A Worker (Rules can’t do both).
“I need to inject or fix a tag (canonical, hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., title, JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal.).”
- → A Worker with
HTMLRewriter. There’s no no-code Cloudflare product for arbitrary body rewriting; this is Workers’ job.
“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.’s crawl dropped after I added Cloudflare.”
- First suspect BotA 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. Fight Mode / Super Bot Fight Mode, not your Worker. Check whether it’s challenging 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. — and remember a WAF allow-rule won’t fix it; you change the mode itself.
- Then check WAF custom rules and whether a
503/interstitial is being served to bots. - Only then audit the Worker code and route scope.
“My injected tag isn’t showing up.”
- Check
CF-Cache-Status.HIT/EXPIRED? You’re seeing a cached response — purge the right layer (Workers Cache API vs. edge cache) and re-test. MISSand still wrong? Now it’s your Worker logic or route scope. Confirm with GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version..
“Should I pre-render only for bots on a Worker?”
- → No. That’s dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., which Google has deprecated. Prefer SSR/static renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. applied to everyone.
Cloudflare Workers SEO checklist
Before you ship a rewrite Worker
- Route is scoped to the paths it needs in
wrangler.toml— not/*by reflex — and you’ve confirmed which deployed version is actually live on that route. - The Worker applies identical logic to every requester (no botA 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.-vs-human content branch).
-
HTMLRewriterhandlers are idempotent and tested against a missing tag, a duplicate/malformed existing tag, and a non-HTML response — not just the happy path. - For 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., you’ve picked the right tool: Bulk Redirects/Rules (small/static), KV (URL-keyed at scale), or D1 (relational) — and confirmed no other redirect system already owns that URL.
- Current plan limits (CPU, subrequests, script size) were checked directly, not remembered.
-
Cache-Controlon rewritten HTML isn’t so aggressive it delays recrawlCrawl frequency is how often a search engine comes back to re-fetch a page it already knows about. Popular pages that change often get refreshed many times a day; stable pages can go weeks or months between crawls — and you influence it indirectly, not by setting a dial. of changed pages. - Version metadata (compatibility date, bindings, routes) is recorded for the release, with a tested rollback path and a defined stop condition for the rollout.
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. sanity
- You know which of the three layers (Workers Cache API / edge cache / origin
Cache-Control) you’re touching. - If the Worker owns the response, it sets a correct
ETagand can short-circuit to304. - Cache purge/invalidation is an explicit step in the deploy.
Bot access
- Bot Fight Mode / Super Bot Fight Mode isn’t challenging 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. (checked directly — a WAF allow-rule does not override it).
- Verified-bots custom rule (
cf.client.bot) is in place if you gate on the WAF side. - Bots get a
503, not a verification interstitial, when you need to slow them.
Verify after deploy
- GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → Test Live URL confirms the injected tag is in the rendered HTML.
-
CF-Cache-Statuschecked (HIT/MISS/EXPIRED) so you know if you’re seeing a cached copy. - IndexNowIndexNow is an open push protocol that lets you instantly tell participating search engines (Bing, Yandex, Naver, Seznam, and Yep) which URLs you've added, changed, or removed via a simple HTTP request — and one submission is shared across all of them. Google does not use it. fired (Bing/others) if a redirect table or tag change just shipped.
- Versioned via Wrangler environments with a tested rollback path.
The mental models
1. One handler, three phases.
Every Worker is a fetch handler, and everything you do lives in one of three phases in order:
rewrite the request → rewrite the response headers → rewrite the response body
(HTMLRewriter). Locate what you’re changing in that sequence before you write a line.
2. “Cache” is three things, not one.
Workers Cache API (caches.default) ≠ Cloudflare edge cache ≠ origin Cache-Control. When a change
“doesn’t show up,” ask which layer you’re actually looking at before you touch the code.
3. The cloaking test: identity vs. logic. Branching on who’s asking to change content = cloaking. Applying the same logic to everyone — even if that logic inspects the UA for logging or speed — is fine. Ask: “would a real user get exactly what 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. got?”
4. The blame order for a crawl drop. BotA 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. Fight Mode → WAF rules → Worker code → route scope. The bot settings run on a pipeline your allow rules don’t reach, so suspect them first.
5. The Worker owns the response — so it owns 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. semantics.
If your Worker generates or rewrites the body, it’s responsible for ETag, 304, and max-age.
That’s a capability (short-circuit a 304 yourself) and a liability (over-cache and delay recrawlCrawl frequency is how often a search engine comes back to re-fetch a page it already knows about. Popular pages that change often get refreshed many times a day; stable pages can go weeks or months between crawls — and you influence it indirectly, not by setting a dial.).
Cloudflare Workers SEO — cheat sheet
Pick the 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. tool
| Situation | Use |
|---|---|
| A few dozen static redirects | Bulk Redirects / Redirect Rules (no code) |
| Thousands, keyed by URL | Worker + KV |
| Relational / per-locale, queried | Worker + D1 |
| Redirect and rewrite headers together | Worker |
The three caches
| Layer | What it is | You touch it via |
|---|---|---|
| Workers Cache API | Programmable, Worker-scoped | caches.default, caches.open() |
| Cloudflare edge cache | The CDN cache | cache rules / purge |
Origin Cache-Control | Response headers | your origin or your Worker |
HTMLRewriter handler API
getAttribute/setAttribute— read/set a tag attribute (e.g., canonicalhref)prepend/append— add markup inside an element (e.g., a tag intohead)setInnerContent— replace an element’s contentsreplace— swap the element entirely
Fast facts
- CPU limit: 10 ms free / 30 ms paid (wall-clock
fetchwaits don’t count). - Cloaking = content difference by requester identity to manipulate rankings — not “the Worker read the UA.”
- BotA 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. Fight Mode runs outside the WAF Ruleset Engine — allow-rules don’t reach it; change the mode.
- Verify a Worker change: GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. Test Live URL +
CF-Cache-Statusheader. - Google recommends
ETag; matching 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. → return 304 with no body.
Verify what Googlebot actually got — after a Worker deploy
Fetch as 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. and diff (shell)
# Fetch as a normal browser
curl -sS -A "Mozilla/5.0" https://example.com/page/ -o user.html -D user.headers
# Fetch as Googlebot's UA
curl -sS -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/page/ -o bot.html -D bot.headers
# The bodies should be identical — a diff is a cloaking red flag
diff user.html bot.html && echo "identical (good)"
# Check what cache layer served it
grep -i "cf-cache-status" bot.headers # HIT / MISS / EXPIREDConfirm real 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. (UA strings are trivially spoofed) — reverse + forward DNS
# 1) Reverse DNS the IP from your logs — must end in googlebot.com / google.com
host 66.249.66.1
# 2) Forward DNS that hostname back — must resolve to the same IP
host crawl-66-249-66-1.googlebot.comIf either check fails, it isn’t Googlebot. You can also match against Google’s published googlebot.json ranges.
Read the injected tags out of the rendered HTML (DevTools console)
// Paste into the browser console on the live page to confirm your Worker's injection
[...document.querySelectorAll('link[rel="canonical"]')].map(l => l.href);
[...document.querySelectorAll('link[rel="alternate"][hreflang]')]
.map(l => `${l.hreflang} -> ${l.href}`);
[...document.querySelectorAll('script[type="application/ld+json"]')].map(s => s.textContent);A minimal 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. / 304 short-circuit inside a Worker
export default {
async fetch(request, env, ctx) {
const res = await fetch(request);
const body = await res.text();
const etag = `"${await sha1(body)}"`; // your hash of choice
if (request.headers.get("If-None-Match") === etag) {
return new Response(null, { status: 304 }); // no body, per Google's guidance
}
const headers = new Headers(res.headers);
headers.set("ETag", etag);
return new Response(body, { ...res, headers });
},
}; Patrick's relevant free tools
- Redirect Chain Mapper — Trace every hop of a redirect chain — status codes, what changed at each step (HTTPS, www, slash, domain, path), a severity verdict, meta-refresh detection, and cleanup rules exportable for Cloudflare, .htaccess, and nginx. Single URL or batch of 8.
- HTTP Status & Redirect Checker — Paste up to 500 URLs — status codes, full redirect chains, final destinations, per-hop and total latency, response-header evidence, canonical checks, and redirect-system clues. Filter, compare snapshots, and export CSV. No signup, nothing stored.
- Redirect Checker — Check where a URL redirects — final status code, every hop in the chain, and the destination — for one URL or a quick batch. A fast, no-frills redirect checker; for per-hop cleanup rules use the Redirect Chain Mapper, and for hundreds of URLs use the Bulk HTTP Status Code Checker.
Tools for building and verifying Workers SEO
- Wrangler — Cloudflare’s CLI for developing, versioning, and deploying Workers (route scoping, environments, rollback, secrets). This is where deployment hygiene lives.
- HTMLRewriter — the built-in streaming HTML parser; the API for all body rewriting.
- Workers KV / D1 — the storage for 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. tables and config (KV for key lookups, D1 for SQL).
- GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → Test Live URL — fetches and renders the page as Google so you can confirm an injected canonical/hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others./JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. actually landed.
CF-Cache-Statusheader (viacurl -Ior DevTools Network) — tells youHIT/MISS/EXPIREDso you know whether you’re looking at a cached copy or a fresh Worker response.- IndexNowIndexNow is an open push protocol that lets you instantly tell participating search engines (Bing, Yandex, Naver, Seznam, and Yep) which URLs you've added, changed, or removed via a simple HTTP request — and one submission is shared across all of them. Google does not use it. — ping Bing and other participating engines the instant a Worker-driven change ships.
- Server log analysis — the ground truth for whether real (verified) 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. is reaching your Worker’s routes at all.
Audit a Worker for SEO consistency and cache behavior
Review this Cloudflare Worker fetch handler as an SEO edge change. Trace the request,
response-header, body-rewrite, redirect, and caching paths. Return:
1. Every branch based on user agent, bot status, cookie, geography, or request header
2. Whether Googlebot/no-cookie traffic can receive different indexable content or SEO tags
3. HTMLRewriter selectors that fail when a tag is missing or create duplicates
4. Redirect lookups that can chain, loop, or fall through unexpectedly
5. Each use of the Cache API, Cloudflare edge cache behavior, and origin Cache-Control—kept as separate layers
6. Cache keys that could mix variants or preserve a stale canonical/robots/header change
7. A minimal test matrix for users, verified bots, cache hit/miss, and representative URLs
Apply the same content and SEO logic to bots and users. Flag intentional personalization
for human review rather than calling it cloaking automatically. Do not invent Cloudflare
settings, bindings, routes, cache rules, or origin behavior that are not in my input.
Worker code, bindings, routes, and relevant cache/security configuration:
[PASTE INPUT] Review an HTMLRewriter change before deployment
Audit this HTMLRewriter implementation for one SEO task: [CANONICAL / HREFLANG / JSON-LD].
Check whether it handles existing, missing, and duplicate elements; produces valid absolute
URLs or JSON; applies to the intended route cohort; and behaves identically for every
requester. Then return corrected code plus raw-response and rendered-response tests.
Do not add product, organization, locale, URL, or schema facts that are not supplied.
Code and expected per-route output:
[PASTE INPUT] Test yourself: Cloudflare Workers SEO
Five quick questions on doing technical SEOTechnical SEO is the practice of making a site easy for search engines to crawl, render, index, and (now) be eligible for AI answers. It's the foundation that lets your content and links rank — not a ranking trick of its own. with Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user.. Pick an answer for each, then check.
Resources worth your time
My related writing
- 11 Types of Redirects & Their SEO Impact (Ahrefs) — the 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. options on Cloudflare, and why I prefer edge-level redirects over server-level.
- The Beginner’s Guide to Technical SEO (Ahrefs) — where edge changes fit in the wider picture.
- JavaScript SEO Issues & Best Practices (Ahrefs) — the renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. side, relevant to any pre-render-on-the-edge temptation.
My speaking
- Fine-Tune your Technical SEO, Page Speed, and Security (Marketing Speak interview) — where I walk through using Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user. to rewrite before the user ever sees the page, and offloading redirects to the CDN. Spoken-word interview transcript; treat specific phrasings as paraphrase rather than exact quotes.
From around the industry
- Diving into Technical SEO using Cloudflare Workers — Igor Krestov (SALT.agency) & Dan Taylor on the Cloudflare blog; the origin of the filter-chain (request/response/body) pattern.
- What is edge SEO? (Search Engine Land) — the concept this article’s parent hub covers, in third-party form.
- Edge SEO (Dan Taylor) — from the person who coined the term off Cloudflare Workers research.
- HTMLRewriter (Cloudflare docs) — the canonical reference for the body-rewriting API.
- How the cache works (Cloudflare docs) — untangles the Cache API from the edge cache.
- Redirects for AI Training (Cloudflare blog) — edge-enforced canonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. as a product feature, a useful contrast to hand-rolling it in a Worker.
Go deeper / sideways
- Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. — the parent hub: general concept, platform comparison, Snippets vs. Workers, the cloaking rule in full.
Cloudflare Workers SEO
Cloudflare Workers SEO is using Cloudflare's serverless V8-isolate runtime — the fetch handler, the HTMLRewriter streaming parser, KV/D1 storage, and the Cache API — to make technical SEO changes (redirects, header and meta-tag rewriting, canonical/hreflang/structured-data injection) at the CDN edge, before a response reaches Googlebot or a user, without deploying to the origin or CMS.
Related: Edge SEO, Canonicalization
Cloudflare Workers SEO
Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user. SEO is the practice of using Cloudflare Workers — a serverless runtime built on V8 isolates — to apply technical SEOTechnical SEO is the practice of making a site easy for search engines to crawl, render, index, and (now) be eligible for AI answers. It's the foundation that lets your content and links rank — not a ranking trick of its own. changes at the CDN edge instead of at the origin server or CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms.. It’s the most common concrete implementation of the broader edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. idea, because Workers is the most mature and widely adopted serverless edge platform for this use case.
Every request a Worker sees enters through a single fetch handler, and inside it you can do three things in sequence: rewrite the request, rewrite the response headers, and rewrite the response body. Body rewriting — injecting a canonical tagA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content., correcting hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., adding JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal., fixing a title — runs through HTMLRewriter, Cloudflare’s streaming HTML parser. 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. at scale usually live in KV (fast key lookups) or D1 (relational config), and the Workers Cache API (caches.default) is a distinct layer from the Cloudflare edge cache and from origin Cache-Control headers.
The one hard rule is cloaking: whatever a Worker does, it must do identically for 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. and real users — you can’t serve different content by requester identity to manipulate rankings. The most Workers-specific way to hurt yourself isn’t the Worker code at all; it’s BotA 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. Fight Mode or a misconfigured WAF rule silently blocking or slowing 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. before your Worker logic even runs. For the general concept, the cloaking rule, and the cross-platform comparison, see the Edge SEOEdge SEO (serverless SEO) is the practice of making technical SEO changes — redirects, meta tags, canonicals, hreflang, robots.txt, structured data — at the CDN/edge worker layer before the response reaches the user or crawler, instead of editing the origin server or CMS. hub; this term covers the Workers-specific mechanics.
Related: Edge SEO, Canonicalization
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
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Deepened the request-path, redirect-ownership, HTMLRewriter safety, cache-diagnosis, and release-discipline sections with route precedence, idempotency testing, and rollout controls grounded in current Cloudflare docs.
Change details
-
Added route matching/precedence and deployed-version scope to the fetch-handler explanation, with idempotency and edge-case testing guidance (missing/duplicate/malformed/non-HTML) for the HTMLRewriter canonical example.
-
Added redirect-owner precedence guidance (Worker, Bulk Redirect, Redirect Rule, and origin can all fire on one path), an explicit cache-diagnosis sequence (key, layer, location, TTL, invalidation), and expanded deployment hygiene with plan-limit checks, version metadata, scoped-log caveats, and a tested rollback/stop condition.
Full comparison unavailable — no prior snapshot was archived for this revision.