SEO per Nuxt

Nuxt offre il rendering lato server per impostazione predefinita, ma la scelta vale per ogni singola rotta: i crawler ricevono HTML completo solo dove resta attiva. Modalità di rendering, useSeoMeta(), il pacchetto @nuxtjs/seo, idratazione, Nitro, metriche web essenziali ed errori difficili da notare.

Prima pubblicazione: 26 giu 2026 · Ultimo aggiornamento: 13 ago 2026 · Advanced
Lingue
1 segnale di evidenza in questa pagina

Nuxt esegue il rendering lato server per impostazione predefinita, quindi ogni rotta che conserva questa scelta fornisce ai crawler un documento HTML completo invece del guscio vuoto di una semplice SPA Vue. La garanzia non vale però per l'intero progetto: routeRules o un ssr:false globale possono trasformare una rotta in CSR, perciò va controllato l'URL effettivo. La decisione fondamentale è la modalità di rendering della singola rotta: SSR, SSG tramite nuxt generate o regole ibride; meta tag, schema e sitemap vengono dopo. Usa useSeoMeta() per i metadati e considera @nuxtjs/seo di Harlan Wilton un pacchetto facoltativo di terze parti, non parte del nucleo di Nuxt, per robots, sitemap, immagini OG, schema e URL canonici. Evita il rendering dinamico, deprecato da Google, verifica separatamente idratazione, payload, distribuzione e cache di Nitro e ricorda che i crawler AI non condividono un unico contratto di rendering: SSR e SSG inseriscono il contenuto nell'HTML grezzo e massimizzano la copertura.

TL;DR — L’impostazione predefinita di Nuxt è il rendering lato server, quindi una rotta che la mantiene ottiene un DOM completo invece del guscio vuoto fornito da una semplice SPA Vue; il risultato dipende però dalla singola rotta: ssr: false o una regola di routeRules può trasformare qualsiasi rotta in CSR o ibrida, quindi testa la rotta effettiva, non il nome del progetto. La strategia di rendering è la decisione fondamentale — SSR (predefinito), SSG (nuxt generate), o routeRules ibridi — perché meta, schema e sitemap vengono tutti dopo. Usa useSeoMeta() per i meta tag (useHead() per il resto della sezione head, varianti solo server quando non ti serve reattività), e considera il pacchetto @nuxtjs/seo di Harlan Wilton come un pacchetto facoltativo di terze parti per robots, sitemap, immagini OG, schema e URL canonici: non fa parte del nucleo di Nuxt e il suo risultato va comunque controllato. Non usare il rendering dinamico, deprecato da Google. Le capacità dei crawler AI variano in base al fornitore: SSR e SSG massimizzano la copertura dell’HTML grezzo. Oltre all’HTML iniziale, verifica idratazione e payload, configurazione di distribuzione e cache di Nitro, oltre allo stato HTTP diretto: l’HTML del server da solo non prova nessuno di questi. Le solite regole JS-SEO valgono ancora: link reali <a href>, non bloccare JS/CSS, controlla HTML renderizzato vs. grezzo.

Nuxt è la risposta di Vue al problema delle SPA

Vue, da solo, fornisce un’applicazione a pagina singola: un guscio HTML e il JavaScript che costruisce il DOM nel browser. Nuxt è il meta-framework basato su Vue, eseguito dal motore server Nitro in Nuxt 3 e Nuxt 4, e il suo principale vantaggio per la SEO è il rendering lato server predefinito. Ogni pagina arriva come un documento HTML completo, proprio ciò che Googlebot vuole leggere senza dover eseguire JavaScript prima. La SEO di Vue senza Nuxt è un argomento a sé, con modalità di errore specifiche; qui presumo che tu abbia scelto Nuxt proprio per non dover combattere il problema delle SPA.

