Skip to main content

Gatsby installation

Gatsby Testimonial Widget with Script API

Gatsby ships its own Script component, added in gatsby 4.15.0, and it is the right home for the StoryProof embed.js file. Wrap it with the widget div in a small React component, render that component on the page that should carry proof, and Gatsby loads the script after hydration. Because Script deduplicates by src, using the wrapper twice on one page still fetches the file only once.

  • A wrapper built on Gatsby’s Script component
  • Rendering it from a page in src/pages
  • Why the link into that page matters

Gatsby code

Wrapper, page and the link into it

Type your widget id and the three snippets fill in. The first is a reusable component, the second renders it on a page under src/pages, and the third shows how to link to that page.

Shown in StoryProof when you copy a widget’s embed code.

Part 1 · Step A: the wrapper component

src/components/storyproof-widget.tsx

// src/components/storyproof-widget.tsx
import * as React from "react"
import { Script } from "gatsby"

type Props = { id: string }

export function StoryProofWidget({ id }: Props) {
  return (
    <>
      <div data-storyproof-widget={id} />
      {/* Gatsby skips a second copy with the same src */}
      <Script src="https://app.storyproof.io/embed.js" />
    </>
  )
}

Part 2 · Step B: render it on a page

src/pages/customers.tsx

// src/pages/customers.tsx
import * as React from "react"
import { StoryProofWidget } from "../components/storyproof-widget"

export default function CustomersPage() {
  return (
    <main>
      <h1>Customer stories</h1>
      <StoryProofWidget id="YOUR_WIDGET_ID" />
    </main>
  )
}

Part 3 · Step C: the link into that page

Any component or Markdown template that links to it

// Linking to that page from elsewhere on the site
// A plain anchor asks the browser for a fresh page load.
<a href="/customers/">Read customer stories</a>

// Gatsby's <Link to="/customers/"> swaps the page on the client,
// and StoryProof does not claim the widget fills after that.

Run gatsby build followed by gatsby serve, open /customers/ directly in the browser, and confirm the testimonials appear. Then click through to it from the homepage to see how your own navigation behaves.

The snippets are put together in your browser. Nothing you type is stored.

The problem, solved

Gatsby specific snags and how this wrapper handles them

  • Problem 1

    The vendor script tag does nothing

    React does not execute a lowercase script element rendered in JSX, so a copied snippet sits in the page as dead markup.

  • Problem 2

    Two sections, two copies of the script

    A homepage with a carousel near the top and a wall near the footer would mount the wrapper twice.

  • Problem 3

    Quotes hard coded into GraphQL data

    When testimonials live in Markdown or JSON files queried through GraphQL, swapping one means a commit and a rebuild.

  • Problem 4

    Widget empty after clicking a Link

    Gatsby’s Link swaps pages on the client, and the script on a page reached that way does not get a fresh page load.

  • Problem 5

    Video clips bloating the static folder

    Customer videos committed to the repository make every build and deploy heavier.

In StoryProof

Install it in a Gatsby project

Step 1 of 4

Copy the widget id from StoryProof

Choose the layout and which approved testimonials the widget holds. The id is the value of data-storyproof-widget in its embed code.

Which Script strategy suits embed.js

Strategy behaviour as described in Gatsby’s Script API reference.
StrategyWhen Gatsby loads itUse it here?
post-hydrate (default)After the page hydratesYes, the simplest choice
idleAfter hydration, once the main thread is freeYes, for a widget far down the page
off-main-threadIn a web worker through Partytown, with proxied URLsNo: experimental, needs partytownProxiedURLs, and loads only on server rendered navigation

Before you start

What to know before you ship

  • Gatsby docs as of 2026-11-14

    The Script import, strategies, deduplication and wrapPageElement notes follow gatsbyjs.com as read on 2026-11-14. Nobody has built these snippets on a live Gatsby site yet.

  • Client side navigation

    StoryProof does not claim a widget fills itself after a Gatsby Link transition. Plain anchors into the testimonial page avoid the question; test any other route in.

  • No Gatsby plugin

    StoryProof has no Gatsby plugin or theme. The wrapper above is the whole integration, and it lives in your repo.

  • Content Security Policy

    If your host sends a CSP header, app.storyproof.io has to be allowed in script-src or the browser refuses the file.

  • Badge until a paid plan

    Widgets show a small "Powered by StoryProof" badge until Pro.

FAQ

Questions people ask

Short answers to what usually comes up next.

Can I use the idle strategy instead?

Yes. Add strategy="idle" to the Script element and Gatsby waits until the main thread is free. Scroll to the widget on a slow phone afterwards to check it is ready when a reader gets there.

Why not off-main-thread, since it keeps scripts off the main thread?

Gatsby marks it experimental, it needs the script URL listed in partytownProxiedURLs, and its docs say those scripts load only on server rendered navigation. The default strategy is simpler here.

Can the script load once for the whole site instead?

Yes. Gatsby documents Script inside wrapPageElement, and recommends writing that wrapper in both gatsby-browser and gatsby-ssr. Keep only the div in the component if you go that way.

Will a second wrapper on the page load embed.js again?

No. Gatsby uses the src value to deduplicate Script, and one copy of embed.js fills every StoryProof div on the page.

Still have a question? Ask the StoryProof team or book a demo.

Get a widget id for your Gatsby build

Collect and approve testimonials in StoryProof, then pass the id to one small component.

Sources

  1. Gatsby Script API, Gatsby Documentation. Checked 2026-11-14.

Last updated 2026-11-14.