SEO técnico con Cloudflare Workers

Cómo aplicar cambios de SEO técnico con Cloudflare Workers mediante el controlador fetch, HTMLRewriter, redirecciones en KV, las distintas capas de caché y controles que evitan cloaking o bloqueos accidentales de Googlebot.

Publicado por primera vez: 3 jul 2026 · Última actualización: 8 ago 2026 · Avanzado
Idiomas
1 señal de evidencia en esta página

Hacer SEO con Cloudflare Workers significa modificar solicitudes y respuestas en el entorno serverless de Cloudflare. Un Worker solo procesa las rutas que le corresponden y concentra la lógica en un controlador fetch. HTMLRewriter permite insertar una etiqueta canonical, corregir hreflang o añadir JSON-LD sin desplegar el CMS, pero la transformación debe ser idempotente y cubrir HTML ausente, duplicado, malformado o inexistente. Para muchas redirecciones conviene KV o D1; para conjuntos pequeños pueden bastar Bulk Redirects o Redirect Rules, siempre con un único responsable por URL. La API Cache de Workers, la caché perimetral y Cache-Control son capas distintas: diagnostícalas por clave, ubicación, TTL e invalidación. La lógica debe ser idéntica para Googlebot y para las personas, y Bot Fight Mode puede bloquear al rastreador antes de que actúen determinadas reglas del WAF. Registra la versión de cada cambio, prepara una reversión y verifica el resultado con la inspección de URLs de GSC y CF-Cache-Status.

TL;DR — Un Cloudflare Worker solo ve las solicitudes que coinciden con la ruta que tiene configurada, y las intercepta una a una en un único handler fetch, donde se hacen tres cosas en secuencia: reescribir la solicitud, reescribir las cabeceras de la respuesta y reescribir el cuerpo de la respuesta mediante HTMLRewriter. Ese es el mecanismo real detrás de “inyectar una canónica” o “corregir un título”, y necesita ser idempotente y estar probado frente a respuestas con la etiqueta ausente, duplicada y frente a respuestas que no son HTML, no solo frente al camino feliz. Las redirecciones a escala viven en KV (búsqueda rápida por clave) o en D1 (relacional); Bulk Redirects/Rules cubren conjuntos pequeños de forma más simple, y en general prefiero las redirecciones a nivel de edge frente a las de nivel de servidor, pero elija un único responsable por URL, ya que una redirección de Worker, un Bulk Redirect y una redirección de origen pueden dispararse todas en la misma ruta. Tres cosas distintas comparten la palabra “caché” —la Cache API de Workers (caches.default), la caché del edge de Cloudflare y el Cache-Control del origen— y confundirlas es la causa habitual de “mi etiqueta no aparece”; diagnostique la obsolescencia por clave de caché, capa, TTL e invalidación en lugar de adivinar. La propia guía de Google sobre ETag / If-None-Match / 304 es directamente accionable para un Worker que es dueño de la respuesta. La línea del cloaking: lógica idéntica para cada solicitante. La herida autoinfligida más específica de Workers es el Bot Fight Mode, que se ejecuta fuera del WAF Ruleset Engine, así que las reglas de “allow” ordinarias no lo alcanzan. Publique cada cambio que afecte al SEO con metadatos de versión registrados, un rollback probado y una condición de parada, y después verifique con la herramienta de inspección de URL de GSC y CF-Cache-Status.

Qué es este artículo (y qué no)

Este es el complemento práctico, a nivel de código, del hub de Edge SEO. El hub es el propietario de la definición general, de la tabla comparativa de plataformas (Workers, Akamai, Fastly, Lambda@Edge, Vercel, Netlify), de la decisión entre Snippets y Workers, y del tratamiento completo de la regla del cloaking. No voy a volver a deducir nada de eso aquí. Esta página baja un nivel más hacia Cloudflare Workers en concreto —el runtime sobre el que se ejecuta el propio worker de este mismo sitio, conectado mediante run_worker_first en wrangler.toml— con APIs reales en lugar de vaguedades del tipo “el edge computing puede inyectar etiquetas”.

Una nota antes del código: Google no tiene documentación específica de Cloudflare Workers. La guía oficial que rige esto (política de cloaking, caché HTTP, rastreo con CDN) es general y se aplica a cualquier implementación en el edge. Prefiero decirlo con claridad antes que dar a entender que existe un documento de Google que no existe.