Questo è lo stesso punto che faccio su JavaScript in generale: “any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines. Gatsby, Next, Nuxt, etc., are all great.” (traduzione) «qualunque configurazione basata su SSR, rendering statico o prerendering funzionerà bene per i motori di ricerca. Gatsby, Next, Nuxt e simili sono tutte ottime soluzioni.» (fonte originale) Le impostazioni predefinite di Nuxt sono orientate nella giusta direzione. La maggior parte dei problemi SEO di Nuxt nasce quando qualcuno le disattiva o introduce altri errori.

La strategia di rendering è la base — decisa per rotta, non per progetto

Prima dei meta tag, prima dello schema, prima delle sitemap, la domanda che decide tutto è come viene prodotto l’HTML per questa specifica rotta? Nuxt documenta il rendering universale lato server come impostazione predefinita dell’app, ma questa scelta non è una garanzia a livello di rotta: un ssr: false globale commuta l’intera app al rendering lato client, mentre routeRules può assegnare una modalità diversa a qualsiasi schema di URL. Dire “questa è un’app Nuxt” non chiarisce come venga renderizzata una determinata pagina: viene renderizzata — devi controllare la rotta. Nuxt ti offre cinque strategie:

ModalitàCome la impostiImpatto SEOIdeale per
Universale / SSRPredefinito (ssr: true)Eccellente — HTML completo a ogni richiestaContenuti dinamici e personalizzati
Statico / SSGnuxt generateEccellente — HTML costruito al momento della distribuzioneBlog, documentazione, marketing
IbridorouteRules per rottaEccellente — mix per rottaSiti grandi con contenuti misti
SPA / CSRssr: falseScarso per contenuti indicizzatiDashboard, pannelli admin
Lato edgeDestinazione di distribuzioneEccellente — TTFB bassoPrestazioni globali

La documentazione ufficiale di Nuxt è chiara sul perché il rendering lato client sia la scelta sbagliata per i contenuti: “Indexing and updating the content delivered via client-side rendering takes more time” (traduzione) «indicizzare e aggiornare i contenuti forniti tramite rendering lato client richiede più tempo»; con il rendering universale lato server, invece, “web crawlers can directly index the page’s content.” (traduzione) «i crawler web possono indicizzare direttamente il contenuto della pagina». Evidence for this claim Nuxt documents that universal rendering delivers HTML content immediately and allows crawlers to index it directly. Scope: Nuxt rendering; no indexing guarantee. Confidence: high · Verified: Nuxt: Rendering modes (Documentazione sul rendering di Nuxt.) Il CSR (ssr: false) è pensato per back-office, dashboard e giochi — non per qualcosa che vuoi indicizzato.

Il rendering ibrido è la mossa vincente per i siti di grandi dimensioni. Le regole di rotta in nuxt.config.ts permettono di impostare la modalità di rendering e la cache per ogni schema di URL:

routeRules: {
  '/blog/**':     { prerender: true },        // SSG for the blog
  '/product/**':  { swr: 3600 },              // ISR-style: regenerate hourly
  '/admin/**':    { ssr: false },             // SPA for the admin area
  '/checkout/**': { ssr: true },              // always-fresh SSR
}

swr (stale-while-revalidate) e isr (incremental static regeneration) generano una pagina in forma statica e poi la aggiornano in background: è una soluzione ideale per e-commerce con molte pagine o notizie dove una ricostruzione completa a ogni modifica non è pratica. Nuxt Islands (<NuxtIsland>) renderizzano componenti senza inviare JavaScript lato client, riducendo il costo dell’idratazione e migliorando l’INP, la metrica web essenziale che più spesso rappresenta un problema nelle app Nuxt.

Come verificare ciò che hai effettivamente pubblicato: Visualizza sorgente mostra l’HTML grezzo inviato dal server; se il contenuto è presente, il rendering avviene lato server. Il pannello Elements degli strumenti per sviluppatori mostra il DOM renderizzato, mentre lo strumento Controllo URL di GSC mostra ciò che Google ha effettivamente recuperato e renderizzato — la fonte di verità. Non fidarti di “sembra a posto nel mio browser.”

Come Googlebot gestisce un’app Nuxt

Google elabora qualsiasi app JavaScript in tre fasi — scansione, rendering e indicizzazione — e il problema è il tempismo: il rendering avviene in una coda, non istantaneamente. Come ho detto nel mio Guida SEO JavaScript, il renderer è paziente — “there is no fixed timeout for the renderer… It’s really patient, and you should not be concerned.” (traduzione) «non esiste un timeout fisso per il renderer… È davvero paziente e non dovresti preoccuparti». Ma essere paziente non significa essere veloce per i contenuti freschi. Se pubblichi una pagina renderizzata lato client, il tuo contenuto non esiste per Google finché non viene eseguita quella ondata di rendering; SSR e SSG colmano questo divario perché l’HTML è completo al primo recupero.

Altre due cose contano su larga scala. Renderizzare JavaScript è costoso — dal mio talk del 2019 JavaScript SEO (Ungagged), i costi di crawl aumentano di circa 20× una volta che Google deve renderizzare (direzionale, ma l’ordine di grandezza regge ancora). E Google prende la direttiva più restrittiva tra HTML grezzo e renderizzato — quindi un noindex iniettato da JavaScript vincerà su un index nell’HTML grezzo, e viceversa. Un canonical iniettato via JavaScript è rispettato solo se non c’è già un canonical nell’HTML grezzo. Mantieni i segnali robots e canonical nell’HTML renderizzato lato server, cosa che Nuxt fa per te quando SSR è attivo.

La realtà dei crawler AI

Questa è la novità del 2026. I crawler AI, tra cui GPTBot, ClaudeBot e PerplexityBot, altri — generalmente non eseguono affatto JavaScript. Indicizzano l’HTML grezzo e nient’altro. Quindi una pagina Nuxt renderizzata lato client è di fatto invisibile ai motori di risposta AI. SSR o SSG non sono solo migliori per Google qui; sono il prezzo d’ingresso anche per l’ottimizzazione dei motori di risposta. Se vuoi che il tuo contenuto sia citato da ChatGPT, Perplexity o Claude, deve trovarsi nell’HTML già al primo recupero.

Oltre l’HTML iniziale: payload, idratazione e codici di stato

Ottenere dal server un HTML che contenga il testo è necessario ma non sufficiente: molte cose possono ancora andare storte a valle di quella prima risposta, e “ho controllato View Source” non le copre:

  • Payload e idratazione. Il rendering universale invia l’HTML e un payload di dati serializzato che il client usa per idratare la pagina, collegare i gestori degli eventi e riprendere da dove il server ha terminato, senza recuperare nuovamente i dati. Un HTML del server apparentemente corretto non prova che l’idratazione sia riuscita, che la navigazione client riproduca lo stesso contenuto, o che il payload non sia obsoleto. Se una pagina sembra a posto al primo caricamento ma si rompe dopo un cambio di rotta lato client, è un problema di idratazione/payload, non di modalità di rendering.
  • <ClientOnly> e contenuti solo browser. Avvolgere qualcosa in <ClientOnly> — comune per widget che dipendono dalle API del browser — significa che è assente dalla risposta del server anche su una rotta altrimenti universale. Se il tuo contenuto principale, un link chiave o i tuoi meta tag finiscono dentro un confine solo client, i crawler e i bot AI che leggono solo l’HTML grezzo lo perdono, indipendentemente dalla tua impostazione di modalità di rendering. Ispeziona la risposta effettiva, non solo la configurazione della modalità di rendering.
  • Codici di stato e redirect non sono auto-certificanti. Una pagina di errore Nuxt che si renderizza nel browser, o un redirect guidato da navigateTo()/composable, non prova da solo quale stato HTTP la risposta diretta del server ha inviato. Le linee guida di Google sono esplicite che i codici di stato significativi contano per la scansione e l’indicizzazione — conferma l’header effettivo con curl -I, non ciò che la pagina di errore renderizzata dal client mostra.

