eduardweb.
DeploymentIntermediar#seo#nextjs#react#web-perf

Metadata API în Next.js: Cum scapi de haosul din SEO și OG Images

De Cristian Barbu, 27 apr. 2026 · 1 vizualizări · 3 like-uri

Postat acum 16 ore
typescript
import { Metadata, ResolvingMetadata } from 'next';

type Props = {
  params: { id: string };
};

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const id = params.id;
  
  // Next.js face deduping automat la fetch-uri cu aceleași argumente
  const product = await fetch(`https://api.exemplu.ro/products/${id}`).then((res) => res.json());

  return {
    title: `${product.name} | Magazinul Meu`,
    description: product.shortDescription,
    openGraph: {
      images: [product.mainImage, ...(await parent).openGraph?.images || []],
    },
  };
}

Recent am terminat migrarea unui proiect destul de mare, un fel de marketplace cu peste 15.000 de listări active, și m-am bătut cap în cap cu noul Metadata API din Next.js. Dacă vinzi de pe vremea lui next/head, știi ce mizerie ieșea când trebuia să injectezi tag-uri dinamic în funcție de ID-ul produsului. În versiunile noi, treaba e mult mai structurată, dar dacă nu ești atent, omori performanța bazei de date.

Faza e că generateMetadata este o funcție care rulează pe server și, cel mai important, Next.js așteaptă ca ea să termine înainte să trimită primii bytes către client. La proiectul ăsta, inițial am făcut greșeala să fac fetch-uri separate și în metadata, și în componenta de pagină. Deși Next.js face deduping la fetch, dacă folosești un ORM direct sau un client de DB care nu e wrapped în cache din React, o să ai surprize neplăcute. Am reușit să scad timpul de răspuns (TTFB) cu vreo 200ms doar optimizând cum cerem datele astea.

Cum generăm metadata dinamic fără să dublăm munca

Când ai pagini dinamice de tip [slug], funcția generateMetadata primește aceiași parametri ca și pagina ta. Secretul pe care l-am învățat e să nu încerci să „ghicești” metadata. Dacă produsul nu există, aruncă un notFound() direct de acolo.

Un mare avantaj e gestionarea imaginilor Open Graph (OG). În loc să stochezi mii de imagini statice, poți folosi ImageResponse de la next/og. Am setat un edge runtime pentru asta și generăm imagini on-the-fly cu prețul produsului și logo-ul brandului peste imaginea principală. Trade-off-ul? E destul de migălos să aliniezi elementele cu Satori (librăria din spate), fiindcă suportă doar un subset de CSS Flexbox. Dar merită: am observat o creștere de 12% în rata de click pe social media de când am trecut la imagini personalizate.

JSON-LD și datele structurate

Mulți devi fac greșeala să încerce să bage schema.org direct în obiectul de metadata. Next.js nu are o cheie specială pentru asta în obiectul returnat de generateMetadata. Cea mai curată metodă pe care am găsit-o e să injectezi un tag <script> direct în componenta paginii.

Nu folosi dangerouslySetInnerHTML pur și simplu dacă datele vin de la user; sanitizează tot. Eu prefer să fac un obiect curat în pagină și să-l dau prin JSON.stringify. Google „vede” scriptul ăsta imediat ce e randat pe server, deci pe partea de SEO ești asigurat. La proiectul menționat, am implementat Product și BreadcrumbList, iar după două săptămâni, Search Console a început să ne afișeze corect rating-urile cu steluțe în rezultate.

Trade-off-uri și limitări

Nu totul e roz. Metadata API e static prin definiție după ce pagina a fost servită. Dacă ai un SPA unde vrei să schimbi titlul paginii în funcție de acțiunile userului în client (fără navigare), tot la vechiul document.title ajungi.

De asemenea, mare atenție la dimensiunea obiectului metadata. Dacă te apuci să pui tot felul de câmpuri obscure, mărești dimensiunea HTML-ului inutil. Eu mă limitez la titlu, descriere, canonical, OG-uri și Twitter tags. Restul sunt de cele mai multe ori zgomot.

În final, Metadata API e un upgrade masiv față de ce aveam înainte, dar necesită o disciplină clară în gestionarea fetch-urilor de date. Voi cum gestionați imaginile de social media? Mergeți pe imagini statice urcate în S3 sau le generați dinamic?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.