Laravel Open Graph Meta Tags: Blade Templates and Dynamic OG Tags
Add og:title, og:image, og:description, and Twitter card tags to Laravel apps using Blade templates — with layouts, sections, and dynamic data from controllers.
How Laravel and Blade handle OG tags
Laravel uses Blade as its templating engine, which renders HTML on the server. Social crawlers receive fully populated HTML with no JavaScript execution, so adding OG tags is simply a matter of putting <meta> tags in the right Blade layout.
The standard pattern is to define OG tag @yield directives in your layout and fill them with @section in each view.
Base layout with OG tag yields
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<title>@yield('title', config('app.name'))</title>
{{-- Open Graph --}}
<meta property="og:title" content="@yield('og_title', config('app.name'))">
<meta property="og:description" content="@yield('og_description', 'Default description.')">
<meta property="og:image" content="@yield('og_image', asset('images/og-default.jpg'))">
<meta property="og:url" content="@yield('og_url', url()->current())">
<meta property="og:type" content="@yield('og_type', 'website')">
{{-- Twitter Card --}}
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@yield('twitter_title', config('app.name'))">
<meta name="twitter:description" content="@yield('twitter_description', 'Default description.')">
<meta name="twitter:image" content="@yield('twitter_image', asset('images/og-default.jpg'))">
</head>
<body>
@yield('content')
</body>
</html>Override in child views
{{-- resources/views/blog/show.blade.php --}}
@extends('layouts.app')
@section('title', $post->title . ' | My Blog')
@section('og_title', $post->title)
@section('og_description', $post->excerpt)
@section('og_image', $post->cover_image_url)
@section('og_url', route('blog.show', $post->slug))
@section('og_type', 'article')
@section('twitter_title', $post->title)
@section('twitter_description', $post->excerpt)
@section('twitter_image', $post->cover_image_url)
@section('content')
<h1>{{ $post->title }}</h1>
{!! $post->body !!}
@endsectionPassing OG data from controllers
Generate absolute image URLs in your controller using Laravel's asset() or Storage::url() helper:
// app/Http/Controllers/BlogController.php
public function show(string $slug)
{
$post = Post::where('slug', $slug)->firstOrFail();
// Ensure absolute URL for og:image
$ogImage = $post->cover_image
? Storage::url($post->cover_image)
: asset('images/og-default.jpg');
return view('blog.show', [
'post' => $post,
'ogImage' => url($ogImage),
]);
}Using artesaos/seotools package
For complex applications, the artesaos/seotools package provides a fluent API for managing OG tags and SEO metadata:
composer require artesaos/seotools
// In controller:
use ArtesaosSEOToolsFacadesSEOMeta;
use ArtesaosSEOToolsFacadesOpenGraph;
use ArtesaosSEOToolsFacadesTwitterCard;
public function show(string $slug)
{
$post = Post::where('slug', $slug)->firstOrFail();
SEOMeta::setTitle($post->title);
SEOMeta::setDescription($post->excerpt);
OpenGraph::setTitle($post->title)
->setDescription($post->excerpt)
->addImage($post->cover_image_url)
->setUrl(route('blog.show', $post->slug))
->setType('article');
TwitterCard::setTitle($post->title)
->setDescription($post->excerpt)
->setImage($post->cover_image_url);
return view('blog.show', compact('post'));
}
// In layout:
{!! SEOMeta::generate() !!}
{!! OpenGraph::generate() !!}
{!! TwitterCard::generate() !!}Common Laravel OG tag mistakes
- Relative image URLs: always pass absolute URLs to og:image. Use
url($path)orasset()to prefix with your app URL. - Forgetting APP_URL: ensure your
.envhas the correctAPP_URLin production so asset helpers generate correct absolute URLs. - Unescaped content: Blade auto-escapes
{{ }}but not{!! !!}. For meta content, always use the escaped syntax.
Preview your OG tags free at OGFixer.com → Paste your Laravel URL to see how your link card looks on Twitter, LinkedIn, Discord, and Slack.