El SEO Técnico: La Base Invisible de tu Éxito Online
Lanzar un sitio web sin una configuración SEO adecuada es como abrir una tienda en un callejón oscuro sin señalización. Puede que tengas el mejor producto del mundo, pero nadie te encontrará. En 2025, con la explosión de la IA y los motores de búsqueda cada vez más sofisticados, la configuración técnica SEO se ha vuelto más crítica que nunca.
Esta guía te mostrará exactamente cómo configurar dos elementos fundamentales para el SEO de tu sitio: robots.txt y sitemap.xml, usando Next.js 15 y las últimas mejores prácticas.
¿Por Qué Necesitas robots.txt y sitemap.xml?
Antes de sumergirnos en el código, entendamos qué hace cada archivo. Y si quieres profundizar en otros aspectos técnicos del SEO, consulta nuestra guía definitiva de Core Web Vitals y cómo implementar datos estructurados correctamente.
robots.txt: El Guardián de tu Sitio
El archivo robots.txt le dice a los rastreadores web (como Googlebot) qué partes de tu sitio pueden o no pueden indexar. Es tu primera línea de defensa contra:
Nota 2025: Además de robots.txt, considera implementar llms.txt, el nuevo estándar que ayuda a las IAs como ChatGPT y Claude a entender tu sitio. Aprende cómo implementarlo paso a paso.
- Scrapers de IA no deseados (GPTBot, ChatGPT-User, Claude-Web, etc.)
- Indexación de archivos internos (/_next/static/, /api/, etc.)
- Desperdicio de crawl budget en páginas sin valor SEO
sitemap.xml: El Mapa del Tesoro
Un sitemap es como un mapa que le entregas a Google diciendo "estas son todas las páginas importantes de mi sitio". Incluye:
- URLs de todas tus páginas
- Fecha de última modificación
- Frecuencia de actualización esperada
- Prioridad relativa de cada página
Implementación en Next.js 15: robots.txt
Next.js 15 introdujo la MetadataRoute API, que permite generar robots.txt de forma dinámica y type-safe. Aquí está la implementación completa:
Paso 1: Crear el archivo robots.ts
Crea un archivo en src/app/robots.ts:
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://tu-dominio.com';
return {
rules: [
// Regla principal para todos los crawlers
{
userAgent: '*',
allow: '/',
disallow: [
// Archivos internos de Next.js
'/_next/static/',
'/_next/image',
// Rutas API
'/api/',
// Áreas privadas
'/admin/',
'/private/',
// Artefactos de build
'/*.json$',
'/*_buildManifest.js$',
'/*_middlewareManifest.js$',
'/*_ssgManifest.js$',
'/*.js.map$',
// Contenido temporal/draft
'/drafts/',
'/*?preview=*',
],
crawlDelay: 0,
},
// Reglas específicas para Googlebot
{
userAgent: 'Googlebot',
allow: [
'/',
'/blog/',
'/case-studies/',
'/services/',
'/about/',
],
disallow: [
'/_next/',
'/api/',
],
},
// Permitir a Googlebot rastrear imágenes
{
userAgent: 'Googlebot-Image',
allow: '/',
disallow: [
'/_next/static/',
],
},
// Reglas específicas para Bingbot
{
userAgent: 'Bingbot',
allow: '/',
disallow: [
'/_next/',
'/api/',
],
crawlDelay: 1, // Bing recomienda crawl delay
},
// Bloquear scrapers de IA (crucial en 2025)
{
userAgent: [
'GPTBot', // OpenAI crawler
'ChatGPT-User', // ChatGPT
'CCBot', // Common Crawl
'anthropic-ai', // Anthropic
'Claude-Web', // Claude
'cohere-ai', // Cohere
],
disallow: '/',
},
],
sitemap: `${baseUrl}/sitemap.xml`,
host: baseUrl,
};
}
¿Por Qué Bloquear Scrapers de IA?
En 2025, los scrapers de IA son omnipresentes. Empresas como OpenAI, Anthropic y Cohere entrenan sus modelos raspando la web. Mientras que esto puede parecer inofensivo, tiene implicaciones:
- Consumo de ancho de banda sin beneficio directo para tu negocio
- Posible uso de tu contenido en respuestas de IA sin atribución
- Competencia indirecta - la IA puede responder preguntas que antes llevaban tráfico a tu sitio
Bloquearlos te da control sobre cómo se usa tu contenido.
Implementación en Next.js 15: sitemap.xml
El sitemap es más complejo porque necesita ser dinámico - debe incluir todas tus páginas, posts de blog, y cualquier contenido generado dinámicamente.
Paso 2: Crear el archivo sitemap.ts
Crea un archivo en src/app/sitemap.ts:
import { MetadataRoute } from 'next';
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://tu-dominio.com';
// Obtener posts del blog dinámicamente desde el sistema de archivos
const blogPosts: MetadataRoute.Sitemap = (() => {
try {
const postsDirectory = path.join(process.cwd(), 'content/blog');
// Verificar si el directorio existe
if (!fs.existsSync(postsDirectory)) {
return [];
}
const fileNames = fs.readdirSync(postsDirectory);
return fileNames
.filter(fileName => fileName.endsWith('.md'))
.map(fileName => {
const slug = fileName.replace(/\.md$/, '');
const fullPath = path.join(postsDirectory, fileName);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const { data } = matter(fileContents);
return {
slug,
publishDate: data.publishDate,
draft: data.draft || false,
};
})
.filter(post => !post.draft) // Excluir drafts
.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.publishDate),
changeFrequency: 'monthly' as const,
priority: 0.7,
}));
} catch (error) {
console.error('Error reading blog posts for sitemap:', error);
return [];
}
})();
const staticPages: MetadataRoute.Sitemap = [
// Páginas principales (máxima prioridad)
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 1,
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.9,
},
{
url: `${baseUrl}/contact`,
lastModified: new Date(),
changeFrequency: 'yearly' as const,
priority: 0.9,
},
// Páginas de servicios
{
url: `${baseUrl}/services`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.9,
},
// Blog
{
url: `${baseUrl}/blog`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.9,
},
// Páginas legales (prioridad baja)
{
url: `${baseUrl}/legal/privacy-policy`,
lastModified: new Date(),
changeFrequency: 'yearly' as const,
priority: 0.3,
},
{
url: `${baseUrl}/legal/terms-of-service`,
lastModified: new Date(),
changeFrequency: 'yearly' as const,
priority: 0.3,
},
];
// Combinar todas las páginas
return [...staticPages, ...blogPosts];
}
Entendiendo las Prioridades y Frecuencias
La configuración de priority y changeFrequency es estratégica:
Prioridades (0.0 - 1.0):
- 1.0: Homepage (tu página más importante)
- 0.9: Páginas principales (servicios, blog, contacto)
- 0.7-0.8: Contenido específico (posts, productos)
- 0.3: Páginas legales (necesarias pero no críticas para SEO)
Frecuencias de cambio:
- daily/weekly: Contenido que actualizas constantemente (blog index, homepage)
- monthly: Páginas que actualizas ocasionalmente (servicios, about)
- yearly: Páginas estáticas (términos legales)
Solución de Problemas Comunes
Error: "Cannot resolve '@/.velite'"
Este fue un error que encontramos durante el desarrollo de nandark.com. El problema es que Velite genera un directorio .velite con los datos procesados, pero no está disponible durante el build con Turbopack.
Solución: Usar filesystem operations directamente en lugar de importar desde @/.velite:
// ❌ No funciona en build
import { posts } from '@/.velite';
// ✅ Funciona siempre
const postsDirectory = path.join(process.cwd(), 'content/blog');
const fileNames = fs.readdirSync(postsDirectory);
Verificar que robots.txt funciona
Después del deploy, verifica que tu robots.txt es accesible:
curl https://tu-dominio.com/robots.txt
Deberías ver el contenido generado por tu función.
Verificar el sitemap.xml
curl https://tu-dominio.com/sitemap.xml
Checklist de Lanzamiento SEO 2025
Antes de hacer deploy a producción, verifica:
-
robots.txtestá generándose correctamente -
sitemap.xmlincluye todas las páginas importantes - Scrapers de IA están bloqueados (si lo deseas)
- Variables de entorno configuradas (
NEXT_PUBLIC_SITE_URL) - Build exitoso sin errores de TypeScript
- URLs en el sitemap usan HTTPS
- Meta tags configurados en todas las páginas
- Imágenes tienen alt text descriptivo
- Configurado Google Search Console
- Configurado Bing Webmaster Tools
- Sitemap enviado a ambos buscadores
Monitoreo Post-Lanzamiento
Una vez en producción:
- Google Search Console: Monitorea errores de rastreo, cobertura de índice, y Core Web Vitals
- Bing Webmaster Tools: Similar a GSC pero para Bing
- Verifica el sitemap semanalmente: Asegúrate de que se actualiza con contenido nuevo
- Revisa logs de server: Identifica bots desconocidos que intentan rastrear tu sitio
Conclusión: El SEO Técnico es una Inversión, No un Gasto
Configurar correctamente tu robots.txt y sitemap.xml desde el inicio te ahorrará dolores de cabeza y te dará una ventaja competitiva clara. En la era de la IA y los motores de búsqueda semánticos, cada detalle técnico cuenta.
Para completar tu estrategia SEO, recomendamos:
- Auditar tu SEO regularmente con herramientas de IA
- Implementar datos estructurados para resultados enriquecidos
- Prepararte para GEO (Generative Engine Optimization)
¿Necesitas Lanzar Tu Web con SEO Optimizado?
En Nandark construimos sitios con Next.js 15 que salen a producción con SEO técnico perfecto desde el día uno. Incluimos:
- robots.txt y sitemap.xml optimizados para Google y crawlers de IA
- Datos estructurados (Schema.org) server-side
- Core Web Vitals optimizados (LCP < 2.5s)
- llms.txt para aparecer en ChatGPT, Perplexity y Claude
Servicios relacionados
- Desarrollo Web con Next.js: Sitios rápidos y optimizados para SEO
- Optimización SEO Técnica: Auditoría y mejoras para sitios existentes
Conversemos sobre tu proyecto: Respuesta en 24 horas.
