Skip to content

PostHog/posthog-github-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

PostHog GitHub Action

Capture CI/CD metrics in PostHog - track workflow duration, success/failure rates, and analyze performance trends with PostHog's full analytics toolkit.

Quick Start

jobs:
  tests:
    # ... your test job

  ci-metrics:
    needs: [tests]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: PostHog/posthog-github-action@v1
        with:
          posthog-token: ${{ secrets.POSTHOG_API_KEY }}
          event: 'ci-metrics'
          capture-run-duration: true
          github-token: ${{ secrets.GITHUB_TOKEN }}
          status-job: 'tests'

This captures run duration, pass/fail status, and GitHub context (repo, branch, commit, actor).

Why PostHog for CI Metrics?

  • Trends & insights - duration over time, failure rates by branch/author
  • Dashboards - build CI health dashboards alongside product metrics
  • Alerts - get notified when builds slow down or failure rates spike
  • Correlation - connect CI data with your product analytics

Inputs

posthog-token

Required Your write-only PostHog API Token (Project API Key).

posthog-api-host

Your PostHog API Host.

Defaults to https://us.i.posthog.com

event

The event name to send to PostHog (e.g., "ci-metrics"). Optional — omit it when you only want to create an annotation. At least one of event or annotation must be provided.

properties

Optional properties to add to the event. These should be passed as a string containing a JSON object.

The action runs JSON.parse(properties) on the input.

capture-run-duration

Set to true to capture run duration via GitHub API. Adds duration_seconds and run metadata.

capture-job-durations

Set to true to capture timing and status for each job in the workflow. Emits one additional event per completed job (named {event}-job, e.g., ci-metrics-job). All events share the same workflow_run group for correlation in PostHog.

github-token

GitHub token for API access. Required when capture-run-duration, capture-job-durations, or status-job is set.

runner

Optional runner label to include in properties (e.g., 'depot').

status-job

Job name to check for workflow status. Captures that job's conclusion (success, failure, cancelled) as conclusion.

Note: Your metrics job must needs the target job and use if: always() to run even on failure.

annotation

Create a PostHog annotation with this text (e.g., "Deployed to production"). Can be used standalone or alongside event capture.

annotation-token

API key for the annotations REST API — a personal API key with the annotation:write scope. Defaults to posthog-token.

Event ingestion uses a project API key, while the annotations REST API needs a personal key, so the two auth schemes differ. For annotation-only usage you can just set posthog-token to the personal key. When you capture an event and create an annotation in the same step, set posthog-token to the project key and annotation-token to the personal key.

annotation-scope

Annotation scope: 'project' (default) or 'organization'.

annotation-hidden

Set to 'true' to hide the annotation from the PostHog UI (charts and the annotations list) while keeping it readable via the API and MCP. Use for high-frequency markers like deployments that would otherwise crowd the UI. Defaults to 'false'.

annotation-api-host

Host for the PostHog app API used to create annotations — https://us.posthog.com (default), https://eu.posthog.com, or your own host for a self-hosted instance. This is distinct from posthog-api-host, which is the event ingestion host (*.i.posthog.com); the annotations endpoint lives on the app host. The host is not restricted to PostHog Cloud, so self-hosted deployments work.

annotation-project-id

Project to create the annotation in. Defaults to '@current' (the project the token belongs to). Set an explicit numeric id for deterministic targeting.

annotation-dedupe

