vTilt
Why vTiltHow It WorksFeaturesFAQDocs
Docs / Angular
Quick startEvent forwarding
MCP server
Guides
OverviewAuthenticationOAuthAgent skills (prompts)AI intelligenceGoogle Ads
Client setup
CursorClaude DesktopVS CodeCodex
Realtime
Debug ViewRealtime Dashboard
Integration guides
Frontend frameworks
Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus
Backend frameworks
NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails
Backend languages
PythonPHPRubyElixirGoJava.NET / C#Rust
Stack guides
Vue + PHP
SDK
Browser SDK
InstallScript bundlesEvent trackingAutocaptureIdentify & aliasWeb VitalsSession recordingChat widgetFeature readinessRemote configurationReverse proxyDebug logging
Node SDK
Install & setupCapture, identify & aliasContext & shutdown

Documentation

vTilt
Quick startEvent forwarding

MCP server

Realtime

Debug ViewRealtime Dashboard

Integration guides

Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus

SDK

DocsIntegration guidesAngular

Angular

Integrate vTilt with Angular 16+ — npm package or inline script, Router pageviews, identify on every page load.

vTilt drops into Angular through an APP_INITIALIZER (or an inline script), plus a Router subscription that emits a pageview on every navigation. Works with both the classic NgModule setup and the standalone bootstrapApplication API.

#1. Install & initialise

Choose how you load the Browser SDK. npm boots the SDK from an APP_INITIALIZER; the inline script drops a stub in index.html with no package to install. Both expose the same window.vt global — the rest of this guide is identical either way.

Install the package:

npm install @v-tilt/browser
bash

Provide a function that runs on app boot and calls vt.init(). Read the token via environment.ts to keep it out of source:

// src/app/vtilt.ts
import { APP_INITIALIZER, Provider } from '@angular/core'
import { vt } from '@v-tilt/browser'
import { environment } from '../environments/environment'

export const VTILT_INIT: Provider = {
  provide: APP_INITIALIZER,
  multi: true,
  useFactory: () => () => {
    vt.init(environment.vtiltToken, {
      api_host: environment.vtiltHost,
      autocapture: true,
      capture_pageview: false,
      capture_pageleave: true,
    })
  },
}
typescript
// src/environments/environment.ts
export const environment = {
  vtiltToken: 'YOUR_PROJECT_TOKEN',
  vtiltHost: 'https://www.vtilt.com',
}
typescript

Register it on bootstrap:

// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser'
import { provideRouter } from '@angular/router'
import { AppComponent } from './app/app.component'
import { VTILT_INIT } from './app/vtilt'
import { routes } from './app/routes'

bootstrapApplication(AppComponent, {
  providers: [provideRouter(routes), VTILT_INIT],
})
typescript

For NgModule apps, add VTILT_INIT to the providers array of AppModule.

Tip

Tip: Need chat on first paint? Swap array.js for array.chat.js and add chat: { enabled: true }. See Script bundles.

#2. Router pageviews

Subscribe to NavigationEnd events and emit $pageview so SPA navigation registers in vTilt.

// src/app/app.component.ts
import { Component, OnInit, inject } from '@angular/core'
import { Router, NavigationEnd, RouterOutlet } from '@angular/router'
import { filter } from 'rxjs/operators'
import { vt } from '@v-tilt/browser'

@Component({
  standalone: true,
  selector: 'app-root',
  imports: [RouterOutlet],
  template: '<router-outlet></router-outlet>',
})
export class AppComponent implements OnInit {
  private router = inject(Router)

  ngOnInit() {
    this.router.events
      .pipe(filter(e => e instanceof NavigationEnd))
      .subscribe((e: NavigationEnd) => {
        vt.capture('$pageview', {
          $current_url: window.location.href,
          $pathname: e.urlAfterRedirects,
        })
      })
  }
}
typescript

Note

Note: Using the inline script? Replace vt with window.vt and drop the import.

#3. Identify users

Identify whenever your auth service emits a user. The pattern below also identifies on app boot when the user is already logged in.

// src/app/auth.service.ts
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import { vt } from '@v-tilt/browser'

@Injectable({ providedIn: 'root' })
export class AuthService {
  user$ = new BehaviorSubject<{ id: string; email: string } | null>(null)

  constructor() {
    this.user$.subscribe(user => {
      if (user) vt.identify(user.id, { email: user.email })
    })
  }

  logout() {
    vt.capture('user_logged_out')
    vt.resetUser()
    this.user$.next(null)
  }
}
typescript

Important

Important: Make sure your auth service hydrates from the session cookie on app boot, not only after a successful login. Otherwise visitors who already have a session stay anonymous. See Identify & alias for the full model.

#4. Capture events anywhere

import { vt } from '@v-tilt/browser'

@Component({
  /* ... */
})
export class HeroComponent {
  onCta() {
    vt.capture('cta_clicked', { location: 'hero' })
  }
}
typescript

#Next steps

  • Identify & alias — anonymous → known user merge.
  • Autocapture — what's captured automatically.
  • Reverse proxy — block-resistant ingestion.
PreviousAstroIntegration guidesNextTanStack StartIntegration guides

On this page

  • 1. Install & initialise
  • 2. Router pageviews
  • 3. Identify users
  • 4. Capture events anywhere
  • Next steps