Ultimate SEO Guide for Nuxt 3

SEO
Nuxt
December 26, 2022

A comprehensive guide to successful technical search engine optimization with Nuxt 3. Learn topics such as HTML basics, JSON-LD, OGP and Sitemap generation.

The content shown in this post is related to Nuxt 3. If you are looking for SEO with Nuxt 2, you can check out the post Simple steps for successful SEO with Nuxt 2.

Basics

Title & Description

Setting the title and description of websites is considered one of the fundamental measures for SEO. These elements play a crucial role as they are displayed in search engine results and greatly influence a visitor's decision to click and visit your website. By carefully crafting compelling titles and descriptions, you can effectively communicate the value and relevance of your content, increasing the likelihood of attracting and engaging visitors.

Search result on Google for Nuxt website

To set the title and description of a page, Nuxt 3 has the Composable useHead, which can be called inside <script setup> of every page and component to manage your head tags.

Vue
pages/index.vue
<script setup lang="ts">
  useHead({
    title: 'Nuxt: The Intuitive Web Framework',
    meta: [
      {
        name: 'description',
        content: 'Build your next Vue.js application with confidence using Nuxt....' 
      },
    ],
  });
</script>

Alternatively, Nuxt 3 also provides meta components such as <Title /> or <Meta />, which can be used as an alternative to the useHead Composable. These components operate at the template level and need to be wrapped around the <Head /> component.

Vue
pages/index.vue
<template>
  <Head>
    <Title>Nuxt: The Intuitive Web Framework</Title>
    <Meta
      name="description"
      content="Build your next Vue.js application with confidence using Nuxt...."
    />
  </Head>
</template>

Take a look at the list of all available meta components to learn more about them.

Moving forward, our sole focus will be on utilizing useHead.

Language

It is essential to consistently indicate the language of your website. You have two options to achieve this. Firstly, if your site is exclusively in one language, you can set the language globally in the app.vue file. Alternatively, you can continue specifying the language on a per-page basis. In both cases, the useHead method can be employed to accomplish this task effectively.

Vue
app.vue
<script setup lang="ts">
  useHead({
    htmlAttrs: { lang: 'en' },
  });
</script>

Canonical

The canonical URL describes where the original content of your page is located at and should be set for each page. Search engines will consider the canonical URL with increased relevance.

Vue
pages/index.vue
<script setup lang="ts">
  useHead({
    link: [{ rel: 'canonical', href: 'https://nuxt.com/' }],
  });
</script>

Open Graph protocol (OGP)

Specifying metadata for social media plays a vital role as it enables the generation of comprehensive preview cards when sharing your pages. In this example, we will focus on implementing Facebook's Open Graph protocol (OGP) to achieve this.

The Open Graph protocol enables any web page to become a rich object in a social graph. For instance, this is used on Facebook to allow any web page to have the same functionality as any other object on Facebook.

The Open Graph protocol

It is recommended to provide essential metadata such as the title, type, image, and URL of the page when implementing social media preview cards. Additionally, you have the option to specify other properties such as a description or the language. For more in depth information, read further on Open Graph protocol.

Vue
<script setup lang="ts">
  useHead({
    meta: [
      { property: 'og:title', content: 'The Intuitive Web Framework' },
      { property: 'og:description', content: 'Build your next Vue.js application with confidence using Nuxt...' },
      { property: 'og:type', content: 'website' },
      { property: 'og:url', content: 'https://nuxt.com' },
      { property: 'og:locale', content: 'en_US' },
      { property: 'og:image', content: 'https://nuxt.com/social.jpg' },
  });
</script>

These details will result in a preview with title, description and image when shared on social media, as shown in the image below.

Preview card on Twitter for Nuxt website

Structured data (JSON-LD)

JSON-LD is a widely adopted format for creating structured data. It provides a standardized way to organize and present data on your website. For instance, you can utilize JSON-LD to store FAQ elements as structured data. When implemented correctly, these FAQ elements can appear in search results as a distinct questions and answers section, enhancing the visibility and usability of your content.

Setup

We will use the Nuxt module nuxt-jsonld. First, install the dependency.

bash
NPM
npm install nuxt-jsonld

Now add it to your modules inside your Nuxt configuration.

TypeScript
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-jsonld'],
});

