Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Og Image Laravel Package

spatie/laravel-og-image

Generate Open Graph images for your Laravel app by defining OG image HTML inline in Blade views. The package screenshots them, serves them via a dedicated route, and caches them on disk, inheriting your existing CSS, fonts, and Vite assets.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Purpose-built for the Laravel request/response lifecycle: a Blade component (<x-og-image>) emits a hidden <template data-og-image> plus the <meta> tags, and auto-registered middleware injects it into HTML responses. This is a natural fit for a Blade + Vite monolith; it is a poor fit for a headless API or SPA-only frontend where server-rendered HTML is not the delivery mechanism.
  • The value proposition is "no external API, no separate CSS pipeline" — templates inherit the page's existing Tailwind/Vite/font assets. That eliminates a whole class of design-drift bugs that plague standalone OG-image services.
  • Content-hashed URLs (/og-image/{md5}.jpeg) served from the public disk with cache headers is the correct architecture for CDN offload; the design assumes a CDN in front.
  • The hard dependency chain is the architectural pivot point: spatie/laravel-screenshot → Browsershot → Node.js + a Chrome/Chromium binary. This effectively makes a headless browser a production runtime dependency of the web tier.

Integration feasibility

  • Low code footprint: one composer require, optional config publish, one component in the layout or per view, middleware auto-registered. A senior Laravel developer can reach a working spike in under a day.
  • Escape hatch in 1.2.0 (url parameter on the component) allows static or externally hosted images for pages where runtime generation is undesirable — this de-risks partial adoption.
  • Fallback image support covers long-tail pages that have no explicit template, which is important for avoiding blank cards on archive/tag/search pages.
  • Blocking constraint is infrastructure, not PHP: container images must ship Chromium (or the app must use the Cloudflare Browser Rendering driver). On Vapor/Lambda or tightly sized Fargate tasks, local Chrome is often infeasible.

Technical risk

  • Runtime weight: headless Chrome is memory- and CPU-hungry (~150–300 MB per instance). On first request for an uncached URL, generation is synchronous inside the request — a latency spike precisely when a social crawler is fetching.
  • Crawler timeouts: Facebook, LinkedIn, and Slack fetch OG images with short budgets and do not retry generously. A cold-cache generation that exceeds those budgets silently degrades to a text-only card.
  • Middleware blast radius: the package mutates every HTML response. The 1.1.1 fallback cache-poisoning bug (non-HTML responses like RSS/Atom storing a bad cache entry that permanently poisoned all fallback images) is exactly this failure class, and it shipped. 1.1.2 also fixed middleware clobbering ->original.
  • Version hygiene: 1.1.3/1.1.4 were published below 1.3.0, so Composer kept resolving the older tag; 1.3.1 was issued to re-publish them. That is a release-engineering defect that will confuse lockfiles and dependabot. Pin exact versions and read every changelog.
  • Content safety: 1.3.2 fixed the component compiling user content as Blade — titles containing {{ }} or @each are a template-injection/XSS-adjacent surface if any part of the OG template is user-authored.
  • Adoption signal: 37 stars and zero dependents is thin evidence. Vendor reputation (Spatie) is strong and the docs/changelog/releases are real, but there is no third-party battle-testing to lean on.

Key questions

  1. Where does this run? If not on a long-lived container with Chromium, are we committing to the Cloudflare Browser Rendering path, and what does that cost/latency look like?
  2. Can we generate asynchronously (queue/job on publish) so that no crawler ever triggers a cold render? If not, what is the p95 render time and does it fit inside LinkedIn/Slack fetch budgets?
  3. Which routes carry the middleware? Can we scope it to public, shareable, HTML-only routes and explicitly exclude feeds, sitemaps, and API JSON?
  4. Who owns cache lifecycle — TTL, CDN invalidation, and pruning orphaned hash files from disk? Content-hashed filenames mean old images are never overwritten and will accumulate.
  5. Do we have an observability story for render failures (Chrome OOM, timeout, disk full), and does the fallback image cover all of them?

Integration Approach

Stack fit

  • Requires a Laravel version in the supported matrix (1.3.0 added Laravel 13 support) and a compatible PHP version per the updated requirements. Verify against our pinned PHP/Laravel before scheduling.
  • Assumes Blade-rendered HTML and Vite-compiled assets. If any shareable surface is a JS-rendered SPA route, the <template> injection will never reach the crawler and those routes need the url parameter with a pre-built image.
  • Assumes a writable public disk. Confirm S3 vs local disk and whether the OG route serves through the app or is fronted by the CDN directly — the README's "served directly with cache headers" implies we should let the CDN absorb nearly all traffic.