Niente di tutto questo è un argomento contro il rendering universale — è il promemoria che «l’HTML è renderizzato lato server» è il primo controllo, non l’ultimo.

Nitro, configurazioni di distribuzione e confini della cache

La risposta del server Nuxt viene costruita da Nitro, che compila in modo diverso a seconda della configurazione di distribuzione scelta (server Node, Cloudflare, Vercel, Netlify, output statico e altre). Questo conta per la SEO perché configurazioni e adattatori possono differire nelle API disponibili durante l’esecuzione, nel comportamento della cache, nel supporto allo streaming, nella distribuzione regionale e nell’accesso al file system: non è garantito che una regola di rotta o un gestore del server funzionino allo stesso modo con un’altra configurazione. Due conseguenze che vale la pena testare esplicitamente piuttosto che assumere:

  • Chiavi di cache e invalidazione sono specifiche della rotta, non automatiche. Le regole di rotta swr e isr memorizzano nella cache e rigenerano l’output, ma una chiave di cache errata, un’invalidazione mancante o un’intestazione di memorizzazione impostata dalla piattaforma di distribuzione possono restituire HTML obsoleto, personalizzato o incoerente ai crawler. Controlla l’età effettiva della risposta e le intestazioni Cache-Control/Age su un URL pubblico, non solo la configurazione routeRules.
  • L’ambiente di prova non garantisce la parità con la produzione. Una rotta che viene renderizzata correttamente in sviluppo locale o in una distribuzione di anteprima non conferma che la configurazione di produzione restituisca lo stesso risultato: rotte del server, reindirizzamenti e gestione degli errori appartengono allo strato server di Nitro, che è la parte più incline a cambiare tra destinazioni. Verifica direttamente l’URL di produzione dopo ogni modifica alla distribuzione, come faresti per la modalità di rendering.

Meta tag: useSeoMeta() e useHead()

La gestione della sezione head di Nuxt si basa su Unhead e offre due funzioni componibili per compiti diversi.

useSeoMeta() è quello da usare per i meta tag SEO e social. È un’API piatta e sicura rispetto ai tipi, con parametri tipizzati. Evidence for this claim useSeoMeta is a typed Nuxt API for SEO and social meta tags. Scope: Current Nuxt composable. Confidence: high · Verified: Nuxt: useSeoMeta Aiuta a evitare il classico errore Open Graph di usare name dove serviva property:

useSeoMeta({
  title: 'My Page Title',
  ogTitle: 'My Page Title',
  description: 'Concise page-specific description with the key information first',
  ogDescription: 'Concise social description tailored to this page',
  ogImage: 'https://mysite.com/og-image.png', // must be an absolute URL
  twitterCard: 'summary_large_image',
})

useHead() è lo strumento generico per tutto il resto della sezione head: script, tag link, attributi del body e modelli di titolo:

useHead({
  titleTemplate: '%s · My Site Name',
  htmlAttrs: { lang: 'en' },
})

Il pattern di stratificazione affidabile è: impostazioni predefinite statiche (charset, viewport, favicon) in nuxt.config.ts → modello di titolo a livello di sito e impostazioni predefinite OG globali in app.vue → sovrascritture specifiche per pagina tramite useSeoMeta() nel componente della pagina. Un bug comune è mettere useSeoMeta() in un layout invece che nella pagina, il che sovrascrive i tag specifici della pagina con quelli generici. E poiché i motori di ricerca leggono il caricamento iniziale, i meta SEO in genere non devono essere reattivi — useServerHead() salta la riesecuzione lato client.

Quale API, e cosa dimostra realmente:

APIAmbitoReattivo?Cosa dimostra sull’output
useSeoMeta()Solo meta SEO/social piatti e tipizzatiSì (predefinito)Imposta correttamente le proprietà tipizzate — non che la rotta sia unica, canonica o indicizzabile; quella logica resta tua
useHead()Qualsiasi cosa in <head> — script, link, attributi, modello di titoloSì (predefinito)Controllo generale della sezione head; stessa avvertenza — l’uso dell’API non prova che la risposta del server sia corretta
useServerHead() / chiamate solo serverCome sopraNo — solo server, salta la riesecuzione clientConferma che il tag viene inviato una volta nell’HTML del server; non conferma che la navigazione client lo reimposti se ci fai affidamento lì

Chiamare uno di questi composable ti dice che l’API è stata eseguita — non ti dice da solo cosa emette effettivamente una risposta server diretta o un cambio di rotta lato client. Conferma con Visualizza sorgente o curl, non solo “Ho chiamato useSeoMeta().”

L’ecosistema di moduli @nuxtjs/seo di Harlan Wilton — facoltativo, non incluso nel nucleo

Il nucleo di Nuxt non include una sitemap, un robots.txt, la generazione di immagini OG o Schema.org di serie — questi sono al di fuori delle primitive di Nuxt (useHead, useSeoMeta, regole di rotta, modalità di rendering). La comunità colma questa lacuna con @nuxtjs/seo di Harlan Wilton — un pacchetto ombrello di terze parti installato separatamente (nuxtseo.com, attualmente alla v5.x, mantenuto attivamente, pensato per Nuxt 3,16+ e Nuxt 4) che raggruppa sei moduli. Installarlo ti dà la generazione di sitemap, robots, immagini OG e schema, ma non garantisce da solo che il risultato sia corretto per le tue rotte; verifica ciò che produce nello stesso modo in cui verificheresti qualsiasi altra cosa:

ModuloCosa fa
@nuxtjs/robotsrobots.txt + meta robots + intestazione X-Robots-Tag
@nuxtjs/sitemapSitemap XML automatiche da pagine + rotte dinamiche
nuxt-og-imageImmagini OG dinamiche (un template Vue → un’immagine)
nuxt-schema-orgDati strutturati Schema.org JSON-LD
nuxt-seo-utilsURL canonici, breadcrumb, impostazioni predefinite
nuxt-link-checkerRilevamento link rotti in fase di build

Installa l’intero pacchetto con npx nuxt module add seo, oppure prendi i singoli moduli (npx nuxt module add sitemap robots). Alcuni comportamenti che vale la pena conoscere:

  • @nuxtjs/sitemap genera automaticamente dalla tua directory pages/ più le rotte dinamiche, si divide in un indice sitemap automaticamente oltre 50 000 URL, supporta sitemap multilingua i18n e ha supporto IndexNow integrato. Una cosa da fare bene: Google ignora changefreq e priority; conta solo un lastmod accurato, e solo quando il contenuto cambia davvero.
  • @nuxtjs/robots genera robots.txt, il meta tag robots e l’header X-Robots-Tag — e per impostazione predefinita disabilita tutti i crawler su ambienti non di produzione, creando la tipica trappola di indicizzazione negli ambienti di prova delle applicazioni headless. Ti dà anche regole per singolo bot, così puoi bloccare GPTBot specificamente mentre lasci stare tutti gli altri (sii intenzionale — blocca un crawler AI e non ti citerà).
  • nuxt-seo-utils gestisce gli URL canonici e, utilmente, rimuove i parametri di tracciamento (utm_*, fbclid, gclid) dai canonici automaticamente.

nuxt/image e metriche web essenziali

@nuxt/image è il modulo per le immagini: srcset adattivo automatico, formati moderni (WebP/AVIF), ottimizzazione integrata tramite un fornitore CDN e caricamento differito. Due regole portano la maggior parte del valore SEO:

  • Non caricare mai in modo differito l’immagine LCP. L’immagine principale dovrebbe essere caricata subito; il caricamento differito ritarda il tuo Largest Contentful Paint.
  • Imposta sempre width e height così il browser riserva spazio e non subisci un impatto sul Cumulative Layout Shift.
