Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PostHog Data Cleanup Tool

CLI tool to audit and remove person properties from PostHog. Built for PII data cleanup when PostHog doesn't support bulk property removal via the UI.

Features

  • Audit -- Scan all person profiles for any specified property and export CSV reports
  • Cleanup -- Remove properties from person profiles via PostHog's batch API ($unset)
  • PII detection -- Automatically flags distinct_ids that contain emails, phone numbers, or names
  • Safe defaults -- --dry-run to preview, --test to target a single person, --group-a-only to skip PII-only distinct_ids
  • Multi-property support -- Audit or clean up multiple properties in a single run
  • Rate-limit handling -- Automatic retry with exponential backoff on HTTP 429 responses

Prerequisites

  • Python 3.8+
  • A PostHog account with API access
  • A Personal API Key with person and query read scopes
  • Your Project API Key (starts with phc_)

Installation

git clone <repository-url>
cd PosthogDataCleanupTool

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

cp .env.example .env

Then edit .env with your credentials (see Configuration below).

Configuration

Create a .env file from the example:

POSTHOG_PERSONAL_API_KEY=phx_your_personal_api_key_here
POSTHOG_PROJECT_API_KEY=phc_your_project_api_key_here
POSTHOG_PROJECT_ID=your_project_id_here
POSTHOG_API_BASE_URL=https://us.posthog.com

Where to find each value

Variable Where to find it Notes
POSTHOG_PERSONAL_API_KEY PostHog > Settings > Personal API Keys Must have person and query read scopes. Used for reading person profiles and events.
POSTHOG_PROJECT_API_KEY PostHog > Project Settings > Project API Key Starts with phc_. Used for sending $unset events via the batch API.
POSTHOG_PROJECT_ID PostHog > Project Settings Numeric project ID shown in settings or in any PostHog URL.
POSTHOG_API_BASE_URL Depends on your hosting region https://us.posthog.com (US Cloud), https://eu.posthog.com (EU Cloud), or your self-hosted URL.

Usage

Audit -- find who has a property

# Audit a single property
python audit.py <property>

# Audit multiple properties
python audit.py <property1> <property2> <property3>

This creates a timestamped directory under audits/ with:

  • all_persons.csv -- every person who has the property
  • persons_no_safe_distinct_id.csv -- persons whose only distinct_ids are PII (need special handling)
  • persons_with_pii_in_distinct_ids.csv -- persons with PII in any distinct_id
  • summary.json -- machine-readable summary

CSV columns: distinct_id, uuid, <property>, has_safe_id, has_pii_in_ids

Cleanup -- remove a property

# Preview what would be removed (no changes made)
python cleanup.py <property> --dry-run

# Test on a single person first
python cleanup.py <property> --test <distinct_id>

# Remove from persons with safe (non-PII) distinct_ids only
python cleanup.py <property> --group-a-only

# Remove from ALL persons who have the property
python cleanup.py <property>

# Remove multiple properties at once
python cleanup.py <property1> <property2> --dry-run

Recommended workflow

  1. Audit first -- python audit.py <property> to understand the scope
  2. Review the CSVs -- check persons_no_safe_distinct_id.csv for edge cases
  3. Dry run -- python cleanup.py <property> --dry-run to preview
  4. Test one person -- python cleanup.py <property> --test <some_distinct_id>
  5. Clean up safe group -- python cleanup.py <property> --group-a-only
  6. Clean up remaining -- python cleanup.py <property> (after handling PII-only distinct_ids)
  7. Verify -- python audit.py <property> again to confirm removal

CLI flags

Flag Description
--dry-run Preview affected persons without making any changes
--test DISTINCT_ID Send $unset to a single person for testing
--group-a-only Only process persons that have at least one safe (non-PII) distinct_id

How it works

  1. Audit queries GET /api/projects/{id}/persons with a property filter using the Personal API Key. It paginates through all results and classifies each person's distinct_ids as safe (UUIDs, numeric IDs) or PII (emails, phone numbers, name-like strings).

  2. Cleanup sends $set events with a $unset payload via POST /batch/ using the Project API Key. PostHog processes these events asynchronously to remove the specified properties from person profiles.

  3. The $unset operation removes only the specified properties. The person profile, their events, and all other properties remain untouched.

  4. Persons are processed in batches of 500, with automatic retry and exponential backoff on rate limits.

Warnings

  • Cleanup is irreversible. Once properties are unset, there is no undo. Always run --dry-run first.
  • PostHog processes events asynchronously. After cleanup, wait a few minutes before re-auditing to verify.
  • PII-only distinct_ids need care. Persons flagged in persons_no_safe_distinct_id.csv have no UUID-based distinct_id -- sending events to their PII-based distinct_id may re-associate PII. Handle these separately.
  • This tool does not delete events. It only removes properties from person profiles. Event-level properties with PII require a separate approach (e.g., PostHog's data deletion request).
  • Rate limits apply. The tool handles HTTP 429 responses automatically, but large datasets may take time.

Project structure

PosthogDataCleanupTool/
├── config.py            # Shared configuration -- loads .env and defines constants
├── api_client.py        # PostHog API helpers, PII detection, retry logic
├── audit.py             # Audit command -- scans persons and exports CSV reports
├── cleanup.py           # Cleanup command -- sends $unset events to remove properties
├── requirements.txt     # Python dependencies
├── .env.example         # Template for environment variables
├── .gitignore           # Git ignore rules
└── README.md            # This file

About

CLI tool to audit and bulk-remove person properties from PostHog. Built for PII cleanup via the batch API with $unset.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages