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 Embed Laravel Package

bensampo/laravel-embed

Embed YouTube, Vimeo, and other media in Laravel Blade views with a simple component. Laravel Embed offers privacy-friendly no-cookie modes, lazy loading, responsive sizing, and custom drivers, so you can drop video embeds into templates without hand-writing iframes.

Deep Wiki
Context7

Getting Started

composer require bensampo/laravel-embed

The service provider is auto-discovered. Publish the config so you can see what the package actually supports:

php artisan vendor:publish --provider="BenSampo\Embed\EmbedServiceProvider"

Where to look first

  1. config/embed.php — the list of supported providers and the default aspect ratio. This is the whole feature surface of the package; read it before anything else.
  2. src/Embed.php (or the root service class) — the factory/entry point. It takes a URL, resolves a matching provider class, and returns a renderable object.
  3. src/Services/ — one small class per provider (YouTube, Vimeo, Google Slides, SlideShare, etc.). This is where the iframe src translation and the responsive wrapper live.
  4. resources/views/ — the Blade view that emits the padding-bottom ratio wrapper and the <iframe>.

First use case

A CMS posts table with a video_url column. In the Blade view:

{{-- whichever of these two the installed version exposes --}}
<x-embed :url="$post->video_url" />

{!! Embed::make($post->video_url)->render() !!}

Verify against the README in vendor/bensampo/laravel-embed/ — the callable API is narrow and has changed shape across versions, so confirm the method names on the installed tag rather than trusting a blog post.

Implementation Patterns

Store URLs, render HTML at display time. Never persist the rendered iframe. Store the canonical URL, render on output. This lets you swap providers, fix a broken embed service, or add GDPR consent later without a data migration.

Wrap it in your own Blade component. Don't sprinkle <x-embed> through twenty views. Create resources/views/components/video-embed.blade.php:

@props(['url', 'ratio' => null])

@if ($url)
    <div {{ $attributes->class('my-6 rounded-lg overflow-hidden') }}>
        <x-embed :url="$url" :ratio="$ratio" />
    </div>
@endif

Now styling, lazy-loading, and the "what if the URL is unsupported" decision live in one place.

Use it for the 80% case, extend for the rest. If you need a provider the package doesn't ship (Loom, Wistia, Miro, Figma, a self-hosted player), write a small service class implementing the package's embed-service contract, register it in config/embed.php, and ship the PR upstream if it's generic. This is the intended extension point and it is cheap — each provider class is a supports() check plus a src transform.

Override the ratio per embed. Slides and vertical video (Reels, Shorts, TikTok) are not 16:9. If the installed version allows a ratio argument, pass it at the call site; if not, publish the view and add a $ratio variable. A 9:16 iframe inside a 16:9 wrapper is the single most common visual bug with this package.

Livewire and Inertia. In Livewire, render inside the component's Blade view normally — the iframe re-renders on each request, which is wasteful but harmless. If you have a list of 30 embeds, memoize the rendered string on the model (getEmbedHtmlAttribute() caching to a private property) so a re-render doesn't rebuild 30 iframes. In Inertia, keep the embed in the Blade root or expose a url prop and render the iframe with Vue/React directly — round-tripping HTML strings through JSON props is not worth it.

Testing. Rendering is pure string manipulation; no HTTP calls. Assert assertSee('iframe') and assertSee('youtube.com/embed/') on the rendered view. Add one test per provider you actually use — that's your regression net when the package is upgraded.

Gotchas and Tips

CSP will bite you first. Any iframe means frame-src (or legacy child-src) must allow www.youtube.com, player.vimeo.com, docs.google.com, www.slideshare.net, etc. Symptom: blank white box, console error mentioning frame-ancestors or Refused to frame. Fix the policy, not the package.

User-supplied URLs need an allowlist. The package emits raw HTML, which means {!! !!} somewhere. Do not pass an unvalidated URL from a form straight through. Validate the scheme is https and the host is in a known set before handing it to the embed factory. A javascript: or data: URL that slips through a naive provider match is an XSS.

Normalize URLs before matching. youtu.be/ID, youtube.com/watch?v=ID&t=30s, m.youtube.com, /shorts/, and playlist URLs all resolve to different strings. The provider matcher is regex-based and will miss variants it wasn't written for. Either normalize in a model mutator or accept that "unsupported" is a real state you must handle.

Handle unsupported gracefully. Decide now what happens when Embed::make($url) finds no provider: throw, return null, or fall back to a plain <a href> link-out. For user-generated content, the link-out is almost always correct. Log the misses — the resulting list of unhandled hosts tells you exactly which provider class to write next.

Consent and privacy. YouTube's default embed drops tracking cookies on page load. Use youtube-nocookie.com (the package may or may not do this for you — check src/Services/YouTube.php) and, if you operate in the EU, gate the iframe behind a click-to-load placeholder. This is a legal requirement, not a nice-to-have.

CSS conflicts. The responsive wrapper almost certainly uses the padding-top: 56.25% trick. That breaks inside display: flex parents and fights with Tailwind's aspect-video. If you're on Tailwind, consider bypassing the wrapper entirely and putting aspect-video on your own container.

Missing iframe attributes. Add loading="lazy", allowfullscreen, and allow="autoplay; encrypted-media; picture-in-picture" on your wrapper if the package's default output omits them. Without loading="lazy" a page with five embeds tanks LCP.

Never render embeds in email. Gmail, Outlook, and Apple Mail all strip iframes. Use a thumbnail image linking out.

Treat the package as vendored code. 146 stars, MIT, small surface area, low activity. Pin the version in composer.json, and the moment you need anything the package doesn't do, publish the views (--tag=views) and fork the provider class into app/ rather than fighting the upstream API. Debugging starts with inspecting the resolved object — dump it and read the resolved service class and generated src before assuming the URL is wrong.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console