---
title: "PostHog Connector"
description: "Complete PostHog integration guide for syncing product analytics, feature flags, and user behavior data with Brevo through Tajo."
url: https://tajo.io/docs/connectors/custom/posthog/
markdown: https://tajo.io/docs/connectors/custom/posthog.md
lang: en-US
robots: noindex
---

# PostHog Connector

Connector status: Planned Not built yet. Tajo does not run this connector today.

| Source field | Destination field | Sample value |
| --- | --- | --- |
| `record.id` | `source_id` | `record_1042` |
| `record.updated_at` | `updated_at` | `2026-10-18T08:00:00Z` |
| `record.value` | `value` | `sample_value` |

Connect PostHog to Brevo through Tajo to sync product analytics data, user behavior events, and cohort memberships for data-driven marketing campaigns and personalized customer engagement.

## Overview

| Property | Value |
| --- | --- |
| **Platform** | PostHog |
| **Category** | Product Analytics (Custom) |
| **Setup Complexity** | Medium |
| **Official Integration** | No |
| **Data Synced** | Events, Persons, Feature Flags, Cohorts |
| **Auth Method** | Personal API Key / Project Token |

## Features

- **Event sync** - Forward PostHog analytics events to Brevo for behavioral targeting
- **Person profile sync** - Sync PostHog person properties to Brevo contact attributes
- **Cohort-based segmentation** - Map PostHog cohorts to Brevo contact lists
- **Feature flag sync** - Segment contacts by enabled feature flags
- **Funnel data** - Use conversion funnel data for targeted re-engagement
- **Session replay metadata** - Enrich contacts with session engagement metrics

## Prerequisites

Before you begin, ensure you have:

1. A PostHog account (Cloud or self-hosted)
2. A Personal API Key from [PostHog Settings](https://app.posthog.com/settings/user-api-keys)
3. Your Project API Key (token) from [Project Settings](https://app.posthog.com/project/settings)
4. A Brevo account with API access
5. A Tajo account with connector permissions

## Authentication

### Personal API Key (Private Endpoints)

```bash
# Generate at https://app.posthog.com/settings/user-api-keys
export POSTHOG_PERSONAL_API_KEY=phx_your_personal_api_key
export POSTHOG_PROJECT_TOKEN=phc_your_project_token
export POSTHOG_HOST=https://us.posthog.com  # or https://eu.posthog.com
export TAJO_API_KEY=your_tajo_api_key
export BREVO_API_KEY=your_brevo_api_key
```

```javascript
// Private API endpoints use Bearer authentication
const headers = {
  'Authorization': `Bearer ${process.env.POSTHOG_PERSONAL_API_KEY}`,
  'Content-Type': 'application/json'
};

// Public endpoints use the project token
const publicHeaders = {
  'Content-Type': 'application/json'
};
// Token is passed in the request body for public endpoints
```

API Key Security

Personal API keys provide full account access. Never expose them in client-side code. Use the Project API Key (token) for public endpoints like event capture and feature flag evaluation.

## Configuration

### Basic Setup

```yaml
connectors:
  posthog:
    enabled: true
    host: "${POSTHOG_HOST}"
    personal_api_key: "${POSTHOG_PERSONAL_API_KEY}"
    project_token: "${POSTHOG_PROJECT_TOKEN}"
    project_id: "12345"

    sync:
      persons: true
      events: true
      cohorts: true
      feature_flags: true
      schedule: "0 */3 * * *"  # Every 3 hours

    event_filters:
      - "$pageview"
      - "purchase_completed"
      - "signup_completed"
      - "feature_used"

    lists:
      all_users: 25
      active_users: 26
      power_users: 27
```

### Field Mapping

```yaml
field_mapping:
  email: email
  $name: FIRSTNAME
  $browser: BROWSER
  $os: OS
  $initial_referrer: REFERRAL_SOURCE
  total_events: EVENT_COUNT
  last_seen: LAST_ACTIVE_DATE
  signup_date: SIGNUP_DATE
  plan: SUBSCRIPTION_PLAN
  company: COMPANY
  cohort_names: POSTHOG_COHORTS
```

## API Endpoints

| Endpoint | Method | Description |
| --- | --- | --- |
| `{host}/api/projects/{id}/persons/` | GET | List persons |
| `{host}/api/projects/{id}/events/` | GET | List events |
| `{host}/api/projects/{id}/cohorts/` | GET | List cohorts |
| `{host}/api/projects/{id}/feature_flags/` | GET | List feature flags |
| `{host}/api/projects/{id}/feature_flags/evaluation/` | POST | Evaluate flags |
| `{host}/api/projects/{id}/insights/` | GET | List saved insights |
| `{host}/api/projects/{id}/query/` | POST | Run HogQL queries |
| `{host}/i/v0/e` | POST | Capture events (public) |
| `{host}/decide/?v=3` | POST | Feature flag decisions (public) |

## Code Examples

### Initialize Connector

```javascript
import { TajoClient } from '@tajo/sdk';

const tajo = new TajoClient({
  apiKey: process.env.TAJO_API_KEY,
  brevoApiKey: process.env.BREVO_API_KEY
});

await tajo.connectors.connect('posthog', {
  host: process.env.POSTHOG_HOST,
  personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,
  projectToken: process.env.POSTHOG_PROJECT_TOKEN,
  projectId: '12345'
});
```

### Sync Persons to Brevo

```javascript
// Paginate through PostHog persons
let nextUrl = `${posthogHost}/api/projects/${projectId}/persons/?` +
  new URLSearchParams({ limit: '100' });

while (nextUrl) {
  const response = await fetch(nextUrl, {
    headers: {
      'Authorization': `Bearer ${process.env.POSTHOG_PERSONAL_API_KEY}`
    }
  });

  const data = await response.json();

  for (const person of data.results) {
    const email = person.properties.$email || person.properties.email;
    if (!email) continue;

    await tajo.contacts.sync({
      email,
      attributes: {
        FIRSTNAME: person.properties.$name || person.properties.name,
        LAST_ACTIVE_DATE: person.properties.$last_seen,
        SIGNUP_DATE: person.created_at,
        EVENT_COUNT: person.properties.$event_count,
        BROWSER: person.properties.$browser,
        OS: person.properties.$os,
        REFERRAL_SOURCE: person.properties.$initial_referrer
      },
      listIds: [25]
    });
  }

  nextUrl = data.next;
}
```

### Sync Cohorts as Brevo Lists

```javascript
// Get PostHog cohorts and sync members to Brevo lists
const cohortsResponse = await fetch(
  `${posthogHost}/api/projects/${projectId}/cohorts/`,
  {
    headers: {
      'Authorization': `Bearer ${process.env.POSTHOG_PERSONAL_API_KEY}`
    }
  }
);

const { results: cohorts } = await cohortsResponse.json();

for (const cohort of cohorts) {
  // Get persons in this cohort
  const personsResponse = await fetch(
    `${posthogHost}/api/projects/${projectId}/cohorts/${cohort.id}/persons/`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.POSTHOG_PERSONAL_API_KEY}`
      }
    }
  );

  const { results: persons } = await personsResponse.json();

  for (const person of persons) {
    const email = person.properties.$email || person.properties.email;
    if (email) {
      await tajo.contacts.update(email, {
        attributes: {
          POSTHOG_COHORTS: cohort.name
        }
      });
    }
  }
}
```

### Run HogQL Queries for Analytics

```javascript
// Use HogQL to query analytics data
const queryResponse = await fetch(
  `${posthogHost}/api/projects/${projectId}/query/`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.POSTHOG_PERSONAL_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      query: {
        kind: 'HogQLQuery',
        query: `
          SELECT
            properties.$email AS email,
            count() AS event_count,
            max(timestamp) AS last_event
          FROM events
          WHERE event = 'purchase_completed'
            AND timestamp > now() - interval 30 day
          GROUP BY email
          HAVING event_count > 3
          ORDER BY event_count DESC
          LIMIT 1000
        `
      }
    })
  }
);

