404 Not Found

404 Not Found


nginx

SEO Optimization: useHead + useSeoMeta

Charlie's MegaShop has a million product pages, but Google has only indexed 2,000 of them. When Alice searches for a product name, she can't find any pages from MegaShop. Bob checked and found that the product pages lack titles, meta descriptions, Open Graph tags, and structured data. Nuxt 3's SEO toolchain can solve all of these issues.

1. What You'll Learn


2. A True Story of an Architect

(1) Pain Point: Out of a million pages, only 2,000 are indexed by Google

Charlie checked MegaShop using Google Search Console and found that out of 1 million product pages, only 2,000 had been indexed. Bob's analysis revealed that all product pages had the title "MegaShop," empty meta descriptions, and missing Open Graph tags—meaning that when shared on social media, only the website name appeared, with no product information.

(2) Solutions for the Nuxt SEO Toolchain

Nuxt 3's useHead and useSeoMeta allow each product page to have its own SEO metadata:

TYPESCRIPT
// pages/products/[id].vue
useSeoMeta({
  title: product.value?.name,
  ogTitle: product.value?.name,
  description: `Buy ${product.value?.name} for $${product.value?.price} USD`,
  ogImage: product.value?.image
})

(3) Results: Google indexing rate soared 40-fold

After three months, Google's index surged from 2,000 to 800,000, and organic search traffic increased by 340%.


3. SEO Toolchain Architecture

(1) An Overview of the Nuxt 3 SEO Toolchain

100%
graph TB
    A[Nuxt SEO Toolkit] --> B[useHead]
    A --> C[useSeoMeta]
    A --> D[JSON-LD]
    A --> E[@nuxtjs/sitemap]
    A --> F[robots.txt]
    B --> B1[title / meta / link]
    C --> C1[OG / Twitter Card]
    D --> D1[Product / Breadcrumb]
    E --> E1[Dynamic URL Generation]
    F --> F1[Crawler Access Control]
    ```
    
---

## 4. Dynamic Management of useHead

### (1) What can useHead manage?

| Tag Type | Attribute | SEO Impact |
|:---------|:-----|:---------|
| title | Page Title | 🔴 High (Ranking Signal) |
| meta name="description" | Page Description | 🔴 High (Click-Through Rate) |
| meta property="og:*" | Open Graph | 🟡 Medium (Social Sharing) |
| meta name="twitter:*" | Twitter Card | 🟡 Medium (Social Sharing) |
| link rel="canonical" | Canonical URL | 🔴 High (duplicate removal) |
| link rel="alternate" | Multilingual URL | 🟡 Chinese (i18n SEO) |
| script type="application/ld+json" | JSON-LD | 🟡 Supported (Rich Snippets) |

### (1) ▶ Example: Basic Usage of useHead

```typescript
// In any component or page
useHead({
  title: 'Premium Headphones - MegaShop',
  meta: [
    { name: 'description', content: 'Buy Premium Headphones for $299.99 USD. Free shipping.' },
    { name: 'keywords', content: 'headphones, wireless, premium, audio' }
  ],
  link: [
    { rel: 'canonical', href: 'https://megashop.com/products/123' }
  ]
})

Output:

TEXT
// Execution Successful

(2) ▶ Example: Dynamic title (computed, reactive)

VUE
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Dynamic title that updates when product loads
useHead({
  title: computed(() => product.value
    ? `${product.value.name} - MegaShop`
    : 'Loading... - MegaShop'
  )
})
</script>

Output:

TEXT
// Execution Successful

(3) ▶ Example: Global Default Configuration

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      title: 'MegaShop - Premium E-Commerce',
      titleTemplate: '%s | MegaShop',
      meta: [
        { name: 'description', content: 'Over 1 million products shipped worldwide' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
        { charset: 'utf-8' }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
      ]
    }
  }
})

Output:

TEXT
// Execution Successful

4. useSeoMeta Structured SEO

(1) Comparison of useSeoMeta and useHead

Dimension useHead useSeoMeta
Targeting General Head Management SEO-Specific Shortcuts
API Style Array Object Key-Value Pairs
OG/Twitter Requires manual meta tag entry Done in one line
Type Safety ⚠️ Check documentation ✅ Complete type hints
Duplicate Removal ⚠️ Manual Management ✅ Automatic Duplicate Removal