Cómo se sitúa un Worker en el recorrido de solicitud/respuesta

Un Worker es un script serverless que se ejecuta sobre isolates de V8. Cada solicitud que se le enruta entra por un handler fetch. 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 “Que se le enruta” hace un trabajo real en esa frase: un Worker solo ve las solicitudes que coinciden con su ruta o dominio personalizado configurado; todo lo demás nunca llega al handler fetch. Cuando dos rutas podrían coincidir con la misma URL, tiene precedencia el patrón más específico, así que antes de confiar en el comportamiento de un Worker para una URL dada, confirme que la ruta realmente coincide con ella y compruebe qué versión desplegada está activa en esa ruta (los entornos de Wrangler y los despliegues graduales hacen que la versión que sirve el tráfico no siempre sea la que tiene en su editor). Dentro del handler puede hacer tres cosas distintas, en este orden:

  1. Reescribir la solicitud antes de que llegue a su origen.
  2. Reescribir las cabeceras de la respuesta en el camino de vuelta.
  3. Reescribir el cuerpo de la respuesta, mediante HTMLRewriter.

Esta es la forma mínima:

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 });
  },
};

El equipo de SALT.agency, que acuñó el término “edge SEO” a partir de su investigación sobre Cloudflare Workers, construyó sus herramientas como una cadena de filtros: un filtro de solicitud, un filtro de respuesta y un filtro de cuerpo. Es ese mismo patrón de tres fases; simplemente le pusieron nombre. Mantener esas tres fases separadas en la cabeza hace que un Worker resulte legible.

Reescribir HTML con HTMLRewriter

HTMLRewriter es el analizador de HTML en streaming de Cloudflare, y es la API real detrás de cada truco de “inyectar una etiqueta”. 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 Se registran handlers de elemento con .on(selector, handler), y el handler recibe getAttribute / setAttribute, prepend / append, setInnerContent y replace. Como funciona en streaming, no está almacenando todo el documento en memoria.

Inyectar o corregir una etiqueta canónica

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);

Si la página no tiene ninguna canónica, se adjunta un handler a head y se hace append de una en lugar de editar una etiqueta existente. En cualquier caso, recuerde la lección del lado de la canonicalización de esto: rel=canonical es una sugerencia, no una orden; un Worker permite establecerla de forma coherente en toda una plataforma, pero Google sigue decidiendo.

El CanonicalHandler anterior da por hecho que ya existe una etiqueta y que la respuesta es HTML. Ninguna de las dos cosas está garantizada en producción, y equivocarse en esto es como se acaba con dos etiquetas canónicas en una página en lugar de una. Antes de publicar una reescritura así, hágala idempotente y pruébela frente a:

  • Ninguna etiqueta canonical existente — su controlador necesita detectar el caso ausente y hacer append de una en head, no quedarse sin hacer nada en silencio porque link[rel="canonical"] no coincide con nada.
  • Una etiqueta canonical duplicada o malformada ya presente — decida si elimina la etiqueta sobrante o deja que su reescritura añada una segunda (esto último es un error real, no un caso límite: las etiquetas canonical duplicadas son un problema autoinfligido habitual).
  • Una respuesta que no es HTML — una ruta de API, una imagen o una respuesta de redirección que pase por el mismo Worker no debería pasar por HTMLRewriter en absoluto; limite la transformación a las rutas y tipos de contenido que haya comprobado realmente.
  • Ejecutar la transformación dos veces sobre la misma respuesta (un reintento, un fetch anidado) — confirme que no vuelve a añadir una segunda etiqueta.

Añadir o corregir alternativas hreflang

El mismo mecanismo, gobernado por la configuración. Se añade un link[rel="alternate"] por cada locale a head. Si sus alternativas son por locale y relacionales, esa configuración pertenece a D1; si es una búsqueda plana, KV está bien. La cuestión es que HTMLRewriter las inyecta de forma idéntica para cada solicitante: no está ramificando según el agente de usuario.

Inyectar datos estructurados JSON-LD

new HTMLRewriter().on("head", {
  element(head) {
    head.append(
      `<script type="application/ld+json">${JSON.stringify(schema)}</script>`,
      { html: true }
    );
  },
});

Límites de CPU que aprietan a escala

