Angular error tracking installation

Last updated:

|Edit this page|
  1. Installing PostHog Angular SDK

    Required
    Your goal in this step: Install the PostHog Angular SDK.

    Install posthog-js using your package manager:

    npm install --save posthog-js

    Initialize 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. Usually https://us.i.posthog.com for US-based projects and https://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.ts
    import { 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.ts
    import { 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) {}
    }
  2. Verify PostHog is initialized

    Checkpoint
    Confirm you can capture events with PostHog

    Before proceeding, confirm that you can capture events with PostHog using posthog.capture('test_event').

  3. Setting up exception autocapture

    Required
    Your 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.ts
    import { 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.ts
    function 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 environments
    if (
    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-access
    const 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-access
    return 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 the providePostHogErrorHandler function and add it to the providers array:

    src/app/app.config.ts
    // src/app/app.config.ts
    import { 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:

    TypeScript
    posthog.captureException(e, additionalProperties)
  4. Verify error tracking

    Checkpoint
    Confirm events are being sent to PostHog

    Before proceeding, let's make sure exception events are being captured and sent to PostHog. You should see events appear in the activity feed.


    Activity feed with events
    Check for exceptions in PostHog
  5. Upload source maps

    Required

    Great, you're capturing exceptions! If you serve minified bundles, the next step is to upload source maps to generate accurate stack traces.

    Let's continue to the next section.

    Upload source maps for Angular

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

Read next article