Installation
Copy
npm install --save @outlit/browser
Quick Start
Initialize Outlit using anAPP_INITIALIZER:
Copy
// 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
}
]
}
Copy
// 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:Copy
// 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()
}
activate(properties?: Record<string, any>): void {
outlit.activate(properties)
}
engaged(properties?: Record<string, any>): void {
outlit.engaged(properties)
}
paid(properties?: Record<string, any>): void {
outlit.paid(properties)
}
churned(properties?: Record<string, any>): void {
outlit.churned(properties)
}
getVisitorId(): string | null {
return outlit.getInstance().getVisitorId()
}
}
Tracking Events
Inject and use the service in components:Copy
// 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
})
}
}
Copy
<!-- src/app/components/pricing/pricing.component.html -->
<button (click)="handleCheckout('pro')">
Start Free Trial
</button>
Identifying Users
Identify users after authentication:Copy
// 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:Copy
// 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:Copy
// 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:Copy
// 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:Copy
// 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:Copy
// 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
})
}
})
)
}
Copy
// 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])
)
]
}
Journey Stage Events
Track user lifecycle:Copy
// 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.activate({
flow: 'onboarding',
step: 'completed'
})
this.router.navigate(['/dashboard'])
}
}
Stage methods (
activate, engaged, paid, churned) require the user to be identified first.Consent Management
Handle user consent:Copy
// 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)
}
}
Copy
// 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()
}
}
Copy
// 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:Copy
import outlit, { type OutlitOptions, type BrowserTrackOptions } from '@outlit/browser'
const options: OutlitOptions = {
publicKey: environment.outlitPublicKey,
trackPageviews: true,
flushInterval: 5000
}
outlit.init(options)