Installation
npm install --save @outlit/browser
pnpm add @outlit/browser
yarn add @outlit/browser
bun add @outlit/browser
Quick Start
Initialize Outlit using anAPP_INITIALIZER:
// src/app/app.config.ts
import { ApplicationConfig, APP_INITIALIZER } from '@angular/core'
import outlit from '@outlit/browser'
import { environment } from '../environments/environment'
function initializeOutlit() {
return () => {
outlit.init({
publicKey: environment.outlitPublicKey,
trackPageviews: true,
})
}
}
export const appConfig: ApplicationConfig = {
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeOutlit,
multi: true
}
]
}
// src/environments/environment.ts
export const environment = {
production: false,
outlitPublicKey: 'pk_your_public_key_here'
}
For production, create
environment.prod.ts with your production key.Creating a Service
Create a service for better DX:// src/app/services/outlit.service.ts
import { Injectable } from '@angular/core'
import outlit from '@outlit/browser'
@Injectable({
providedIn: 'root'
})
export class OutlitService {
track(eventName: string, properties?: Record<string, any>): void {
outlit.track(eventName, properties)
}
identify(email: string, traits?: Record<string, any>): void {
outlit.identify({ email, traits })
}
setUser(identity: { email?: string; userId?: string; traits?: Record<string, any> }): void {
outlit.setUser(identity)
}
clearUser(): void {
outlit.clearUser()
}
getVisitorId(): string | null {
return outlit.getInstance().getVisitorId()
}
}
Tracking Events
Inject and use the service in components:// src/app/components/pricing/pricing.component.ts
import { Component } from '@angular/core'
import { OutlitService } from '../../services/outlit.service'
@Component({
selector: 'app-pricing',
templateUrl: './pricing.component.html'
})
export class PricingComponent {
constructor(private outlit: OutlitService) {}
handleCheckout(plan: string): void {
this.outlit.track('checkout_started', {
plan,
amount: 99
})
}
}
<!-- src/app/components/pricing/pricing.component.html -->
<button (click)="handleCheckout('pro')">
Start Free Trial
</button>
Identifying Users
Identify users after authentication:// src/app/components/login/login.component.ts
import { Component } from '@angular/core'
import { Router } from '@angular/router'
import { OutlitService } from '../../services/outlit.service'
import { AuthService } from '../../services/auth.service'
@Component({
selector: 'app-login',
templateUrl: './login.component.html'
})
export class LoginComponent {
email = ''
password = ''
constructor(
private auth: AuthService,
private outlit: OutlitService,
private router: Router
) {}
async handleLogin(): Promise<void> {
const user = await this.auth.login(this.email, this.password)
this.outlit.identify(user.email, {
name: user.name,
plan: user.plan
})
this.router.navigate(['/dashboard'])
}
}
Router Integration
Track navigation with Angular Router:// src/app/app.config.ts
import { ApplicationConfig, APP_INITIALIZER } from '@angular/core'
import { provideRouter, Router, NavigationEnd } from '@angular/router'
import { OutlitService } from './services/outlit.service'
import { routes } from './app.routes'
function setupRouterTracking(router: Router, outlit: OutlitService) {
return () => {
router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
outlit.track('pageview', {
path: event.url
})
}
})
}
}
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
{
provide: APP_INITIALIZER,
useFactory: setupRouterTracking,
deps: [Router, OutlitService],
multi: true
}
]
}
If you set
trackPageviews: true during init, pageviews are tracked automatically. The above example is only needed for custom pageview logic.Auth Guard Integration
Track authentication events:// src/app/guards/auth.guard.ts
import { inject } from '@angular/core'
import { Router, CanActivateFn } from '@angular/router'
import { OutlitService } from '../services/outlit.service'
import { AuthService } from '../services/auth.service'
export const authGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthService)
const outlit = inject(OutlitService)
const router = inject(Router)
if (auth.isLoggedIn()) {
const user = auth.getUser()
outlit.setUser({
email: user.email,
userId: user.id,
traits: {
name: user.name
}
})
return true
}
outlit.track('auth_required', {
path: state.url
})
return router.parseUrl('/login')
}
RxJS Integration
Track with observables:// src/app/components/dashboard/dashboard.component.ts
import { Component, OnInit } from '@angular/core'
import { tap } from 'rxjs/operators'
import { OutlitService } from '../../services/outlit.service'
import { DashboardService } from '../../services/dashboard.service'
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html'
})
export class DashboardComponent implements OnInit {
data$ = this.dashboard.getData().pipe(
tap(() => this.outlit.track('dashboard_loaded'))
)
constructor(
private dashboard: DashboardService,
private outlit: OutlitService
) {}
ngOnInit(): void {
this.outlit.track('dashboard_viewed')
}
handleExport(): void {
this.outlit.track('data_exported', {
format: 'csv'
})
}
}
Lifecycle Hooks
Track component lifecycle events:// src/app/components/feature/feature.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core'
import { OutlitService } from '../../services/outlit.service'
@Component({
selector: 'app-feature',
templateUrl: './feature.component.html'
})
export class FeatureComponent implements OnInit, OnDestroy {
private startTime: number
constructor(private outlit: OutlitService) {}
ngOnInit(): void {
this.startTime = Date.now()
this.outlit.track('feature_viewed', {
feature: 'export'
})
}
ngOnDestroy(): void {
const duration = Date.now() - this.startTime
this.outlit.track('feature_time', {
feature: 'export',
duration
})
}
}
Interceptor for API Tracking
Track API calls:// src/app/interceptors/tracking.interceptor.ts
import { HttpInterceptorFn, HttpEventType } from '@angular/common/http'
import { tap } from 'rxjs/operators'
import outlit from '@outlit/browser'
export const trackingInterceptor: HttpInterceptorFn = (req, next) => {
return next(req).pipe(
tap({
next: (event) => {
if (event.type === HttpEventType.Response) {
outlit.track('api_success', {
url: req.url,
method: req.method
})
}
},
error: (error) => {
outlit.track('api_error', {
url: req.url,
method: req.method,
status: error.status
})
}
})
)
}
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core'
import { provideHttpClient, withInterceptors } from '@angular/common/http'
import { trackingInterceptor } from './interceptors/tracking.interceptor'
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([trackingInterceptor])
)
]
}
Activation event
Track the ordinary event selected as your activation signal after the milestone succeeds:// src/app/components/onboarding/onboarding.component.ts
import { Component } from '@angular/core'
import { Router } from '@angular/router'
import { OutlitService } from '../../services/outlit.service'
@Component({
selector: 'app-onboarding',
templateUrl: './onboarding.component.html'
})
export class OnboardingComponent {
constructor(
private outlit: OutlitService,
private router: Router
) {}
handleComplete(): void {
this.outlit.track('onboarding_completed', {
flow: 'onboarding',
step: 'completed'
})
this.router.navigate(['/dashboard'])
}
}
Outlit Core derives activation from your selected ordinary event and derives engagement and inactivity from product activity. Billing comes from verified integrations such as Stripe. See Customer Journey.
Consent Management
Handle user consent:// src/app/services/consent.service.ts
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import outlit from '@outlit/browser'
@Injectable({
providedIn: 'root'
})
export class ConsentService {
private consentGiven = new BehaviorSubject<boolean>(false)
consent$ = this.consentGiven.asObservable()
constructor() {
const hasConsent = localStorage.getItem('tracking-consent') === 'true'
if (hasConsent) {
this.acceptTracking()
}
}
acceptTracking(): void {
localStorage.setItem('tracking-consent', 'true')
outlit.enableTracking()
this.consentGiven.next(true)
}
declineTracking(): void {
localStorage.setItem('tracking-consent', 'false')
this.consentGiven.next(false)
}
}
// src/app/components/cookie-banner/cookie-banner.component.ts
import { Component } from '@angular/core'
import { ConsentService } from '../../services/consent.service'
@Component({
selector: 'app-cookie-banner',
templateUrl: './cookie-banner.component.html'
})
export class CookieBannerComponent {
showBanner = true
constructor(private consent: ConsentService) {
this.consent.consent$.subscribe((hasConsent) => {
this.showBanner = !hasConsent
})
}
accept(): void {
this.consent.acceptTracking()
}
decline(): void {
this.consent.declineTracking()
}
}
// src/app/app.config.ts
function initializeOutlit() {
return () => {
outlit.init({
publicKey: environment.outlitPublicKey,
autoTrack: false, // Wait for consent
})
}
}
TypeScript Support
Full TypeScript support is included:import outlit, { type OutlitOptions, type BrowserTrackOptions } from '@outlit/browser'
const options: OutlitOptions = {
publicKey: environment.outlitPublicKey,
trackPageviews: true,
flushInterval: 5000
}
outlit.init(options)
Next Steps
Server-Side Tracking
Track events from your backend
Identity Resolution
Learn how profiles are merged
NPM Package
Full API reference
React Integration
Use Outlit with React