Una afirmación de la competencia que rebatiría es la de “submilisegundo, sin restricciones”. El techo real es el tiempo de CPU: 10 ms en el plan gratuito, 30 ms en los de pago (el tiempo de reloj esperando a fetch no cuenta; el tiempo de CPU sí). Para reescrituras típicas nunca lo notará. Para pasadas pesadas de HTMLRewriter sobre páginas muy grandes, es una restricción real que hay que tener en cuenta en el diseño, no alarmismo.

Redirecciones en el edge: KV frente a D1 frente a Rules

Normalmente prefiero tener las redirecciones en el edge (a nivel de CDN) antes que tenerlas en el servidor: descarga el trabajo de su origen y se aplica antes de que la página llegue a generarse. En Cloudflare en concreto, en mi guía de Ahrefs sobre redirecciones para SEO expuse que hay varias opciones: redirecciones individuales o masivas, redirect rules, page rules, o Workers con pares clave-valor, o un Worker que modifica cabeceras para añadir una redirección.

Para una tabla gestionada por un Worker, KV es el hogar natural: una búsqueda de clave rápida y eventualmente consistente, indexada por 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);
  },
};

Recurra a D1 cuando las redirecciones sean relacionales (SQL por locale, por segmento, que quiera consultar). Y sepa cuándo un Worker es excesivo: para un conjunto pequeño y estático de redirecciones, los Bulk Redirects de Cloudflare o las Redirect Rules son más simples y no necesitan nada de código. No se fabrique a mano un Worker con KV para cincuenta redirecciones.

Elija un único responsable para una URL dada y no deje que una redirección de Worker, un Bulk Redirect, una Redirect Rule y una redirección de origen se apliquen todos a la misma ruta: son sistemas separados que pueden dispararse cada uno en la misma solicitud, y cuando coincide más de uno, acaba depurando precedencias en lugar de tener una redirección limpia. Antes de añadir una redirección en cualquier sitio, compruebe si ya existe una para esa ruta en los otros sistemas, y elija la capa según la complejidad de la coincidencia (1:1 simple frente a basada en patrones), la escala y quién necesita observarla o revertirla: una redirección de Worker vive en su código y en sus logs; un Bulk Redirect o una Rule vive en el panel y es más fácil de auditar o revertir para alguien que no programa.

Caché: tres cosas distintas, un nombre confuso

Esta es la sección que las páginas de la competencia se saltan, y es la que genera más confusión del tipo “por qué no apareció mi cambio”. Tres capas distintas comparten la palabra caché:

  • La Cache API de Workerscaches.default y caches.open(). Es una caché programable de ámbito Worker que se lee y se escribe desde el código.
  • La caché del edge de Cloudflare — la caché de CDN que sirve sus recursos. Distinta de la Cache API.
  • El Cache-Control del origen — las cabeceras que establece su origen (o su Worker), que influyen en las dos anteriores y en lo que hace Googlebot.

Confúndalas y jurará que un cambio no se desplegó cuando en realidad se está sirviendo desde una capa que no purgó.

Cuando un cambio realmente no aparece, no adivine: diagnostíquelo capa por capa:

  1. Clave de caché. ¿Qué atributos de la solicitud determinan si dos solicitudes alcanzan la misma entrada en caché (la URL y, a veces, cabeceras o cookies si su clave de caché las incluye)? Una reescritura que varía según algo que no está en la clave de caché puede servir la variante equivocada.
  2. Qué capa sirvió la respuesta. Compruebe CF-Cache-Status (HIT/MISS/EXPIRED/DYNAMIC) para ver si respondió siquiera la caché del edge o si la solicitud llegó a su Worker.
  3. Ubicación/estado. La caché de Cloudflare está distribuida entre centros de datos: una purga o un despliegue nuevo no invalida necesariamente cada ubicación del edge al instante.
  4. TTL y la regla que lo estableció. Confirme si el TTL lo controla una regla de caché, una cabecera Cache-Control de su origen o una cabecera que estableció el propio Worker.
  5. Invalidación. ¿Purgó la URL concreta, purgó todo o se apoyó en la expiración del TTL? Una entrada de la Cache API gestionada por el Worker (caches.default) necesita su propio delete() explícito: purgar la caché de la CDN no la toca.

Qué hace Googlebot con ETag / If-None-Match / 304

