GEOAnalyticsTutorial

Cómo Medir tu Visibilidad en Búsqueda con IA en 2026: Crawlers, GA4 y Logs

14 de octubre de 2026
12 min de lectura
Medición de visibilidad en búsqueda con IA con logs de crawlers y GA4
Compartir:

Cuando saqué de GA4 los últimos 90 días de este sitio, el 91% de las sesiones era Direct. No eran personas: Chrome desde ubicaciones de data centers con cerca de cero segundos de engagement. Mientras tanto, ChatGPT, Copilot y Perplexity mandaron 6 sesiones en total. Con un vistazo al dashboard por defecto habría sacado dos conclusiones equivocadas.

Este es un playbook de medición, no de estrategia (la estrategia está en los dos posts de GEO que dejo al final). Vas a ver qué bots de IA existen y qué dice cada proveedor que hacen, cómo escribir robots.txt por bot, cómo leer el canal AI Assistant de GA4 y respaldarlo con una regex, cómo contar hits de crawlers desde los logs y cómo comprobar que un bot es genuino. Cada afirmación de proveedor de abajo sale de su propia documentación, revisada en octubre de 2026.

1. El Problema: tu Dashboard Mide las Cosas Equivocadas

La búsqueda con IA rompe la medición en tres lugares, y cada uno falla en una dirección distinta. Los bots que ejecutan tu JavaScript inflan Direct con sesiones falsas. Los bots que solo piden HTML nunca llegan a GA4, así que no los ves. Y las personas reales que hacen clic en una respuesta dentro de una app de IA muchas veces llegan sin referrer, así que también se esconden en Direct. Un solo dashboard no desenreda eso: necesitás tres fuentes, analytics, logs del servidor y robots.txt.

El Error Más Común

Leer Direct como ’gente que tipea mi URL’ o, peor, como ’tráfico de IA que GA4 no vio’. GA4 solo excluye bots conocidos, y Google dice que no podés desactivar esa exclusión ni ver cuánto se excluyó. Un Chrome automatizado desde un data center se cuenta como una sesión normal. Primero filtrá las sesiones con pinta de bot, después interpretá.

Los números de este sitio (datos propios, 90 días hasta el 14 de oct de 2026)

Sacados con la GA4 Data API para este portfolio. Es un sitio chico, no una estadística de la industria: leelo como un ejemplo de cómo los canales crudos engañan, no como un benchmark.

📈

~1.568 sesiones

total, 90 días

Todo lo que GA4 registró, antes de filtrar nada.

🤖

~1.434 Direct (91%)

casi todo automatizado

Sobre todo Chrome desde ubicaciones de data centers con cerca de 0 s de engagement: clientes automatizados que ejecutan JavaScript, no lectores.

🔎

100 Organic Search

el canal humano real

La búsqueda clásica sigue siendo de donde viene la mayoría de los visitantes humanos de este sitio.

💬

6 AI Assistant

muestra mínima

chatgpt.com 2, copilot.com 2, perplexity.ai 2. Más Referral 5 y Organic Social 4.

La comparación que importa: unas 17 sesiones humanas de búsqueda clásica por cada una de un asistente de IA, acá. Con números tan chicos no leería una tendencia, pero tampoco confiaría en un reporte que muestre el tráfico de IA en cero, ni en uno que muestre Direct como el 91% de mi audiencia.

2. Conceptos Mínimos Antes de Tocar Código

Seis ideas cubren casi todo lo que necesitás. Con esto claro, el robots.txt, el canal de GA4 y el script de logs se leen como castellano simple.

🧭

Tres trabajos de bots

la taxonomía que importa

Los proveedores separan los bots por propósito: entrenamiento o mejora de modelos (GPTBot, ClaudeBot, meta-externalagent), indexación para búsqueda (OAI-SearchBot, Claude-SearchBot, PerplexityBot) y fetches disparados por el usuario (ChatGPT-User, Claude-User, Perplexity-User). Cada uno tiene su propio token de robots.txt, así que podés tratarlos distinto.

🏷️

Token vs crawler

control sin tráfico