(1) ▶ Example: Product Detail Page SEO

VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Structured SEO metadata - type-safe
useSeoMeta({
  title: () => `${product.value?.name} - Buy Online`,
  ogTitle: () => `${product.value?.name} - MegaShop`,
  description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. ${product.value?.reviewCount} reviews, ${product.value?.rating} stars. Free shipping worldwide.`,
  ogDescription: () => `Premium ${product.value?.name} - $${product.value?.price} USD`,
  ogImage: () => product.value?.image || '/images/og-default.jpg',
  ogUrl: () => `https://megashop.com/products/${route.params.id}`,
  ogType: 'product',
  twitterCard: 'summary_large_image',
  twitterTitle: () => `${product.value?.name} - MegaShop`,
  twitterImage: () => product.value?.image || '/images/og-default.jpg'
})
</script>

Output:

TEXT
// Execution Successful

(2) ▶ Example: Homepage SEO

TYPESCRIPT
// pages/index.vue
useSeoMeta({
  title: 'MegaShop - Over 1 Million Products',
  ogTitle: 'MegaShop - Premium E-Commerce Platform',
  description: 'Shop over 1 million products with free worldwide shipping. Electronics, fashion, home & garden at the best prices.',
  ogDescription: 'Discover 1 million+ products on MegaShop. Free shipping on orders over $50 USD.',
  ogImage: '/images/og-homepage.jpg',
  ogUrl: 'https://megashop.com',
  ogType: 'website'
})

Output:

TEXT
// Execution Successful

5. JSON-LD Structured Data

(1) The Impact of Structured Data on Search Results

Data Type Google Rich Snippet Results Compatible with MegaShop
Product Price/Rating/Inventory ✅ Product Details Page
BreadcrumbList Breadcrumb Navigation ✅ All Pages
Organization Company Information ✅ Home
Website Site Search Box ✅ Home
Review Review Summary ✅ Product Page

(1) ▶ Example: Product JSON-LD

VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// JSON-LD structured data for Google rich results
useHead({
  script: [
    {
      type: 'application/ld+json',
      innerHTML: computed(() => JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.value?.name,
        image: product.value?.image,
        description: product.value?.description,
        sku: `MEGA-${product.value?.id}`,
        offers: {
          '@type': 'Offer',
          url: `https://megashop.com/products/${route.params.id}`,
          priceCurrency: 'USD',
          price: product.value?.price,
          availability: product.value?.inStock
            ? 'https://schema.org/InStock'
            : 'https://schema.org/OutOfStock'
        },
        aggregateRating: {
          '@type': 'AggregateRating',
          ratingValue: product.value?.rating,
          reviewCount: product.value?.reviewCount
        }
      }))
    }
  ]
})
</script>

Output:

TEXT
// Execution Successful

(2) ▶ Example: Breadcrumb JSON-LD

TYPESCRIPT
// composables/useBreadcrumbLd.ts
export function useBreadcrumbLd(items: { name: string; url: string }[]) {
  useHead({
    script: [{
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'BreadcrumbList',
        itemListElement: items.map((item, index) => ({
          '@type': 'ListItem',
          position: index + 1,
          name: item.name,
          item: item.url
        }))
      })
    }]
  })
}

// Usage in page
useBreadcrumbLd([
  { name: 'Home', url: 'https://megashop.com' },
  { name: 'Products', url: 'https://megashop.com/products' },
  { name: 'Premium Headphones', url: 'https://megashop.com/products/123' }
])

Output:

TEXT
// Execution Successful

6. Sitemap and robots.txt

(1) ▶ Example: Installing @nuxtjs/sitemap

BASH
npm install @nuxtjs/sitemap

Output:

TEXT
# Command executed successfully
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/sitemap'],

  sitemap: {
    hostname: 'https://megashop.com',
    gzip: true,
    routes: async () => {
      // Dynamic routes for 1 million products
      const products = await $fetch('/api/products/all-ids')
      return products.map((id: number) => ({
        loc: `/products/${id}`,
        lastmod: new Date().toISOString(),
        changefreq: 'daily',
        priority: 0.8
      }))
    },
    defaults: {
      changefreq: 'weekly',
      priority: 0.5
    }
  }
})

