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.
Install
1npm install @avsbhq/browser@^1 @avsbhq/angular@^1Obtain your SDK key
Open Settings > Environments in your A vs B project and copy the SDK key. Add it to your Angular environment files:
1export const environment = {2 production: false,3 avsbSdkKey: 'sdk_development_xxxxxxxxxxxxxxxx',4}1export const environment = {2 production: true,3 avsbSdkKey: 'sdk_production_xxxxxxxxxxxxxxxx',4}Register provideAvsb in app.config.ts (standalone)
For standalone component apps (Angular 17+ default), call provideAvsb in app.config.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}AvsbModule.forRoot({ sdkKey, context }) in your AppModule imports array instead of using provideAvsb.Read a flag via AvsbService
Inject AvsbService into any component or service. It exposes typed evaluator methods that return Flag<T>.
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).value17 }18}Read a flag via the *avsbFlag directive
The structural directive *avsbFlag conditionally renders elements based on a flag value, keeping templates clean:
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>Track an event
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}Identify a user
Call identify on the service after the user logs in.
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:
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
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()