SEO Metadata in Laravel Inertia & Vue — Full Guide With Examples

Search Engine Optimization (SEO) plays a major role in helping search engines understand the content of your pages. For a blog, SEO metadata is even more important because each post needs its own unique title, description, image, and structured data.
When using Laravel + Inertia.js + Vue, you don't have a traditional Blade <head> section for every page load. Instead, you generate SEO metadata in Laravel and pass it to your Vue layout, which updates the <head> dynamically using Inertia's <Head> component.
In this article, you'll learn how to implement a complete SEO system, including which metadata to add, how to generate it for each blog post, and how to render it properly in Vue.
What will you learn?
- What tags to include in a blog post.
- How to structure them.
- How to generate them in Laravel.
- How to pass them through Inertia.
- How to render them in Vue.
- How the SEO helper fits into the entire workflow.
In this article, I assume that you have a basic understanding of SEO metadata and how you can implement them inside the <head> tag in ordinary HTML or a Laravel Blade file.
What SEO Metadata Should a Blog Post Include?
A typical blog post should include:
1- Standard SEO Tags
These help Google understand your content:
<title><meta name="description"><meta name="keywords">(optional but acceptable).<meta name="author"><link rel="canonical">(to prevent duplicate indexing)
<title>How to Use Laravel Queues — A Complete Guide</title>
<meta name="description" content="Learn how Laravel queues work with jobs, workers, and real-world examples.">
<meta name="keywords" content="Laravel, Queues, Jobs, PHP, Inertia">
<meta name="author" content="John Doe" />
<link rel="canonical" href="https://example.com/blog/how-to-use-laravel-queues">
2- Open Graph Tags (Facebook, LinkedIn, Instagram, etc.)
Used for social sharing:
og:titleog:derscriptionog:imageog:urlog:type(articlefor blog posts)
<meta property="og:title" content="How to Use Laravel Queues — A Complete Guide" />
<meta property="og:description" content="Learn how Laravel queues work with real examples." />
<meta property="og:image" content="https://example.com/storage/posts/123-cover.jpg" />
<meta property="og:url" content="https://example.com/blog/how-to-use-laravel-queues" />
<meta property="og:type" content="article" />
3- Twitter Card Tags
For Twitter/X previews:
- twitter:title
- twitter:descrion
- twitter:image
- twitter:card (usually "summary_large_image")
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="How to Use Laravel Queues — A Complete Guide" />
<meta name="twitter:description" content="Learn how Laravel queues work with real examples." />
<meta name="twitter:image" content="https://example.com/storage/posts/123-cover.jpg" />
4- JSON-LD Structured Data
Google recommends HTML <script type="application/ld+json"> to help them understand your article:
- "@type": "BlogPosting"
- "headline"
- "image"
- "datePublished"
- "author"
- "description"
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "How to Use Laravel Queues — A Complete Guide",
"image": "https://example.com/storage/posts/123-cover.jpg",
"author": {
"@type": "Person",
"name": "John Doe"
},
"datePublished": "2024-11-10",
"description": "Learn how Laravel queues work with real examples."
}
5- Optional Additional Tags
Useful but not required:
<meta name="robots"><meta name="theme-color">
We will generate all of these automatically using a custom Laravel SEO helper.
Laravel Side - Building a Reusable SEO Helper
To avoid repeating code in every controller, we will create a global SEO helper that builds metadata arrays for different models.
1- Create app/Helpers/Seo.php file
The file contains two static methods for easy use without instantiating - make() and forPost().
<?php
namespace App\Helpers;
class Seo
{
public static function make(array $data): array
{
return [
'title' => $data['title'] ?? config('app.name'),
'description' => $data['description'] ?? '',
'keywords' => $data['keywords'] ?? '',
'author' => $data['author'] ?? '',
'image' => $data['image'] ?? asset('default-cover.png'),
'url' => $data['url'] ?? url()->current(),
'type' => $data['type'] ?? 'article',
'published_at' => $data['published_at'] ?? null,
'json_ld' => $data['json_ld'] ?? [],
];
}
public static function forPost($post): array
{
return self::make([
'title' => $post->seo_title ?? $post->title,
'description' => $post->seo_description ?? substr(strip_tags($post->excerpt), 0, 160),
'keywords' => $post->seo_keywords ?? '',
'image' => $post->cover_image_url,
'url' => route('posts.show', $post->slug),
'author' => $post->author->name,
'published_at' => $post->published_at?->toDateString(),
'json_ld' => [
"@context" => "https://schema.org",
"@type" => "BlogPosting",
"headline" => $post->title,
"image" => $post->cover_image_url,
"url" => route('posts.show', $post->slug),
"author" => [
"@type" => "Person",
"name" => $post->author->name
],
"datePublished" => $post->published_at?->toDateString(),
"description" => $post->seo_description ?? substr(strip_tags($post->excerpt), 0, 160)
],
]);
}
}
This helper returns a clean SEO array with everything your Vue layout needs.
2- Autoload the Helper
Add this to composer.json so Laravel loads the helper automatically:
"autoload": {
"files": [
"app/Helpers/Seo.php"
]
}
Then run in your terminal:
composer dump-autoload -o
Now you can call the helper anywhere in your application.
3- Passing SEO Metadata to Inertia
In your PostController, include the SEO data when returning the post page.
use App\Helpers\Seo;
public function show(Post $post)
{
return inertia('Blog/Show', [
'post' => $post,
'seo' => Seo::forPost($post),
]);
}
Now Show.vue and your layout will receive:
page.props.seo
Vue Side - Display Metadata in <Head>
Your website probably uses a main layout such as:
resources/js/Layouts/MainLayout.vue
Inside the layout, render SEO tags dynamically:
<script setup>
import { usePage, Head } from '@inertiajs/vue3'
const page = usePage()
const seo = page.props.seo ?? {}
</script>
<template>
<Head>
<!-- Basic SEO -->
<title>{{ seo.title }}</title>
<meta name="description" :content="seo.description" />
<meta name="keywords" :content="seo.keywords" />
<meta name="author" :content="seo.author" />
<link rel="canonical" :href="seo.url" />
<!-- Open Graph -->
<meta property="og:title" :content="seo.title" />
<meta property="og:description" :content="seo.description" />
<meta property="og:image" :content="seo.image" />
<meta property="og:url" :content="seo.url" />
<meta property="og:type" :content="seo.type" />
<!-- Twitter -->
<meta name="twitter:title" :content="seo.title" />
<meta name="twitter:description" :content="seo.description" />
<meta name="twitter:image" :content="seo.image" />
<meta name="twitter:card" content="summary_large_image" />
<!-- JSON-LD -->
<component :is="'script'" type="application/ld+json" v-html="JSON.stringify(seo.json_ld)"></component>
</Head>
<slot />
</template>
We used a dynamic component with JSON-LD because we can't use <script> tags directly inside Vue <tamplate>, and if you are using Vite with Laravel, it will fire a runtime error.
So, the dynamic component <component :is="'script'" >:
- Renders a native
<script>tag at runtime. - It bypasses the Vite compiler's static check because it's not a literal
<script>tag in the source code. v-htmlensures JSON content is injected without being escaped (preserving quotes and structure).
Why Is This Approach The Best?
This method has several advantages:
- Centralized SEO logic: One helper for everything.
- Clean controller: No duplicated meta tag building.
- Dynamic Vue
<head>rendering: Works perfectly with inertia SPA-style navigation. - Google-ready structured data: JSON-LD improves search ranking.
- Social media preview support: Open Graph + Twitter Cards included.
- Easy to extend: You can add
og:site_name,robots, or custom fields anytime.
Conclusion
Integrating SEO metadata in a Laravel + Inertia.js + Vue application doesn't have to be complicated. By generating your metadata on the backend using a simple helper and rendering it dynamically in your Vue layout, you get a clean, scalable, and fully optimized system for managing blog post SEO.
This setup ensures your post looks great on Google, Social Media, and anywhere else they appear - all while keeping your code elegant and maintainable.