Migration path

  • Typical incumbent patterns to displace: (a) hand-rolled spatie/browsershot calls in a controller, (b) Intervention/Imagick compositing with a static background, (c) a third-party OG service (Cloudinary, Vercel OG, Bannerbear).
  • Recommended path is additive, not a cutover: install alongside the incumbent, adopt the component only on the top ~20 shareable templates, keep the existing pipeline as the fallback image source, then retire the incumbent once parity is confirmed.
  • The url parameter makes partial migration clean — untemplated pages can keep their existing static asset while templated pages move to generation.

Compatibility

  • Verify Chromium availability and version parity with Browsershot's expectations in our base image; a mismatch is a silent "screenshot is blank" failure, not an exception.
  • Verify Node is present in the runtime image (not just the build image). Many Laravel deploys strip Node after asset compilation — that will break this package at runtime, not at deploy time.
  • Check CDN behavior around query strings: the preview mode (?ogimage) and the fixed query-parameter handling in 1.3.1 mean query-string caching rules must be deliberate.
  • Confirm the middleware does not conflict with existing response-mutating middleware (minifiers, CSP nonce injectors, debugbars) that also rewrite </body>.

Sequencing

  1. Spike in staging: install, Chromium in the image, one template, measure p95 cold and warm render time.
  2. Instrument: log render duration, failures by cause, disk write errors. Establish a baseline before any production exposure.
  3. Add a queue-based pre-generation job so images exist before a crawler arrives; treat synchronous first-render as a fallback, not the primary path.
  4. CDN and storage policy: cache headers, purge procedure, and a scheduled prune of hash-orphaned files.
  5. Roll out by route group, highest-share-value pages first, with the fallback image registered globally.
  6. Retire the incumbent pipeline and its credentials.

Operational Impact

Maintenance

  • Pin an exact version (not ^1.3). The cadence between 1.0.0 and 1.3.2 was fast and included behavioral fixes to middleware and caching; the 1.1.3/1.1.4 misnumbering means a loose constraint can silently resolve to a tag the maintainers did not intend.
  • Budget recurring effort for: base-image Chromium updates and CVE patching, Chromium/Browsershot version alignment, and changelog review on every bump. This is the dominant ongoing cost, not the PHP code.
  • Expect the Chromium dependency to be the thing that breaks on base-image upgrades, not the package itself.

Support

  • MIT, no SLA, no vendor escalation path. Support is community issues plus the Spatie docs site and changelog. Internal ownership must be explicit — most likely the platform/backend team.
  • The Laravel Boost skill (1.1.0) materially lowers the cost of producing correct integration code with AI assistance; it is a genuine ramp-up accelerant but not a support channel.

Scaling

  • Rendering scales with distinct content, not with traffic — content-hashed URLs plus CDN mean steady-state cost is near zero. The scaling problem is entirely about the cold-miss tail: newly published pages, sitemap crawls, and bulk re-renders after a template change (which changes every hash at once and invalidates the whole CDN corpus).
  • A template/CSS change is a full-corpus invalidation event. Plan for that deliberately: staged rollout of template changes, or accept a render storm.
  • Storage grows monotonically by design. Without a prune job, hash-orphaned JPEGs accumulate indefinitely.
  • Concurrency: multiple simultaneous cold renders will saturate Chrome workers and CPU. Bound concurrency explicitly and prefer queue workers on a separate pool from web requests.

Failure modes

  • Chromium absent or OOM-killed → renders fail; without a registered fallback, crawlers get a broken image or a 500.
  • Synchronous render exceeds crawler timeout → card degrades to text-only, with no error surfaced to us.
  • Disk full or S3 permission drift → image URL 404s while the meta tags still advertise it.
  • Middleware applied to non-HTML responses → the 1.1.1 poisoning class of bug; scope the middleware to HTML routes only.
  • User-supplied text containing Blade syntax → template compilation/injection; on ≥1.3.2 this is fixed, on older versions it is live.
  • Stale CDN entry after a template change → old image served under a hash that no longer corresponds to current HTML.
  • Query-string edge cases on page URLs → wrong image or a cache collision; addressed in 1.3.1, so verify we are above it.

Ramp-up

  • Developer ramp-up is low: it is a Blade component and a config file, and the mental model (template → hash → route → screenshot) is easy to explain. Estimate 2–3 days for a senior Laravel developer to reach production-ready on a capable host.
  • Ops ramp-up is the real cost: Chromium in the container, memory limits, worker isolation, and a render-failure runbook. Estimate 1–2 days of platform engineer time plus a base-image change.
  • Recommendation: conditional pilot. Adopt for a bounded set of high-value shareable routes on a host that can run Chromium or use Cloudflare Browser Rendering, with async pre-generation and a global fallback image. Do not adopt as a platform-wide default until render latency, CDN behavior, and the storage-prune story are measured in staging.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style