@sheepit-ai/react
v0.9.1
Published
Sheepit React bindings — Provider, hooks, and components for feature flags, experiments, and analytics
Maintainers
Readme
@sheepit-ai/react
React hooks and components for Sheepit feature flags, experiments, and events.
React bindings for Sheepit, built on @sheepit-ai/sdk-js: a provider, hooks for flags, experiments, and events, and components for flag-gated UI, experiment variants, page views, and render errors.
Install
@sheepit-ai/sdk-js is a peer dependency, so install both:
npm install @sheepit-ai/react @sheepit-ai/sdk-jsRequires React 18 or later.
Key type
Use a publishable key (lp_pub_…). Never put a secret key (lp_sec_…) in client code.
Quick start
Wrap your app once. In the Next.js App Router, do it in a client component:
"use client";
import type { ReactNode } from "react";
import { SheepitProvider } from "@sheepit-ai/react";
export function Providers({
children,
user,
}: {
children: ReactNode;
user: { id: string; traits?: Record<string, unknown> } | null;
}) {
return (
<SheepitProvider config={{ apiKey: process.env.NEXT_PUBLIC_SHEEPIT_KEY! }} user={user}>
{children}
</SheepitProvider>
);
}Then use the hooks in any client component:
"use client";
import { useExperiment, useFlag, useTrack } from "@sheepit-ai/react";
export function CheckoutButton() {
const track = useTrack();
const newCheckout = useFlag("new_checkout_flow", false);
const { variant } = useExperiment("checkout_copy");
return (
<button onClick={() => track("checkout_started", { variant, new_checkout: newCheckout })}>
{variant === "bold" ? "Get it now" : "Buy"}
</button>
);
}Release attribution
config is passed straight to Sheepit.create(), so release works as in @sheepit-ai/sdk-js:
pass the commit SHA your bundler injects at build time: Next.js
process.env.NEXT_PUBLIC_SHEEPIT_RELEASE, Vite import.meta.env.VITE_SHEEPIT_RELEASE (set to
$CI_COMMIT_SHA in CI). process does not exist in a plain browser or Vite bundle. It must equal the version sheepit ci release registered (default: the full commit
SHA). Events report context.sdk.name = "sdk-react".
Provider behaviour
configis anySheepitConfig. The provider callsSheepit.create(config)once, in an effect on mount, and callsdestroy()on unmount. Changingconfiglater has no effect; remount the provider to use a new key.- Until the client is created (server render, first client render), and whenever creation fails, the context holds a no-op client:
useFlagreturns your default anduseExperimentreturns{ variant: "control" }. A failed creation (for example, a missing or non-publishable key) is reported withconsole.warn, not thrown. userdrives identity: whenuser.idchanges to a new value the provider callsidentify(user.id, user.traits).undefinedandnullare treated the same (no user): going from a user the provider identified to either one callsreset(). If you never pass a user, the provider never callsidentify()orreset(), so you can manage identity yourself withuseSheepit(). On web,traitsare not used for flag targeting yet.- The SDK evaluates nothing locally. Flag values and experiment assignments come from the API, and
useFlag/useExperimentre-render automatically when configuration loads or changes. See how flags and experiments resolve for refresh timing.
API
| Export | Kind | Purpose |
| --------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------- |
| <SheepitProvider config user?> | Component | Creates the client and provides it via context |
| useFlag(key, default = false) | Hook | Current flag value, or default when there is none |
| useExperiment(key) | Hook | { variant, payload? }; "control" when there is no assignment |
| useTrack() | Hook | Stable track(event, properties?) function |
| useSheepit() | Hook | The underlying client (identify, reset, flush, overrides, status, …) |
| <Feature flagKey fallback? match?> | Component | Renders children when the flag is truthy, or equals match |
| <Experiment experimentKey variants? fallback?> or render-prop | Component | Renders variants[variant], else fallback, else variants.control |
| <PageViewTracker pathname searchParams? /> | Component | On route change: $page_leave for the previous route, then $page_view |
| <ErrorBoundary fallback? onError?> | Component | Catches render errors and tracks them as $error |
| noopClient | Value | The silent client the provider uses before init |
Flush and teardown are handled by the provider and the underlying SDK. To flush explicitly, call useSheepit().flush().
Components
"use client";
import { usePathname } from "next/navigation";
import { ErrorBoundary, Experiment, Feature, PageViewTracker } from "@sheepit-ai/react";
export function Page() {
const pathname = usePathname();
return (
<ErrorBoundary fallback={<p>Something went wrong.</p>}>
<PageViewTracker pathname={pathname} />
<Feature flagKey="new_banner" fallback={null}>
<p>New banner</p>
</Feature>
<Experiment
experimentKey="hero_copy"
variants={{ control: <h1>Ship faster</h1>, bold: <h1>Ship today</h1> }}
/>
<Experiment experimentKey="pricing_layout">
{({ variant, payload }) => (
<p>
{variant} {JSON.stringify(payload ?? {})}
</p>
)}
</Experiment>
</ErrorBoundary>
);
}Identity without the user prop
"use client";
import { useSheepit } from "@sheepit-ai/react";
export function LogoutButton({ onLogout }: { onLogout: () => Promise<void> }) {
const sheepit = useSheepit();
return (
<button
onClick={async () => {
await onLogout();
sheepit.reset();
}}
>
Log out
</button>
);
}Testing
@sheepit-ai/react/test exports TestProvider, createMockClient, and noopClient. TestProvider takes a client (a full or partial client); any method you do not supply falls back to the no-op client.
import { render } from "@testing-library/react";
import { vi } from "vitest";
import { TestProvider, createMockClient } from "@sheepit-ai/react/test";
import { CheckoutButton } from "./checkout-button";
// Partial client: set flag values directly
render(
<TestProvider
client={{ flag: (key, fallback) => (key === "new_checkout_flow" ? true : (fallback ?? false)) }}
>
<CheckoutButton />
</TestProvider>,
);
// Spies on every method (pass your test runner's fn factory)
const client = createMockClient({}, vi.fn);
render(
<TestProvider client={client}>
<CheckoutButton />
</TestProvider>,
);Runtime support
Client components only. The hooks and components use React context and effects, so they cannot run in React Server Components; use @sheepit-ai/server on the server. React 18+; Node.js 20+ for tooling (engines).
Deprecated exports
GoaTechProvider, GoaTechProviderProps, useGoaTech, IGoaTech, and GoaTechConfig are aliases of the Sheepit* names. Use the Sheepit* names.
Links
@sheepit-ai/sdk-js·@sheepit-ai/server·@sheepit-ai/cli- Android and .NET SDKs: coming soon.
- sheepit.ai
License
MIT. Copyright (c) 2026 GoaTech AI LLC. See LICENSE.