Google-Extended y Applebot-Extended son tokens de robots.txt, no crawlers. Google dice que Google-Extended no tiene un user agent propio y que el rastreo usa los user agents existentes de Google, así que nunca aparece en tus logs.

🔗

Referrer, UTM o nada

tres formas de llegar

Una visita desde una app de IA trae referrer HTTP, un tag UTM, ambos o ninguno. Ninguno significa Direct. Los datos de proveedores varían mucho: la muestra de abril de 2026 de Clickport tenía 35,7% de sesiones clasificadas como IA con un tag de fuente pero sin referrer registrado, y cita a otro proveedor (Loamly, feb 2026) que reporta 70,6% sin referrer.

📊

Canal AI Assistant de GA4

integrado desde mayo de 2026

El grupo de canales predeterminado de Google tiene un canal AI Assistant: el medium debe coincidir exactamente con ai-assistant, y se aplica cuando el referrer coincide con la lista de Google. AI Overviews y AI Mode quedan excluidos y cuentan como Organic Search.

🪪

Los user agents son afirmaciones

falsificable por cualquiera

Un string de User-Agent no prueba nada. Los crawlers genuinos se pueden comprobar contra rangos de IP que publica el proveedor (OpenAI, Anthropic, Perplexity, Google, Apple) o con DNS inverso (Google, Apple).

📜

Los logs ven lo que los tags no

la otra mitad

GA4 solo ve clientes que ejecutan tu tag. Un cliente que pide HTML sin ejecutar JavaScript nunca lo dispara, así que solo los logs del servidor muestran a GPTBot, ClaudeBot o ChatGPT-User.

El modelo mental a conservar

Los logs responden ’quién me pidió y para qué’. GA4 responde ’quién llegó e hizo algo’. robots.txt responde ’quién puede usarme y cómo’. Un hit de bot nunca es una visita, y un referrer ausente nunca prueba cero influencia de IA.

3. Paso 1 — Inventario de Bots (Desde la Documentación de los Proveedores)

Arrancá por lo que los proveedores publican de sí mismos, no por blogs: los nombres cambian y algunas guías todavía listan agentes que el proveedor ya no documenta (el artículo de ayuda actual de Anthropic lista ClaudeBot, Claude-User y Claude-SearchBot y no menciona anthropic-ai). Todo lo de abajo se revisó contra la página de cada proveedor en octubre de 2026.

🔎

OAI-SearchBot

OpenAI · búsqueda

Muestra sitios en las funciones de búsqueda de ChatGPT. Si te excluís, no aparecés en las respuestas de búsqueda de ChatGPT, aunque podés seguir apareciendo como enlace de navegación. OpenAI dice que los cambios de robots.txt tardan unas 24 horas en aplicarse a la búsqueda.

🧠

GPTBot

OpenAI · entrenamiento

Rastrea contenido que puede usarse para entrenar los modelos fundacionales de OpenAI. Prohibirlo señala que tu contenido no debe usarse para entrenamiento.

🙋

ChatGPT-User

OpenAI · acciones del usuario

Se usa para ciertas acciones del usuario en ChatGPT y Custom GPTs, no para rastreo automático. OpenAI aclara que, como lo inicia un usuario, las reglas de robots.txt pueden no aplicar, y que no se usa para decidir la inclusión en Search.

🔎

Claude-SearchBot

Anthropic · búsqueda

Analiza contenido para mejorar la relevancia y precisión de los resultados de búsqueda. Desactivarlo impide que tu contenido se indexe para optimización de búsqueda.

🧠

ClaudeBot

Anthropic · entrenamiento

Reúne contenido que puede usarse para entrenar modelos. Bloquearlo señala que el contenido futuro debe excluirse de los datasets de entrenamiento. Anthropic dice que respeta robots.txt y soporta la extensión no estándar Crawl-delay.

🙋

Claude-User

Anthropic · consultas del usuario

Pide páginas cuando un usuario de Claude hace una pregunta. Desactivarlo impide recuperar tu contenido en respuesta a una consulta de usuario.

🔎

PerplexityBot

Perplexity · búsqueda