Set to 'true' to skip creating the annotation when a matching one already exists, making re-runs idempotent (e.g. a GitHub "Re-run jobs" won't duplicate a deploy marker). The match is by annotation-dedupe-key, or the full annotation text if no key is set. Defaults to 'false'.

annotation-dedupe-key

Content prefix used to detect an existing annotation when annotation-dedupe is 'true'. Defaults to the full annotation text. Use a stable prefix (e.g. "Deployed acme/app@abc1234 to prod") so a volatile suffix — like a list of PR numbers — doesn't defeat deduplication.

Automatically Included Properties

The following GitHub context properties are automatically added to every event:

  • sha - The commit SHA
  • ref - The branch or tag ref
  • workflow - The workflow name
  • runNumber - The run number
  • runId - The run ID
  • repository - The repository name
  • repositoryOwner - The repository owner
  • actor - The user who triggered the workflow
  • actor_type - "bot" if actor ends in [bot] or matches a known bot account (currently Copilot), otherwise "human". Useful for slicing CI metrics by bot vs. human-driven runs.
  • eventName - The event that triggered the workflow

When capture-run-duration is enabled:

  • duration_seconds - Time elapsed since run started
  • url - URL to the run
  • attempt - The attempt number
  • started_at - ISO 8601 timestamp

When status-job is set:

  • conclusion - Referenced job's conclusion (success, failure, cancelled)

When capture-job-durations is enabled, each per-job event ({event}-job) includes:

  • name - The job's display name
  • duration_seconds - Time from job start to completion
  • conclusion - Job result (success, failure, cancelled, skipped)
  • started_at - ISO 8601 timestamp
  • completed_at - ISO 8601 timestamp
  • runner - The runner that executed the job

Groups & Correlation

All events are tagged with a workflow_run group (owner/repo/run_id) for correlation in PostHog.

When capture-job-durations is enabled, group properties are also set via groupIdentify:

workflow_run: PostHog/posthog/12345
├── group properties: { conclusion: 'success' }     ← only with capture-job-durations
│
├── event: ci-metrics                               ← run-level metrics
│   └── { duration_seconds: 1080, conclusion: 'success', ... }
│
├── event: ci-metrics-job                           ← per-job metrics
│   └── { name: 'Build', duration_seconds: 120, conclusion: 'success', ... }
│
└── event: ci-metrics-job
    └── { name: 'Test', duration_seconds: 300, conclusion: 'success', ... }

This enables:

  • Filter job events by workflow outcome - use group property workflow_run.conclusion
  • See all jobs in a run - filter by workflow_run = owner/repo/run_id
  • Correlate across events - breakdown by group in insights

Example Usage

Custom event with properties

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_API_KEY }}
    event: "deploy-completed"
    properties: '{"environment": "production"}'

With run duration

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_API_KEY }}
    event: "ci-metrics"
    capture-run-duration: true
    github-token: ${{ secrets.GITHUB_TOKEN }}

With per-job metrics

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_API_KEY }}
    event: "ci-metrics"
    capture-run-duration: true
    capture-job-durations: true
    github-token: ${{ secrets.GITHUB_TOKEN }}
    status-job: 'Tests'

Using with EU Cloud

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_API_KEY }}
    posthog-api-host: "https://eu.i.posthog.com"
    event: "ci-metrics"
    capture-run-duration: true
    github-token: ${{ secrets.GITHUB_TOKEN }}

Create an annotation on deploy

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_ANNOTATION_API_KEY }}
    annotation: "Deployed ${{ github.repository }}@${{ github.sha }} to production"
    annotation-scope: organization

Hidden, idempotent deploy marker (readable via API/MCP, hidden from the UI)

- uses: PostHog/posthog-github-action@v1
  with:
    posthog-token: ${{ secrets.POSTHOG_ANNOTATION_API_KEY }}
    annotation: "Deployed ${{ github.repository }}@${{ github.sha }} to prod-us"
    annotation-hidden: true
    annotation-project-id: "2"
    # Re-running the workflow won't create a duplicate marker for this repo@sha+env
    annotation-dedupe: true
    annotation-dedupe-key: "Deployed ${{ github.repository }}@${{ github.sha }} to prod-us"

Complete Workflow Example

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  ci-metrics:
    needs: [test]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: PostHog/posthog-github-action@v1
        with:
          posthog-token: ${{ secrets.POSTHOG_API_KEY }}
          event: "ci-metrics"
          capture-run-duration: true
          capture-job-durations: true
          github-token: ${{ secrets.GITHUB_TOKEN }}
          status-job: 'test'

Development

Prerequisites

  • Node.js 20+
  • act for local testing (requires Docker)

Setup

# Install dependencies
npm install

# Copy secrets template and add your PostHog API token
cp .secrets.example .secrets

Building

This action uses @vercel/ncc to bundle all dependencies into a single file. You must rebuild before committing changes:

npm run build

This compiles index.js and all dependencies into dist/index.js.

Testing Locally

Test the action locally using act:

# Dry run (validates workflow without running)
npm run test:dry-run

# Full test (sends real event to PostHog)
npm test

Note: act requires Docker to be running.

Releasing

1. Build the Bundle

Always rebuild before releasing to ensure the dist folder is up to date:

npm run build

2. Commit and Merge

# Update version in package.json manually
git add package.json dist/
git commit -m "1.x.x"
# Create PR and merge to main

3. Tag the Release

git checkout main && git pull
git tag v1.x.x
git push origin v1.x.x

The release workflow creates the GitHub Release and updates the v1 tag automatically.

License

MIT

About

Capture CI/CD metrics in PostHog - workflow duration, success rates, and performance trends

Topics

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages