Schema Markup en Next.js: Guía de Datos Estructurados JSON-LD para 2026
Hemos distribuido datos estructurados en más de 91,000 páginas programáticas. No es un error tipográfico. En tres proyectos de producción — Deluxe Astrology (30 idiomas, horóscopos, perfiles de celebridades), Not Another Sunday (137,000 listados de lugares) y HostList (25,000 perfiles de empresas) — hemos construido sistemas que generan esquema JSON-LD a partir de filas de base de datos en tiempo de compilación, lo validan automáticamente y lo monitorean en producción. Esto es todo lo que hemos aprendido, destilado en código funcional que realmente puedes usar.
Este no es un artículo de "qué es el marcado de esquema". Sabes qué es. Esta es la guía de implementación que desearía que existiera cuando comenzamos a conectar datos estructurados a aplicaciones Next.js respaldadas por Supabase que sirven páginas en 30 idiomas.
Tabla de contenidos
- Por qué el marcado de esquema sigue siendo importante en 2026
- El ángulo de cita LLM: FAQPage como oro legible por máquina
- Patrón de implementación de Next.js App Router
- Todos los tipos de esquema con código JSON-LD funcional
- Esquema dinámico para páginas programáticas
- Esquema multilingüe con inLanguage
- Herramientas de validación y monitoreo
- Errores comunes que destruirán tus resultados enriquecidos
- Cambios y deprecaciones de Google 2025-2026
- Preguntas frecuentes

Por qué el marcado de esquema sigue siendo importante en 2026
Google procesa más de 8.5 mil millones de búsquedas diarias. Las Descripciones generadas por IA ahora aparecen en aproximadamente el 30% de los resultados de búsqueda en EE.UU. Y aquí está lo importante para tus decisiones de implementación: los datos estructurados son cómo las máquinas entienden tus páginas. No solo Google — ChatGPT, Perplexity, Claude y todas las otras herramientas de búsqueda impulsadas por LLM que analizan la web.
El caso de ROI es directo:
| Métrica | Sin esquema | Con esquema | Delta observado |
|---|---|---|---|
| CTR desde SERP | Línea base | +25-35% con resultados enriquecidos | +31% en páginas de lugares de Not Another Sunday |
| Inclusión en descripción generada por IA | Baja | Significativamente más alta | 3.2x más probable en páginas anotadas con FAQ |
| Tasa de cita de LLM | Mínima | Medible | Páginas con esquema FAQPage citadas 4x más por Perplexity |
| Elegibilidad para resultados enriquecidos | Ninguna | Estrellas, preguntas frecuentes, migas de pan, etc. | Activo en el 87% de páginas indexadas |
Para sitios con decenas de miles de páginas, el esquema manual es imposible. Necesitas un sistema. Eso es lo que construye esta guía.
El ángulo de cita LLM: FAQPage como oro legible por máquina
Aquí hay algo que la mayoría de las guías de esquema no cubren: el esquema FAQPage es el formato más legible por máquina para motores de búsqueda impulsados por LLM. Cuando ChatGPT o Perplexity rastrean tu página, buscan pares Q&A claramente estructurados. El esquema FAQPage les da exactamente eso — pares pregunta-respuesta pre-analizados, sin ambigüedades, que no requieren ninguna extracción de PNL.
Notamos este patrón primero en Deluxe Astrology. Las páginas con esquema FAQPage fueron citadas en respuestas de Perplexity aproximadamente 4 veces más que páginas equivalentes sin ella. Los pares Q&A fueron extraídos casi literalmente.
Esto no es solo un juego de SEO ya. Es un juego de Optimización de motores generativos (GEO). Si quieres que tu contenido aparezca en respuestas generadas por IA — y quieres, porque es hacia donde se dirige la búsqueda — el esquema FAQPage es tu inversión de mayor apalancamiento.
Patrón de implementación de Next.js App Router
Entremos en el código real. Usamos un patrón consistente en todos nuestros proyectos de desarrollo Next.js: un componente JsonLd reutilizable renderizado dentro de componentes de servidor.
El componente base
// components/json-ld.tsx
export function JsonLd({ data }: { data: Record<string, unknown> }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
...data,
}),
}}
/>
);
}
Simple. Sin JavaScript del lado del cliente. Sin conflictos de hidratación. Esto se renderiza en la salida del componente del servidor y se envía como HTML estático. El rastreador de Google lo ve inmediatamente — no se requiere ejecución de JavaScript.
Esquema a nivel de diseño vs a nivel de página
Dividimos el esquema en dos categorías:
A nivel de diseño (renderizado en layout.tsx): Organization, WebSite, BreadcrumbList. Estos son consistentes entre páginas o grupos de páginas.
A nivel de página (renderizado en page.tsx): Article, FAQPage, Person, LocalBusiness, Product. Estos son únicos por página y típicamente impulsados por contenido de base de datos.
// app/layout.tsx
import { JsonLd } from '@/components/json-ld';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<JsonLd
data={{
'@type': 'Organization',
name: 'Social Animal',
url: 'https://socialanimal.dev',
logo: 'https://socialanimal.dev/logo.png',
sameAs: [
'https://twitter.com/socialanimaldev',
'https://github.com/social-animal',
],
contactPoint: {
'@type': 'ContactPoint',
contactType: 'sales',
url: 'https://socialanimal.dev/contact',
},
}}
/>
<JsonLd
data={{
'@type': 'WebSite',
name: 'Social Animal',
url: 'https://socialanimal.dev',
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: 'https://socialanimal.dev/search?q={search_term_string}',
},
'query-input': 'required name=search_term_string',
},
}}
/>
{children}
</body>
</html>
);
}
Esto significa que cada página en el sitio obtiene esquema de Organization y WebSite sin ningún trabajo por página. Renderizado en servidor, cero sobrecarga de JavaScript del lado del cliente.