Muestra y enlaza sitios en los resultados de Perplexity. Perplexity dice que no se usa para rastrear con fines de modelos fundacionales de IA y recomienda permitirlo en robots.txt.

🙋

Perplexity-User

Perplexity · acciones del usuario

Visita una página cuando la pregunta de un usuario la necesita. Perplexity dice que generalmente ignora robots.txt porque un usuario pidió el fetch.

🏷️

Google-Extended

Google · token, sin crawler

Un token de robots.txt que gobierna si el contenido que Google rastrea puede usarse para entrenar futuros modelos Gemini y para grounding en Gemini Apps y Vertex AI. Google dice que no afecta la inclusión en Search ni el ranking. AI Overviews y AI Mode siguen los controles normales de Search (Googlebot, nosnippet, max-snippet).

🍎

Applebot / Applebot-Extended

Apple · búsqueda + token

Applebot rastrea para funciones de Spotlight, Siri y Safari y sus datos también pueden ayudar a entrenar modelos fundacionales de Apple. Applebot-Extended es un token secundario que solo controla ese uso de entrenamiento: no rastrea y prohibirlo no te saca de la búsqueda.

👥

meta-webindexer, -externalagent, -externalfetcher

Meta · tres trabajos

meta-webindexer mejora la calidad de la búsqueda de Meta AI; meta-externalagent rastrea para entrenamiento o indexación; meta-externalfetcher pide enlaces a pedido de un usuario y puede saltarse robots.txt.

🧪

Fetchers de Google disparados por el usuario

Google · relacionados con IA

Google lista fetchers relacionados con IA como Google-Agent, Google-GeminiNotebook, Google-Pinpoint y Google-Read-Aloud, y dice que los fetchers disparados por el usuario generalmente ignoran robots.txt porque un usuario pidió el fetch.

Cómo leer la lista

Los bots de búsqueda alimentan respuestas, los de entrenamiento alimentan modelos, los fetchers del usuario son una persona haciendo una pregunta. Un hit de ChatGPT-User o Claude-User es la señal de log más cercana a ’un asistente está usando mi página ahora mismo’, pero igual no es una visita humana ni un clic de cita.

4. Paso 2 — robots.txt, un Grupo por Trabajo

En robots.txt la taxonomía se vuelve política: permitís los bots que recuperan tu contenido para respuestas, decidís el entrenamiento por separado y mantenés un grupo comodín. Varias líneas User-agent pueden ir encima de un mismo set de reglas, como muestran los docs de Google.

public/robots.txt — un grupo por trabajo (el Pages Router lo sirve como archivo estático)

# 1) Search and retrieval bots: they feed answers, allow them
User-agent: OAI-SearchBot
User-agent: Claude-SearchBot
User-agent: PerplexityBot
User-agent: meta-webindexer
User-agent: Applebot
Allow: /
Disallow: /admin
Disallow: /api/

# 2) User-triggered fetchers: a person asked about one of your pages.
#    Some vendors say these may ignore robots.txt anyway.
User-agent: ChatGPT-User
User-agent: Claude-User
User-agent: Perplexity-User
User-agent: meta-externalfetcher
Allow: /
Disallow: /admin
Disallow: /api/

# 3) Training / model improvement: YOUR decision (example: opt out)
User-agent: GPTBot
User-agent: ClaudeBot
User-agent: Google-Extended
User-agent: Applebot-Extended
User-agent: meta-externalagent
Disallow: /

# 4) Everyone else (Googlebot, Bingbot, ...)
User-agent: *
Allow: /
Disallow: /admin
Disallow: /api/

Sitemap: https://www.diego-rodriguez.work/sitemap.xml

Si generás el archivo con next-sitemap, los mismos grupos van en robotsTxtOptions.policies. Hay una sutileza que muerde: los docs de Google dicen que un user agent coincide solo con el primer grupo más específico, así que un grupo de un bot no hereda los Disallow del grupo *. Por eso cada grupo de arriba repite /admin y /api/.

Bots de entrenamiento: un tradeoff neutral

