Perché il traffico cala dopo una migrazione headless, e come fermarlo
Rendering lato client, canonical persi e un'origine lenta. I tre modi in cui una migrazione headless costa silenziosamente traffico organico — e come chiudere ciascuno.
Un CMS headless non ha opinioni sul tuo HTML. Restituisce contenuti su un'API;
tutto ciò che un motore di ricerca vede è prodotto da codice che hai scritto tu.
È per questo che "headless fa male alla SEO?" è la domanda sbagliata. Quella giusta è:
cosa ha cambiato la ricompilazione riguardo all'HTML? In pratica la risposta è una di
tre cose, e tutte e tre sono risolvibili.
#Perdita 1 — Contenuto che esiste solo dopo l'esecuzione di JavaScript
La più comune e la più costosa.
Sei passato a un framework con rendering lato server e poi hai recuperato il corpo dell'articolo
in un effect lato client, perché è quello che faceva il tutorial. Ora:
Googlebot ottiene un guscio vuoto al primo passaggio, e il rendering viene messo in coda per
dopo — a volte molto dopo.
Altri crawler (Bing, crawler IA, bot di anteprima social) per lo più non renderizzano
affatto. I tuoi link si aprono in bianco.
Il Largest Contentful Paint misura il contenuto, e il tuo contenuto arriva un
round trip dopo il guscio.
Diagnosi — un comando, nessuno strumento:
0 significa che il tuo contenuto non è nell'HTML. Tutto il resto in questo articolo è
secondario finché questo non restituisce 1.
Soluzione — recupera sul server. Nell'App Router di Next.js questo è il comportamento predefinito;
l'errore è di solito un confine 'use client' posizionato troppo in alto nell'albero.
Spostalo verso il basso sul componente interattivo invece di avvolgere la pagina.
#Perdita 2 — Canonical, meta e dati strutturati persi nella ricompilazione
Il vecchio CMS aveva un plugin SEO che produceva tag canonical, meta description,
tag Open Graph e schema Article per ogni pagina. Nessuno ha deciso esplicitamente di
rimuoverlo. Semplicemente non era nella checklist della ricompilazione.
Sintomi: raggruppamento per contenuto duplicato (URL con parametri, varianti con slash finale,
archivi paginati che vengono tutti indicizzati separatamente), rich result mancanti e
condivisioni social che si aprono con il titolo sbagliato.
Soluzione — rendi questi campi parte del modello di contenuto, non del tema. In
corpusctl il modulo SEO memorizza titolo, description, canonical e immagine
social per singola voce accanto al contenuto, così viaggiano con la voce anziché
vivere in qualunque cosa la renderizzi.
Poi affermali nella CI. Un test che recupera dieci URL rappresentativi e verifica
che ciascuno abbia esattamente un canonical auto-referenziale, una description non vuota
sotto i 155 caratteri e JSON-LD valido costa un'ora e blocca questa classe di
regressione in modo permanente.
#Perdita 3 — Un'origine lenta dietro una cache a cui non hai pensato
Headless di solito migliora le prestazioni. Le peggiora quando il front end
recupera dal CMS a ogni richiesta e il CMS è a una query di database di distanza.
Il tuo TTFB è ora il tempo di risposta del CMS più il tuo tempo di rendering, a ogni cache
miss, e ogni cache miss è un utente reale che aspetta.
Soluzione — decidi dove vive il contenuto al momento della richiesta. Tre opzioni, in
ordine crescente di quanto bene reggono:
Fetch per richiesta. Il CMS è sul percorso critico. Va bene per una
dashboard, sbagliato per contenuti che vuoi posizionare.
ISR con una finestra temporale. Il contenuto è vecchio al massimo di N secondi; ogni
scadenza della finestra è un cache miss che qualcuno paga.
Pre-compila e servi dalla cache. Renderizzato al momento della pubblicazione, servito come
artefatto statico. Il più veloce e il più economico — a patto che l'invalidazione sia gestita.
La parte difficile della terza opzione è l'invalidazione, perché la pagina è una copia di un
calcolo che potrebbe cambiare in qualsiasi momento.
corpusctl elimina il problema invece di gestirlo. La pubblicazione scrive il contenuto
in un file immutabile e indirizzato tramite hash nell'object storage e aggiorna un
manifest; il client risolve lo slug in uno shard del manifest localmente, poi recupera
quell'indirizzo dalla cache edge nginx. L'indirizzo è un hash del contenuto, quindi lo
stesso indirizzo non può mai restituire contenuti diversi — è memorizzabile nella cache per trenta
giorni, e la pubblicazione scrive un nuovo indirizzo. Non c'è nulla da purgare.
Per i Core Web Vitals questo conta direttamente: il documento arriva da una cache
anziché da un calcolo, quindi il TTFB smette di variare con il carico del database e l'LCP
smette di dipendere dal fatto che tu abbia ottenuto un cache hit.
Se gestisci più lingue — e un CMS headless viene spesso scelto proprio
per questo — questa è la quarta perdita.
Regole facili da enunciare e facili da sbagliare:
Ogni versione linguistica rimanda a ogni altra versione, compresa se stessa.
C'è un x-default che punta alla versione per i visitatori non corrispondenti.
I link sono reciproci. Un hreflang unidirezionale viene ignorato del tutto.
I codici lingua sono BCP 47 validi. Il cinese semplificato è zh-Hans, non zh-CN,
quando intendi lo script anziché la regione.
L'URL in hreflang corrisponde al canonical della pagina a cui punta.
Non verificarlo a mano. Recupera ogni URL e afferma l'intero set:
Correlato: l'URL radice che negozia la lingua dovrebbe restituire 302, non 301. La
risposta varia in base ad Accept-Language, quindi non è permanente; un 301 viene messo in cache
nel browser e la persona successiva su quella macchina non può cambiare la propria lingua.
Invia Vary: Accept-Language, Cookie con esso, altrimenti una cache intermedia
servirà la lingua del primo visitatore a tutti.
Almeno due settimane dopo il cutover. I ranking si muovono secondo il proprio calendario e un
panico di tre giorni non ti dice nulla.
Search Console → Copertura. Un aumento dei 404 significa un redirect che hai mancato. Un
aumento di "Scansionata – attualmente non indicizzata" spesso significa output scarno o duplicato
da un template.
Search Console → Prestazioni, segmentato per tipo di pagina. Se un template ha perso
più degli altri, il bug è in quel template, non nella migrazione.
Log del server, non solo Search Console. Il log di scansione ti dice cosa Googlebot
ha effettivamente richiesto e cosa ha ricevuto. Un 404 lì è gratuito da correggere oggi e
costoso da correggere tra un mese.
Dati sul campo dei Core Web Vitals, non i punteggi di laboratorio. I punteggi di laboratorio misurano il tuo laptop.
Un CMS headless che si adatta a Next.js invece di combatterlo
Modalità bozza, ISR, l'App Router e lo strato di rendering. Cosa conta davvero quando colleghi un CMS headless a Next.js — e i tre modi in cui va storto.