Generated banner for Integration Angular
Generated logo for Integration Angular

Integration Angular

PostHogOfficialCreated by PostHog

  • Skill
  • Tool integration
  • Data and AI
  • MIT
  • No issues found

From the author

PostHog integration for Angular applications
— the description by PostHog

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured approach to integrating the PostHog JavaScript SDK into Angular projects. It emphasizes creating a singleton service to wrap the SDK, ensuring SSR safety, and following best practices for environment configuration and user identification. The integration covers event tracking, session recording, and error monitoring, with specific patterns for modern Angular versions.

What it does

  • Provides a pattern for creating a singleton PostHog service in Angular.
  • Ensures SSR safety when using PostHog in Angular applications.
  • Guides the configuration of environment variables for API keys and hosts.
  • Demonstrates how to identify users during authentication flows.
  • Includes patterns for capturing custom events and tracking errors.
  • Offers guidance on initializing PostHog outside the Angular zone for performance.

When to use it

  • When you need to add product analytics to an Angular application.
  • When you want to implement session replay or error tracking in Angular.
  • When you need to identify users to link frontend events to backend data.
  • When you are setting up a new Angular project and want to include PostHog from the start.

Advantages

  • Promotes a clean, maintainable architecture using singleton services.
  • Prevents performance issues by running PostHog outside the Angular zone.
  • Ensures secure handling of API keys via environment variables.
  • Provides SSR-safe implementation patterns for universal Angular apps.

Usage examples

“How do I initialize PostHog in my Angular app?”
The skill guides you to create a PostHogService singleton and initialize it in the root component, ensuring it is ready before other components render.
“How do I track a user login in Angular with PostHog?”
The skill provides the pattern for using the identify method within your authentication service to link user sessions to specific IDs.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/posthog/integration-angular/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip integration-angular.zip -d .agents/skills

Documentation by PostHog

PostHog integration for Angular

This skill helps you add PostHog analytics to Angular applications.

Workflow

Follow these steps in order to complete the integration:

  1. basic-integration-1.0-begin.md - PostHog Setup - Begin ← Start here

  2. basic-integration-1.1-edit.md - PostHog Setup - Edit

  3. basic-integration-1.2-revise.md - PostHog Setup - Revise

  4. basic-integration-1.3-conclude.md - PostHog Setup - Conclusion

Reference files

  • references/EXAMPLE.md - Angular example project code

  • references/angular.md - Angular - docs

  • references/identify-users.md - Identify users - docs

  • references/basic-integration-1.0-begin.md - PostHog setup - begin

  • references/basic-integration-1.1-edit.md - PostHog setup - edit

  • references/basic-integration-1.2-revise.md - PostHog setup - revise

  • references/basic-integration-1.3-conclude.md - PostHog setup - conclusion

The example project shows the target implementation pattern. Consult the documentation for API details.

Key principles

  • Environment variables: Always use environment variables for PostHog keys. Never hardcode them.

  • Minimal changes: Add PostHog code alongside existing integrations. Don't replace or restructure existing code.

  • Match the example: Your implementation should follow the example project's patterns as closely as possible.

Framework guidelines

  • Use inject() instead of constructor injection. PostHog service should be injected via inject() in components/services that need it.

  • Create a dedicated PosthogService as a singleton root service that wraps the PostHog SDK.

  • Always use standalone components over NgModules.

  • Configure PostHog credentials in src/environments/environment.ts files, as Angular reads environment variables from these configuration files

Identifying users

Identify users during login and signup events. Refer to the example code and documentation for the correct identify pattern for this framework. If both frontend and backend code exist, pass the client-side session and distinct ID using X-POSTHOG-DISTINCT-ID and X-POSTHOG-SESSION-ID headers to maintain correlation.

Error tracking

Add PostHog error tracking to relevant files, particularly around critical user flows and API boundaries.

Files

references/EXAMPLE.md

PostHog Angular Example Project

