Framework wrappers
All wrappers are subpath exports of the same package and add no dependencies. Each dedupes route-change tracking against the SDK’s own History API patch, so you never get duplicate navigation events.
import { BackstoryProvider, useBackstory } from "@backstory/browser/react";
export function App() { return ( <BackstoryProvider config={{ projectKey: import.meta.env.VITE_BACKSTORY_KEY }}> <Routes /> </BackstoryProvider> );}
function Checkout() { const rw = useBackstory(); return <button onClick={() => rw.track("checkout_started")}>Pay</button>;}If you use React Router, call useBackstoryRoute(location.pathname) once in your layout so route patterns are attached to navigation events.
Next.js (App Router)
Section titled “Next.js (App Router)”import { BackstoryNext } from "@backstory/browser/next";
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html><body> <BackstoryNext config={{ projectKey: process.env.NEXT_PUBLIC_BACKSTORY_KEY! }} /> {children} </body></html> );}withBackstory(nextConfig) is a no-op helper that documents where release injection for source maps goes; the SDK reads release from config.
import { createApp } from "vue";import { BackstoryVue } from "@backstory/browser/vue";
createApp(App).use(BackstoryVue, { projectKey: "pk_live_…" }).mount("#app");The plugin tracks router.afterEach when a Vue Router instance is present.
Angular
Section titled “Angular”import { provideBackstory, trackAngularRouter } from "@backstory/browser/angular";
bootstrapApplication(AppComponent, { providers: [provideBackstory({ projectKey: "pk_live_…" })] });// in a root component:trackAngularRouter(this.router.events);SvelteKit
Section titled “SvelteKit”import { initBackstory, trackSvelteKitPage } from "@backstory/browser/svelte";import { browser } from "$app/environment";import { page } from "$app/stores";
if (browser) { initBackstory({ projectKey: import.meta.env.VITE_BACKSTORY_KEY }); page.subscribe((p) => trackSvelteKitPage(p.url.pathname));}Anything else
Section titled “Anything else”Call Backstory.init() once after first paint. The SDK patches history.pushState/replaceState and listens to popstate and hashchange, so most SPA routers need nothing more.