Vite + Svelte 5 integration
This guide assumes a Vite project using Svelte 5 with runes enabled. By the end you'll have reactive flag evaluation and event tracking wired into your app using @avsbhq/browser and @avsbhq/svelte.
Install
1npm install @avsbhq/browser@^1 @avsbhq/svelte@^1Obtain your SDK key
Open Settings > Environments in your A vs B project and copy the SDK key. Store it in your Vite environment file:
1VITE_AVSB_SDK_KEY=sdk_production_xxxxxxxxxxxxxxxxMount AvsbProvider in App.svelte
Wrap your root component with AvsbProvider. It accepts the same sdkKey and context props as the other framework adapters.
1<script lang="ts">2 import AvsbProvider from '@avsbhq/svelte/AvsbProvider.svelte'3 import Home from './Home.svelte'4</script>5
6<AvsbProvider7 sdkKey={import.meta.env.VITE_AVSB_SDK_KEY}8 context={{ kind: 'user', key: 'anonymous' }}9>10 <Home />11</AvsbProvider>.svelte SFC ships as raw source via thesvelte field in package.json — your Vite Svelte plugin compiles it. For non-SFC contexts (e.g. a shared util initialising the client imperatively) import thecreateAvsbContext() factory from @avsbhq/svelte instead.Read a flag
Use the flag store from @avsbhq/svelte. It returns a Readable<Flag<T>>that integrates with Svelte's reactive $ syntax.
1<script lang="ts">2 import { flag } from '@avsbhq/svelte'3
4 const heroVariant = flag('homepage-hero', 'control')5</script>6
7{#if $heroVariant.value === 'variant-a'}8 <HeroBannerVariantA />9{:else if $heroVariant.value === 'variant-b'}10 <HeroBannerVariantB />11{:else}12 <HeroBannerControl />13{/if}flag store is a Svelte Readable. It updates whenever the flag value changes — for example after a datafile polling cycle or after identify is called.Track an event
1<script lang="ts">2 import { getContext } from 'svelte'3 import type { AvsbClient } from '@avsbhq/browser'4
5 const client = getContext<AvsbClient>('avsb-client')6
7 function handlePurchase() {8 client.track('purchase', { value: 49.99, properties: { source: 'cart' } })9 }10</script>11
12<button type="button" on:click={handlePurchase}>Complete purchase</button>Alternatively, get a stable track function via getTrack():
1<script lang="ts">2 import { getTrack } from '@avsbhq/svelte'3
4 const track = getTrack()5</script>6
7<button type="button" on:click={() => track('purchase', { value: 49.99 })}>8 Complete purchase9</button>Identify a user
Access the avsbClient context to call identify after login:
1<script lang="ts">2 import { getContext } from 'svelte'3 import type { AvsbClient } from '@avsbhq/browser'4
5 const client = getContext<AvsbClient>('avsb-client')6
7 function onLogin(userId: string, plan: string) {8 client.identify({ kind: 'user', key: userId, plan })9 }10</script>SvelteKit support
For SvelteKit projects, @avsbhq/svelte ships a sveltekit/hooks.ts helper that bootstraps the datafile server-side in hooks.server.ts:
1import { withAvsbHooks } from '@avsbhq/svelte/sveltekit'2import type { Handle } from '@sveltejs/kit'3
4const baseHandle: Handle = async ({ event, resolve }) => resolve(event)5
6export const handle = withAvsbHooks(baseHandle, {7 sdkKey: process.env.AVSB_SDK_KEY!,8 contextFrom: (event) => ({9 kind: 'user',10 key: event.cookies.get('uid') ?? 'anon',11 }),12})Client components then read the bootstrapped datafile from $page.data.avsbBootstrap and pass it to AvsbProvider.
Graceful shutdown
AvsbProvider calls client.close()on the Svelte component's onDestroy lifecycle hook. In a production SPA the provider is never destroyed, but the SDK also handles cleanup via visibilitychange events.
Testing
1import { createMockClient, TestData } from '@avsbhq/test'2import { render } from '@testing-library/svelte'3import HeroBanner from './HeroBanner.svelte'4
5const td = TestData.flag('homepage-hero').stringFlag().fallthroughVariation('variant-a')6const client = createMockClient({ flags: [td.build()] })7
8render(HeroBanner, { context: new Map([['avsb-client', client]]) })