Permitir bots de entrenamiento significa que los proveedores pueden usar tus páginas para entrenar o mejorar modelos; ninguno de los docs que leí promete más citas a cambio. Bloquear es el opt-out declarado de los proveedores para entrenamiento, y OpenAI, Apple y Google dicen cada uno que los controles de entrenamiento están separados de la inclusión en búsqueda (GPTBot vs OAI-SearchBot, Applebot-Extended, Google-Extended). Es una decisión de licencias y de marca, no un truco de ranking. Este sitio permite todo, lo cual encaja en un portfolio; un publisher que monetiza un archivo puede razonablemente elegir otra cosa.

robots.txt es un pedido, no una cerradura

Los crawlers que cumplen lo respetan. Los fetchers disparados por el usuario pueden no hacerlo (OpenAI, Perplexity, Meta y Google lo dicen de los suyos) y un user agent falsificado lo ignora por completo. Si un contenido no debe ser pedido, poné autenticación o una regla de firewall del CDN delante.

5. Paso 3 — GA4: el Canal AI Assistant y una Regex de Respaldo

Algunas guías viejas todavía te dicen que GA4 no tiene canal de IA y que tenés que armar uno. La documentación de Google dice que sí: se agregó un canal AI Assistant al grupo de canales predeterminado el 13 de mayo de 2026 (notas de versión de Analytics). La regla es que el medium coincida exactamente con ai-assistant, y GA4 asigna ese medium (y la campaña (ai-assistant)) cuando el referrer coincide con una lista de asistentes de IA. Google nombra ChatGPT, Gemini, DeepSeek, Copilot y Grok como ejemplos, publica la lista completa solo como hoja de cálculo y deja AI Overviews y AI Mode en Organic Search.

Dos límites importan. Primero, solo funciona cuando GA4 vio un referrer reconocido: las sesiones sin referrer ni tag siguen cayendo en Direct, y notas independientes también reportan sesiones con tag pero sin medium que terminan en Unassigned. Segundo, la lista es de Google, no tuya. En esta propiedad perplexity.ai ya caía en AI Assistant, mientras que una nota independiente reporta que Perplexity queda en Referral, así que verificalo con tus datos. Un grupo de canales personalizado te da una lista que controlás vos, al lado de la nativa.

GA4 Admin → Data display → Channel groups → Create new channel group

Channel name:  AI assistants (custom)
Condition:     Source   matches regex
Pattern:       ^(.*\.)?(chatgpt\.com|chat\.openai\.com|perplexity\.ai|claude\.ai|gemini\.google\.com|copilot\.com|copilot\.microsoft\.com|deepseek\.com|grok\.com|you\.com)$
Order:         drag it ABOVE Referral (and above Organic Search if AI sources show up there)

Por qué dominios exactos, y qué es retroactivo

La regex de GA4 es de coincidencia completa y distingue mayúsculas por defecto, así que el patrón tiene que describir el valor entero de Source. El ejemplo de Google usa substrings amplios como .*gpt.*, que también pueden atrapar fuentes ajenas; una lista de dominios es más estricta. El tráfico va al primer canal cuya definición cumple, así que el orden importa, y Google dice que los grupos personalizados pueden aplicarse retroactivamente a los reportes (no a las audiencias). Las propiedades estándar permiten 2 grupos personalizados. Ampliá la lista desde tu propio reporte de Source.

scripts/ga4-channels.js — canales con engagement, Direct con pinta de bot marcado

// npm i @google-analytics/data
// GOOGLE_APPLICATION_CREDENTIALS=key.json GA_PROPERTY_ID=123456789 node scripts/ga4-channels.js
const { BetaAnalyticsDataClient } = require("@google-analytics/data");

const client = new BetaAnalyticsDataClient();
const HUMAN = ["Organic Search", "AI Assistant", "Referral", "Organic Social"];

