Docs / SDKs View as Markdown

React

SplitHubProvider, <Experiment>/<Variant>, useVariant, useValue, useTrack, pageview goals.

@splithub/react renders experiments in any React 18+ app (Vite, CRA, Remix, Astro islands). Next.js App Router has its own package, see Next.js.

npm i @splithub/react @splithub/core

Provider

import { SplitHubProvider } from '@splithub/react';
import config from '../splithub.config';

createRoot(document.getElementById('root')!).render(
  <SplitHubProvider config={config}>
    <App />
  </SplitHubProvider>
);

The provider creates the client synchronously, reads or sets the sh_vid cookie, applies cached live overrides (cloud mode) and starts the event queue. Props: config, visitorId? (SSR: pass the id from the cookie so server and client agree), overrides?, client?, pageviews?, context?, remote?, autoGoals?, devtools?.

Component experiments

import { Experiment, Variant } from '@splithub/react';

<Experiment id="hero-cta">
  <Variant name="control"><Hero /></Variant>
  <Variant name="bold"><HeroBold /></Variant>
</Experiment>

One <Variant> renders by assignment; the exposure is recorded on mount. Unknown or not-running experiments render the control.

Value experiments

const title = useValue<string>('hero-title');
const price = useValue<number>('price-anchor');
const layout = useValue<{ columns: number; dense: boolean }>('grid');

useValue returns the control's value when the experiment is not running, so the page never breaks when a test is paused.

Hooks

Hook Returns
useVariant(id) the variant key ('control', 'bold'…); records an exposure the first time
useValue(id) the payload of a value experiment
useTrack() (goal, props?) => void
usePageview(path) fires pageview goals on client-side navigation
useSplitHub() the underlying @splithub/core client

useVariant is for the same experiment in several places: the visitor gets one variant everywhere.

Goals

const track = useTrack();
return (
  <>
    <button onClick={() => track('signup')}>Sign up</button>
    <button onClick={() => track('purchase', { revenue: 49 })}>Buy</button>
  </>
);

Pageview goals fire on mount for the current path; in SPAs call usePageview(location.pathname) once in the layout. Click goals are bound automatically from the config's selectors.

QA

Append ?sh_force=hero-cta:bold to any URL to see a variant, running or draft; no exposure is recorded. Keep the parameter in the URL while previewing; it is not saved across navigation. Several at once: ?sh_force=hero-cta:bold,hero-title:outcome.

To run drafts while you develop without forcing anything, set runDraftsInDev: true in the config (see Drafts in development). Add ?sh_debug=1, or run npx splithub dev, to log every assignment with its reason and get a panel that switches variants. In Vite apps, splithub() from @splithub/core/vite prints what each experiment does in your dev terminal (see Drafts in development).

SSR

Any framework that renders on the server: read the sh_vid cookie, pass it as visitorId to the provider on both sides, set the cookie on the response when missing. @splithub/core exports newVisitorId() and assign() for server-side decisions.

Rules

  • Never nest an <Experiment> inside a <Variant> of the same experiment.
  • Hooks follow the rules of hooks: no conditional calls.
  • Keep the config import at the top of the app; the provider must be above every component that uses a hook.
SplitHub
Test ideas. Ship winners.