Repository: https://github.com/PostHog/context-mill Path: basics/angular


README.md

PostHog Angular Example

This is an Angular example demonstrating PostHog integration with product analytics, session replay, and error tracking.

Features

  • Product analytics: Track user events and behaviors

  • Session replay: Record and replay user sessions

  • Error tracking: Capture and track errors

  • User authentication: Demo login system with PostHog user identification

  • SSR-safe: Uses platform checks for browser-only PostHog calls

  • Reverse proxy: PostHog ingestion through Angular proxy

Getting started

1. Install dependencies
pnpm install
2. Configure environment variables

Create a .env file in the root directory:

VITE_POSTHOG_PROJECT_TOKEN=your_posthog_project_token
VITE_POSTHOG_HOST=https://us.posthog.com

Get your PostHog project token from your PostHog project settings.

3. Run the development server
pnpm start

Open http://localhost:3000 with your browser to see the app.

Project structure

src/
├── app/
│   ├── components/
│   │   └── header/            # Navigation header with auth state
│   ├── pages/
│   │   ├── home/              # Home/Login page
│   │   ├── burrito/           # Demo feature page with event tracking
│   │   └── profile/           # User profile with error tracking demo
│   ├── services/
│   │   ├── posthog.service.ts # PostHog service wrapper (SSR-safe)
│   │   └── auth.service.ts    # Auth service with PostHog integration
│   ├── guards/
│   │   └── auth.guard.ts      # Route guard for protected pages
│   ├── app.component.ts       # Root component with PostHog init
│   ├── app.routes.ts          # Route definitions
│   └── app.config.ts          # App configuration
├── environments/
│   ├── environment.ts         # Dev environment config
│   └── environment.production.ts
└── main.ts                    # App entry point

Key integration points

PostHog service (services/posthog.service.ts)

A wrapper service that handles SSR safety and provides access to the PostHog instance:

import { Injectable, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import posthog from 'posthog-js';

@Injectable({ providedIn: 'root' })
export class PostHogService {
  private readonly platformId = inject(PLATFORM_ID);

  get posthog(): typeof posthog {
    if (isPlatformBrowser(this.platformId)) {
      return posthog;
    }
    // Return a no-op proxy for SSR safety
    return new Proxy({} as typeof posthog, {
      get: () => () => undefined,
    });
  }

  init(apiKey: string, options: Partial<PostHogConfig>): void {
    if (isPlatformBrowser(this.platformId)) {
      posthog.init(apiKey, options);
    }
  }
}
PostHog initialization (app.component.ts)

PostHog is initialized in the root component's ngOnInit:

import { PostHogService } from './services/posthog.service';
import { environment } from '../environments/environment';

export class AppComponent implements OnInit {
  private readonly posthogService = inject(PostHogService);

  ngOnInit(): void {
    this.posthogService.init(environment.posthogKey, {
      api_host: '/ingest',
      ui_host: environment.posthogHost || 'https://us.posthog.com',
      capture_exceptions: true,
    });
  }
}
User identification (services/auth.service.ts)
import { PostHogService } from './posthog.service';

const posthogService = inject(PostHogService);

posthogService.posthog.identify(username, {
  username,
  isNewUser,
});
Event tracking (pages/burrito/burrito.component.ts)
import { PostHogService } from '../../services/posthog.service';

const posthogService = inject(PostHogService);

posthogService.posthog.capture('burrito_considered', {
  total_considerations: count,
  username: username,
});
Error tracking (pages/profile/profile.component.ts)
posthogService.posthog.capture('$exception', {
  $exception_message: error.message,
  $exception_type: error.name,
  $exception_stack_trace_raw: error.stack,
});

Angular-specific details

This example uses Angular 21 with modern features:

  1. Standalone components: No NgModules, all components use standalone: true

  2. Signals: Reactive state management with Angular signals

  3. SSR support: Uses isPlatformBrowser() checks for SSR safety

  4. Dependency injection: PostHog wrapped in an injectable service

  5. Proxy configuration: Uses proxy.conf.json for PostHog API calls

  6. Environment files: Generated from .env at build time via prebuild script

Environment variable handling

Angular CLI doesn't natively support .env files. This project uses a prebuild script:

  1. scripts/generate-env.js reads .env and generates environment.generated.ts

  2. The script runs automatically before pnpm start and pnpm build

  3. Environment files import from the generated file

Learn more


.env.example

NG_APP_POSTHOG_PROJECT_TOKEN=<ph_project_token>
NG_APP_POSTHOG_HOST=https://us.posthog.com

src/app/app.component.ts

import {
  Component,
  inject,
  OnInit,
  PLATFORM_ID,
  ChangeDetectionStrategy,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HeaderComponent } from './components/header/header.component';
import { PostHogService } from './services/posthog.service';
import { environment } from '../environments/environment';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet, HeaderComponent],
  template: `
    <app-header />
    <router-outlet />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit {
  private readonly platformId = inject(PLATFORM_ID);
  private readonly posthogService = inject(PostHogService);

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.posthogService.init(environment.posthogKey, {
        api_host: '/ingest',
        ui_host: environment.posthogHost || 'https://us.posthog.com',
        capture_exceptions: true,
      });
    }
  }
}

src/app/app.config.server.ts

import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering, withRoutes } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';

const serverConfig: ApplicationConfig = {
  providers: [provideServerRendering(withRoutes(serverRoutes))],
};

export const config = mergeApplicationConfig(appConfig, serverConfig);

src/app/app.config.ts

import { ApplicationConfig } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import {
  provideClientHydration,
  withEventReplay,
} from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withComponentInputBinding()),
    provideHttpClient(withFetch()),
    provideClientHydration(withEventReplay()),
  ],
};

src/app/app.routes.server.ts

import { RenderMode, ServerRoute } from '@angular/ssr';

export const serverRoutes: ServerRoute[] = [
  {
    path: '',
    renderMode: RenderMode.Server,
  },
  {
    path: 'burrito',
    renderMode: RenderMode.Client, // Protected route, render client-side
  },
  {
    path: 'profile',
    renderMode: RenderMode.Client, // Protected route, render client-side
  },
  {
    path: '**',
    renderMode: RenderMode.Server,
  },
];

src/app/app.routes.ts

import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';

export const routes: Routes = [
  {
    path: '',
    title: 'Burrito Consideration App',
    loadComponent: () =>
      import('./pages/home/home.component').then((m) => m.HomeComponent),
  },
  {
    path: 'burrito',
    title: 'Burrito Consideration - Burrito Consideration App',
    loadComponent: () =>
      import('./pages/burrito/burrito.component').then(
        (m) => m.BurritoComponent
      ),
    canActivate: [authGuard],
  },
  {
    path: 'profile',
    title: 'Profile - Burrito Consideration App',
    loadComponent: () =>
      import('./pages/profile/profile.component').then(
        (m) => m.ProfileComponent
      ),
    canActivate: [authGuard],
  },
  {
    path: '**',
    redirectTo: '',
  },
];

src/app/components/header/header.component.ts

import { Component, inject, ChangeDetectionStrategy } from '@angular/core';
import { RouterLink } from '@angular/router';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'app-header',
  imports: [RouterLink],
  template: `
    <a class="skip-link" href="#main-content">Skip to main content</a>
    <header class="header" role="banner">
      <div class="header-container">
        <nav aria-label="Main navigation">
          <a routerLink="/">Home</a>
          @if (auth.isAuthenticated()) {
            <a routerLink="/burrito">Burrito Consideration</a>
            <a routerLink="/profile">Profile</a>
          }
        </nav>
        <div class="user-section">
          @if (auth.user(); as user) {
            <span>Welcome, {{ user.username }}!</span>
            <button (click)="auth.logout()" class="btn-logout">Logout</button>
          } @else {
            <span>Not logged in</span>
          }
        </div>
      </div>
    </header>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderComponent {
  readonly auth = inject(AuthService);
}