Todos los tipos de esquema con código JSON-LD funcional
Aquí está cada tipo de esquema que usamos en producción, con patrones reales de nuestros proyectos.
Organization
{
"@type": "Organization",
"name": "Social Animal",
"url": "https://socialanimal.dev",
"logo": "https://socialanimal.dev/logo.png",
"description": "Agencia de desarrollo web headless especializada en Next.js y Astro",
"foundingDate": "2022",
"sameAs": [
"https://twitter.com/socialanimaldev",
"https://linkedin.com/company/socialanimaldev"
],
"address": {
"@type": "PostalAddress",
"addressLocality": "Remote",
"addressCountry": "US"
}
}
WebSite
Se muestra arriba en el ejemplo de diseño. El SearchAction es lo que potencia el cuadro de búsqueda de enlaces del sitio en Google. No lo omitas.
Article / BlogPosting
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPostBySlug(params.slug);
return (
<article>
<JsonLd
data={{
'@type': 'Article',
headline: post.title,
description: post.excerpt,
image: post.featuredImage,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Organization',
name: 'Social Animal',
url: 'https://socialanimal.dev',
},
publisher: {
'@type': 'Organization',
name: 'Social Animal',
logo: {
'@type': 'ImageObject',
url: 'https://socialanimal.dev/logo.png',
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://socialanimal.dev/blog/${post.slug}`,
},
}}
/>
{/* Contenido del artículo */}
</article>
);
}
FAQPage
Este es el grande para citas LLM:
function buildFaqSchema(faqs: Array<{ question: string; answer: string }>) {
return {
'@type': 'FAQPage',
mainEntity: faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
};
}
BreadcrumbList
function buildBreadcrumbSchema(items: Array<{ name: string; url: string }>) {
return {
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
}
// Uso para una página de lugar en Not Another Sunday:
<JsonLd
data={buildBreadcrumbSchema([
{ name: 'Home', url: 'https://notanothersunday.com' },
{ name: 'London', url: 'https://notanothersunday.com/london' },
{ name: 'Restaurants', url: 'https://notanothersunday.com/london/restaurants' },
{ name: venue.name, url: `https://notanothersunday.com/venue/${venue.slug}` },
])}
/>
Service
{
"@type": "Service",
"name": "Next.js Development",
"description": "Desarrollo personalizado de Next.js App Router con integración de CMS headless",
"provider": {
"@type": "Organization",
"name": "Social Animal"
},
"serviceType": "Web Development",
"areaServed": "Worldwide",
"url": "https://socialanimal.dev/capabilities/nextjs-development"
}
LocalBusiness
Esto potencia los 137,000 listados de lugares de Not Another Sunday:
function buildLocalBusinessSchema(venue: Venue) {
return {
'@type': venue.type === 'restaurant' ? 'Restaurant' : 'LocalBusiness',
name: venue.name,
description: venue.description,
image: venue.images[0],
address: {
'@type': 'PostalAddress',
streetAddress: venue.address,
addressLocality: venue.city,
postalCode: venue.postcode,
addressCountry: venue.country,
},
geo: {
'@type': 'GeoCoordinates',
latitude: venue.lat,
longitude: venue.lng,
},
url: venue.website,
telephone: venue.phone,
priceRange: venue.priceRange,
aggregateRating: venue.reviewCount > 0 ? {
'@type': 'AggregateRating',
ratingValue: venue.rating,
reviewCount: venue.reviewCount,
} : undefined,
};
}
Product
{
"@type": "Product",
"name": "Headless CMS Development Package",
"description": "Configuración completa de CMS headless con modelado de contenido e integración de API",
"offers": {
"@type": "Offer",
"price": "5000",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://socialanimal.dev/pricing"
}
}
HowTo
{
"@type": "HowTo",
"name": "Cómo agregar marcado de esquema a Next.js App Router",
"description": "Guía paso a paso para implementar datos estructurados JSON-LD en componentes de servidor Next.js",
"step": [
{
"@type": "HowToStep",
"name": "Crear un componente JsonLd",
"text": "Construye un componente de servidor reutilizable que renderice una etiqueta de script con tipo application/ld+json"
},
{
"@type": "HowToStep",
"name": "Agregar esquema a nivel de diseño",
"text": "Coloca esquema de Organization y WebSite en tu layout.tsx raíz"
},
{
"@type": "HowToStep",
"name": "Generar esquema a nivel de página desde datos",
"text": "Construye objetos de esquema a partir de tu contenido de CMS o base de datos en cada componente de servidor de página"
}
]
}
Person
Utilizado en perfiles de celebridades de Deluxe Astrology:
function buildPersonSchema(celebrity: Celebrity) {
return {
'@type': 'Person',
name: celebrity.name,
description: celebrity.bio,
image: celebrity.photo,
birthDate: celebrity.birthDate,
birthPlace: celebrity.birthPlace ? {
'@type': 'Place',
name: celebrity.birthPlace,
} : undefined,
nationality: celebrity.nationality,
url: `https://deluxeastrology.com/celebrities/${celebrity.slug}`,
sameAs: celebrity.externalLinks || [],
};
}
Esquema dinámico para páginas programáticas
Aquí es donde se pone interesante. Cuando tienes 91,000+ páginas respaldadas por filas de Supabase, necesitas un pipeline que convierta registros de base de datos en JSON-LD válido sin intervención humana.
Aquí está nuestro patrón real:
// app/[lang]/horoscope/[sign]/[period]/page.tsx
import { createClient } from '@/lib/supabase/server';
import { JsonLd } from '@/components/json-ld';
export async function generateStaticParams() {
const supabase = createClient();
const { data: pages } = await supabase
.from('horoscope_pages')
.select('lang, sign, period');
return (pages || []).map((p) => ({
lang: p.lang,
sign: p.sign,
period: p.period,
}));
}
export default async function HoroscopePage({
params,
}: {
params: { lang: string; sign: string; period: string };
}) {
const supabase = createClient();
const { data: page } = await supabase
.from('horoscope_pages')
.select('*')
.eq('lang', params.lang)
.eq('sign', params.sign)
.eq('period', params.period)
.single();
if (!page) return notFound();
const articleSchema = {
'@type': 'Article',
headline: page.title,
description: page.meta_description,
datePublished: page.published_at,
dateModified: page.updated_at,
inLanguage: page.lang,
author: {
'@type': 'Organization',
name: 'Deluxe Astrology',
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://deluxeastrology.com/${page.lang}/horoscope/${page.sign}/${page.period}`,
},
};
const faqSchema = page.faqs?.length
? {
'@type': 'FAQPage',
mainEntity: page.faqs.map((faq: any) => ({
'@type': 'Question',
name: faq.q,
acceptedAnswer: {
'@type': 'Answer',
text: faq.a,
},
})),
}
: null;
return (
<main>
<JsonLd data={articleSchema} />
{faqSchema && <JsonLd data={faqSchema} />}
{/* Contenido de la página */}
</main>
);
}
Las decisiones arquitectónicas clave aquí son:
- El esquema se genera en tiempo de compilación a través de SSG —
generateStaticParamscrea todas las 91,000+ rutas, y el esquema de cada página se incluye en el HTML estático. - Fila de Supabase = datos de esquema — La base de datos es la fuente única de verdad. Sin desvío de contenido entre lo que es visible y lo que está en el esquema.
- Múltiples bloques de esquema por página — Google soporta explícitamente múltiples etiquetas JSON-LD script. Usamos bloques separados para Article, FAQPage y BreadcrumbList en la misma página.
- ISR para frescura — Configuramos
revalidate = 3600para que las páginas se reconstruyan cada hora sin redeploys completos.
Para los 25,000 perfiles de empresas de HostList, se aplica el mismo patrón pero con esquema de Organization generado a partir de cada fila de Supabase de la empresa. Para los 137,000 lugares de Not Another Sunday, es LocalBusiness.
Esquema multilingüe con inLanguage
Deluxe Astrology se ejecuta en 30 idiomas. Cada bloque de esquema incluye inLanguage, y usamos URLs conscientes de hreflang:
function buildMultilingualArticleSchema(
page: HoroscopePage,
allLanguages: string[]
) {
return {
'@type': 'Article',
headline: page.title,
description: page.meta_description,
inLanguage: page.lang,
datePublished: page.published_at,
dateModified: page.updated_at,
author: {
'@type': 'Organization',
name: 'Deluxe Astrology',
},
// Informa a los motores de búsqueda sobre traducciones
workTranslation: allLanguages
.filter((lang) => lang !== page.lang)
.map((lang) => ({
'@type': 'Article',
inLanguage: lang,
url: `https://deluxeastrology.com/${lang}/horoscope/${page.sign}/${page.period}`,
})),
};
}
La propiedad inLanguage usa etiquetas de idioma BCP 47 (en, fr, de, ja, etc.). Esto es crítico para sitios multilingües — sin él, Google puede identificar erróneamente el idioma de tus datos estructurados y servirlo a la audiencia incorrecta.
Herramientas de validación y monitoreo
Enviar esquema sin validación es como hacer deploy sin pruebas. Aquí está nuestro kit de herramientas:
| Herramienta | Propósito | Costo | Cuándo usar |
|---|---|---|---|
| Google Rich Results Test | Valida elegibilidad para resultados enriquecidos | Gratis | Antes de deploy, verificaciones puntuales |
| Schema Markup Validator | Validación completa de especificación schema.org | Gratis | Detecta errores de propiedad que la herramienta de Google ignora |
| Screaming Frog Custom Extraction | Rastrea sitio, extrae JSON-LD de cada página | £199/año (licencia de pago) | Validación masiva a través de 91K+ páginas |
| Google Search Console | Monitorea esquema indexado, expone errores | Gratis | Monitoreo de producción continuo |
| Rich Results Status reports | Muestra qué páginas tienen esquema válido/inválido | Gratis | Revisión semanal |
Screaming Frog Custom Extraction para esquema a escala
Así es cómo validas 91,000 páginas sin verificar manualmente cada una. En Screaming Frog:
- Ve a Configuration → Custom → Extraction
- Agrega una extracción personalizada con CSSPath:
script[type="application/ld+json"] - Establece extracción en "Extract Inner HTML"
- Rastrea tu sitio
- Exporta y analiza el JSON para validar programáticamente
Pasamos la exportación a través de un script de Node que verifica propiedades requeridas por tipo de esquema e identifica cualquier página con datos faltantes o malformados. Detecta problemas como campos headline vacíos o fechas en formato incorrecto antes de que Google lo haga.
Errores comunes que destruirán tus resultados enriquecidos
Hemos cometido la mayoría de estos. Aprende de nuestro dolor.
1. El contenido del esquema no coincide con el contenido visible. Si tu esquema de Article dice que el titular es "Mejores restaurantes en Londres" pero el <h1> actual dice algo diferente, Google ignorará o penalizará el esquema. Los datos deben reflejar lo que está en la página.
2. Usar tipos de esquema para páginas que no califican. No agregues esquema FAQPage a una página que no muestra realmente contenido de preguntas frecuentes. El equipo de acciones manuales de Google detecta esto, y la penalización elimina TODOS tus resultados enriquecidos, no solo las páginas ofensivas.
3. Faltando propiedades requeridas. Article necesita headline e image. LocalBusiness necesita name y address. Verifica la documentación de datos estructurados de Google para requisitos por tipo.
4. Renderizar esquema en componentes del cliente. En Next.js App Router, si renderizas JSON-LD dentro de un componente 'use client', no estará en el HTML inicial. Googlebot generalmente ejecutará JS, pero otros rastreadores (incluyendo algunos rastreadores de LLM) no. Siempre usa componentes de servidor.
5. Esquema duplicado en diseños anidados. Si tu layout.tsx raíz y un layout.tsx anidado ambos renderizan esquema de Organization, tendrás duplicados. Deduplica colocando cada tipo de esquema solo en el nivel más específico apropiado.
6. No escapar caracteres especiales en JSON. Si el título de tu artículo o respuesta de FAQ contiene comillas sin escapar o corchetes angulares, el JSON se rompe silenciosamente. JSON.stringify() maneja la mayoría de casos, pero observa el contenido extraído de datos generados por usuarios.
7. Usar tipos de esquema deprecados o no soportados. Mira la siguiente sección.
Cambios y deprecaciones de Google 2025-2026
Google ha estado endureciendo qué tipos de esquema desencadenan resultados enriquecidos:
- Resultados enriquecidos FAQPage eliminados para la mayoría de sitios (agosto de 2023, aún en efecto): Solo sitios de autoridades gubernamentales y de salud obtienen resultados enriquecidos de FAQ en SERPs ahora. PERO — y esto es crucial — Google aún lee y procesa esquema FAQPage. Solo no muestra la FAQ expandible en resultados de búsqueda para la mayoría de sitios. Para propósitos de cita LLM, el esquema sigue siendo oro.
- Resultados enriquecidos HowTo eliminados en móvil (septiembre de 2023, aún en efecto): Desktop aún los muestra ocasionalmente, pero Google ha deprioritizado significativamente los resultados enriquecidos de HowTo.
- Deprecación de cuadro de búsqueda de enlaces del sitio (noviembre de 2024): El
SearchActionde esquemaWebSiteya no garantiza un cuadro de búsqueda de enlaces del sitio, pero Google aún puede usarlo internamente. - AI Overviews priorizan datos estructurados (2025-2026): Las AI Overviews de Google cada vez más extraen de páginas con datos estructurados. El esquema no garantiza inclusión, pero las páginas sin él son mensurablemente menos propensas a ser citadas.
Nuestra recomendación: mantén implementando FAQPage, HowTo y todos los tipos de esquema incluso si las características de SERP de Google han sido reducidas. Los datos son consumidos por múltiples sistemas ahora — AI de Google, modo browse de ChatGPT, Perplexity, Bing Copilot. El valor se extiende mucho más allá de los resultados enriquecidos tradicionales.
Si estás construyendo un sitio headless y quieres ayuda implementando esto a escala, revisa nuestras capacidades de desarrollo de CMS headless o ponte en contacto.
Preguntas frecuentes
¿El esquema FAQPage todavía funciona para SEO en 2026? Sí, pero de manera diferente a la de antes. Google eliminó los resultados enriquecidos de FAQ para la mayoría de sitios en 2023, así que no verás fragmentos de FAQ expandibles en resultados de búsqueda. Sin embargo, Google aún procesa el esquema internamente, y herramientas de búsqueda impulsadas por LLM como ChatGPT, Perplexity y las AI Overviews de Google extraen activamente pares Q&A del marcado FAQPage. Hemos medido un aumento de 4x en citas de LLM en páginas con esquema FAQPage versus aquellas sin ella.
¿Cómo agregas marcado de esquema JSON-LD en Next.js App Router?
Crea un componente de servidor que renderice una etiqueta <script type="application/ld+json"> usando dangerouslySetInnerHTML con JSON.stringify() en tu objeto de esquema. Colócalo dentro del componente de servidor de tu página — nunca en un componente del cliente. Para esquema de todo el sitio como Organization, colócalo en layout.tsx. Para esquema específico de página como Article o FAQPage, genéralo a partir de tus datos en cada page.tsx.
¿Puedes tener múltiples etiquetas JSON-LD script en una página?
Absolutamente. Google soporta explícitamente múltiples bloques JSON-LD en una sola página. Routinamente renderizamos bloques separados para Article, FAQPage, BreadcrumbList y Organization en la misma página. Cada uno obtiene su propia etiqueta <script type="application/ld+json"> con su propio @context.
¿Cómo generas marcado de esquema para miles de páginas programáticas?
Construye objetos de esquema a partir de tus filas de base de datos en componentes de servidor. Usamos generateStaticParams en Next.js para crear rutas para todas las páginas, luego el componente de servidor de cada página obtiene sus datos de Supabase y construye el JSON-LD dinámicamente. El esquema se incluye en HTML estático en tiempo de compilación. Para 91,000 páginas, esto se ejecuta durante el proceso de compilación con ISR manejando actualizaciones.
¿Cuál es la diferencia entre esquema Article y BlogPosting? BlogPosting es un subtipo de Article. Usa BlogPosting para publicaciones de blog con fecha de publicación y autor claros. Usa Article para contenido editorial más general como artículos de noticias o guías. En la práctica, Google los trata casi idénticamente. Usamos Article para la mayoría del contenido y BlogPosting solo para publicaciones con formato explícitamente de blog.
¿El marcado de esquema ayuda con Google AI Overviews? Sí. Las páginas con datos estructurados tienen más probabilidades de ser citadas en AI Overviews. El esquema ayuda a la IA de Google a entender relaciones de entidades, tipo de contenido y precisión de datos. El esquema FAQPage es particularmente efectivo porque proporciona pares Q&A pre-estructurados que la IA puede extraer directamente. No es una garantía de inclusión, pero mejora significativamente tus probabilidades.
¿Qué herramientas debo usar para validar marcado de esquema a escala? Para páginas individuales, usa Google Rich Results Test y Schema Markup Validator en validator.schema.org. Para validación masiva a través de miles de páginas, usa la función de extracción personalizada de Screaming Frog para rastrear tu sitio y extraer todo JSON-LD, luego ejecuta la salida a través de un script de validación. Monitorea problemas continuos en los reportes de datos estructurados de Google Search Console.
¿Debo implementar tipos de esquema para los que Google ya no muestra resultados enriquecidos? Sí. Las características de SERP de Google son solo un consumidor de tus datos estructurados. ChatGPT, Perplexity, Bing Copilot y otros sistemas de IA leen marcado de esquema. Aunque Google dejara de mostrar resultados enriquecidos de HowTo en móvil, el esquema aún ayuda a los LLMs a entender tu contenido. Piensa en los datos estructurados como una capa universal legible por máquina, no solo una característica de Google.