async function main() {
  const [res] = await client.runReport({
    property: "properties/" + process.env.GA_PROPERTY_ID,
    dateRanges: [{ startDate: "90daysAgo", endDate: "today" }],
    dimensions: [{ name: "sessionDefaultChannelGroup" }, { name: "sessionSource" }],
    metrics: [{ name: "sessions" }, { name: "userEngagementDuration" }],
    limit: 500,
  });

  const by = {};
  for (const row of res.rows || []) {
    const [channel, source] = row.dimensionValues.map((d) => d.value);
    const sessions = Number(row.metricValues[0].value);
    const engaged = Number(row.metricValues[1].value); // seconds, summed
    const c = (by[channel] ||= { sessions: 0, engaged: 0, sources: {} });
    c.sessions += sessions;
    c.engaged += engaged;
    c.sources[source] = (c.sources[source] || 0) + sessions;
  }

  const total = Object.values(by).reduce((n, c) => n + c.sessions, 0);
  const sorted = Object.entries(by).sort((a, b) => b[1].sessions - a[1].sessions);
  for (const [name, c] of sorted) {
    const avg = c.engaged / Math.max(c.sessions, 1);
    const top = Object.entries(c.sources).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([s, n]) => s + " " + n).join(", ");
    // heuristic, not a verdict: lots of sessions with ~0 s engagement
    const verdict = HUMAN.includes(name) ? "human" : avg < 1 && c.sessions > 20 ? "BOT-LIKE" : "check";
    console.log([name.padEnd(18), String(c.sessions).padStart(6), ((100 * c.sessions) / total).toFixed(0) + "%", avg.toFixed(1) + "s", verdict, top].join("  "));
  }
}
main().catch((e) => { console.error(e.message); process.exit(1); });

Corrélo y leé la columna de engagement al lado de la cantidad de sesiones. Un canal con cientos de sesiones y menos de un segundo de engagement no es una audiencia; ese es el número que hay que sacar antes de que alguien presente un porcentaje de participación de IA.

6. Paso 4 — Logs: Contá los Bots que GA4 No Ve

Los logs de tu servidor o CDN registran cada request, incluso de clientes que nunca ejecutan JavaScript. Dos formas baratas de armar un reporte de bots: parsear el access log que ya tenés, o emitir una línea JSON por cada hit de bot de IA desde un middleware.

scripts/ai-bots-report.js — hits por bot desde un log en formato combined

// node scripts/ai-bots-report.js /var/log/nginx/access.log   (Node 16+)
const fs = require("node:fs");
const readline = require("node:readline");

// user-agent token -> job
const BOTS = {
  "OAI-SearchBot": "search", GPTBot: "training", "ChatGPT-User": "user fetch",
  "Claude-SearchBot": "search", ClaudeBot: "training", "Claude-User": "user fetch",
  PerplexityBot: "search", "Perplexity-User": "user fetch",
  Applebot: "search (+training)", "meta-webindexer": "search",
  "meta-externalagent": "training", "meta-externalfetcher": "user fetch",
};

// combined log format: ip - - [time] "METHOD path HTTP/x" status bytes "referer" "user-agent"
const LINE = /^(\S+) \S+ \S+ \[[^\]]+\] "\S+ (\S+)[^"]*" (\d{3}) \S+ "[^"]*" "([^"]*)"/;

async function main(file) {
  const stats = {};
  const rl = readline.createInterface({ input: fs.createReadStream(file) });
  for await (const line of rl) {
    const m = LINE.exec(line);
    if (!m) continue;
    const [, ip, path, status, ua] = m;
    const bot = Object.keys(BOTS).find((n) => ua.toLowerCase().includes(n.toLowerCase()));
    if (!bot) continue;
    const s = (stats[bot] ||= { job: BOTS[bot], hits: 0, ok: 0, robots: 0, ips: new Set(), paths: {} });
    s.hits++;
    if (status[0] === "2") s.ok++;
    if (path === "/robots.txt") s.robots++;
    s.ips.add(ip);
    s.paths[path] = (s.paths[path] || 0) + 1;
  }
  const top = (paths) => Object.entries(paths).sort((a, b) => b[1] - a[1])[0][0];
  console.table(
    Object.entries(stats)
      .sort((a, b) => b[1].hits - a[1].hits)
      .map(([bot, s]) => ({ bot, job: s.job, hits: s.hits, "2xx %": Math.round((100 * s.ok) / s.hits), robots: s.robots, ips: s.ips.size, top: top(s.paths) }))
  );
}
main(process.argv[2]).catch((e) => { console.error(e.message); process.exit(1); });