(2) ▶ Example: robots.txt

TEXT
// public/robots.txt
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /profile/

Sitemap: https://megashop.com/sitemap.xml

Output:

TEXT
Execution Successful

(1) Comparison of Sitemap Strategies

Strategy Advantages Disadvantages Applicability
Single-file sitemap.xml Simple ≤ 50,000 URLs Small site
Sitemap Index Supports millions of URLs Requires splitting MegaShop
Dynamically Generate Routes Automatically Overwrite New Pages Build-Time Queries Product Pages
Automatic module generation Zero configuration Limited Small to medium-sized sites

7. Comprehensive Example: Complete SEO Guide for MegaShop Product Pages

VUE
<!-- pages/products/[id].vue -->
<template>
  <div v-if="product" class="product-page">
    <h1>{{ product.name }}</h1>
    <p class="price">${{ product.price }} USD</p>
    <p>{{ product.reviewCount }} reviews · {{ product.rating }} stars</p>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
const productUrl = `${config.public.siteUrl}/products/${route.params.id}`

// SEO Meta
useSeoMeta({
  title: () => `${product.value?.name} - MegaShop`,
  ogTitle: () => product.value?.name,
  description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. Free shipping. ${product.value?.reviewCount} reviews.`,
  ogDescription: () => `${product.value?.name} - $${product.value?.price} USD on MegaShop`,
  ogImage: () => product.value?.image,
  ogUrl: () => productUrl,
  ogType: 'product',
  twitterCard: 'summary_large_image'
})

// Canonical URL
useHead({
  link: [{ rel: 'canonical', href: productUrl }]
})

// JSON-LD
useHead({
  script: [{
    type: 'application/ld+json',
    innerHTML: computed(() => JSON.stringify({
      '@context': 'https://schema.org',
      '@type': 'Product',
      name: product.value?.name,
      image: product.value?.image,
      offers: {
        '@type': 'Offer',
        priceCurrency: 'USD',
        price: product.value?.price,
        availability: product.value?.inStock ? 'InStock' : 'OutOfStock'
      },
      aggregateRating: {
        '@type': 'AggregateRating',
        ratingValue: product.value?.rating,
        reviewCount: product.value?.reviewCount
      }
    }))
  }]
})
</script>

❓ FAQ

Q Can useSeoMeta and useHead be used together?
A Yes, they operate on the same Head instance. useSeoMeta manages SEO tags, while useHead manages other tags (canonical/JSON-LD/style).
Q How should I handle a sitemap for a product page with a million items?
A Use Sitemap Index to split it into multiple sub-sitemaps (each with ≤ 50 thousand URLs). The @nuxtjs/sitemap module supports automatic splitting.
Q Does JSON-LD's innerHTML pose an XSS risk?
A Nuxt 3 applies security measures to the innerHTML of script tags. However, it's best to use JSON.stringify and escape dynamic data to prevent injection.
Q Do SEO metadata work in CSR mode?
A Search engine crawlers do not support meta tags rendered via CSR. Pages requiring SEO must use SSR, ISR, or SSG. Meta tags on CSR pages only appear after client-side hydration.
Q How do I use titleTemplate?
A Set titleTemplate: '%s | MegaShop' in nuxt.config.ts. In the page's useHead, simply set the title content, and the template will automatically be constructed.
Q Are there any size requirements for ogImage images?
A Facebook recommends 1200x630px, and Twitter recommends 1200x600px (summary_large_image). Images that are too small may not display.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty: ⭐): Use useHead to set the title and meta description for the homepage, then view the source code to verify.
  2. Advanced Exercise (Difficulty: ⭐⭐): Use useSeoMeta to configure complete OG and Twitter Card metadata for the product detail page, and validate it using the Facebook Sharing Debugger.
  3. Challenge (Difficulty: ⭐⭐⭐): Implement automatic generation of JSON-LD for product pages, JSON-LD for breadcrumbs, and sitemaps, and validate the structured data using the Google Rich Results Test.

---|

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