React
A hooks and provider wrapper around the JavaScript/TypeScript SDK, built
for React apps. Ships as ESM and CJS with full TypeScript types, and is
safe to import from Next.js Server Components (marked 'use client').
Install
npm install @shipsilently/reactbun add @shipsilently/reactyarn add @shipsilently/reactpnpm add @shipsilently/reactWrap your app in the provider
ShipSilentlyProvider creates one client for the component
tree, evaluates every flag for the given context on mount,
and subscribes to real-time updates (falling back to polling).
import { ShipSilentlyProvider } from '@shipsilently/react';
export function App() {
return (
<ShipSilentlyProvider
config={{ apiKey: import.meta.env.VITE_SHIPSILENTLY_KEY }}
context={{ userId: user.id, plan: user.plan }}
>
<Checkout />
</ShipSilentlyProvider>
);
}Read a flag with useFlag
useFlag(flagKey, defaultValue) reads through the provider's
synced cache and re-renders whenever the server pushes an update. The
default value's type drives the return type.
import { useFlag } from '@shipsilently/react';
export function Checkout() {
const checkoutV2 = useFlag('checkout-v2', false);
return checkoutV2 ? <NewCheckout /> : <LegacyCheckout />;
}Read every flag with useFlags
useFlags() returns the full flag map plus a loading
flag for the first evaluation — useful for a loading skeleton before flags
are ready.
import { useFlags } from '@shipsilently/react';
export function FeatureGate() {
const { flags, loading } = useFlags();
if (loading) return <Skeleton />;
return <pre>{JSON.stringify(flags, null, 2)}</pre>;
}Escape hatch: useShipSilentlyClient
Need the raw client — for a one-off evaluate() call or to
force-flush analytics before unmount? useShipSilentlyClient()
returns the same JavaScript/TypeScript SDK
client instance the provider created.
Next.js
The package ships with a 'use client' banner, so
ShipSilentlyProvider and the hooks are safe to import from
Client Components in the App Router. For Server Components, evaluate
flags server-side with the JavaScript/TypeScript
SDK directly instead.