En un hosting sin access logs crudos, el middleware te da la misma señal. Esta es sintaxis del Pages Router de Next.js 13; Next.js 16 renombró la convención a proxy.js, así que ajustalo si actualizás. Corre en cada request que matchea, así que mantenelo barato: es una herramienta de medición, no un firewall.

middleware.js — una línea JSON por request de bot de IA

// middleware.js  (project root, next to pages/)  ·  Next.js 13 Pages Router
import { NextResponse } from "next/server";

const AI_BOTS =
  /(OAI-SearchBot|GPTBot|ChatGPT-User|Claude-SearchBot|ClaudeBot|Claude-User|PerplexityBot|Perplexity-User|Applebot|meta-webindexer|meta-externalagent|meta-externalfetcher|Google-Agent)/i;

export function middleware(request) {
  const ua = request.headers.get("user-agent") || "";
  const hit = ua.match(AI_BOTS);
  if (hit) {
    // one JSON line per hit: grep it, or ship it with your host's log drain
    const ip = request.headers.get("x-forwarded-for");
    console.log(JSON.stringify({ type: "ai-bot", bot: hit[1], path: request.nextUrl.pathname, ip, t: new Date().toISOString() }));
  }
  return NextResponse.next();
}

// run on pages and robots.txt, skip build assets
export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Qué significa un hit de bot (y qué no)

Contá los fetches de robots.txt aparte de los de páginas: un bot que lee robots.txt primero es evidencia de que sigue las reglas. Los hits de bots de búsqueda muestran que estás indexado para recuperación, los de fetchers del usuario muestran que una persona preguntó por una página tuya, los de bots de entrenamiento no muestran nada sobre visibilidad. Ninguno es una visita, una cita ni un clic.

7. Paso 5 — Verificá que el Bot Sea Real

Un string de user agent es una afirmación que cualquier script puede hacer. Antes de que un número entre a un reporte, revisá la IP de origen: OpenAI, Anthropic, Perplexity, Google y Apple publican rangos de IP como listas JSON de prefijos CIDR, y Google y Apple documentan también DNS inverso (Google: lookup inverso, hostname bajo googlebot.com, google.com o googleusercontent.com, y después lookup directo que vuelva a la misma IP).

scripts/verify-bot-ip.js — rangos publicados más DNS inverso y directo

// node scripts/verify-bot-ip.js 203.0.113.7 GPTBot   (Node 18+: global fetch)
const { BlockList, isIP } = require("node:net");
const dns = require("node:dns").promises;

// IP range files published by each vendor: { prefixes: [{ ipv4Prefix | ipv6Prefix }] }
const RANGES = {
  GPTBot: "https://openai.com/gptbot.json",
  "OAI-SearchBot": "https://openai.com/searchbot.json",
  "ChatGPT-User": "https://openai.com/chatgpt-user.json",
  ClaudeBot: "https://claude.com/crawling/bots.json", // one list for Anthropic's bots
  PerplexityBot: "https://www.perplexity.com/perplexitybot.json",
  Googlebot: "https://developers.google.com/static/crawling/ipranges/common-crawlers.json",
  Applebot: "https://search.developer.apple.com/applebot.json",
};
// Google and Apple also document reverse DNS (hostname suffixes)
const RDNS = {
  Googlebot: [".googlebot.com", ".google.com", ".googleusercontent.com"],
  Applebot: [".applebot.apple.com"],
};

async function inRanges(bot, ip) {
  const { prefixes } = await (await fetch(RANGES[bot])).json();
  const list = new BlockList();
  for (const p of prefixes) {
    const [addr, len] = (p.ipv4Prefix || p.ipv6Prefix).split("/");
    list.addSubnet(addr, Number(len), p.ipv4Prefix ? "ipv4" : "ipv6");
  }
  return list.check(ip, isIP(ip) === 6 ? "ipv6" : "ipv4");
}

