Toate articolele
·de · Manilla Services·Next.jsStructured DataJSON-LDSchema.orgApp Router

Structured data pentru Next.js App Router: ghidul complet

Cum adaugi corect JSON-LD schema.org în Next.js App Router: pattern-ul @graph centralizat, convenții de @id, un nod per tip de pagină și cum eviți duplicatele care strică rich results.

Structured data pentru Next.js App Router: ghidul complet

Pe scurt: în Next.js App Router adaugi structured data ca JSON-LD, injectat printr-un component de <script type="application/ld+json">, ideal ca un singur @graph per pagină cu @id-uri stabile. Cel mai frecvent bug nu e schema lipsă, ci schema duplicată — același tip emis de două ori de pe surse diferite. Mai jos, pattern-ul care scalează.

De ce contează în App Router

App Router randează majoritatea paginilor pe server (Server Components), ceea ce e ideal pentru structured data: JSON-LD ajunge în HTML-ul inițial, exact ce vede crawlerul, fără să aștepte JavaScript. Nu ai nevoie de biblioteci externe — un simplu component care serializează un obiect e suficient.

Componentul JsonLd

Cel mai curat mod e un component minimal reutilizabil:

export default function JsonLd({ data }: { data: object }) {
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
    />
  );
}

dangerouslySetInnerHTML sună periculos, dar aici e corect: serializezi un obiect pe care îl controlezi tu, nu input de utilizator. Îl folosești în orice Server Component, inclusiv în layout.tsx pentru schema globală și în page.tsx pentru schema specifică paginii.

Pattern-ul @graph centralizat

Greșeala clasică e să împrăștii noduri JSON-LD prin mai multe componente — unul din layout, altul din pagină, altul dintr-un component de breadcrumb, altul dintr-un FAQ. Rezultatul: aceeași pagină emite trei <script>-uri separate, cu noduri care se suprapun.

Soluția: un singur @graph per pagină, cu toate nodurile într-un array, fiecare cu un @id unic:

<JsonLd data={{
  '@context': 'https://schema.org',
  '@graph': [
    { '@type': 'WebPage', '@id': `${url}#webpage`, /* ... */ },
    { '@type': 'BreadcrumbList', '@id': `${url}#breadcrumb`, /* ... */ },
    { '@type': 'FAQPage', '@id': `${url}#faq`, /* ... */ },
  ],
}} />

Nodurile se referă între ele prin @id (ex: WebPage.breadcrumb → { '@id': '...#breadcrumb' }), formând un graf conectat pe care Google îl citește ca un întreg coerent.

Convenția de @id

Folosește @id-uri stabile bazate pe URL + fragment: ${url}#webpage, ${url}#breadcrumb, ${baseUrl}/#org pentru entitatea globală. Astfel:

Ce schema pe ce tip de pagină

Capcana duplicatelor

Ăsta e bug-ul care apare cel mai des și e invizibil în cod — îl vezi doar în Rich Results Test. Sursele comune:

Am scris un studiu de caz întreg despre asta — cum elimini duplicatele JSON-LD — cu cele patru surse și fix-ul pe fiecare.

Cum validezi

npx tsc --noEmit verifică tipurile, dar NU graful randat. Structured data se validează la runtime:

Regula: după fiecare pagină nouă cu schema, ruleaz-o prin Rich Results Test. Tipurile corecte în cod nu garantează @graph corect randat.

Rezumat

Structured data în App Router e simplu dacă respecți trei reguli: un singur @graph per pagină, @id-uri stabile bazate pe URL, și validare la runtime nu doar la compilare. Restul e maparea tipului de schema pe tipul de pagină.

Dacă vrei un audit al structured data existente cu fix-urile aplicate direct în cod, asta facem în auditul SEO/AI. Pentru monitoring și îmbunătățiri continue, e parte din SEO continuu.