Si su Worker genera o reescribe la respuesta, es dueño de las cabeceras de caché, lo que significa que la guía de caché HTTP de Google de diciembre de 2024 es directamente accionable para usted. Google admite el almacenamiento en caché HTTP heurístico mediante ETag/If-None-Match y Last-Modified/If-Modified-Since, recomienda encarecidamente ETag porque es menos propenso a errores, y dice que cuando el ETag del rastreador coincide, su servidor debería devolver un 304 Not Modified sin cuerpo. Un Worker que genera la respuesta puede implementar exactamente eso: calcular un ETag, compararlo con If-None-Match y cortocircuitar él mismo a un 304, ahorrando cómputo y dando a Googlebot una señal rápida y cacheable.

El compromiso entre max-age y el nuevo rastreo

Google también dice que se plantee establecer Cache-Control: max-age para ayudar a los rastreadores a decidir cuándo volver a rastrear. La pega para un Worker que reescribe HTML: un max-age agresivo en una página cuyas etiquetas inyectadas por el Worker acaban de cambiar puede retrasar que Googlebot vea la actualización que acaba de publicar. No le ponga una vida de caché larga al HTML reescrito y se olvide.

La frontera del cloaking, aplicada a Workers

La regla dura, en términos de Workers: ejecute la misma lógica para cada solicitante. La política de spam de Google define el cloaking como presentar contenido distinto a usuarios y motores de búsqueda para manipular las posiciones, y señala específicamente insertar texto o palabras clave solo cuando quien solicita es un motor de búsqueda.

Un par de aclaraciones, porque aquí la gente sobrecorrige:

  • Inspeccionar el agente de usuario no es automáticamente cloaking. Registrar el tráfico de bots, o servir una respuesta cacheada más rápido a cualquier cliente, está bien. La línea está en una diferencia de contenido según la identidad de quien solicita, hecha para manipular los rankings.
  • Las pruebas A/B por división de páginas en Workers están bien. Dividir a los usuarios por URL y tratar igual a cada solicitante es legítimo. Dividir según quién pregunta —bot frente a humano— no lo es.

Un ejemplo práctico del patrón seguro: la propia puerta de preview de este sitio es un Worker que devuelve un 404 en cualquier ruta /preview/ salvo que una cookie coincida con un secreto. Devuelve ese 404 a todo el mundo que no tenga la cookie, Googlebot incluido. Esa es exactamente la forma segura: no está ocultando una cosa a los bots y mostrando otra a los usuarios; aplica una única regla de manera uniforme.

Y no se apoye en un paso de prerenderizado solo para bots, aunque lo construya de forma limpia sobre Workers. Google ha calificado el renderizado dinámico como una solución provisional y no una solución a largo plazo; un Worker que prerenderiza solo para bots hereda esa obsolescencia.

Cómo un Worker puede bloquear o ralentizar a Googlebot sin querer

Esta es la manera más específica de Workers de dispararse en el pie, y normalmente no está en el código de su Worker.

El Bot Fight Mode se ejecuta fuera del Ruleset Engine

Bot Fight Mode (y Super Bot Fight Mode) puede producir falsos positivos contra rastreadores legítimos, Googlebot incluido. La trampa: el Bot Fight Mode se evalúa en una cadena separada de la del WAF Ruleset Engine, así que sus reglas personalizadas ordinarias de “allow” o “skip” en el WAF no lo anulan. Si el Bot Fight Mode está desafiando a Googlebot, no lo arregla con una regla de allow: tiene que cambiar o desactivar el modo en sí. (Confirme la mecánica actual con la documentación de Cloudflare sobre Bot Fight Mode y Super Bot Fight Mode antes de fiarse de ello: los productos de bots cambian.)

El patrón de regla personalizada para bots verificados

Cloudflare expone un campo cf.client.bot y un patrón de allow para bots verificados para que pueda permitir rastreadores conocidos y legítimos en sus reglas personalizadas: útil para el lado del WAF, aunque (según lo anterior) no alcanza al Bot Fight Mode.

La propia CDN es neutra o positiva

Para dejar claro el mito: Cloudflare como CDN no perjudica el SEO. El propio trabajo de 2024 de Google en Crawling December señala que Google aumenta la frecuencia de rastreo cuando detecta una CDN, pero también que una CDN puede bloquear accidentalmente a Googlebot mediante reglas de WAF o de bots, y que un 503 es mejor que un intersticial de verificación de bots. El riesgo es un Worker o una configuración de bots mal configurados, no la infraestructura.

Verificar qué recibió realmente Googlebot