const queryResult = await queryResponse.json();

for (const row of queryResult.results) {
  await tajo.contacts.update(row[0], {
    attributes: {
      PURCHASE_COUNT_30D: row[1],
      LAST_PURCHASE: row[2]
    }
  });
}
```

## Rate Limits

| Endpoint Category | Limit | Notes |
| --- | --- | --- |
| Analytics endpoints | 240/min, 1,200/hr | GET persons, events, insights |
| Query endpoint | 2,400/hr | HogQL and custom queries |
| Feature flag evaluation | 600/min | Local evaluation endpoint |
| CRUD endpoints | 480/min, 4,800/hr | Create, update, delete operations |
| Public endpoints (capture) | Unlimited | Event capture, flag decisions |

Batch Exports

For large-scale event data exports, use PostHog’s batch exports feature instead of the API. Batch exports support S3, BigQuery, Snowflake, and other destinations.

## Troubleshooting

| Issue | Cause | Solution |
| --- | --- | --- |
| 401 Unauthorized | Invalid API key | Verify Personal API Key in settings |
| 400 Invalid project | Wrong project ID | Check project ID in PostHog URL |
| Empty persons list | No identified users | Ensure `posthog.identify()` is called |
| Missing properties | Properties not set | Verify `$set` calls in client SDK |
| Rate limit 429 | Too many requests | Implement backoff, check rate limit headers |

### Debug Mode

```yaml
connectors:
  posthog:
    debug: true
    log_level: verbose
    log_queries: true
    log_sync: true
```

## Best Practices

1. **Identify users** - Always call `posthog.identify()` with email to enable person sync
2. **Use cohorts for segmentation** - Leverage PostHog’s behavioral cohorts for Brevo lists
3. **Batch API requests** - Use pagination and batch processing for large datasets
4. **Use HogQL for complex queries** - Extract custom analytics with SQL-like queries
5. **Set up batch exports** - For large data volumes, prefer batch exports over API polling
6. **Filter relevant events** - Sync only marketing-relevant events to reduce noise

## Security

- **Personal API Key** - Scoped Bearer token authentication
- **Project token** - Public token for client-side operations only
- **HTTPS only** - All endpoints require TLS encryption
- **IP allowlisting** - Available for self-hosted instances
- **Key scoping** - Create API keys with specific permission scopes
- **GitHub secret scanning** - PostHog partners with GitHub for leaked key detection

## Related Resources

- [Optimizely Connector](https://tajo.io/docs/connectors/custom/optimizely)
- [Segment Connector](https://tajo.io/docs/connectors/custom/segment)
- [Snowflake Connector](https://tajo.io/docs/connectors/custom/snowflake)
- [PostHog API Documentation](https://posthog.com/docs/api)

## Open-Source Implementation Map

No official open-source repository was found in the current Tajo connector catalog for PostHog. Keep this page focused on the verified public API contract and vendor documentation until an official schema, SDK, MCP server, or public integration repository is available.

### Tajo Revamp Checklist

- Verify authentication and scope requirements against the vendor documentation before each connector release.
- Document primary sync objects, external IDs, pagination strategy, and rate limits explicitly.
- Add smoke tests from public API examples rather than undocumented behavior.
- Capture webhook signature verification and replay protection when the vendor supports webhooks.
- Record gaps where no official public repository or schema exists so future maintainers know what still needs source-backed validation.
