/Docs

Angular 17+ integration

This guide assumes an Angular 17 or later project bootstrapped with the Angular CLI. It supports both classic NgModule-based apps and standalone component apps. By the end you'll have injectable flag evaluation and event tracking using @avsbhq/browser and @avsbhq/angular.

1

Install

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

Obtain your SDK key

Open Settings > Environments in your A vs B project and copy the SDK key. Add it to your Angular environment files:

src/environments/environment.ts
ts
1export const environment = {
2 production: false,
3 avsbSdkKey: 'sdk_development_xxxxxxxxxxxxxxxx',
4}
src/environments/environment.prod.ts
ts
1export const environment = {
2 production: true,
3 avsbSdkKey: 'sdk_production_xxxxxxxxxxxxxxxx',
4}
3

Register provideAvsb in app.config.ts (standalone)

For standalone component apps (Angular 17+ default), call provideAvsb in app.config.ts:

src/app/app.config.ts
ts
1import { ApplicationConfig } from '@angular/core'
2import { provideRouter } from '@angular/router'
3import { provideAvsb } from '@avsbhq/angular'
4import { environment } from '../environments/environment'
5import { routes } from './app.routes'
6
7export const appConfig: ApplicationConfig = {
8 providers: [
9 provideRouter(routes),
10 provideAvsb({
11 sdkKey: environment.avsbSdkKey,
12 context: { kind: 'user', key: 'anonymous' },
13 }),
14 ],
15}
Info
For NgModule-based apps, import AvsbModule.forRoot({ sdkKey, context }) in your AppModule imports array instead of using provideAvsb.
4

Read a flag via AvsbService

Inject AvsbService into any component or service. It exposes typed evaluator methods that return Flag<T>.

src/app/checkout/checkout.component.ts
ts
1import { Component, inject } from '@angular/core'
2import { AvsbService } from '@avsbhq/angular'
3
4@Component({
5 selector: 'app-checkout',
6 standalone: true,
7 template: `
8 <app-new-checkout *ngIf="showNewCheckout" />
9 <app-legacy-checkout *ngIf="!showNewCheckout" />
10 `,
11})
12export class CheckoutComponent {
13 private avsb = inject(AvsbService)
14
15 get showNewCheckout(): boolean {
16 return this.avsb.getBoolFlag('checkout-v2', false).value
17 }
18}
5

Read a flag via the *avsbFlag directive

The structural directive *avsbFlag conditionally renders elements based on a flag value, keeping templates clean:

src/app/dashboard/dashboard.component.html
html
1<section *avsbFlag="'new-dashboard'; default: false">
2 <app-new-dashboard />
3</section>
4
5<section *avsbFlag="'new-dashboard'; default: false; else legacyDashboard">
6 <app-new-dashboard />
7</section>
8<ng-template #legacyDashboard>
9 <app-legacy-dashboard />
10</ng-template>
6

Track an event

src/app/checkout/checkout.component.ts
ts
1import { Component, inject } from '@angular/core'
2import { AvsbService } from '@avsbhq/angular'
3
4@Component({ selector: 'app-checkout', standalone: true, template: '...' })
5export class CheckoutComponent {
6 private avsb = inject(AvsbService)
7
8 onPurchase(amount: number) {
9 this.avsb.track('purchase', { value: amount, properties: { source: 'checkout' } })
10 }
11}
7

Identify a user

Call identify on the service after the user logs in.

ts
1import { inject } from '@angular/core'
2import { AvsbService } from '@avsbhq/angular'
3
4// Inside your auth callback or guard:
5const avsb = inject(AvsbService)
6avsb.identify({ kind: 'user', key: userId, plan: 'pro' })

RxJS Observables

@avsbhq/angular ships RxJS helpers for teams that prefer reactive streams. The flag$ function returns an Observable<Flag<T>> that emits whenever the flag changes:

ts
1import { Component, inject } from '@angular/core'
2import { AsyncPipe } from '@angular/common'
3import { AvsbService } from '@avsbhq/angular'
4import { flag$ } from '@avsbhq/angular'
5
6@Component({
7 selector: 'app-hero',
8 standalone: true,
9 imports: [AsyncPipe],
10 template: `
11 <ng-container *ngIf="heroVariant$ | async as heroFlag">
12 <app-hero-variant-a *ngIf="heroFlag.value === 'variant-a'" />
13 <app-hero-control *ngIf="heroFlag.value !== 'variant-a'" />
14 </ng-container>
15 `,
16})
17export class HeroComponent {
18 private avsb = inject(AvsbService)
19 heroVariant$ = flag$(this.avsb, 'homepage-hero', 'control')
20}

Graceful shutdown

AvsbService implements Angular's OnDestroylifecycle and calls client.close() when the Angular application is destroyed. This ensures pending events are flushed before the process exits.

Testing

ts
1import { createMockClient, TestData } from '@avsbhq/test'
2import { TestBed } from '@angular/core/testing'
3import { provideAvsb } from '@avsbhq/angular'
4import { CheckoutComponent } from './checkout.component'
5
6const td = TestData.flag('checkout-v2').booleanFlag().fallthroughVariation(true)
7const client = createMockClient({ flags: [td.build()] })
8
9TestBed.configureTestingModule({
10 imports: [CheckoutComponent],
11 providers: [provideAvsb({ client })],
12})
13
14const fixture = TestBed.createComponent(CheckoutComponent)
15fixture.detectChanges()

What's next