Laravel installation
Laravel Blade Testimonial Widget Embed
In a Laravel app the cleanest home for the StoryProof embed is an anonymous Blade component. It renders the div from an id prop and pushes the script onto a named stack with @pushOnce, so however many times a view uses the component, the layout’s @stack prints embed.js a single time. No package to install, no database table for quotes.
- An anonymous component with an id prop
- @pushOnce so the script is never duplicated
- The @stack line your layout needs
Blade snippets
Component, layout stack and usage
Enter a widget id. Snippet 1 is the anonymous component. Snippet 2 is the line your layout needs before the body closes. Snippet 3 shows the component in a view, with the id passed as an attribute.
Part 1 · Snippet 1: the component
resources/views/components/storyproof-widget.blade.php
@props(['id'])
<div {{ $attributes }} data-storyproof-widget="{{ $id }}"></div>
@pushOnce('scripts', 'storyproof-embed')
<script src="https://app.storyproof.io/embed.js" async></script>
@endPushOncePart 2 · Snippet 2: render the stack in the layout
resources/views/layouts/app.blade.php (or components/layout.blade.php), before </body>
@stack('scripts')
</body>
</html>Part 3 · Snippet 3: use it in any view
resources/views/pricing.blade.php
<section class="testimonials">
<h2>Teams that switched</h2>
<x-storyproof-widget id="YOUR_WIDGET_ID" class="mt-8" />
</section>Load the route in the browser and view source. You should find the div inside the section and one embed.js tag at the end of the body, even if the view uses the component twice.
Your id is only used to fill in the snippets on this page.
The problem, solved
What goes wrong in Laravel views, and the fix
- Problem 1
The script printed twice on one page
A partial that carries its own script tag repeats it every time a view includes the partial.
How StoryProof solves it
@pushOnce with an identifier pushes embed.js to the stack a single time, and one copy fills every StoryProof div on the page.
- Problem 2
A testimonials package means migrations
Packages add tables, models and an admin form just to show a few quotes.
How StoryProof solves it
The component renders a StoryProof div and nothing else. Testimonials are collected, approved and chosen for each widget in StoryProof.
- Problem 3
Different praise on different routes
One hard coded block of quotes repeats the same three customers on every page.
How StoryProof solves it
Create a widget per audience in StoryProof and pass its id to the component on each view. Each can use its own layout.
- Problem 4
Building upload handling for video
Accepting customer video in your own app means storage, encoding limits and moderation code.
How StoryProof solves it
Customers record video, audio or text through one StoryProof link in the browser, so your app stores none of it.
In StoryProof
Add it to a Laravel app
Step 1 of 4
Create the component
Save Snippet 1 as resources/views/components/storyproof-widget.blade.php. Any Blade file in that folder works as an anonymous component; @props declares id as a prop.
Step 2 of 4
Render the stack in the layout
Add @stack('scripts') just before the closing body tag of the layout every page uses. If a scripts stack already exists, reuse it.
Step 3 of 4
Use the component in views
Write <x-storyproof-widget id="..." /> where testimonials belong. Extra attributes such as class pass through to the div via $attributes.
Step 4 of 4
Check the rendered HTML
Open the page, view source, and confirm the div and exactly one embed.js tag. Then deploy the way you normally do.
Blade tools for the script line
Before you start
Boundaries of this guide
Laravel docs as of 2026-11-13
Stacks, @pushOnce and anonymous components follow the Laravel 12 Blade docs read on 2026-11-13; Laravel 13 is current and was not checked separately. Not run in a live app.
Blade only, not Inertia
Apps whose pages are Vue or React through Inertia render views in JavaScript. Place the widget in those components instead; see the React and Next.js guide.
Content Security Policy
If middleware sends a CSP header, allow app.storyproof.io in script-src, or the browser blocks the script.
No Laravel package
StoryProof does not publish a Composer package for Laravel. The component is your own code.
Badge on lower plans
A small "Powered by StoryProof" badge appears under widgets until Pro.
FAQ
Questions people ask
Short answers to what usually comes up next.
My layout uses @yield, not components. Does this still work?
Yes. Stacks work with either style of layout. Put @stack('scripts') before the closing body tag of the layout your views extend.
Why does @pushOnce take a second argument?
The identifier lets Blade recognise the same push coming from different templates, so the script is rendered once even if two different components push it.
Can I load the script with Vite instead?
Keep it as a plain script tag with the src exactly as given. Bundling a copy would stop it receiving changes made to the hosted file.
Does the widget work in Livewire components?
The div can sit in a Livewire view, but this guide does not cover Livewire page navigation. Test the widget after navigating between pages, not only on a full load.
Still have a question? Ask the StoryProof team or book a demo.
Skip the testimonials table
Collect and approve in StoryProof, then render one Blade component.
Sources
- Blade Templates (Stacks, The @once Directive, Anonymous Components), Laravel Documentation (12.x). Checked 2026-11-13.
Last updated 2026-11-13.