Manual installation

React Router

Wire the Sunboard React SDK into a React Router (framework mode) app by hand.

Most people don't need this

sunboard init does all of this automatically — see the Quick start. Follow this page if you'd rather wire things by hand, or want to understand exactly what init changes.

This covers React Router framework mode (the successor to Remix). It's Vite-based, so the setup mirrors Vite — the one difference is where you mount the provider: your root route, app/root.tsx, inside the Layout export.

Install the SDK

npm install @sunboard/react
pnpm add @sunboard/react
yarn add @sunboard/react
bun add @sunboard/react

Add your publishable key

React Router framework mode runs on Vite, so it exposes VITE_-prefixed env vars to the browser. Put your project's runtime key in .env.local:

.env.local
VITE_SUNBOARD_KEY=pk_live_xxx

Create the runtime wrapper

This component reads the current location and renders the Sunboard widgets. It uses React Router's useNavigate and useLocation so tour route changes stay client-side. Create it next to your root route, under app/.

app/sunboard-provider.tsx
import { SunboardProvider, Sunboard } from "@sunboard/react";
import { useLocation, useNavigate } from "react-router";
import type { ReactNode } from "react";

export function SunboardRuntime({ children }: { children: ReactNode }) {
  const navigate = useNavigate();
  const location = useLocation();
  const route = `${location.pathname}${location.search}`;

  return (
    <SunboardProvider
      publishableKey={import.meta.env.VITE_SUNBOARD_KEY}
      // Replace with your real authenticated user.
      user={{
        id: "demo-user",
        email: "demo@example.com",
        group: "demo",
      }}
      route={route}
      navigate={(url) => navigate(url)}
    >
      {children}
      <Sunboard.Checklist />
      <Sunboard.Hotspots />
      <Sunboard.Tour />
    </SunboardProvider>
  );
}

Mount it in your root route

Import the Sunboard stylesheet before your own global CSS, then wrap the {children} your Layout renders (inside <body>). The Layout export runs inside the router context, so useNavigate / useLocation work there.

app/root.tsx
import "@sunboard/react/styles.css";
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
import { SunboardRuntime } from "./sunboard-provider";

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <SunboardRuntime>{children}</SunboardRuntime>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}

Match your project's root

Keep your existing Meta / Links / Scripts and any providers — only add the Sunboard stylesheet import and wrap {children} with <SunboardRuntime>. If your appDirectory is src/ instead of app/, adjust the paths to match.

Wire your real user

The wrapper ships a placeholder user. Replace it with your authenticated user so segments and analytics are accurate. Only id is required; anything you put under properties is available for segment targeting:

user={{
  id: currentUser.id,
  email: currentUser.email,
  group: currentUser.plan, // optional cohort, e.g. "trial" / "pro"
  properties: {
    // Any custom attributes you want to target on.
    role: currentUser.role,
    signupDate: currentUser.createdAt,
    workflowsCreated: currentUser.workflowCount,
  },
}}

Verify

Run your dev server. Once you've authored a spec and promoted a version in Sunboard, the checklist appears. To preview a local spec before deploying, use /sunboard.preview, or run sunboard doctor to check the wiring.

Next steps

On this page