Nuxt 3 SEO Unleashed - Elevate the online presence with the power of Nuxt 3's SEO capabilities.

nuxt seo

Learn about Nuxt 3 technical search engine optimization techniques. Explore SEO essential like HTML fundamentals, JSON-LD, OGP, generating Sitemaps and robots.txt in Nuxt 3.


Nuxt 3 offer default head configuration, composables, and components to enhance the search engine optimization (SEO). These are so customizable and helps us to acheive technical SEO with a breeze in a Nuxt web app. We will deep dive on all these available options in this blog.

Crafting SEO-Friendly Page Title and Description in a Nuxt 3 WebApp

Page Title and Description in nuxt.config.ts

By default, we can set the page title and description in a nuxt app in the nuxt.config.ts. These are mentioned in the app.head property in the nuxt.config.ts. This method does not allow you to provide reactive data. Example Usage:

export default defineNuxtConfig({
  app: {
    head: {
      title: "My WebPage",
      description: "This is my webpage blog",
      charset: 'utf-8',
      viewport: 'width=device-width, initial-scale=1',
    }
  }
})

UseHead Composable to set the Page Title and Description

Leverage the useHead composable function to take command of your head tags with a dynamic and responsive approach, empowered by the formidable Unhead. useHead is a composables and it can only be used with a components setup and lifecycle hooks in the nuxt app. This can be used to set the title and the description along with other SEO attributes of a webpage.

Example Usage in your page or component inside the script setup as the useHead:

<script setup lang="ts">
useHead({
  title: 'My WebPage',
  meta: [
    { name: 'description', content: 'This is my webpage blog' }
  ]
})
</script>

UseSeoMeta Composable to set the Page Title and Description

useSeoMeta is a new composable and this allows to define the site's SEO meta tags as a flat object with full TypeScript support. This can also be used to set the Page title and description and is much easier way to set all the SEO metadata.

Example:

<script setup lang="ts">
useSeoMeta({
  title: 'My WebPage',
  description: 'This is my webpage blog',
})
</script>

Title and Description using the Nuxt Components

Nuxt 3 provides components such as <Title>, <Base>, <NoScript>, <Style>, <Meta>, <Link>, <Body>, <Html> and <Head> which can be used as an alternatives to composables which are explained above. The components <Title> and <Meta> can be used to set the title and description for the webpage and this need to be wrapped inside the <Head /> component.

Example Usage:

<script setup lang="ts">
const title = ref('Hello World')
</script>

<template>
  <div>
    <Head>
      <Title>{{ title }}</Title>
      <Meta name="description" :content="title" />
      <Style type="text/css" children="body { background-color: green; }" />
    </Head>

    <h1>{{ title }}</h1>
  </div>
</template>

Social Meta Tags in Nuxt 3

OGP metadata enables any web page to become a rich object in a social media. It is recommended to provide ogp metadata in each page and essential metadata are the title, type, image, and URL of the page. These details will result in a preview with title, description and image when shared on social media.

Set OGP metadata in Nuxt 3 using UseHead

<script setup lang="ts">
useHead({
  title: 'My App',
  meta: [
    { name: 'description', content: 'My amazing site.' },
    { name: 'og:title', content: 'My amazing site.' }
    { name: 'og:description', content: 'My amazing site.' },
    { name: 'og:image', content: 'www.example.com/image.jpg' },
  ]
})
</script>

Set OGP metadata in Nuxt 3 using useSeoMeta

<script setup lang="ts">
useSeoMeta({
  title: 'My Amazing Site',
  ogTitle: 'My Amazing Site',
  description: 'This is my amazing site, let me tell you all about it.',
  ogDescription: 'This is my amazing site, let me tell you all about it.',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
</script>

Set OGP metadata using Nuxt 3 components Meta

<script setup lang="ts">
const title = ref('Hello World')
</script>

<template>
  <div>
    <Head>
      <Title>{{ title }}</Title>
      <Meta name="description" :content="title" />
      <Meta name="og:title" :content="title" />
      <Meta name="og:description" :content="title" />
      <Meta name="og:image" :content="www.example.com/image.jpg" />
    </Head>

    <h1>{{ title }}</h1>
  </div>
</template>

Generate Sitemap in Nuxt 3 Projects

The sitemap of a website allows search engines to index. The sitemaps are in the xml format and include all the pages of website, so that crawlers can crawl the website.

For generating a sitemap in Nuxt 3, we need to use the module nuxt-simple-sitemap. This package need to be added as dev dependency and add the below code to the nuxt.config.ts

export default defineNuxtConfig({
  modules: ['nuxt-simple-sitemap']
})

Exploring the functionalities of the Nuxt Site Config module, it endeavors to autonomously configure your site URL during runtime sitemap generation. To mitigate concerns related to duplicate content, it is advisable to establish a canonical site URL. To accomplish this, simply specify your desired site URL within the nuxt.config file for seamless integration.

nuxt.config.ts
export default defineNuxtConfig({
  site: {
    url: 'https://example.com',
  },
})

In the process of sitemap generation, the module embarks on a quest to unearth all pertinent URLs slated for inclusion. It draws insights from diverse data sources, encompassing default page files (enabled by default, with the option to disable via inferStaticPagesAsRoutes: false), prerendered routes (refer to Prerendering), and dynamic routes (refer to Dynamic URLs). Notably, the module adeptly identifies and incorporates prerendered routes into your sitemap automatically.

For those seeking to integrate dynamic routes into their sitemap without the hassle of creating a bespoke API endpoint, a straightforward solution is to activate full prerendering. The activation of this feature requires configuration adjustments for seamless implementation.

export default defineNuxtConfig({
  nitro: {
    prerender: {
      crawlLinks: true,
      routes: [
        '/',
      ]
    }
  }
})

For sites where all the pages aren't prerendered, you may want to provide the list of dynamic routes to be included in your sitemaps. The recommended approach is to create your own API endpoint that returns the list of all dynamic routes. By default, the module will check for a server/api/_sitemap-urls.ts endpoint. An example of URLs might look like this:

export default defineEventHandler(async () => {
  const [
    posts,
    pages,
    products
  ] = await Promise.all([
    $fetch('/api/posts'),
    $fetch('/api/pages'),
    $fetch('/api/products')
  ])
  return [...posts, ...pages, ...products].map((p) => {
    return { loc: p.url, lastmod: p.updatedAt }
  })
})

This API endpoint will be called by the sitemap module to fetch the list of dynamic URLs whenever a sitemap is generated.

Generate robots.txt using nuxt-simple-robots

Nuxt-simple-robots helps to generate the robots.txt file with minimal configuration.

Installation of nuxt-simple-robots

  • Nuxt simple robots can be installed by using the below command, npm install -D nuxt-simple-robots
  • Add it to modules section to nuxt.config,
    export default defineNuxtConfig({
      modules: ['nuxt-simple-robots']
    })

As the default configuration, the module employs server middleware to dynamically generate a robots.txt during runtime or generates a prerendered robots.txt file in the public directory. You can conveniently access this file at /robots.txt through your web browser.