Angular

schematic-angular is a client-side Angular library for Schematic which provides an injectable service to track events, check flags, and more. schematic-angular provides the same capabilities as schematic-js, for Angular apps.

Install

$npm install @schematichq/schematic-angular
$# or
$yarn add @schematichq/schematic-angular
$# or
$pnpm add @schematichq/schematic-angular

Usage

Setup with provideSchematic

Add provideSchematic to your application’s providers. This works with both standalone and NgModule-based apps.

Standalone app (app.config.ts):

1import { ApplicationConfig } from "@angular/core";
2import { provideSchematic } from "@schematichq/schematic-angular";
3
4export const appConfig: ApplicationConfig = {
5 providers: [
6 provideSchematic({ publishableKey: "your-publishable-key" }),
7 ],
8};

NgModule-based app:

1import { NgModule } from "@angular/core";
2import { provideSchematic } from "@schematichq/schematic-angular";
3
4@NgModule({
5 providers: [
6 provideSchematic({ publishableKey: "your-publishable-key" }),
7 ],
8})
9export class AppModule {}

You can also pass a pre-configured client:

1import { Schematic } from "@schematichq/schematic-angular";
2
3const client = new Schematic("your-publishable-key", { useWebSocket: true });
4
5provideSchematic({ client });

Setting context

To set the user context for events and flag checks, use the identify method on SchematicService:

1import { Component, OnInit, inject } from "@angular/core";
2import { SchematicService } from "@schematichq/schematic-angular";
3
4@Component({ selector: "app-root", template: `<router-outlet />` })
5export class AppComponent implements OnInit {
6 private schematic = inject(SchematicService);
7
8 ngOnInit() {
9 this.schematic.identify({
10 keys: { id: "my-user-id" },
11 company: {
12 keys: { id: "my-company-id" },
13 traits: { location: "Atlanta, GA" },
14 },
15 });
16 }
17}

To learn more about identifying companies with the keys map, see key management in Schematic public docs.

Tracking usage

Once you’ve set the context with identify, you can track events:

1import { Component, inject } from "@angular/core";
2import { SchematicService } from "@schematichq/schematic-angular";
3
4@Component({
5 selector: "app-usage",
6 template: `<button (click)="onQuery()">Run Query</button>`,
7})
8export class UsageComponent {
9 private schematic = inject(SchematicService);
10
11 onQuery() {
12 this.schematic.track({ event: "query" });
13 }
14}

If you want to record large numbers of the same event at once, or measure usage in terms of a unit like tokens or memory, you can optionally specify a quantity:

1this.schematic.track({ event: "query", quantity: 10 });

Checking flags

Use flagValue$ to get an Observable of a flag’s boolean value:

With async pipe:

1import { Component, inject } from "@angular/core";
2import { AsyncPipe } from "@angular/common";
3import { SchematicService } from "@schematichq/schematic-angular";
4
5@Component({
6 selector: "app-feature",
7 standalone: true,
8 imports: [AsyncPipe],
9 template: `
10 @if (isFeatureEnabled$ | async) {
11 <app-feature />
12 } @else {
13 <app-fallback />
14 }
15 `,
16})
17export class FeatureComponent {
18 private schematic = inject(SchematicService);
19 isFeatureEnabled$ = this.schematic.flagValue$("my-flag-key");
20}

With Signals (Angular 16+):

1import { Component, inject } from "@angular/core";
2import { toSignal } from "@angular/core/rxjs-interop";
3import { SchematicService } from "@schematichq/schematic-angular";
4
5@Component({
6 selector: "app-feature",
7 standalone: true,
8 template: `
9 @if (isFeatureEnabled()) {
10 <app-feature />
11 } @else {
12 <app-fallback />
13 }
14 `,
15})
16export class FeatureComponent {
17 private schematic = inject(SchematicService);
18 isFeatureEnabled = toSignal(this.schematic.flagValue$("my-flag-key"), {
19 initialValue: false,
20 });
21}

Checking entitlements

Use entitlement$ to get an Observable with detailed entitlement data including usage information:

1import { Component, inject } from "@angular/core";
2import { AsyncPipe } from "@angular/common";
3import { SchematicService } from "@schematichq/schematic-angular";
4
5@Component({
6 selector: "app-entitlement",
7 standalone: true,
8 imports: [AsyncPipe],
9 template: `
10 @if (isPending$ | async) {
11 <app-loader />
12 } @else if (entitlement$ | async; as entitlement) {
13 @if (entitlement.featureUsageExceeded) {
14 <div>
15 You have used all of your usage
16 ({{ entitlement.featureUsage }} / {{ entitlement.featureAllocation }})
17 </div>
18 } @else if (entitlement.value) {
19 <app-feature />
20 } @else {
21 <app-no-access />
22 }
23 }
24 `,
25})
26export class EntitlementComponent {
27 private schematic = inject(SchematicService);
28 isPending$ = this.schematic.isPending$();
29 entitlement$ = this.schematic.entitlement$("my-flag-key");
30}

Note: isPending$ checks if entitlement data has been loaded, typically via identify. It should be used to wrap flag and entitlement checks, but never the initial call to identify.

Checking plans

Use plan$ to get an Observable of the current plan information:

1import { Component, inject } from "@angular/core";
2import { AsyncPipe } from "@angular/common";
3import { SchematicService } from "@schematichq/schematic-angular";
4
5@Component({
6 selector: "app-plan",
7 standalone: true,
8 imports: [AsyncPipe],
9 template: `
10 @if (plan$ | async; as plan) {
11 <div>Current plan: {{ plan.name }}</div>
12 } @else {
13 <div>No active subscription</div>
14 }
15 `,
16})
17export class PlanComponent {
18 private schematic = inject(SchematicService);
19 plan$ = this.schematic.plan$();
20}

API Reference

provideSchematic(config)

Configures the Schematic client for dependency injection. Accepts either a publishableKey string or a pre-configured client instance, plus any SchematicOptions.

SchematicService

Injectable service providing all Schematic functionality:

MethodReturn TypeDescription
getClient()SchematicAccess the underlying Schematic client
setContext(ctx)voidSet the evaluation context (company/user)
identify(body)voidIdentify a user and/or company
track(body)voidTrack a usage event
flagValue$(key, fallback?)Observable<boolean>Observe a feature flag’s boolean value
entitlement$(key, fallback?)Observable<CheckFlagReturn>Observe detailed entitlement data
plan$()Observable<CheckPlanReturn | undefined>Observe plan information
isPending$()Observable<boolean>Observe loading state

SCHEMATIC_CLIENT

InjectionToken<Schematic> for direct access to the raw client instance via Angular DI.

Fallback Behavior

The SDK includes built-in fallback behavior to ensure your application continues to function even when unable to reach Schematic.

Flag Check Fallbacks

When flag checks cannot reach Schematic, they use fallback values in the following priority order:

  1. Callsite fallback: provided as the second argument to flagValue$ or entitlement$
  2. Initialization defaults: configured via flagCheckDefaults or flagValueDefaults options in provideSchematic
  3. Default value: returns false if no fallback is configured
1// Provide a fallback value at the callsite
2isFeatureEnabled$ = this.schematic.flagValue$("feature-flag", true);
3
4// Or configure defaults at initialization
5provideSchematic({
6 publishableKey: "your-publishable-key",
7 flagValueDefaults: {
8 "feature-flag": true,
9 },
10});

Event Queueing and Retry

When events (track, identify) cannot be sent due to network issues, they are automatically queued and retried:

  • Events are queued in memory (up to 100 events by default, configurable via maxEventQueueSize)
  • Failed events are retried with exponential backoff (up to 5 attempts by default, configurable via maxEventRetries)
  • Events are automatically flushed when the network connection is restored

WebSocket Fallback

In WebSocket mode, if the WebSocket connection fails, the SDK will provide the last known value or the configured fallback values as outlined above. The WebSocket will also automatically attempt to re-establish its connection using an exponential backoff.

Troubleshooting

For debugging and development, Schematic supports two special modes:

Debug Mode

Enables console logging of all Schematic operations:

1provideSchematic({
2 publishableKey: "your-publishable-key",
3 debug: true,
4});
5
6// Or via URL parameter
7// https://yoursite.com/?schematic_debug=true

Offline Mode

Prevents network requests and returns fallback values for all flag checks:

1provideSchematic({
2 publishableKey: "your-publishable-key",
3 offline: true,
4});
5
6// Or via URL parameter
7// https://yoursite.com/?schematic_offline=true

Offline mode automatically enables debug mode to help with troubleshooting.

License

MIT

Support

Need help? Please open a GitHub issue or reach out to support@schematichq.com and we’ll be happy to assist.