// reverse DNS -> hostname ends with a documented suffix -> forward DNS returns the same IP
async function rdnsOk(bot, ip) {
  try {
    for (const host of await dns.reverse(ip)) {
      if (!RDNS[bot].some((s) => host.endsWith(s))) continue;
      if ((await dns.lookup(host, { all: true })).some((a) => a.address === ip)) return true;
    }
  } catch (e) {
    // no PTR record: not verified
  }
  return false;
}

(async () => {
  const [ip, bot] = process.argv.slice(2);
  if (!RANGES[bot]) throw new Error("unknown bot: " + bot);
  console.log({ bot, ip, inRanges: await inRanges(bot, ip), rdnsOk: RDNS[bot] ? await rdnsOk(bot, ip) : "n/a" });
})();

Cacheá los JSON, cambian. Anthropic advierte que bloquear por IP puede impedir que su crawler lea tu robots.txt y que puede no dar un opt-out confiable, así que usá los rangos para verificar lo que ya registraste y robots.txt para la política. Para proveedores cuyas páginas leí sin lista de IPs (Meta, por ejemplo), tratá los conteos solo por user agent como no verificados.

8. Paso 6 — Datos Estructurados y los Reportes de los Proveedores

En el Pages Router, JSON-LD es un tag script común con type application/ld+json dentro de next/head. Los docs de Next.js recomiendan un script nativo en lugar de next/script y advierten que JSON.stringify no sanitiza strings, así que reemplazá < por su escape unicode. Dale una key al tag para que no se duplique entre renders.

components/JsonLd.js — Pages Router

// components/JsonLd.js  (Pages Router: render inside next/head)
import Head from "next/head";

export default function JsonLd({ id, data }) {
  return (
    <Head>
      <script
        key={id}
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          // JSON.stringify does not sanitize: escape "<" so a value can never close the tag
          __html: JSON.stringify(data).replace(/</g, "\\u003c"),
        }}
      />
    </Head>
  );
}

// pages/blog/my-post.js
<JsonLd
  id="article-ld"
  data={{
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    headline: "Measuring AI search visibility",
    datePublished: "2026-10-14",
    dateModified: "2026-10-14",
    author: { "@type": "Person", name: "Diego Rodriguez", url: "https://www.diego-rodriguez.work" },
  }}
/>

Qué dicen realmente los proveedores sobre datos estructurados

Google: no necesitás archivos legibles por máquina nuevos, archivos de texto para IA ni markup schema.org especial para aparecer en AI Overviews y AI Mode, y los datos estructurados deben coincidir con el texto visible. Microsoft: Fabrice Canel dijo en SMX Munich (marzo de 2025) que el schema markup ayuda a los LLMs de Bing a entender el contenido, según reportó Search Engine Land. Las páginas de bots de OpenAI, Anthropic y Perplexity que leí no dicen nada sobre datos estructurados. Tratá JSON-LD como higiene que quita ambigüedad, no como una palanca que puedas medir aislada.

Reportes de los proveedores que vale la pena abrir

Bing Webmaster Tools tiene un reporte AI Performance (vista previa pública desde febrero de 2026) con citas, páginas citadas por día, conteos por página y grounding queries en Copilot, resúmenes de IA en Bing y socios seleccionados. Bing dice que las grounding queries son una muestra, y el anuncio no menciona datos de clics. Google dice que el tráfico de funciones de IA está incluido en los totales de búsqueda web de Search Console. Ninguno reemplaza tus propios logs.

9. Una Rutina de Medición que Aguanta

La medición se pudre cuando es de una sola vez. Esta es la cadencia que correría en cualquier sitio que se preocupe por la visibilidad en IA, en el orden en que los datos se vuelven más baratos de leer:

📅 Cada semana (10 minutos)

  1. Canales de GA4: corré ga4-channels.js y leé el engagement al lado de las sesiones, nunca solo los nombres de canal
  2. Log de bots: corré ai-bots-report.js sobre los últimos 7 días: hits por bot, porcentaje 2xx, fetches de robots.txt, paths top
  3. Fuentes nuevas: revisá las fuentes dentro de Referral y Unassigned buscando dominios con pinta de IA

