Mount once in gatsby-browser.js wrapPageElement. Survives client routing.
Gatsby prerenders every page to static HTML, so the widget belongs in the browser-only lifecycle. wrapPageElement in gatsby-browser.js runs on the client and keeps the widget mounted across Gatsby Link navigations.
npm install @usero/sdkimport { initUseroFeedbackWidget } from '@usero/sdk'
let widget
export const onClientEntry = () => {
widget = initUseroFeedbackWidget({ clientId: 'YOUR_CLIENT_ID' })
}
// HMR-safe teardown in dev
if (import.meta.webpackHot) {
import.meta.webpackHot.dispose(() => widget?.destroy())
}Replace YOUR_CLIENT_ID with the id from your Usero dashboard.
Built for Gatsby
Code in gatsby-browser.js never runs during the SSG build. The widget boots after the static HTML hydrates, so prerendering stays untouched.
It fires a single time when the app first loads, which is exactly when you want to create the widget. No per-page wiring.
Because the init happens at the app level, the widget stays mounted through every client-side route change, not torn down per page.
This is purely a browser concern. You do not touch gatsby-node.js, GraphQL, or the build pipeline.
Frill ships an iframe that reloads on every client navigation. The vanilla SDK mounts once in onClientEntry and survives Gatsby Link transitions.
FAQ
A component in a page template would remount on every navigation. onClientEntry in gatsby-browser.js runs once at app start, so the widget lives for the whole session.
No. gatsby-browser.js code is excluded from the SSG build and only runs in the browser, so prerendered HTML is unaffected.
Yes, render UseroFeedbackWidget from @usero/sdk/react inside wrapRootElement in gatsby-browser.js if you prefer the component form.
Yes. The widget runs entirely client-side, so the host that serves your static files is irrelevant to it.
Free tier. No credit card. Two-minute install. Cancel by deleting two lines of code.
Install guides