<NuxtImg
  src="/hero.jpg"
  width="1200"
  height="630"
  alt="Descriptive alt text"
  :loading="isHeroImage ? 'eager' : 'lazy'"
  format="webp"
/>

Gli obiettivi 2026 da raggiungere (p75): LCP ≤ 2,5 s, INP ≤ 200ms, CLS ≤ 0,1. Sulle app Nuxt, INP è la metrica che tende a peggiorare perché l’idratazione crea ritardi nella risposta agli input, proprio il problema che Nuxt Islands e <NuxtIsland> aiutano a ridurre.

Nuxt Content + SEO

Se stai usando @nuxt/content (il modulo per contenuti markdown/MDX), l’integrazione con @nuxtjs/seo è semplice ma ha un problema di ordinamento: carica @nuxtjs/seo prima di @nuxt/content nel tuo array di moduli. Puoi quindi impostare la SEO nel frontmatter dei contenuti (title, description, robots, ogImage, schemaOrg) e estrarla nel tuo template [slug].vue con useSeoMeta() dopo aver recuperato il contenuto. Questa è la versione nativa di Nuxt del pattern headless-CMS, e vale la stessa disciplina di “ricostruire ciò che il plugin faceva”.

Errori SEO comuni di Nuxt

  1. Usare la modalità SPA (ssr: false) per contenuti che vuoi indicizzare. L’errore più costoso — e quello che ti rende invisibile ai crawler AI.
  2. URL relativi per le immagini OG. ogImage deve essere un URL assoluto o le anteprime social si rompono.
  3. useSeoMeta() in un layout invece che nella pagina — i tag generici sovrascrivono quelli specifici della pagina.
  4. Non verificare l’HTML renderizzato — View Source ≠ DevTools ≠ ciò che Google ha renderizzato. Usa URL Inspection.
  5. Bloccare JS/CSS in robots.txt — Google non renderizza da file bloccati.
  6. Lasciare il noindex/disallow di staging in posizione dopo il lancio (o, al contrario, dimenticare che @nuxtjs/robots blocca per impostazione predefinita gli ambienti diversi dalla produzione e chiedersi perché la produzione funziona ma un ambiente personalizzato no).
  7. Caricare in modo differito l’immagine LCP — peggiora il valore LCP.
  8. Mancanza di width/height sulle immagini — CLS.
  9. changefreq/priority nelle sitemap — Google li ignora; solo lastmod conta.
  10. Ricorrere al rendering dinamico. Google lo ha deprecato“dynamic rendering is a workaround and not a long-term solution” (traduzione) «il rendering dinamico è una soluzione temporanea e non una soluzione a lungo termine» — e serve solo ai motori per cui lo configuri, perdendo Bing e ogni crawler AI. Con Nuxt non ti serve mai: SSR e SSG danno già ai crawler HTML completo.

llms.txt e AEO

llms.txt è un file di testo semplice — il cugino di robots.txt — che aiuta gli strumenti AI a navigare i tuoi contenuti. Il modulo nuxt-llms genera automaticamente /llms.txt e /llms-full.txt da Nuxt Content. Dalla fine del 2025 i suoi principali utilizzatori sono i server MCP e gli strumenti di programmazione assistita dall’AI (Cursor, Claude Code) piuttosto che ChatGPT o Perplexity direttamente, ed è più utile per siti di documentazione e blog tecnici — meno per e-commerce o notizie. Vale la pena aggiungerlo se sei un sito di documentazione/dev; non è una priorità altrimenti.

Dove si colloca

La SEO di Nuxt è in realtà un’applicazione concreta di JavaScript SEO attraverso le convenzioni di Nuxt — e si sovrappone pesantemente con l’argomento SEO per un CMS headless quando il tuo frontend Nuxt attinge da un backend headless. I principi non cambiano; Nuxt ti dà solo buone impostazioni predefinite e un forte ecosistema di moduli per implementarli.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.