Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add Open Graph tags to the shared Blade layout’s <head>, then set each page’s title, description, canonical URL and image from its view or controller. This makes the metadata available in the server-rendered HTML that link-preview services fetch. The tags describe a page; they do not guarantee how or when a particular platform displays or refreshes its preview.

Which Open Graph tags should a Laravel page include?

The protocol’s four basic properties are og:title, og:type, og:image and og:url. Add og:description for a useful summary, and og:site_name when the site name helps identify the page. For an image, include og:image:alt: the Open Graph protocol says pages specifying og:image should also specify its alt text. Describe what the image shows rather than using the field as a caption.

Use the page’s canonical, publicly reachable URL for og:url and a publicly reachable image URL for og:image. These fields identify URL resources; check that the URLs resolve as intended. The protocol also defines image details including og:image:secure_url, og:image:type, og:image:width and og:image:height, as well as optional properties such as og:locale and og:determiner. See the Open Graph protocol for the property definitions.

For a simple site, ordinary Blade tags are usually the most direct approach. For an application that needs shared defaults, runtime metadata, field-level precedence or framework integrations, consider Laravel Head, after checking that its package guidance matches your installed Laravel version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add tags with a shared Blade layout

Laravel views commonly live under resources/views. Put the tags in a layout used by the pages you want to share, for example resources/views/layouts/app.blade.php. The following is an illustrative pattern; adapt the defaults and route conventions to your project.

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <title>@yield('title', config('app.name'))</title>

    <meta property="og:title" content="@yield('og_title', config('app.name'))">
    <meta property="og:type" content="@yield('og_type', 'website')">
    <meta property="og:url" content="@yield('og_url', url()->current())">
    <meta property="og:description" content="@yield('og_description', '')">
    <meta property="og:image" content="@yield('og_image', asset('images/social-default.jpg'))">
    <meta property="og:image:alt" content="@yield('og_image_alt', '')">
</head>
<body>
    @yield('content')
</body>
</html>

Make sure the default image exists and its generated URL is publicly reachable. A default value prevents a missing section from leaving a tag empty, but it should be a valid fallback suitable for the page.

Set different metadata for each page

Use Blade sections in a child view

A child view can provide post-specific values to the layout:

@extends('layouts.app')

@section('title', $post->title)
@section('og_title', $post->social_title ?: $post->title)
@section('og_type', 'article')
@section('og_url', route('posts.show', $post))
@section('og_description', $post->meta_description ?: Str::limit(strip_tags($post->body), 200))
@section('og_image', $post->social_image_url)
@section('og_image_alt', $post->social_image_alt ?: $post->title)

@section('content')
    <article>
        <h1>{{ $post->title }}</h1>
        {!! $post->body !!}
    </article>
@endsection

Use the actual route name and model fields in your application. The example deliberately uses escaped Blade section output in the layout for the metadata values. Laravel’s Blade documentation explains that {{ }} echoes are passed through PHP’s htmlspecialchars; do not render user-provided metadata with unescaped output. The unescaped {!! $post->body !!} above is separate page-body content, not metadata: only use that pattern if the content is trusted or appropriately sanitized for your requirements. See Laravel’s Blade documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Pass metadata from a controller

If your team prefers to assemble view data in the controller, Laravel’s view helper accepts an array of values:

public function show(Post $post)
{
    return view('posts.show', [
        'post' => $post,
        'ogTitle' => $post->social_title ?: $post->title,
        'ogDescription' => $post->meta_description,
        'ogUrl' => route('posts.show', $post),
        'ogImage' => $post->social_image_url,
        'ogImageAlt' => $post->social_image_alt ?: $post->title,
    ]);
}

In that case, make the corresponding variables available to the layout or a metadata partial, and keep the output escaped. Laravel documents returning views and passing data in its views documentation and routing documentation.

Choose the right image markup

  • Use absolute, reachable URLs. The page URL and image URL should identify resources a remote preview fetcher can reach; a path that works only inside your app is not a useful share URL.
  • Describe the image in alt text. For example, describe the post’s actual cover image rather than repeating a promotional caption.
  • Keep image properties attached to the right image. If a page emits multiple og:image values, the protocol says the first is preferred in conflicts. Put structured image fields after the corresponding root og:image tag.
  • Use the appropriate object type. The protocol’s og:type distinguishes object types; a general page commonly uses website, while a post may use article.

Use Laravel Head for centralized metadata

Laravel’s 13.x documentation describes Laravel Head for Blade, Livewire and Inertia. It provides a structured API for defaults and page-specific metadata rather than hand-maintained tags in each layout. Confirm its package version and API against your application’s Laravel release before adopting it.

Install the package

composer require laravel/head

Define defaults and post metadata

For example, define site defaults in a service provider and override them when loading a post:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
use LaravelHeadEnumsOgType;
use LaravelHeadFacadesHead;
use LaravelHeadHeadBuilder;

// In a service provider boot method:
Head::defaults(fn (HeadBuilder $head) => $head
    ->title(config('app.name'))
    ->description('')
    ->og(siteName: config('app.name'), type: OgType::Website));

// In a controller action for one post:
Head::title($post->title)
    ->description($post->meta_description)
    ->og(type: OgType::Article, title: $post->title)
    ->ogImage($post->social_image_url, alt: $post->social_image_alt ?: $post->title);

return view('posts.show', ['post' => $post]);

Render the resolved tags in the shared layout:

<head>
    <meta charset="utf-8">
    @head
</head>

Laravel Head resolves defaults, route metadata, runtime metadata and error metadata with higher layers replacing lower values field by field. Its @head directive renders synchronously, so define page metadata before the layout is rendered. Consult the Laravel Head documentation for setup and API details.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Verify the rendered page and troubleshoot previews

  1. Open a representative page and inspect its actual response HTML, not just the Blade source.
  2. Confirm the expected og: tags appear inside <head>, and that the values correspond to that page rather than the site-wide defaults.
  3. Check that og:url is the canonical public page URL and that og:image resolves publicly. Confirm the image’s alt text describes it.
  4. If a share preview still lacks an image or has old text, first distinguish a Laravel response issue from platform behavior: verify what your server currently returns, then use the target platform’s current preview tooling when you need to check its fetch or refresh behavior.

The Laravel and Open Graph documentation establish how to emit metadata, but do not promise how a particular social platform will render or refresh a preview. Platform cache expiry and debugger behavior can vary, so do not treat a correct HTML response as proof that a platform has fetched the latest values.

Or skip the browser setup

If you need a screenshot of the page to inspect its rendered appearance after adding metadata, ScreenshotNeo provides a website screenshot API and MCP server. A single request can return a PNG, JPEG, WebP or PDF. For example, capture a page with cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/posts/sample -o shot.webp

See the ScreenshotNeo API documentation for options and response details. Cookie banners, newsletter popups and chat widgets are removed before the shot; bot checks, blank pages and failed loads are not billed. Its MCP server lets AI agents use screenshot tools, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo or sign up free for 1,000 screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.