/Docs

Vite + Solid integration

This guide assumes a Vite project using Solid 1.8 or later. By the end you'll have signal-based flag evaluation and event tracking using @avsbhq/browser and @avsbhq/solid.

1

Install

bash
1npm install @avsbhq/browser@^1 @avsbhq/solid@^1
2

Obtain your SDK key

Open Settings > Environments in your A vs B project and copy the SDK key:

.env
bash
1VITE_AVSB_SDK_KEY=sdk_production_xxxxxxxxxxxxxxxx
3

Mount AvsbProvider in App.tsx

Wrap your root component with AvsbProvider from @avsbhq/solid. The provider initialises the client and provides it to all descendant components via Solid's context API.

src/App.tsx
tsx
1import { AvsbProvider } from '@avsbhq/solid'
2import { Home } from './pages/Home'
3
4export function App() {
5 return (
6 <AvsbProvider
7 sdkKey={import.meta.env.VITE_AVSB_SDK_KEY}
8 context={{ kind: 'user', key: 'anonymous' }}
9 >
10 <Home />
11 </AvsbProvider>
12 )
13}
4

Read a flag

Use createFlag to create a reactive accessor for a flag. It returns a function — () => Flag<T>— consistent with Solid's signal pattern. Call it in JSX to get the current value reactively.

src/components/CheckoutButton.tsx
tsx
1import { createFlag } from '@avsbhq/solid'
2import { Show } from 'solid-js'
3
4export function CheckoutButton() {
5 const checkoutV2 = createFlag('checkout-v2', false)
6
7 return (
8 <Show when={checkoutV2().value} fallback={<LegacyCheckout />}>
9 <NewCheckout />
10 </Show>
11 )
12}
Tip
createFlagintegrates with Solid's fine-grained reactivity system. Only the accessor call sites that read checkoutV2() re-evaluate when the flag value changes — not the parent component.
5

Track an event

src/components/PurchaseForm.tsx
tsx
1import { useTrack } from '@avsbhq/solid'
2
3export function PurchaseForm() {
4 const track = useTrack()
5
6 function handleSubmit() {
7 track('purchase', { value: 79.0, properties: { form: 'checkout' } })
8 }
9
10 return (
11 <form onSubmit={handleSubmit}>
12 <button type="submit">Complete purchase</button>
13 </form>
14 )
15}
6

Identify a user

Access the client via useAvsbClient and call identify after login:

tsx
1import { useAvsbClient } from '@avsbhq/solid'
2
3export function PostLoginEffect({ userId, plan }: { userId: string; plan: string }) {
4 const client = useAvsbClient()
5 client?.identify({ kind: 'user', key: userId, plan })
6 return null
7}

Solid Start support

For Solid Start projects, @avsbhq/solid ships a solid-start/handler.tshelper that integrates with Solid Start's server-side request pipeline. This bootstraps the datafile before the first render:

src/entry-server.tsx
ts
1import { withAvsbServerContext } from '@avsbhq/solid/solid-start'
2
3// Wrap your Solid Start request handler. event.locals.avsb is populated
4// with a request-scoped UserBoundClient for use inside route loaders.
5export default withAvsbServerContext({
6 sdkKey: process.env.AVSB_SDK_KEY!,
7 contextFrom: (event) => ({
8 kind: 'user',
9 key: event.request.headers.get('x-user-id') ?? 'anon',
10 }),
11})

Graceful shutdown

AvsbProvider calls client.close() via onCleanup when the Solid component tree is disposed. This drains any pending events and stops the polling interval.

ts
1// If you manage the client manually outside the provider:
2import { onCleanup } from 'solid-js'
3import { AvsbClient } from '@avsbhq/browser'
4
5const client = new AvsbClient({ sdkKey: import.meta.env.VITE_AVSB_SDK_KEY })
6onCleanup(() => client.close())

Testing

tsx
1import { createMockClient, TestData } from '@avsbhq/test'
2import { render } from '@solidjs/testing-library'
3import { AvsbProvider } from '@avsbhq/solid'
4import { CheckoutButton } from './CheckoutButton'
5
6const td = TestData.flag('checkout-v2').booleanFlag().fallthroughVariation(true)
7const client = createMockClient({ flags: [td.build()] })
8
9render(() => (
10 <AvsbProvider client={client}>
11 <CheckoutButton />
12 </AvsbProvider>
13))

What's next