Astro installation
Astro Site Testimonial Widget Embed
Astro bundles and rewrites script tags by default, and a script pointing at another domain has to be marked is:inline to be left alone. So the StoryProof script goes once in your base layout with is:inline, and the widget itself is a one-line .astro component that ships no JavaScript of its own. If your site uses Astro’s ClientRouter, read the navigation note before you ship.
- Layout with the script marked is:inline
- A props-only StoryProofWidget component
- The ClientRouter caveat and the fix
Code generator
Layout, component and page for Astro
Type your widget id. The layout loads embed.js once; the component outputs only the div, so it adds nothing to your JavaScript budget.
Part 1 · Base layout: the script, once
src/layouts/BaseLayout.astro
---
// src/layouts/BaseLayout.astro
---
<html lang="en">
<head>
<meta charset="utf-8" />
<slot name="head" />
</head>
<body>
<slot />
<!-- is:inline: Astro outputs this tag exactly as written.
It lives in the layout, so it appears once per page. -->
<script is:inline src="https://app.storyproof.io/embed.js" async></script>
</body>
</html>Part 2 · The widget component
src/components/StoryProofWidget.astro
---
// src/components/StoryProofWidget.astro
interface Props {
id: string;
}
const { id } = Astro.props;
---
<div data-storyproof-widget={id}></div>Part 3 · Using it on a page
src/pages/index.astro
---
// src/pages/index.astro
import BaseLayout from '../layouts/BaseLayout.astro';
import StoryProofWidget from '../components/StoryProofWidget.astro';
---
<BaseLayout>
<h2>What customers say</h2>
<StoryProofWidget id="YOUR_WIDGET_ID" />
</BaseLayout>Run astro build and open the built page in dist, or run astro preview. View source: you should see one embed.js tag, untouched, before the closing body tag.
The files are generated in your browser from the id you enter.
The problem, solved
Astro gotchas with hosted widgets, solved
- Problem 1
Astro rewrote my script tag
Without a directive, Astro processes script tags, bundling them and turning them into modules, which is not what a script from another domain needs.
How StoryProof solves it
StoryProof’s embed is a div plus one async script from its own host. Mark that script is:inline and Astro outputs it as written.
- Problem 2
Script repeated for every widget
Astro duplicates an is:inline script for each instance of the component that contains it.
How StoryProof solves it
Keep the script in the layout, not the component. One embed.js fills every StoryProof div on the page.
- Problem 3
I picked Astro to ship less JavaScript
Adding a framework component just to show testimonials would undo the reason the site is fast.
How StoryProof solves it
The component outputs a single div with no client code. Choose a compact layout for long pages so the widget stays light on screen too.
- Problem 4
Content collections need a review step
Hard-coding quotes into Markdown means each new testimonial waits for a commit, with no record of approval.
How StoryProof solves it
Testimonials are approved in StoryProof before they can appear, and you choose which approved ones each widget id shows.
- Problem 5
Blog posts need a quote image
A static post sometimes wants a single striking quote as an image rather than a live widget.
How StoryProof solves it
From Pro, the social image designer turns an approved testimonial into a branded image you can drop into a post.
In StoryProof
Add it to an Astro site
Step 1 of 4
Copy the widget id
Build the widget in StoryProof and copy the data-storyproof-widget value from its embed code.
Step 2 of 4
Put the script in the layout
Add the is:inline script before the closing body tag of the layout every page shares. Astro’s docs say external scripts need is:inline to skip processing.
Step 3 of 4
Create the component and place it
Add StoryProofWidget.astro and use it in any page, Markdown layout or MDX file with the widget id as a prop.
Step 4 of 4
Decide on ClientRouter
If the site uses ClientRouter, add data-astro-reload to links that lead to pages with a widget, so those pages load in full. Then build and check.
Which Astro script option for the StoryProof embed
Before you start
Limits for Astro
Client-side navigation
Under ClientRouter, Astro runs bundled scripts once and may re-run inline ones. StoryProof has not documented how embed.js behaves there, so use full loads for widget pages.
Content Security Policy
If your host sends a CSP header, add the StoryProof script host to script-src.
No Astro integration
StoryProof is not an Astro integration package. The files above are plain Astro code in your repo.
Badge on lower plans
Widgets show a small "Powered by StoryProof" badge until Pro.
Astro docs, not a live run
The code follows Astro’s documentation as read on 2026-11-13. It has not been run against a live StoryProof widget on an Astro site for this guide.
FAQ
Questions people ask
Short answers to what usually comes up next.
Do I need a React or Vue island for this?
No. The widget is a div and a script. An .astro component outputs the div with no client framework.
Why not import embed.js into a bundled script?
It is a hosted file from StoryProof, not a module in your project. Astro’s docs point scripts outside src to is:inline.
Does this work on a fully static Astro build?
Yes. The div and script are in the built HTML, and the widget is filled in the visitor’s browser.
Can I use it inside MDX posts?
Yes. Import StoryProofWidget into the MDX file and use it like any other component, as long as the post uses the layout with the script.
Still have a question? Ask the StoryProof team or book a demo.
Add real testimonials to your Astro site
Collect testimonials with one link and render them with a zero-JS component.
Sources
- Scripts and event handling, Astro Docs. Checked 2026-11-13.
- View transitions, Astro Docs. Checked 2026-11-13.
Last updated 2026-11-13.