- 1
Installing PostHog Angular SDK
RequiredYour goal in this step: Install the PostHog Angular SDK.Install
posthog-js
using your package manager:npm install --save posthog-jsInitialize the PostHog client
Generate environment files for your project with
ng g environments
. Configure the following environment variables:posthogKey
: Your project API key from your project settings.posthogHost
: Your project's client API host. Usuallyhttps://us.i.posthog.com
for US-based projects andhttps://eu.i.posthog.com
for EU-based projects.
For Angular v17 and above, you can set up PostHog as a singleton service. To do this, start by creating and injecting a
PosthogService
instance.Create a service by running
ng g service services/posthog
. The service should look like this:posthog.service.ts// src/app/services/posthog.service.tsimport { DestroyRef, Injectable, NgZone } from "@angular/core";import posthog from "posthog-js";import { environment } from "../../environments/environment";import { Router } from "@angular/router";@Injectable({ providedIn: "root" })export class PosthogService {constructor(private ngZone: NgZone,private router: Router,private destroyRef: DestroyRef,) {this.initPostHog();}private initPostHog() {this.ngZone.runOutsideAngular(() => {posthog.init(environment.posthogKey, {api_host: environment.posthogHost,defaults: '2025-05-24',});});}}The service is initialized outside of the Angular zone to reduce change detection cycles. This is important to avoid performance issues with session recording.
Then, inject the service in your app's root component
app.component.ts
. This will make sure PostHog is initialized before any other component is rendered.app.component.ts// src/app/app.component.tsimport { Component } from "@angular/core";import { RouterOutlet } from "@angular/router";import { PosthogService } from "./services/posthog.service";@Component({selector: "app-root",styleUrls: ["./app.component.scss"],template: `<router-outlet />`,imports: [RouterOutlet],})export class AppComponent {title = "angular-app";constructor(posthogService: PosthogService) {}} Verify PostHog is initialized
CheckpointConfirm you can capture events with PostHogBefore proceeding, confirm that you can capture events with PostHog using
posthog.capture('test_event')
.- 2
Setting up exception autocapture
RequiredYour goal in this step: Enable automatic exception tracking for your Angular application.Exception autocapture can be enabled during initialization of the PostHog client to automatically capture any exception thrown by your Angular application.This requires overriding Angular's default
ErrorHandler
provider:src/app/posthog-error-handler.tsimport { ErrorHandler, Injectable, Provider } from '@angular/core';import { HttpErrorResponse } from '@angular/common/http';import posthog from 'posthog-js';/*** Implementation of Angular's ErrorHandler provider that can be used as a drop-in replacement for the stock one.*/@Injectable({ providedIn: 'root' })class PostHogErrorHandler implements ErrorHandler {public constructor() {}/*** Method called for every value captured through the ErrorHandler*/public handleError(error: unknown): void {const extractedError = this._extractError(error) || 'Unknown error';runOutsideAngular(() => posthog.captureException(extractedError));}protected _extractError(errorCandidate: unknown): unknown {const error = tryToUnwrapZonejsError(errorCandidate);if (error instanceof HttpErrorResponse) {return extractHttpModuleError(error);}if (typeof error === 'string' || isErrorOrErrorLikeObject(error)) {return error;}return null;}}// https://github.com/angular/angular/blob/master/packages/core/src/util/errors.tsfunction tryToUnwrapZonejsError(error: unknown): unknown | Error {// TODO: once Angular14 is the minimum requirement ERROR_ORIGINAL_ERROR and// getOriginalError from error.ts can be used directly.return error && (error as { ngOriginalError: Error }).ngOriginalError? (error as { ngOriginalError: Error }).ngOriginalError: error;}function extractHttpModuleError(error: HttpErrorResponse): string | Error {// The `error` property of http exception can be either an `Error` object, which we can use directly...if (isErrorOrErrorLikeObject(error.error)) {return error.error;}// ... or an`ErrorEvent`, which can provide us with the message but no stack...// guarding `ErrorEvent` against `undefined` as it's not defined in Node environmentsif (typeof ErrorEvent !== 'undefined' &&error.error instanceof ErrorEvent &&error.error.message) {return error.error.message;}// ...or the request body itself, which we can use as a message instead.if (typeof error.error === 'string') {return `Server returned code ${error.status} with body "${error.error}"`;}// If we don't have any detailed information, fallback to the request message itself.return error.message;}function isErrorOrErrorLikeObject(value: unknown): value is Error {if (value instanceof Error) {return true;}if (value === null || typeof value !== 'object' || Array.isArray(value)) {return false;}return 'name' in value && 'message' in value && 'stack' in value;}// This would be exposed in the global environment whenever `zone.js` is// included in the `polyfills` configuration property. Starting from Angular 17,// users can opt-in to use zoneless change detection.declare const Zone: any;// In Angular 17 and future versions, zoneless support is forthcoming.// Therefore, it's advisable to safely check whether the `run` function is// available in the `<root>` context.// eslint-disable-next-line @typescript-eslint/no-unsafe-member-accessconst isNgZoneEnabled = typeof Zone !== 'undefined' && Zone.root?.run;export function runOutsideAngular<T>(callback: () => T): T {// Running the `callback` within the root execution context enables Angular// processes (such as SSR and hydration) to continue functioning normally without// timeouts and delays that could affect the user experience. This approach is// necessary because some of the Sentry functionality continues to run in the background.// eslint-disable-next-line @typescript-eslint/no-unsafe-member-accessreturn isNgZoneEnabled ? Zone.root.run(callback) : callback();}export function providePostHogErrorHandler(): Provider {return {provide: ErrorHandler,useValue: new PostHogErrorHandler(),};}Then, in your
src/app/app.config.ts
, import theprovidePostHogErrorHandler
function and add it to the providers array:src/app/app.config.ts// src/app/app.config.tsimport { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';import { provideRouter } from '@angular/router';import { routes } from './app.routes';import { providePostHogErrorHandler } from './posthog-error-handler';export const appConfig: ApplicationConfig = {providers: [...providePostHogErrorHandler(),],};If there are more errors you'd like to capture, you can manually call the
captureException
method:TypeScriptposthog.captureException(e, additionalProperties) - 4
Angular error tracking installation
Questions? Ask Max AI.
It's easier than reading through 698 pages of documentation
Community questions
Was this page useful?
Next article
Nuxt error tracking installation
Before proceeding, confirm that you can capture events using posthog.capture('test_event') . To send errors directly using the PostHog client, import it and use the captureException method like this: On the server side, you can use the posthog object directly. Update your posthog.client.js to add an error hook