🗓️ Cada mes

  1. Verificar: comprobá cualquier nombre de bot nuevo contra los rangos publicados del proveedor antes de que entre a un reporte
  2. Diff de proveedores: releé la página de bots de cada proveedor, los nombres y propósitos cambian
  3. Consolas de proveedores: exportá Bing AI Performance y comparalo con las páginas que tus logs muestran como pedidas

🧹 Cada trimestre

  1. Revisión de regex: actualizá el grupo de canales personalizado con los dominios que viste en Referral
  2. Revisión de política: ¿la decisión de permitir o bloquear entrenamiento sigue alineada con tu negocio?
  3. Línea base: anotá sesiones humanas, sesiones de AI Assistant y hits verificados de bots de IA, e ignorá el Direct crudo

10. Errores Comunes (Todos Arreglables en una Tarde)

Casi cada número engañoso de tráfico de IA que vi cae en uno de estos baldes. La columna izquierda es lo que hacen los reportes confiables; la derecha es lo que produce una slide equivocada pero muy segura de sí misma.

✅ Hacé esto

  • • Filtrá las sesiones con pinta de bot (Direct, ~0 s de engagement, ubicaciones de data centers) antes de leer cualquier canal
  • • Tratá bots de búsqueda, de entrenamiento y disparados por el usuario como tres políticas separadas
  • • Verificá las IPs de los bots contra los rangos del proveedor antes de reportar hits
  • • Reportá sesiones de IA como ’al menos N’: las visitas sin referrer son invisibles
  • • Mantené un grupo de canales personalizado junto al canal nativo AI Assistant y compará ambos
  • • Repetí las reglas Disallow dentro de cada grupo de robots.txt específico de un bot

❌ No esto

  • • Leer Direct como humano, o como ’tráfico de IA que GA4 no vio’
  • • Bloquear Google-Extended para cambiar AI Overviews: Google dice que no afecta a Search
  • • Contar hits de GPTBot o ClaudeBot como visibilidad: son rastreos de entrenamiento
  • • Agregar llms.txt o markup solo para IA pensando en Google: Google dice que no hace falta
  • • Usar robots.txt como control de acceso para rutas sensibles
  • • Citar el ’X% del tráfico de IA es Direct’ de un estudio de proveedor como si fuera una ley: 35,7% y 70,6% salieron de muestras distintas

Regla de oro

Medí en tres capas, logs para quién te pidió, GA4 para quién llegó, consolas de proveedores para quién te citó, y nunca las fundas en un solo número. Cada una responde una pregunta distinta, y un hit de bot no es una visita.

Conclusión

Ahora tenés tres instrumentos: un inventario de bots sacado de la documentación de los proveedores, un robots.txt que codifica una política por trabajo y dos reportes (GA4 por canal y engagement, logs por bot) que podés verificar contra rangos de IP publicados. Ninguno te dice solo ’qué tan visible soy en las respuestas de IA’. Juntos te dicen qué podés afirmar y qué no.

Esta semana: corré los dos scripts una vez, anotá tres números (sesiones humanas, sesiones de AI Assistant, hits verificados de bots de IA) y dejá de reportar la línea cruda de Direct. Después usá los posts de GEO de abajo para decidir qué cambiar, y volvé en un mes para ver si los números se movieron.

Machete del Tutorial

Bots

  • • Búsqueda / entrenamiento / fetch de usuario
  • • Verificá por rango de IP o rDNS
  • • Los logs cuentan hits, no visitas

GA4

  • • Canal AI Assistant (ai-assistant)
  • • Canal regex propio sobre Referral
  • • Filtrá Direct con ~0 s de engagement

robots.txt

  • • Permití búsqueda + fetchers de usuario
  • • Decidí el entrenamiento por separado
  • • Repetí Disallow en cada grupo

Fuentes

Diego Rodriguez

Diego Rodriguez

Ingeniero Senior Full-Stack & AI

Diego tiene mas de 9 anos de experiencia construyendo aplicaciones potenciadas por IA de produccion, desde orquestacion de LLMs y pipelines RAG hasta deteccion de riesgos con ML y sistemas de trading algoritmico.

Conoce mas sobre Diego →