SEO Nuxt tidak lagi cukup hanya dengan menambahkan title dan description di setiap halaman. Pada aplikasi modern berbasis SSR, SSG, maupun hybrid rendering, SEO teknis harus memastikan bahwa metadata benar-benar dirender di HTML awal, konsisten antarhalaman, tidak duplikat, dan mudah divalidasi oleh crawler maupun alat audit. Di Nuxt versi terbaru, pendekatan yang disarankan adalah menggunakan head management modern berbasis composable, lalu melengkapinya dengan canonical URL, robots directives, Open Graph, Twitter Card, schema markup Nuxt, dan sitemap yang dihasilkan dari sumber data aktual.
Artikel ini membahas implementasi praktis untuk kebutuhan umum developer: blog dan e-commerce. Fokus utamanya adalah bagaimana menyusun meta tags Nuxt yang dinamis, aman, mudah dipelihara, dan benar secara SEO.
Mengapa SEO di Nuxt harus berbasis render HTML awal
Mesin pencari modern memang semakin baik dalam mengeksekusi JavaScript, tetapi HTML hasil render awal tetap menjadi fondasi SEO teknis yang paling aman. Dengan Nuxt, Anda bisa memastikan bahwa title, meta description, OG tags, canonical, dan schema sudah tersedia saat respons pertama dikirim.
Keuntungan pendekatan ini:
- Lebih andal untuk crawler yang tidak selalu menunggu hidrasi JavaScript selesai.
- Lebih cepat divalidasi dengan View Source, curl, atau pemeriksaan response HTML dari server.
- Mengurangi risiko mismatch antara metadata di server dan client.
- Lebih mudah di-cache pada arsitektur edge atau CDN.
Kesalahan yang sering terjadi pada proyek Nuxt adalah metadata diatur terlambat di sisi client setelah data API selesai dimuat. Secara visual mungkin terlihat benar di browser, tetapi crawler bisa saja hanya melihat HTML awal tanpa tag yang diharapkan.
Head management modern di Nuxt
Pada Nuxt modern, pengelolaan head dilakukan melalui composable seperti useHead dan useSeoMeta. Keduanya memudahkan pembuatan metadata yang reaktif dan aman, termasuk pada halaman dinamis.
Kapan memakai useSeoMeta dan useHead
Gunakan useSeoMeta untuk metadata SEO umum seperti title, description, og tags, dan twitter tags. Gunakan useHead ketika Anda perlu kontrol yang lebih umum, misalnya menambahkan link rel="canonical", script type="application/ld+json", atau atribut HTML tertentu.
Contoh pola dasar untuk halaman statis:
<script setup lang="ts">
useSeoMeta({
title: 'Panduan SEO Nuxt',
description: 'Panduan teknis SEO Nuxt untuk meta tags, OG, schema, dan sitemap.',
ogTitle: 'Panduan SEO Nuxt',
ogDescription: 'Panduan teknis SEO Nuxt untuk meta tags, OG, schema, dan sitemap.',
ogType: 'article',
ogImage: 'https://example.com/og/seo-nuxt.jpg',
twitterCard: 'summary_large_image'
})
useHead({
link: [
{ rel: 'canonical', href: 'https://example.com/blog/seo-nuxt' }
]
})
</script>Pisahkan metadata global dan metadata per halaman. Metadata global cocok untuk nilai default seperti nama situs, fallback image, atau locale dasar. Metadata halaman harus menimpa default tersebut berdasarkan konten aktual.
Membuat helper SEO agar konsisten
Pada proyek besar, sebaiknya buat composable seperti usePageSeo() agar logika canonical, OG image fallback, title template, dan robots tidak tersebar di banyak file.
// composables/usePageSeo.ts
export function usePageSeo(input: {
title: string
description: string
path: string
image?: string
robots?: string
}) {
const siteUrl = 'https://example.com'
const siteName = 'Contoh Nuxt Site'
const canonical = new URL(input.path, siteUrl).toString()
const image = input.image || `${siteUrl}/og/default.jpg`
useSeoMeta({
title: `${input.title} · ${siteName}`,
description: input.description,
ogTitle: input.title,
ogDescription: input.description,
ogUrl: canonical,
ogImage: image,
ogSiteName: siteName,
twitterCard: 'summary_large_image',
twitterTitle: input.title,
twitterDescription: input.description,
twitterImage: image,
robots: input.robots || 'index, follow'
})
useHead({
link: [{ rel: 'canonical', href: canonical }]
})
}Keuntungan pendekatan ini adalah konsistensi. Selain itu, jika nanti struktur domain, default robots, atau format OG berubah, Anda hanya perlu mengubah satu tempat.
Meta tags Nuxt yang dinamis per halaman
Nilai SEO terbaik datang dari data aktual halaman. Untuk blog, title dan description biasanya berasal dari CMS atau API artikel. Untuk e-commerce, metadata biasanya berasal dari nama produk, ringkasan, brand, harga, dan gambar utama.
Contoh implementasi untuk halaman blog
Misalkan Anda memiliki route dinamis /blog/[slug] dan data artikel diambil saat SSR.
<script setup lang="ts">
const route = useRoute()
const { data: post } = await useAsyncData(`post-${route.params.slug}`, () =>
$fetch(`/api/posts/${route.params.slug}`)
)
if (!post.value) {
throw createError({ statusCode: 404, statusMessage: 'Artikel tidak ditemukan' })
}
usePageSeo({
title: post.value.title,
description: post.value.excerpt,
path: `/blog/${post.value.slug}`,
image: post.value.coverImage
})
</script>Mengapa pola ini penting? Karena await useAsyncData() pada level halaman memungkinkan data tersedia saat SSR, sehingga meta tags Nuxt langsung ikut dirender dalam HTML awal.
Hindari pola seperti memanggil API hanya di onMounted() lalu baru mengisi metadata. Itu membuat metadata hadir terlambat di sisi client.
Contoh implementasi untuk halaman produk e-commerce
Pada e-commerce, Anda sering perlu metadata yang lebih kontekstual, misalnya stok, kategori, harga, dan brand. Untuk meta description, jangan menyalin seluruh deskripsi panjang produk. Buat ringkasan yang singkat, jelas, dan unik.
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useAsyncData(`product-${route.params.slug}`, () =>
$fetch(`/api/products/${route.params.slug}`)
)
if (!product.value) {
throw createError({ statusCode: 404, statusMessage: 'Produk tidak ditemukan' })
}
const description = `${product.value.name} dari ${product.value.brand}. ${product.value.shortDescription}`
usePageSeo({
title: product.value.name,
description,
path: `/products/${product.value.slug}`,
image: product.value.image,
robots: product.value.isActive ? 'index, follow' : 'noindex, nofollow'
})
</script>Trade-off: metadata dinamis meningkatkan kualitas SEO, tetapi Anda harus menjaga sanitasi data dari API. Jangan masukkan HTML mentah atau string yang terlalu panjang tanpa kontrol.
Open Graph, Twitter Card, canonical, dan robots
Open Graph dan Twitter Card
OG tags penting untuk tampilan tautan saat dibagikan ke media sosial atau aplikasi chat. Set minimal yang sebaiknya Anda isi:
og:titleog:descriptionog:typeog:urlog:imagetwitter:card
Gunakan URL absolut untuk gambar dan canonical. Banyak masalah preview berasal dari penggunaan path relatif seperti /images/og.jpg pada sistem tertentu.
Canonical URL
Canonical mencegah kebingungan mesin pencari ketika satu konten dapat diakses melalui beberapa URL, misalnya dengan query parameter, pagination, atau versi trailing slash yang berbeda. Atur canonical ke URL utama yang ingin diindeks.
Kesalahan umum:
- Menggunakan canonical relatif, bukan absolut.
- Semua halaman menunjuk ke homepage.
- Canonical halaman produk varian diarahkan ke produk utama tanpa pertimbangan konten unik.
Robots meta dan robots.txt
meta name="robots" berguna untuk kontrol per halaman, misalnya halaman pencarian internal, cart, checkout, atau produk nonaktif. Sementara robots.txt berguna untuk aturan yang lebih global bagi crawler.
Contoh robots.txt sederhana:
User-agent: *
Disallow: /cart
Disallow: /checkout
Disallow: /account
Sitemap: https://example.com/sitemap.xmlJangan salah kaprah: Disallow di robots.txt bukan jaminan halaman tidak akan muncul di hasil pencarian jika URL itu sudah diketahui dari tempat lain. Jika benar-benar tidak ingin diindeks, gunakan noindex pada halaman tersebut.
Schema markup Nuxt dengan JSON-LD
Schema markup Nuxt umumnya paling praktis diterapkan dengan JSON-LD melalui tag script type="application/ld+json". Format ini lebih mudah dipelihara dibanding menyisipkan microdata di HTML template.
Schema untuk artikel blog
<script setup lang="ts">
const articleSchema = computed(() => ({
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.value.title,
description: post.value.excerpt,
image: [post.value.coverImage],
datePublished: post.value.publishedAt,
dateModified: post.value.updatedAt || post.value.publishedAt,
author: {
'@type': 'Person',
name: post.value.author.name
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://example.com/blog/${post.value.slug}`
}
}))
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify(articleSchema.value)
}
]
})
</script>Pastikan data schema selaras dengan konten yang benar-benar tampil di halaman. Jangan menulis tanggal publikasi atau author yang berbeda dari tampilan nyata.
Schema untuk produk e-commerce
<script setup lang="ts">
const productSchema = computed(() => ({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value.name,
image: [product.value.image],
description: product.value.shortDescription,
sku: product.value.sku,
brand: {
'@type': 'Brand',
name: product.value.brand
},
offers: {
'@type': 'Offer',
priceCurrency: 'IDR',
price: product.value.price,
availability: product.value.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock',
url: `https://example.com/products/${product.value.slug}`
}
}))
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify(productSchema.value)
}
]
})
</script>Untuk toko online, schema Product bisa membantu mesin pencari memahami harga, ketersediaan, dan identitas produk. Namun ingat, schema bukan jaminan rich result akan selalu muncul. Validitas data dan kualitas halaman tetap berpengaruh.
Sitemap modern dan hreflang bila relevan
Membangun sitemap dari data nyata
Sitemap sebaiknya dihasilkan dari sumber data aktual, bukan daftar statis yang mudah basi. Untuk blog, ambil daftar slug artikel yang terbit. Untuk e-commerce, ambil produk aktif, kategori, brand, dan halaman statis penting.
Prinsip sitemap yang baik:
- Hanya masukkan URL kanonis yang memang boleh diindeks.
- Jangan masukkan halaman noindex.
- Perbarui otomatis saat konten berubah.
- Gunakan beberapa sitemap jika URL sangat banyak.
Jika Anda menggunakan modul sitemap atau endpoint server untuk menghasilkan XML, pastikan URL yang keluar sama persis dengan canonical yang dipakai halaman.
Hreflang untuk situs multibahasa
Jika situs Anda memiliki versi bahasa atau regional berbeda, hreflang membantu mesin pencari memahami hubungan antarhalaman yang setara. Ini relevan jika Anda memiliki versi Indonesia dan Inggris, atau per negara seperti Indonesia dan Malaysia.
Contoh link hreflang:
useHead({
link: [
{ rel: 'alternate', hreflang: 'id-ID', href: 'https://example.com/id/produk/a' },
{ rel: 'alternate', hreflang: 'en-US', href: 'https://example.com/en/product/a' },
{ rel: 'alternate', hreflang: 'x-default', href: 'https://example.com/product/a' }
]
})Kesalahan umum hreflang adalah pasangan tidak lengkap, URL tidak saling mereferensikan, atau konten kedua halaman ternyata tidak benar-benar ekuivalen.
Validasi hasil render SSR dan debugging
Setelah implementasi selesai, jangan hanya mengandalkan panel Elements di browser. Validasi harus dilakukan pada HTML respons awal.
Cara memeriksa hasil render
- Buka View Source dan cari title, meta description, OG, canonical, dan JSON-LD.
- Gunakan
curluntuk melihat respons mentah:
curl -L https://example.com/blog/seo-nuxt | grep -i canonical
curl -L https://example.com/products/sample-product | grep -i 'application/ld+json'- Uji URL dengan alat inspeksi mesin pencari.
- Validasi schema dengan rich results tester atau schema validator.
- Periksa preview OG dengan debugger sosial bila perlu.
Masalah yang paling sering ditemukan
- Metadata kosong saat SSR karena data diambil di client-only lifecycle.
- Canonical salah karena host dibangun dari request lokal atau environment yang keliru.
- Title duplikat karena metadata global tidak dioverride dengan benar.
- Schema invalid karena JSON rusak atau field wajib tidak tersedia.
- Halaman terindeks padahal tidak diinginkan karena hanya di-disallow di robots.txt tanpa noindex.
Tip debugging: jika metadata terlihat benar di browser tetapi salah di source HTML, fokuslah pada alur SSR,
useAsyncData, dan apakah data benar-benar tersedia sebelumuseSeoMeta()dipanggil.
Praktik terbaik untuk blog dan e-commerce
Untuk blog
- Gunakan title unik per artikel.
- Isi meta description dari excerpt, bukan paragraf pertama mentah.
- Tambahkan schema Article atau BlogPosting.
- Sertakan canonical per slug.
- Masukkan hanya artikel terbit ke sitemap.
Untuk e-commerce
- Gunakan title yang mengandung nama produk dan brand bila relevan.
- Jangan indeks halaman filter atau sort yang menghasilkan URL tipis dan duplikatif tanpa strategi khusus.
- Gunakan schema Product dan Offer.
- Atur noindex untuk produk nonaktif, cart, checkout, dan halaman akun.
- Pastikan gambar OG dan gambar produk memakai URL absolut yang dapat diakses publik.
Penutup
Implementasi SEO Nuxt yang baik bertumpu pada tiga hal: metadata dirender di HTML awal, struktur tag konsisten di seluruh halaman, dan semua sinyal SEO teknis selaras dengan konten nyata. Dengan useSeoMeta, useHead, JSON-LD, canonical, robots, dan sitemap yang dibangun dari data aktual, Anda bisa membuat fondasi SEO yang kuat untuk blog maupun e-commerce.
Jika Anda ingin hasil yang stabil, prioritaskan alur SSR yang benar terlebih dahulu. Setelah itu, rapikan meta tags Nuxt, tambahkan Open Graph dan Twitter Card, lengkapi schema markup Nuxt, lalu tutup dengan validasi source HTML dan sitemap. Pendekatan ini tidak rumit, tetapi menuntut disiplin pada detail implementasi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!