IndexNow en Next.js: guía completa para indexación rápida
Implementa IndexNow en tu app Next.js con TypeScript. Aprende a generar tu API key, enviar URLs a Bing automáticamente y configurar el webhook de Vercel.
IndexNow en Next.js: guia completa para indexacion rapida
Este tutorial de IndexNow en Next.js documenta la implementacion real que uso en este sitio. Si publicaste contenido nuevo y quieres que Bing lo indexe rapido en lugar de esperar al crawler, IndexNow es la herramienta correcta.
La implementacion tiene cuatro partes: generar tu API key, crear el servicio de envio en TypeScript, conectarlo a tu sitemap existente y automatizarlo con el deploy de Vercel. Todo con codigo listo para copiar.
Una advertencia antes de empezar: IndexNow notifica a los buscadores, no garantiza indexacion. La diferencia importa.
Que es IndexNow y como funciona
Los motores de busqueda descubren contenido de dos formas. El modelo pull es el clasico: el crawler visita tu sitio periodicamente, lee el sitemap y indexa lo que encuentra. Funciona, pero puede tardar dias o semanas en detectar contenido nuevo.
El modelo push es lo que introduce IndexNow. Tu envias una notificacion directa al buscador diciendo "esta URL cambio, revisala". El buscador decide si la indexa y cuando, pero al menos ya sabe que existe.
El flujo es simple:
- Publicas o actualizas contenido
- Tu servidor hace un GET o POST al endpoint de IndexNow con la URL
- El buscador recibe la notificacion y la encola para crawlear
- El crawler visita tu URL (pronto, pero sin fecha garantizada)
Una sola notificacion llega a todos los motores que implementan el protocolo. El endpoint de api.indexnow.org distribuye automaticamente a Bing, Yandex y cualquier otro buscador participante.
IndexNow es un protocolo abierto, no una herramienta de Bing. Cualquier buscador puede implementarlo.
Que buscadores soportan IndexNow hoy
Antes de invertir tiempo en la implementacion, vale saber exactamente donde funciona.
| Buscador | Soporte IndexNow | Notas |
|---|---|---|
| Bing | Si, completo | Desarrollaron el protocolo con Yandex |
| Yandex | Si, completo | Co-creadores del protocolo |
| Naver | Si | Buscador principal de Corea del Sur |
| Seznam | Si | Buscador de Republica Checa |
| No oficialmente | Ha evaluado el protocolo pero no lo implementa | |
| DuckDuckGo | No (usa Bing) | Se beneficia indirectamente via Bing |
La realidad sobre Google: a la fecha de este post, Google no implementa IndexNow. Si tu prioridad es trafico de Google, IndexNow no te ayuda directamente. Sigue siendo util para Bing y Yandex, que juntos representan una porcion real del trafico dependiendo del nicho y la region.
Para Google, sigues necesitando tu sitemap bien configurado y Search Console. Revisa la guia de SEO en Next.js con Metadata API y sitemap para cubrir esa parte.
Paso 1: Generar y verificar tu API key
La API key de IndexNow es una string hexadecimal que identifica tu sitio. Necesitas dos cosas: la key en si misma, y un archivo de verificacion en tu dominio que demuestre que controlas ese sitio.
Generar la key con Node.js
// scripts/generate-indexnow-key.ts
import crypto from "crypto";
// Genera una key hexadecimal de 32 caracteres
const key = crypto.randomBytes(16).toString("hex");
console.log("Tu API key:", key);
console.log("Guarda esto en INDEXNOW_API_KEY en tus env vars");Ejecutala una sola vez:
npx tsx scripts/generate-indexnow-key.tsCopia el resultado a tu .env.local y a las variables de entorno en Vercel:
INDEXNOW_API_KEY=tu-key-generada-aquiCrear el archivo de verificacion
El archivo de verificacion va en /public/{key}.txt con la key como contenido. Este archivo es lo que IndexNow usa para confirmar que eres el dueno del dominio.
# Reemplaza {key} con tu key real
echo "tu-key-aqui" > public/tu-key-aqui.txtCuando hagas deploy, el archivo estara disponible en https://tudominio.com/tu-key-aqui.txt. IndexNow verifica ese archivo antes de aceptar tus notificaciones.
Antes de hacer deploy, verifica que no tengas variables de entorno expuestas en tu repositorio. El Escaner de archivos expuestos detecta si algun .env o credencial esta accesible publicamente en tu sitio. Es gratis y no requiere registro.
Verificar que el archivo es accesible
# En local
curl http://localhost:3000/tu-key-aqui.txt
# En produccion
curl https://tudominio.com/tu-key-aqui.txtLa respuesta debe ser exactamente tu API key, sin espacios ni saltos de linea extra.
Paso 2: El servicio de envio en TypeScript
Con la key verificada, ahora necesitas la funcion que hace el envio. Esta es la que uso en este sitio:
// lib/indexnow.ts
const INDEXNOW_API = "https://api.indexnow.org/indexnow";
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://rodalexanderson.com";
export interface IndexNowResult {
success: boolean;
status?: number;
error?: string;
}
// Envio de una sola URL (GET)
export async function submitUrlToIndexNow(url: string): Promise<IndexNowResult> {
const apiKey = process.env.INDEXNOW_API_KEY;
if (!apiKey) {
return { success: false, error: "INDEXNOW_API_KEY no esta configurada" };
}
try {
const encodedUrl = encodeURIComponent(url);
const keyLocation = encodeURIComponent(`${SITE_URL}/${apiKey}.txt`);
const endpoint = `${INDEXNOW_API}?url=${encodedUrl}&key=${apiKey}&keyLocation=${keyLocation}`;
const response = await fetch(endpoint, {
method: "GET",
headers: { "User-Agent": "NextJS/IndexNow-Client" },
});
if (response.status === 200 || response.status === 202) {
return { success: true, status: response.status };
}
return {
success: false,
status: response.status,
error: `Error HTTP ${response.status}`,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Error desconocido",
};
}
}
// Envio de multiples URLs (POST batch)
export async function submitBatchToIndexNow(urls: string[]): Promise<IndexNowResult> {
const apiKey = process.env.INDEXNOW_API_KEY;
if (!apiKey) {
return { success: false, error: "INDEXNOW_API_KEY no esta configurada" };
}
if (urls.length === 0) {
return { success: false, error: "La lista de URLs esta vacia" };
}
const host = new URL(SITE_URL).hostname;
const keyLocation = `${SITE_URL}/${apiKey}.txt`;
const payload = {
host,
key: apiKey,
keyLocation,
urlList: urls,
};
try {
const response = await fetch(INDEXNOW_API, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
"User-Agent": "NextJS/IndexNow-Client",
},
body: JSON.stringify(payload),
});
if (response.status === 200 || response.status === 202) {
return { success: true, status: response.status };
}
return {
success: false,
status: response.status,
error: `Error HTTP ${response.status}`,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Error desconocido",
};
}
}Nota como process.env.INDEXNOW_API_KEY nunca se loguea ni se expone. El valor viaja directo al payload del fetch, nunca al cliente.
Paso 3: Envio automatico desde el pipeline de contenido
El servicio ya funciona. Ahora conectalo a tu lista de URLs. La fuente mas natural es tu app/sitemap.ts existente.
Si ya tienes un sitemap bien estructurado (ver la guia de sitemap automatico en Next.js), puedes extraer las URLs de ahi:
// lib/get-site-urls.ts
import { getAllPosts } from "@/lib/content";
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://rodalexanderson.com";
export async function getSiteUrls(): Promise<string[]> {
// Paginas estaticas
const staticUrls = [
SITE_URL,
`${SITE_URL}/blog`,
`${SITE_URL}/sobre-mi`,
`${SITE_URL}/docs`,
];
// Posts del blog (desde tu pipeline de contenido)
const posts = await getAllPosts();
const blogUrls = posts.map((post) => `${SITE_URL}/blog/${post.slug}`);
return [...staticUrls, ...blogUrls];
}Y el script que los combina:
// scripts/submit-all-urls.ts
import { getSiteUrls } from "../lib/get-site-urls";
import { submitBatchToIndexNow } from "../lib/indexnow";
async function main() {
console.log("Obteniendo URLs del sitio...");
const urls = await getSiteUrls();
console.log(`Total de URLs: ${urls.length}`);
const result = await submitBatchToIndexNow(urls);
if (result.success) {
console.log(`Envio exitoso. Status: ${result.status}`);
} else {
console.error(`Error en envio: ${result.error}`);
process.exit(1);
}
}
main().catch(console.error);Paso 4: Integracion con el deploy de Vercel
Hay dos formas de automatizar el envio en cada deploy. Elige la que mejor encaja con tu flujo.
Opcion A: Script postbuild
Agrega el script a tu package.json:
{
"scripts": {
"build": "next build",
"postbuild": "tsx scripts/submit-all-urls.ts"
}
}Con postbuild, el script se ejecuta automaticamente despues de cada next build exitoso. Vercel lo corre como parte del proceso de deploy.
Opcion B: Route Handler como webhook
Esta opcion te da mas control. Crea un endpoint que Vercel llama via Deploy Hook:
// app/api/indexnow/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getSiteUrls } from "@/lib/get-site-urls";
import { submitBatchToIndexNow } from "@/lib/indexnow";
export async function POST(request: NextRequest) {
// Verifica el token de seguridad para evitar llamadas no autorizadas
const authHeader = request.headers.get("authorization");
const expectedToken = process.env.INDEXNOW_WEBHOOK_SECRET;
if (!expectedToken || authHeader !== `Bearer ${expectedToken}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
const urls = await getSiteUrls();
const result = await submitBatchToIndexNow(urls);
if (!result.success) {
return NextResponse.json(
{ error: result.error, status: result.status },
{ status: 500 }
);
}
return NextResponse.json({
success: true,
urlsSubmitted: urls.length,
indexNowStatus: result.status,
});
} catch (error) {
return NextResponse.json(
{ error: "Error interno del servidor" },
{ status: 500 }
);
}
}Para llamar al webhook desde Vercel, configura un Deploy Hook en el dashboard (Settings > Git > Deploy Hooks) y usa la URL generada.
Cualquier endpoint que reciba webhooks debe tener autenticacion. El Verificador de headers de seguridad gratuito te muestra si tu sitio tiene los headers de seguridad correctamente configurados en produccion. Util para confirmar que el endpoint no es accesible sin el token.
Agrega INDEXNOW_WEBHOOK_SECRET a tus variables de entorno en Vercel con una string aleatoria segura.
Envio en batch: multiples URLs de una vez
El endpoint POST acepta hasta 10,000 URLs por request. El payload completo:
// Ejemplo de payload para batch submission
const payload = {
host: "rodalexanderson.com",
key: process.env.INDEXNOW_API_KEY, // Nunca el valor literal
keyLocation: "https://rodalexanderson.com/f790fd5bff194046a27c7c2ed7ad836f.txt",
urlList: [
"https://rodalexanderson.com/blog/indexnow-nextjs-guia-completa",
"https://rodalexanderson.com/blog/seo-nextjs-metadata-og-sitemap",
"https://rodalexanderson.com/",
],
};Reglas importantes para el batch:
- Todas las URLs deben pertenecer al mismo
host - El
keyLocationdebe ser accesible publicamente - No mezcles URLs de diferentes dominios en el mismo request
- Si tienes mas de 10,000 URLs, divide en multiples requests
// lib/indexnow.ts -- funcion para dividir en chunks si es necesario
export async function submitAllUrlsInBatches(urls: string[]): Promise<IndexNowResult[]> {
const CHUNK_SIZE = 10_000;
const results: IndexNowResult[] = [];
for (let i = 0; i < urls.length; i += CHUNK_SIZE) {
const chunk = urls.slice(i, i + CHUNK_SIZE);
const result = await submitBatchToIndexNow(chunk);
results.push(result);
// Pequeña pausa entre batches para no saturar el API
if (i + CHUNK_SIZE < urls.length) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
return results;
}Como verificar que funciono
Bing Webmaster Tools
La forma mas directa. Ve a Bing Webmaster Tools y en el menu lateral busca "URL Submission" o "IndexNow". Ahi puedes ver el historial de URLs enviadas y su estado.
Si acabas de implementar IndexNow, dale algunas horas antes de verificar. Bing no indexa instantaneo, solo lo pone en cola rapido.
Request manual para probar
# Prueba un envio individual
curl -v "https://api.indexnow.org/indexnow?url=https://tudominio.com/blog/tu-post&key=tu-api-key"
# Respuesta esperada: 200 OK o 202 AcceptedLogs en Vercel
Si usas el Route Handler, revisa los logs en Vercel > Functions. Cada invocacion muestra el status de respuesta de IndexNow.
IndexNow vs Google Ping para sitemaps
Son mecanismos distintos para objetivos distintos. No son lo mismo.
| Caracteristica | IndexNow | Google Sitemap Ping |
|---|---|---|
| Metodo | Push (tu notificas) | Pull con aviso (Google decide) |
| Buscadores | Bing, Yandex, Naver, Seznam | Google (principalmente) |
| Granularidad | URL especifica | Sitemap completo |
| Limite de URLs | 10,000 por request | Sin limite documentado |
| Latencia | Horas a dias | Dias a semanas |
| Garantia de indexacion | Ninguna | Ninguna |
| Complejidad de setup | Media (necesitas API key) | Baja (un GET request) |
La conclusion practica: implementa ambos. Son complementarios.
Para el ping de sitemap de Google:
// lib/google-ping.ts
export async function pingGoogleSitemap(sitemapUrl: string): Promise<boolean> {
try {
const pingUrl = `https://www.google.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`;
const response = await fetch(pingUrl);
return response.ok;
} catch {
return false;
}
}Llama a ambas funciones despues del build:
// scripts/notify-search-engines.ts
import { submitBatchToIndexNow } from "../lib/indexnow";
import { pingGoogleSitemap } from "../lib/google-ping";
import { getSiteUrls } from "../lib/get-site-urls";
async function main() {
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "https://rodalexanderson.com";
// IndexNow para Bing y Yandex
const urls = await getSiteUrls();
const indexNowResult = await submitBatchToIndexNow(urls);
console.log("IndexNow:", indexNowResult.success ? "OK" : indexNowResult.error);
// Ping de sitemap para Google
const sitemapUrl = `${siteUrl}/sitemap.xml`;
const googleResult = await pingGoogleSitemap(sitemapUrl);
console.log("Google Ping:", googleResult ? "OK" : "Error");
}
main().catch(console.error);Errores comunes y troubleshooting
Los codigos de respuesta del API de IndexNow son claros. Aca la tabla completa:
| Codigo | Significado | Causa mas comun | Solucion |
|---|---|---|---|
| 200 | OK | -- | Envio exitoso, URLs en cola |
| 202 | Accepted | -- | Recibido, se procesara despues |
| 400 | Bad Request | JSON invalido o campos faltantes | Verifica el payload con el schema |
| 403 | Forbidden | API key invalida o no verificada | Verifica que el archivo .txt es accesible |
| 422 | Unprocessable | URL fuera del host declarado | Todas las URLs deben ser del mismo host |
| 429 | Too Many Requests | Rate limit excedido | Espera y reintenta, no envies tan seguido |
Error 403: el mas comun
El 403 casi siempre es el archivo de verificacion. Checklist:
# 1. Verifica que el archivo existe
curl https://tudominio.com/tu-api-key.txt
# 2. El contenido debe ser exactamente la key
# Sin espacios, sin saltos de linea al final
# 3. Verifica que el keyLocation en el payload es correcto
# Debe coincidir con la URL del archivo que creasteError 422: URL fuera del host
// MAL: mezclando hosts
const payload = {
host: "rodalexanderson.com",
urlList: [
"https://rodalexanderson.com/blog/post-1",
"https://otro-dominio.com/pagina", // Este causa el 422
],
};
// BIEN: solo URLs del host declarado
const payload = {
host: "rodalexanderson.com",
urlList: [
"https://rodalexanderson.com/blog/post-1",
"https://rodalexanderson.com/blog/post-2",
],
};Error 429: rate limit
IndexNow no publica sus limites exactos, pero la practica recomendada es no enviar mas de una vez por deploy. Si tienes un sitio de alto volumen con multiples deploys por dia, agrega logica para enviar solo las URLs que cambiaron, no todo el sitemap.
La implementacion completa en este sitio
Para dar contexto real: este sitio ya tiene IndexNow implementado. El archivo de verificacion esta en /public/f790fd5bff194046a27c7c2ed7ad836f.txt. El flujo es el del Paso 4 (postbuild), que lee las URLs del app/sitemap.ts existente y las envia a api.indexnow.org despues de cada build exitoso en Vercel.
El resultado practico: posts nuevos aparecen en los resultados de Bing entre unas horas y un par de dias. Antes de IndexNow, podia tardar semanas.
Para el deploy completo en Vercel y configuracion de variables de entorno, revisa la guia de deploy en Vercel para Next.js que cubre todo el proceso paso a paso.
FAQ
Como funciona IndexNow y para que sirve?
IndexNow es un protocolo push que te permite notificar a buscadores (Bing, Yandex) cuando publicas o actualizas contenido. En lugar de esperar a que el crawler descubra tu pagina, tu envias la URL directamente. No garantiza indexacion inmediata, pero reduce el tiempo de espera significativamente.
Google soporta IndexNow?
No oficialmente. Google ha dicho que evalua el protocolo pero a la fecha de este post no lo implementa. IndexNow funciona principalmente con Bing y Yandex. Para Google sigues dependiendo del sitemap, Search Console y el crawler normal.
Como genero y verifico una API key de IndexNow?
Genera una string hexadecimal de al menos 8 caracteres con crypto.randomBytes(16).toString("hex") en Node.js. Luego crea un archivo /public/{tu-key}.txt con la key como contenido. Ese archivo sirve como verificacion de propiedad del dominio. Guarda la key como variable de entorno INDEXNOW_API_KEY.
Cual es la diferencia entre IndexNow y el ping de sitemap de Google?
El ping de sitemap de Google es un GET que le avisa que tu sitemap cambio, pero Google decide cuando crawlear. IndexNow es un push directo de URLs especificas a buscadores que lo soportan (Bing, Yandex). Son mecanismos complementarios, no excluyentes. Implementa ambos.
Como enviar multiples URLs en batch con IndexNow?
Usa el endpoint POST https://api.indexnow.org/indexnow con un JSON que incluye host, key, keyLocation y urlList (array de hasta 10,000 URLs). La respuesta 200 o 202 confirma recepcion exitosa.
IndexNow funciona con Next.js desplegado en Vercel?
Si. La opcion mas simple es un script en postbuild de tu package.json. La opcion mas flexible es un Route Handler que recibe un webhook de Vercel en cada deploy. Ambas funcionan y estan documentadas en el Paso 4 de esta guia.
Recursos
- Documentacion oficial de IndexNow -- spec completa del protocolo
- IndexNow en Bing Webmaster Tools -- panel de verificacion y estadisticas
- IndexNow API Reference -- endpoint y codigos de respuesta
Preguntas frecuentes
Como funciona IndexNow y para que sirve?
IndexNow es un protocolo push que te permite notificar a buscadores (Bing, Yandex) cuando publicas o actualizas contenido. En lugar de esperar a que el crawler descubra tu pagina, tu envias la URL directamente. No garantiza indexacion inmediata, pero reduce el tiempo de espera significativamente.
Google soporta IndexNow?
No oficialmente. Google ha dicho que evalua el protocolo pero a la fecha de este post no lo implementa. IndexNow funciona principalmente con Bing y Yandex. Para Google sigues dependiendo del sitemap, Search Console y el crawler normal.
Como genero y verifico una API key de IndexNow?
Genera una string hexadecimal de al menos 8 caracteres (puedes usar crypto.randomUUID() o crypto.randomBytes() de Node.js). Luego crea un archivo de texto en /public/{tu-key}.txt con la key como contenido. Ese archivo sirve como verificacion de propiedad del dominio.
Cual es la diferencia entre IndexNow y el ping de sitemap de Google?
El ping de sitemap de Google es un GET a un endpoint que le avisa que tu sitemap cambio, pero Google decide cuando crawlear. IndexNow es un push directo de URLs especificas a buscadores que lo soportan (Bing, Yandex). Son mecanismos complementarios, no excluyentes.
Como enviar multiples URLs en batch con IndexNow?
Usa el endpoint POST https://api.indexnow.org/indexnow con un JSON que incluye host, key, keyLocation y urlList (array de URLs). Puedes enviar hasta 10,000 URLs por request. La respuesta 200 confirma recepcion exitosa.
IndexNow funciona con Next.js desplegado en Vercel?
Si. La implementacion mas comun es un Route Handler que recibe un webhook en cada deploy y envia las URLs al API de IndexNow. Tambien puedes ejecutarlo como script postbuild. Ambas opciones funcionan perfectamente en Vercel.
Articulos relacionados
12 Errores SEO que Arruinan tu Blog (y Como Arreglarlos)
Los errores SEO mas comunes que destrozan blogs de desarrolladores. Diagnostico, fix y verificacion para cada uno. Para blogs en Next.js y cualquier stack.
Indexar tu Blog en Google: Guia Tecnica
Como indexar un blog en Google Search Console: sitemap, robots.txt, canonical URLs, structured data, Core Web Vitals e IndexNow. Guia tecnica completa.
SEO en Next.js: Metadata API, Open Graph y Sitemap
Optimiza el SEO de tu app Next.js. Metadata API, Open Graph, Twitter Cards, sitemap dinámico, robots.txt y structured data con JSON-LD.