Implementation

Now we have the composable useJsonld() available within <script setup>, allowing us to specify any structured data. In the following we will add a single FAQ element to the page as structured data.

Vue
pages/index.vue
<script setup lang="ts">
  useJsonld({
    '@context': 'https://schema.org',
    '@type': 'FAQPage',
    mainEntity: [
      {
        '@type': 'Question',
        name: 'How do I implement SEO with Nuxt 3?',
        acceptedAnswer: {
          '@type': 'Answer',
          text: 'I think you have the solution in front of you.',
        },
      },
    ],
  });
</script>

You can use the playground of json-ld.org to try out some examples. Also, you can test your structured data at any time with Test Rich Results. On Schma.org, you can see all the different types and parameters that are available to use.

HTML

Headline hierarchy

Search engines try to understand your website. It is advisable to establish a well-structured heading structure. For example, each page should only have one <h1> element. The headings should be logically structured according to the content.

But you don't have to check the structure manually in your HTML. There are tools for that. If you use Google Chrome, I can highly recommend META SEO inspector.

Insights from META SEO Inspector

Links

When creating links, it is important to include both the link text and the relation attribute, such as rel="external". Search engines rely on this information to better understand the purpose and nature of the links. If you have a link that only displays an icon, you can still include a hidden text using CSS. It is essential to provide this information for all links on your website.

For a comprehensive list of possible rel attribute values and their meanings, you can refer to the MDN article on this topic. The article will provide you with valuable insights into the available options for specifying the relationship between your links and the linked resources.

Vue
<template>
  <!-- INTERNAL LINK -->
  <NuxtLink to="/" rel="next">
    <Logo />
    <!-- TEXT HIDDEN WITH CSS -->
    <span class="sr-only">Homepage</span>
  </NuxtLink>
  <!-- EXTERNAL LINK -->
  <NuxtLink to="https://nuxt.com/" rel="external">
    Nuxt
  </NuxtLink>
</template>

Images

When it comes to images, similar principles apply as with links, but with the usage of different attributes. It is essential to consider the following guidelines:

  • Alternative Text: Each image should have descriptive alternative text that conveys the meaning of the image. The alt attribute is used for this purpose and is crucial for accessibility and search engine understanding.

  • Loading: The loading attribute specifies when an image should load. For images located far outside the visible area, you can use the value "lazy." This means the image will only load as it approaches the viewport. If you want the image to load immediately, you can specify the value "eager."

  • Width and Height: Always include the width and height attributes for images to avoid layout shifts (Cumulative Layout Shift - CLS). When the dimensions are specified, it helps the browser allocate the necessary space for the image, preventing unexpected layout changes. Search engines, including Google, consider a good user experience and stable layout as important ranking factors.

  • Title: The title attribute can provide additional context and information about the image. It serves both accessibility purposes and aids search engines in understanding the image's content.

Vue
<template>
  <img
    src="https://placeholder.pics/svg/640x480"
    alt="A description of the image"
    loading="lazy"
    width="640"
    height="480"
    title="A description of the image"
  />
</template>

Favicon

Your website should also show your logo in the browser tab. For this purpose, there is a really handy tool called realfavicongenerator. You can upload your logo, and it will help you convert it to favicons. After that, you can download the favicons and paste them into your /public directory.

The only thing left for you to do is to include the favicons globally. For this, we will use app.vue in this example to set the favicon globally.

This is how it could look like:

Vue
app.vue
<script setup lang="ts">
  useHead({
    link: [
      { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' },
      { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' },
    ],
  });
</script>

Sitemap (coming soon)

Every website should have a sitemap. The sitemap allows your website to be indexed by search engines. It contains all the subpages of the website that you want to show as well. Mostly, the sitemap is called sitemap.xml and is addressable in the main directory of a page.

A solution for the sitemap will be added in the future.

Conclusion

I hope you were able to get a good insight into how to successfully implement for SEO with Nuxt 3.

Thanks for reading! If you have any feedback, please feel free to email us to info@thenextbit.de. We are happy to receive any feedback.