Manual installation

TanStack Start

Wire the Sunboard React SDK into a TanStack Start 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.

TanStack Start is Vite-based, so the setup is the same as Vite — the one difference is where you mount the provider: your root route, src/routes/__root.tsx, instead of a client entry.

Install the SDK

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

Add your publishable key

Like Vite, TanStack Start 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. The typeof window guard keeps it safe during server rendering.

src/sunboard-provider.tsx
import { SunboardProvider, Sunboard } from "@sunboard/react";
import type { ReactNode } from "react";

export function SunboardRuntime({ children }: { children: ReactNode }) {
  const route =
    typeof window === "undefined"
      ? "/"
      : `${window.location.pathname}${window.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) => window.location.assign(url)}
    >
      {children}
      <Sunboard.Checklist />
      <Sunboard.Hotspots />
      <Sunboard.Tour />
    </SunboardProvider>
  );
}

Client-side navigation

The default navigate does a full-page load. To keep tour route changes client-side, swap it for TanStack Router's navigation.

Mount it in your root route

Import the Sunboard stylesheet before your own global CSS, then wrap the {children} your root document renders (inside <body>).

src/routes/__root.tsx
import "@sunboard/react/styles.css";
import appCss from "../styles/app.css?url";
import { createRootRoute, Outlet, Scripts } from "@tanstack/react-start";
import { SunboardRuntime } from "../sunboard-provider";

export const Route = createRootRoute({
  head: () => ({
    links: [{ rel: "stylesheet", href: appCss }],
  }),
  component: RootComponent,
});

function RootComponent() {
  return (
    <RootDocument>
      <Outlet />
    </RootDocument>
  );
}

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SunboardRuntime>{children}</SunboardRuntime>
        <Scripts />
      </body>
    </html>
  );
}

Match your project's root

The exact shape of __root.tsx varies by TanStack Start version. The only thing that matters is that <SunboardRuntime> wraps the {children} / <Outlet /> your root renders. Keep your existing imports and head config.

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