How to add Open Graph tags in Laravel (Blade)

Laravel renders server-side, so scrapers see exactly what Blade produces — no hydration tricks needed. The clean pattern is the same as everywhere: social tags live in one layout, pages override the values. You do not need a package for this.

Want to see how your page looks right now?

The free checker shows your previews for nine platforms — from X and WhatsApp to iMessage, Discord and Bluesky.

Check your URL

Add the tags to your layout

In resources/views/layouts/app.blade.php, render og:title, og:description, og:image, og:url and twitter:card from variables with sensible defaults (see the snippet). Every view that extends the layout can override them.

Pass values per page

From controllers: return view("posts.show", ["post" => $post]) and in the view set the sections/props from $post. Title from the model, description from an excerpt, image from the post or a default.

Keep URLs absolute

Use url()->current() (or route(...)) for og:url and asset("og/default.png") for images — both produce full URLs based on APP_URL. Set APP_URL correctly in production or every tag points at localhost.

Verify like a scraper

curl the page or paste the URL into the MetaPeek checker. If tags differ from the browser, look at cached views (php artisan view:clear) or middleware that varies output per user agent.

Code example

{{-- resources/views/layouts/app.blade.php --}}
<head>
  <title>@yield('title', config('app.name'))</title>
  <meta property="og:title" content="@yield('title', config('app.name'))" />
  <meta property="og:description" content="@yield('og_description', 'Default description')" />
  <meta property="og:type" content="@yield('og_type', 'website')" />
  <meta property="og:url" content="{{ url()->current() }}" />
  <meta property="og:image" content="@yield('og_image', asset('og-default.png'))" />
  <meta name="twitter:card" content="summary_large_image" />
</head>

{{-- resources/views/posts/show.blade.php --}}
@extends('layouts.app')
@section('title', $post->title)
@section('og_description', $post->excerpt)
@section('og_type', 'article')
@section('og_image', $post->social_image_url)

Common mistakes

Frequently asked questions

Should I use a SEO package instead?

Packages like artesaos/seotools or spatie/laravel-seo are fine if you want a fluent API, but for Open Graph alone the layout pattern above is all you need — fewer dependencies, same output.

Does this work with Inertia or Livewire?

Yes — the head is still rendered by Blade server-side. For Inertia, set the values in the root Blade template from shared props; scrapers never run your JavaScript.

How do I test locally?

View-source the page (Ctrl+U) and paste the HTML into the MetaPeek paste-HTML mode — scrapers cannot reach your local environment, pasting works around that.

Changed your tags? Verify the result.

Paste your URL and see within two seconds whether everything is right — on every platform.

Open the checker

Related guides