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

The most basic measures for SEO is probably setting the title and description of the respective pages. The title and description show up in search engine results and are very important to convince the visitor of your website.

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.

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>

As an alternative, you can also use meta components like <Title /> or <Meta /> provided by Nuxt. These work similar to useHead, only on the template level, and has 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.

From now on, we will focus only on the use of useHead.

Language

You should always specify which language your site is in. For example, if your site has only one language, you could specify it globally in the app.vue or continue to specify it on a page-by-page basis. For this, you can again use the useHead method.

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 is an important aspect, allowing you to generate a detailed preview card of your pages when sharing. In this example, we will cover how to implement Facebooks Open Graph protocol (OGP).

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

You should specify at least the title, type, image, and the URL of the page. You can of course specify other properties like 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 standardized format for writing structured data. For example, you can store FAQ elements of your website as structured data and these will show up in search results as questions and answers element if implemented correctly.

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

Links should always contain a text and the relation attribute like rel="external". Search engines try to understand these links. If you have a link with only an icon, you can still place a text and hide the text via CSS. Include this information with all links. The list of possible rel values can be seen in this MDN article.

Images

With images, it is like with links, only here other attributes are used.

  • Each image must contain an alternative text that describes the image. This is implemented by using the alt attribute.

  • The loading attribute specifies when the image should load. Suppose an image is far outside the visibility area, then the image does not necessarily have to be loaded. In this case, the value can be lazy. The image will load only when you approach it. If you want the image to load immediately, specify the value eager.

  • Always use the width and height attributes to avoid layout shift (CLS). Search engines like Google will rank your page poorly if the layout of your page shifts as it builds.

  • The title is also helpful for accessibility and understanding the context by search engines.

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

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.