src/app/guards/auth.guard.ts

import { inject } from '@angular/core';
import { Router, CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth.service';

export const authGuard: CanActivateFn = () => {
  const auth = inject(AuthService);
  const router = inject(Router);

  if (auth.isAuthenticated()) {
    return true;
  }

  return router.createUrlTree(['/']);
};

src/app/pages/burrito/burrito.component.ts

import {
  Component,
  inject,
  signal,
  ChangeDetectionStrategy,
} from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { PostHogService } from '../../services/posthog.service';

@Component({
  selector: 'app-burrito',
  template: `
    <main id="main-content" tabindex="-1">
      <div class="container">
        <h1>Burrito consideration zone</h1>
        <p>Take a moment to truly consider the potential of burritos.</p>

        <div style="text-align: center">
          <button (click)="handleConsideration()" class="btn-burrito">
            I have considered the burrito potential
          </button>

          @if (hasConsidered()) {
            <p class="success" role="status" aria-live="polite">
              Thank you for your consideration! Count:
              {{ auth.user()?.burritoConsiderations }}
            </p>
          }
        </div>

        <div class="stats">
          <h3>Consideration stats</h3>
          <p>Total considerations: {{ auth.user()?.burritoConsiderations }}</p>
        </div>
      </div>
    </main>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BurritoComponent {
  readonly auth = inject(AuthService);
  private readonly posthogService = inject(PostHogService);
  private readonly router = inject(Router);

  hasConsidered = signal(false);

  constructor() {
    // Redirect if not authenticated
    if (!this.auth.isAuthenticated()) {
      this.router.navigate(['/']);
    }
  }

  handleConsideration(): void {
    const user = this.auth.user();
    if (!user) return;

    this.auth.incrementBurritoConsiderations();
    this.hasConsidered.set(true);
    setTimeout(() => this.hasConsidered.set(false), 2000);

    this.posthogService.posthog.capture('burrito_considered', {
      total_considerations: user.burritoConsiderations + 1,
      username: user.username,
    });
  }
}

src/app/pages/home/home.component.ts

import {
  Component,
  inject,
  signal,
  ChangeDetectionStrategy,
} from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'app-home',
  imports: [ReactiveFormsModule],
  template: `
    <main id="main-content" tabindex="-1">
      @if (auth.user(); as user) {
        <div class="container">
          <h1>Welcome back, {{ user.username }}!</h1>
          <p>You are now logged in. Feel free to explore:</p>
          <ul>
            <li>Consider the potential of burritos</li>
            <li>View your profile and statistics</li>
          </ul>
        </div>
      } @else {
        <div class="container">
          <h1>Welcome to Burrito Consideration App</h1>
          <p>Please sign in to begin your burrito journey</p>

          <form [formGroup]="loginForm" (ngSubmit)="handleSubmit()" class="form">
            <div class="form-group">
              <label for="username">Username:</label>
              <input
                type="text"
                id="username"
                formControlName="username"
                placeholder="Enter any username"
                autocomplete="username"
              />
            </div>

            <div class="form-group">
              <label for="password">Password:</label>
              <input
                type="password"
                id="password"
                formControlName="password"
                placeholder="Enter any password"
                autocomplete="current-password"
              />
            </div>

            @if (error()) {
              <p class="error" role="alert">{{ error() }}</p>
            }

            <button type="submit" class="btn-primary">Sign In</button>
          </form>

          <p class="note">
            Note: This is a demo app. Use any username and password to sign in.
          </p>
        </div>
      }
    </main>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {
  private readonly fb = inject(FormBuilder);
  readonly auth = inject(AuthService);

  loginForm = this.fb.nonNullable.group({
    username: ['', Validators.required],
    password: ['', Validators.required],
  });

  error = signal('');

  handleSubmit(): void {
    this.error.set('');

    if (this.loginForm.invalid) {
      this.error.set('Please provide both username and password');
      return;
    }

    const { username, password } = this.loginForm.getRawValue();

    const success = this.auth.login(username, password);
    if (success) {
      this.loginForm.reset();
    } else {
      this.error.set('Please provide both username and password');
    }
  }
}

src/app/pages/profile/profile.component.ts

import {
  Component,
  inject,
  computed,
  ChangeDetectionStrategy,
} from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { PostHogService } from '../../services/posthog.service';

@Component({
  selector: 'app-profile',
  template: `
    <main id="main-content" tabindex="-1">
      <div class="container">
        <h1>User Profile</h1>

        <div class="stats">
          <h2>Your Information</h2>
          <p><strong>Username:</strong> {{ auth.user()?.username }}</p>
          <p>
            <strong>Burrito Considerations:</strong>
            {{ auth.user()?.burritoConsiderations }}
          </p>
        </div>

        <div style="margin-top: 2rem">
          <button
            (click)="triggerTestError()"
            class="btn-primary"
            style="background-color: #dc3545"
          >
            Trigger Test Error (for PostHog)
          </button>
        </div>

        <div style="margin-top: 2rem">
          <h3>Your Burrito Journey</h3>
          <p>{{ journeyMessage() }}</p>
        </div>
      </div>
    </main>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProfileComponent {
  readonly auth = inject(AuthService);
  private readonly posthogService = inject(PostHogService);
  private readonly router = inject(Router);

  journeyMessage = computed(() => {
    const count = this.auth.user()?.burritoConsiderations ?? 0;

    if (count === 0) {
      return "You haven't considered any burritos yet. Visit the Burrito Consideration page to start!";
    } else if (count === 1) {
      return "You've considered the burrito potential once. Keep going!";
    } else if (count < 5) {
      return "You're getting the hang of burrito consideration!";
    } else if (count < 10) {
      return "You're becoming a burrito consideration expert!";
    } else {
      return 'You are a true burrito consideration master!';
    }
  });

  constructor() {
    if (!this.auth.isAuthenticated()) {
      this.router.navigate(['/']);
    }
  }

  triggerTestError(): void {
    try {
      throw new Error('Test error for PostHog error tracking');
    } catch (err) {
      const error = err as Error;
      this.posthogService.posthog.capture('$exception', {
        $exception_message: error.message,
        $exception_type: error.name,
        $exception_stack_trace_raw: error.stack,
      });
      console.error('Captured error:', err);
      alert('Error captured and sent to PostHog!');
    }
  }
}

src/app/services/auth.service.ts

import {
  Injectable,
  signal,
  computed,
  inject,
  PLATFORM_ID,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { PostHogService } from './posthog.service';

export interface User {
  username: string;
  burritoConsiderations: number;
}

@Injectable({ providedIn: 'root' })
export class AuthService {
  private readonly platformId = inject(PLATFORM_ID);
  private readonly posthogService = inject(PostHogService);

  // In-memory user store (matches TanStack behavior)
  private readonly users = new Map<string, User>();

  // Signals for reactive state
  private readonly _user = signal<User | null>(null);

  // Public computed signals
  readonly user = this._user.asReadonly();
  readonly isAuthenticated = computed(() => this._user() !== null);

  constructor() {
    // Initialize from localStorage on browser
    if (isPlatformBrowser(this.platformId)) {
      const storedUsername = localStorage.getItem('currentUser');
      if (storedUsername) {
        const existingUser = this.users.get(storedUsername);
        if (existingUser) {
          this._user.set(existingUser);
        }
      }
    }
  }

  login(username: string, password: string): boolean {
    if (!username || !password) {
      return false;
    }

    // Get or create user in local map (no API call)
    let user = this.users.get(username);
    const isNewUser = !user;

    if (!user) {
      user = { username, burritoConsiderations: 0 };
      this.users.set(username, user);
    }

    this._user.set(user);

    if (isPlatformBrowser(this.platformId)) {
      localStorage.setItem('currentUser', username);
    }

    // PostHog identification (client-side only)
    this.posthogService.posthog.identify(username, {
      username,
      isNewUser,
    });

    this.posthogService.posthog.capture('user_logged_in', {
      username,
      isNewUser,
    });

    return true;
  }

  logout(): void {
    this.posthogService.posthog.capture('user_logged_out');
    this.posthogService.posthog.reset();

    this._user.set(null);

    if (isPlatformBrowser(this.platformId)) {
      localStorage.removeItem('currentUser');
    }
  }

  incrementBurritoConsiderations(): void {
    const currentUser = this._user();
    if (currentUser) {
      const updated = {
        ...currentUser,
        burritoConsiderations: currentUser.burritoConsiderations + 1,
      };
      this.users.set(currentUser.username, updated);
      this._user.set(updated);
    }
  }
}

src/app/services/posthog.service.ts

import { Injectable, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import posthog, { PostHogConfig } from 'posthog-js';

@Injectable({ providedIn: 'root' })
export class PostHogService {
  private readonly platformId = inject(PLATFORM_ID);
  private initialized = false;

  /**
   * The posthog instance. Use this directly to call posthog methods.
   * Returns the actual posthog instance on browser, or a no-op proxy on server.
   */
  get posthog(): typeof posthog {
    if (isPlatformBrowser(this.platformId) && this.initialized) {
      return posthog;
    }
    // Return a no-op proxy for SSR safety
    return new Proxy({} as typeof posthog, {
      get: () => () => undefined,
    });
  }

  init(apiKey: string, options: Partial<PostHogConfig>): void {
    if (isPlatformBrowser(this.platformId) && !this.initialized) {
      posthog.init(apiKey, options);
      this.initialized = true;
    }
  }
}

src/env.d.ts

// Define the type of the environment variables.
declare interface Env {
  readonly NODE_ENV: string;
  readonly NG_APP_POSTHOG_PROJECT_TOKEN: string;
  readonly NG_APP_POSTHOG_HOST: string;
}

// Use import.meta.env.YOUR_ENV_VAR in your code.
declare interface ImportMeta {
  readonly env: Env;
}

src/environments/environment.prod.ts

export const environment = {
  production: true,
  posthogKey: import.meta.env['NG_APP_POSTHOG_PROJECT_TOKEN'] || '<ph_project_token>',
  posthogHost: import.meta.env['NG_APP_POSTHOG_HOST'] || 'https://us.posthog.com',
};

src/environments/environment.production.ts

export const environment = {
  production: true,
  posthogKey: import.meta.env['NG_APP_POSTHOG_PROJECT_TOKEN'] || '<ph_project_token>',
  posthogHost: import.meta.env['NG_APP_POSTHOG_HOST'] || 'https://us.posthog.com',
};

src/environments/environment.ts

export const environment = {
  production: false,
  posthogKey: import.meta.env['NG_APP_POSTHOG_PROJECT_TOKEN'] || '<ph_project_token>',
  posthogHost: import.meta.env['NG_APP_POSTHOG_HOST'] || 'https://us.posthog.com',
};

src/index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Burrito Consideration App</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Consider the potential of burritos">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

src/main.server.ts

import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';

const bootstrap = (context: BootstrapContext) =>
  bootstrapApplication(AppComponent, config, context);

export default bootstrap;

src/main.ts

import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig).catch((err) =>
  console.error(err)
);

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
PostHog
Publisher
PostHog (Official)
Source
PostHog/skills · skills/posthog/integration/skills/angular · commit a5d30e7
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Also distributed in
PostHog/skills

AutoGineer is not affiliated with or endorsed by PostHog.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download integration-angular.zip