Después de cualquier despliegue de un Worker, confirme qué obtuvo realmente un rastreador; no lo dé por hecho:

  • Inspección de URL de GSC → Probar URL publicada. Obtiene la página como Google y muestra el HTML renderizado, para que pueda confirmar que su canónica/hreflang/JSON-LD inyectados están realmente presentes.
  • Compruebe CF-Cache-Status junto con el HTML. HIT / MISS / EXPIRED le dice si está viendo una respuesta fresca del Worker o una cacheada: la forma más rápida de detectar un “el cambio no apareció” que en realidad es un problema de capa de caché.
  • Haga la petición como Googlebot directamente. Solicite con el agente de usuario de Googlebot y compare, pero recuerde que hacer coincidir la cadena no prueba nada sobre la identidad; verifique al Googlebot real con DNS inverso y directo contra los rangos publicados de Google (véase la pestaña Scripts).

Higiene de despliegue específica de Workers

Un wrangler deploy correcto le dice que el script se publicó; no le dice que Googlebot esté recibiendo la salida renderizada correcta. Trate cada cambio de Worker que afecte al SEO como una release con registro, no como un simple push:

  • Delimite sus rutas. No ejecute un Worker en /* por defecto. Ajústelo a las rutas que necesita en los patrones de ruta de su wrangler.toml para que un fallo no pueda tumbar todo su sitio.
  • Compruebe los límites actuales antes de prometer escala. El tiempo de CPU, el número de subsolicitudes y los límites de tamaño de script varían según el plan y cambian con el tiempo: confírmelos en la página de límites actuales de Cloudflare antes de diseñar una reescritura en torno a un techo concreto, en lugar de fiarse de un número recordado.
  • Registre los metadatos de versión de la release. El modelo de versiones y despliegues de Cloudflare registra la versión de origen, la fecha de compatibilidad, los bindings y las rutas de cada despliegue: anote qué versión está activa en qué ruta para que la afirmación “el Worker hace X” sea comprobable frente a lo que está realmente desplegado, no frente a lo que hay en su editor.
  • Versione y haga rollback con los entornos de Wrangler. Publique en un entorno de staging, despliegue gradualmente por porcentaje y conserve la capacidad de volver a la versión anterior al instante.
  • Use logs delimitados para monitorizar el despliegue, teniendo en cuenta sus límites. Los Workers Logs de Cloudflare y el seguimiento de logs pueden servir de apoyo para depurar un despliegue gradual, pero los logs se muestrean y se conservan durante una ventana limitada: trátelos como evidencia acotada de las solicitudes que capturaron, no como un registro completo de cada visita de un rastreador.
  • Fije una condición de parada y pruebe el rollback antes de necesitarlo. Decida de antemano qué comportamiento observado (tasa de errores, una respuesta incorrecta en una comprobación puntual, una caída de la frecuencia de rastreo) detiene el despliegue, y confirme que la vía de rollback funciona de verdad en lugar de suponer que funcionará.
  • Purgue la caché como parte del despliegue. Como hay tres capas de caché en juego, haga de la purga/invalidación de caché un paso explícito de publicar una reescritura, no una ocurrencia tardía.

Una nota sobre Bing y algo con vistas al futuro

Bing tampoco tiene ninguna guía específica de Cloudflare ni del edge. Pero como el despliegue de un Worker es instantáneo mientras que los rastreos no lo son, IndexNow es el complemento natural: dispárelo en el momento en que se publique una tabla de redirecciones o un cambio de etiquetas impulsado por un Worker, para que Bing (y otros motores participantes) vuelvan a rastrear con prontitud. Y merece un vistazo: Cloudflare lanzó la canonicalización aplicada en el edge como una función de producto (“Redirecciones para el entrenamiento de IA”): los rastreadores de entrenamiento de IA verificados reciben una redirección 301 a su URL canonical con un solo interruptor. Es un contraste útil frente a programar a mano la lógica canonical en su propio Worker, y un recordatorio de que “servir a los rastreadores algo distinto de lo que ven los usuarios” es un patrón del que Microsoft se ha mostrado públicamente escéptica en otras funciones de Cloudflare para rastreadores de IA: una buena comprobación de sentido común para cualquier Worker condicionado por bots.

Para el panorama más amplio —la comparación de plataformas, Snippets frente a Workers, los ángulos de cola de desarrollo y de gobernanza— vuelva al hub de Edge SEO.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.