Use spatie/laravel-og-image when Laravel must generate a social preview image from a Blade template rather than merely point to an existing file. You define the design in Blade, the package renders it in a browser, and middleware adds og:image, twitter:image, and twitter:card tags. The standard output is 1,200 × 630 pixels rendered at 2× resolution for sharp retina previews.
This guide covers installation, the request lifecycle, Blade patterns, browser requirements, caching, troubleshooting, and a hosted alternative when you do not want to run Chrome.
Choose generated images or an existing image URL
There are two different Laravel tasks:
- Declare an existing image: use Laravel Head to add Open Graph and Twitter metadata, including image URL, alt text, dimensions, MIME type, and large-image Twitter cards. It does not create an image.
- Generate an image from page data: use Spatie’s package. The visual is HTML in a Blade component or view, so it can reuse your application’s CSS, fonts, and Vite assets.
For a generated design, remove manually maintained og:image, twitter:image, and twitter:card tags after adopting the component. Keep other metadata such as title, description, type, and article dates.
Requirements and installation
Install the package with Composer:
composer require spatie/laravel-og-image
The current Packagist registry entry (version 1.3.1, published June 16, 2026) lists PHP ^8.3, Laravel components illuminate/contracts ^12.0|^13.0 and illuminate/support ^12.0|^13.0, plus spatie/laravel-screenshot ^1.1. Confirm those constraints against your application before upgrading because registry metadata can change.
Recommended Free Tools
#1 Best Overall
The package registers its web middleware automatically. Browsershot is the default screenshot driver, so a self-hosted installation needs Node.js and a Chrome or Chromium executable. Cloudflare is the documented alternative driver. Supported output formats are JPEG, PNG, and WebP.
How the generation request works
- Your page renders a hidden
<template data-og-image>containing the author’s HTML. - The component hashes that HTML and records the page URL.
- Middleware points image metadata to a URL shaped like
/og-image/{hash}.jpeg. - When a crawler requests that URL, the controller revisits the page with the
?ogimagequery parameter, renders only the template, loads the page’s CSS, fonts, and Vite assets, and takes a screenshot. - The generated file is stored and served directly on later requests. Changing the template content produces a new hash and therefore a new image URL.
This means the first crawler request can do browser work, while subsequent requests normally read the cached file. Make sure the public page is reachable by the screenshot process and that its assets use URLs the browser can load.
Define an OG image in Blade
Place the package component in the page view that owns the share metadata. The exact component attributes should follow the version’s package documentation, but the design itself is ordinary Blade/HTML. A typical pattern is:
<x-og-image>
<div class="og-card">
<span class="eyebrow">{{ config('app.name') }}</span>
<h1>{{ $article->title }}</h1>
<p>{{ $article->excerpt }}</p>
<small>{{ $article->author->name }}</small>
</div>
</x-og-image>
Keep the layout deterministic. Escape user-provided text through normal Blade output, constrain long titles, and avoid content that depends on a logged-in session. Because the template inherits your page’s CSS, fonts, and Vite assets, test the same route in the screenshot browser rather than assuming a font available only on your workstation.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsLoading a view with data
For reusable designs, put the card in a Blade view and pass a data array through the package’s documented view option. This keeps typography and spacing in one file and lets controllers supply title, subtitle, author, category, or a background URL. If you already have a finished image, pass its URL instead; the package then skips screenshot generation.
Metadata and dimensions
The middleware injects og:image, twitter:image, and twitter:card. The documented standard is 1,200 × 630 pixels at 2× resolution. Use a predictable contrast ratio, keep essential text away from edges, and test titles at their longest realistic length. Social platforms may crop previews differently, so the important content belongs in the central safe area.
Storage, caching, and invalidation
Generated files default to the public disk under og-images/. You can change the disk, including to S3, in configuration. The documentation describes cache headers and Cloudflare caching for subsequent requests.
- First request: a crawler can trigger rendering and file creation.
- Later requests: the stored image is served without repeating the screenshot.
- Template change: changed HTML creates a different content hash and image URL, avoiding stale previews tied to the old design.
- Existing image URL: no screenshot is generated when you provide one.
Give the web process permission to write the selected disk and ensure your deployment copies or shares that storage across instances. With object storage, configure public access or an appropriate signed/public URL strategy so crawlers can fetch the result.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchBrowser-driver decisions
Browsershot on your server
Browsershot keeps rendering inside your infrastructure and requires Node.js plus Chrome or Chromium. This gives the template access to the same route assets but adds browser maintenance: executable paths, sandbox permissions, memory limits, and upgrades become deployment concerns.
Cloudflare driver
Cloudflare is supported as an alternative driver. Select it when you prefer a hosted browser instead of installing and operating Chrome locally; apply the package’s documented credentials and driver configuration for your version.
Rank #3
Production checklist
- Run the package on PHP 8.3+ with compatible Laravel 12 or 13 components.
- Verify Node.js and Chrome/Chromium availability if using Browsershot.
- Open the public route from the rendering environment and confirm CSS, fonts, images, and Vite assets return successfully.
- Confirm the selected disk is writable and that generated files are publicly fetchable.
- Inspect page source for one generated
og:image, onetwitter:image, and the intended Twitter card value. - Share a newly changed page and check that its hash-based URL differs from the previous version.
- Warm important images after deployment if waiting for the first crawler request would be undesirable.
Troubleshooting common failures
The image URL returns an error or stays empty
Check application logs, disk permissions, and the screenshot executable. A missing Chrome binary, an incorrect executable path, or a Node.js error prevents Browsershot from completing. If local browser operation is not practical, configure the supported Cloudflare driver.
Fonts or CSS are missing
The browser may be unable to reach asset URLs, or the font may load after the screenshot begins. Use absolute, reachable asset URLs, verify Vite’s production build, and use the package’s documented waiting options where a page needs time to finish loading.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Changes do not appear on social networks
Inspect the generated hash URL first. If the hash changed, Laravel produced a new image; the social platform may still have its own cache. If the hash did not change, the rendered HTML did not change from the package’s perspective.
Rendering works locally but fails in deployment
Compare PHP, Node.js, browser versions, environment variables, filesystem permissions, and network access. Containers often need the Chrome sandbox configured according to their security model and enough shared memory for Chromium.
Pages expose private or unstable data
The renderer revisits a URL. Keep OG templates independent of authentication and request-specific state, and never place secrets in HTML, query strings, custom headers, or asset URLs.
Rank #4
Performance, reliability, and cost trade-offs
Screenshot generation is browser work, so its cost is operational rather than a documented per-image package fee. The first request consumes CPU, memory, and time; caching prevents that work on later requests. A self-hosted browser avoids an external image API but requires you to monitor browser processes and storage. Cloudflare moves browser operations to a hosted driver but introduces provider configuration and dependency.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
No independent speed, reliability, adoption, or conversion benchmark is established for this package. Treat capacity as an infrastructure question: measure your own routes, concurrent crawler traffic, image sizes, and cache-hit ratio before choosing worker limits.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If you want a URL-to-image service instead of installing Node.js and Chrome, ScreenshotNeo is the first alternative to try: it removes cookie banners, popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; and its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots.
One request returns a PNG, JPEG, WebP, or PDF:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the complete options and response headers in the ScreenshotNeo documentation. The response identifies page and billing status with X-Page-Verdict and X-Billed headers. For Laravel, call the endpoint from a queued job or controller, save the binary to your configured disk, and use the resulting public URL in Laravel Head or your own metadata.
Create a free ScreenshotNeo account with 1,000 shots per month and no credit card.
Laravel implementation alternatives
Use Spatie’s package when the image is a living Blade design that should inherit page assets and invalidate through content hashes. Use Laravel Head when the image already exists and you only need correct metadata. Use ScreenshotNeo when you want a hosted capture endpoint, browser-cleaning steps, billing protection for failed captures, or MCP access for AI agents.
Best Value
Frequently Asked Questions
Does spatie/laravel-og-image require Chrome?
The default Browsershot driver requires Node.js and a Chrome or Chromium binary. Cloudflare is the documented alternative driver.
What happens when the Blade template changes?
The package hashes the template HTML, so changed content produces a new hash-based image URL.
Can I use an existing image instead of generating one?
Yes. Pass the image URL through the package’s documented option and screenshot generation is skipped.
Where are generated files stored?
By default they are stored on the public disk under og-images/. The configured disk can be changed, including to S3.
Quick Recap
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.

