
August 14, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Achieving a reliable SEO for Laravel sites complete setup requires integrating metadata management, XML sitemaps, structured data, and performance optimization directly into your application architecture rather than treating them as afterthoughts. Unlike WordPress, Laravel provides no built-in SEO interface, so you must deliberately wire these systems during development to avoid indexation failures and poor rankings. This guide covers the exact configuration I use on production legal-tech portals and eCommerce platforms, linking to foundational concepts in my on-page SEO checklist for Nepal where relevant.
How Do You Configure Meta Tags and Open Graph in Laravel?
Dynamic meta tags are the foundation of any SEO for Laravel sites complete setup. Hardcoding titles and descriptions in Blade templates creates maintenance nightmares and duplicate content risks when routes share layouts. The artesaos/seotools package (v1.x for Laravel 12) provides a service-based approach that integrates cleanly with controllers and middleware.
Installation and Base Configuration
composer require artesaos/seotools
php artisan vendor:publish --provider="Artesaos\SEOTools\Providers\SEOToolsServiceProvider" In config/seotools.php, set sensible defaults that apply site-wide while allowing per-route overrides:
'defaults' => [
'title' => 'Nepal Legal Services | Court Marriage & Notary',
'description' => 'Expert legal guidance for court marriage, divorce, and notary services in Nepal.',
'separator' => ' - ',
'keywords' => ['nepal lawyer', 'court marriage nepal', 'notary kathmandu'],
'open_graph' => [
'type' => 'website',
'site_name' => 'Court Marriage In Nepal',
'locale' => 'en_US',
],
], Controller-Level Metadata Assignment
Set metadata in controllers, not views. This keeps SEO logic testable and co-located with business logic:
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\OpenGraph;
public function show(string $slug)
{
$service = Service::where('slug', $slug)->firstOrFail();
SEOMeta::setTitle($service->meta_title ?? $service->name);
SEOMeta::setDescription($service->meta_description ?? Str::limit($service->body, 155));
SEOMeta::addKeyword([$service->category->name, 'nepal legal service']);
SEOMeta::setCanonical(route('services.show', $service->slug));
OpenGraph::setTitle($service->name);
OpenGraph::setDescription($service->meta_description);
OpenGraph::addImage($service->featured_image_url);
OpenGraph::setType('article');
return view('services.show', compact('service'));
} In your master Blade layout, render tags once in the <head>:
<head>
{!! SEOMeta::generate() !!}
{!! OpenGraph::generate() !!}
</head> This pattern prevents missing or duplicate tags across hundreds of routes. On a recent legal portal project, this eliminated 47 duplicate-title warnings within two weeks of deployment.
How Do You Generate and Maintain XML Sitemaps Automatically?
Sitemaps are non-negotiable for indexation. Manual sitemap files break the moment you add content. Use spatie/laravel-sitemap (v7.x) to generate sitemaps dynamically or via scheduled commands.
Static Sitemap Generation via Artisan
For most Laravel applications, static generation on deploy or schedule is safer than dynamic rendering:
composer require spatie/laravel-sitemap Create app/Console/Commands/GenerateSitemap.php:
use Spatie\Sitemap\SitemapGenerator;
class GenerateSitemap extends Command
{
protected $signature = 'sitemap:generate';
public function handle(): void
{
SitemapGenerator::create(config('app.url'))
->writeToFile(public_path('sitemap.xml'));
$this->info('Sitemap generated successfully.');
}
} Register in routes/console.php or scheduler to run after every deployment:
Schedule::command('sitemap:generate')->daily()->at('03:00'); Custom URLs for Dynamic Content
Crawlers won't discover filtered pages, paginated archives, or user-generated profiles automatically. Add them explicitly:
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
$sitemap = Sitemap::create();
Service::chunk(100, function ($services) use ($sitemap) {
foreach ($services as $service) {
$sitemap->add(
Url::create(route('services.show', $service->slug))
->setLastModificationDate($service->updated_at)
->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY)
->setPriority(0.8)
);
}
});
$sitemap->writeToFile(public_path('sitemap.xml')); On high-traffic sites, chunk queries to avoid memory exhaustion. I've seen sitemap generation crash servers processing 50k+ records without chunking — always paginate.
How Do You Implement Schema Markup for Rich Results?
Structured data drives rich snippets, knowledge panels, and enhanced SERP features. For legal-tech and service businesses, LegalService, Attorney, and FAQPage schemas are particularly valuable. Never rely on plugins that inject generic schema — craft it per entity.
JSON-LD in Blade Templates
Output schema as inline JSON-LD in the <head>. Create a reusable component:
// resources/views/components/schema/legal-service.blade.php
@props(['service'])
<script type="application/ld+json">
{!! json_encode([
'@context' => 'https://schema.org',
'@type' => 'LegalService',
'name' => $service->name,
'description' => $service->meta_description,
'url' => route('services.show', $service->slug),
'telephone' => config('business.phone'),
'address' => [
'@type' => 'PostalAddress',
'streetAddress' => config('business.address'),
'addressLocality' => 'Kathmandu',
'addressCountry' => 'NP',
],
'priceRange' => 'Rs 5000-50000',
'openingHoursSpecification' => [[
'@type' => 'OpeningHoursSpecification',
'dayOfWeek' => ['Monday','Tuesday','Wednesday','Thursday','Friday'],
'opens' => '10:00',
'closes' => '17:00',
]],
], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) !!}
</script> Validate every schema output with Google's Rich Results Test before deploying. Invalid JSON-LD silently fails and wastes implementation effort.
How Do You Optimize Core Web Vitals in Laravel 12?
Google uses Core Web Vitals as ranking signals. Laravel applications often fail LCP and CLS due to unoptimized asset pipelines and layout shifts. Address these systematically.
Vite Asset Optimization
Laravel 12 ships with Vite 6.x by default. Configure critical CSS inlining and code splitting:
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
build: {
cssCodeSplit: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'alpinejs'],
},
},
},
},
}); In production, preload critical assets in your layout:
@vite(['resources/css/app.css', 'resources/js/app.js'])
<link rel="preload" as="style" href="{{ Vite::asset('resources/css/critical.css') }}"> Eliminating Layout Shifts
CLS kills rankings. Reserve space for images, ads, and dynamic content:
- Always set explicit
widthandheightattributes on<img>tags - Use CSS
aspect-ratiofor responsive containers - Avoid injecting content above existing DOM elements after load
- Font-display: swap with size-adjust to prevent FOUT shifts
On an eCommerce project, fixing image dimensions alone improved CLS from 0.42 to 0.03. Measure with Lighthouse CI in your pipeline — don't guess.
| Metric | Target (2026) | Laravel Fix | Validation Tool |
|---|---|---|---|
| LCP | ≤ 2.5s | Preload hero image, server-side render above-fold content | PageSpeed Insights |
| INP | ≤ 200ms | Defer non-critical JS, use Alpine/Livewire over heavy frameworks | Chrome DevTools |
| CLS | ≤ 0.1 | Explicit image dimensions, font-display: swap, reserved ad slots | Lighthouse CI |
How Do You Handle Canonical URLs and Duplicate Content?
Duplicate content destroys crawl budget and dilutes ranking signals. Laravel applications create duplicates through pagination, filters, sorting parameters, and HTTP/HTTPS variants.
Canonical Tag Strategy
Set canonicals explicitly on every page. Never assume Laravel's URL helper produces the correct canonical:
// In controller or middleware
SEOMeta::setCanonical(route('services.show', ['slug' => $service->slug]));
// For paginated pages, canonical points to page 1 unless intentional
if ($page > 1) {
SEOMeta::setCanonical(route('services.index'));
}
// Strip tracking params from canonical
$cleanUrl = request()->url(); // Excludes query string
SEOMeta::setCanonical($cleanUrl); Robots and Noindex Directives
Block crawlers from low-value pages programmatically:
// Middleware or controller
if (request()->has('sort') || request()->has('filter')) {
SEOMeta::setRobots('noindex, follow');
}
// Admin, preview, and staging routes
Route::middleware('auth')->group(function () {
// These should never be indexed
}); Generate robots.txt dynamically to reflect environment:
// routes/web.php
Route::get('/robots.txt', function () {
if (app()->environment('production')) {
return response("User-agent: *\nAllow: /\nSitemap: " . url('/sitemap.xml'), 200)
->header('Content-Type', 'text/plain');
}
return response("User-agent: *\nDisallow: /", 200)
->header('Content-Type', 'text/plain');
}); What Monitoring and Validation Workflow Prevents SEO Regressions?
SEO breaks silently. Establish automated checks before they impact traffic. For teams managing multiple Laravel properties, understanding SEO service pricing in Nepal helps budget for ongoing monitoring versus one-time fixes.
Pre-Deploy Validation Checklist
- Run
php artisan sitemap:generateand diff against previous version - Validate JSON-LD with
google/rich-results-testCLI or API - Lighthouse CI threshold gates in GitLab/GitHub Actions
- Check meta tag presence on sample routes via HTTP test
- Verify robots.txt returns correct directives for environment
Post-Launch Monitoring
Connect Google Search Console immediately. Monitor:
- Coverage report for crawl errors and excluded pages
- Core Web Vitals assessment (field data, not lab)
- Manual actions or security issues
- Sitemap processing status and discovered pages count
Set up weekly automated reports pulling GSC API data into your Laravel admin panel. Catch indexation drops before clients notice traffic loss. For deeper technical audits, reference the technical SEO audit guide which covers server-level diagnostics specific to Nepal hosting environments.
If you're building a Laravel application in Nepal and need hands-on implementation support, these patterns scale from single-service sites to multi-tenant platforms handling thousands of indexed pages.
Implementing SEO for Laravel Sites Complete Setup
A durable SEO for Laravel sites complete setup integrates metadata, sitemaps, schema, performance, and duplicate-content controls into your development workflow — not as post-launch patches. Start with artesaos/seotools and spatie/sitemap, validate every change against Google's tools, and monitor field metrics continuously. If you need help implementing this stack on a production Laravel application, reach out to discuss your project.

