Vite + React integration
This guide assumes a Vite project using React 18 or 19 as a single-page application. By the end you'll have flag evaluation and event tracking wired into your app using @avsbhq/browser and @avsbhq/react. No server-side rendering is required.
Install
1npm install @avsbhq/browser@^1 @avsbhq/react@^1Obtain your SDK key
Open Settings > Environments in your A vs B project and copy the SDK key. For Vite, expose it via a VITE_AVSB_SDK_KEY environment variable so the build tool inlines it:
1VITE_AVSB_SDK_KEY=sdk_production_xxxxxxxxxxxxxxxxVITE_ to the browser bundle. The SDK key grants read-only flag evaluation — it is not a secret.Wrap your app with AvsbProvider
Mount AvsbProvider at the root of your React tree. Pass the initial context so the SDK can evaluate flags immediately. You can update the context later with useIdentifyonce the user's identity is known.
1import React from 'react'2import ReactDOM from 'react-dom/client'3import { AvsbProvider } from '@avsbhq/react'4import { App } from './App'5
6ReactDOM.createRoot(document.getElementById('root')!).render(7 <React.StrictMode>8 <AvsbProvider9 sdkKey={import.meta.env.VITE_AVSB_SDK_KEY}10 context={{ kind: 'user', key: 'anonymous' }}11 >12 <App />13 </AvsbProvider>14 </React.StrictMode>15)Read a flag
Use useFlag in any component inside the provider. The hook returns a Flag<T> object. Access the evaluated value via .value, or use the shorthand useFlagValue to get the raw value directly.
1import { useFlag } from '@avsbhq/react'2
3export function CheckoutPage() {4 const checkoutV2 = useFlag('checkout-v2', false)5
6 return checkoutV2.value ? <NewCheckout /> : <LegacyCheckout />7}useFlag re-renders the component when the flag value changes due to a polling update or a call to identify. Each flag subscription is independent — only components that use a changed flag re-render.Track an event
1import { useTrack } from '@avsbhq/react'2
3export function PricingCard({ plan }: { plan: string }) {4 const track = useTrack()5
6 function handleUpgrade() {7 track('plan_upgrade', {8 value: 49.99,9 properties: { plan, source: 'pricing_page' },10 })11 }12
13 return <button type="button" onClick={handleUpgrade}>Upgrade to {plan}</button>14}Identify a user
Call useIdentify once the user logs in. This replaces the anonymous context and rehashes all bucketing so the user receives consistent variant assignments.
1import { useIdentify } from '@avsbhq/react'2
3export function usePostLoginEffect(userId: string, plan: string) {4 const identify = useIdentify()5
6 // Call once after the login promise resolves.7 identify({ kind: 'user', key: userId, plan })8}Multi-context targeting
If your flags target organisations or devices in addition to users, pass a multi-context object:
1import { useIdentify } from '@avsbhq/react'2
3identify({4 kind: 'multi',5 user: { kind: 'user', key: userId, plan: 'pro' },6 organization: { kind: 'organization', key: orgId, tier: 'enterprise' },7})Graceful shutdown
AvsbProvider calls client.close() automatically when it unmounts (e.g. the React tree is torn down). In a Vite SPA this typically only happens during development hot-module replacement. No manual teardown is required.
Testing
Use AvsbTestProvider in Vitest or Jest to control flag values without a network call:
1import { AvsbTestProvider, TestData } from '@avsbhq/test'2import { render, screen } from '@testing-library/react'3import { CheckoutPage } from './CheckoutPage'4
5const td = TestData.flag('checkout-v2').booleanFlag().fallthroughVariation(true)6
7render(8 <AvsbTestProvider flags={[td.build()]}>9 <CheckoutPage />10 </AvsbTestProvider>11)12
13expect(screen.getByTestId('new-checkout')).toBeInTheDocument()What's next
- Multi-context identity
- Sticky bucketing — persist variant assignments across sessions with localStorage or IndexedDB.
@avsbhq/browserAPI reference@avsbhq/reactAPI reference