# PostHog

> Drive PostHog product analytics from a workflow: send events and person properties in, read events, people and saved insights back out, run SQL over any of it, roll feature flags out and back, and mark releases on your charts. Works with PostHog Cloud in either region and with a self-hosted install.

App · Analytics · 20 actions. Web page: https://docs.lodol.com/docs/integrations/posthog

## Actions

### Capture event

Record a product-analytics event against a person, with any properties you want to break it down by later. The person is named by a distinct ID - your own user ID, an email, anything stable - and PostHog creates them the first time it sees one. Events are queued for ingestion rather than stored on the spot, so an event captured here takes a moment to appear in PostHog and will not reliably be found by a 'List events' step immediately afterwards.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Event name (`event`, text, required): What happened, in your own words - 'signed up', 'invoice paid'. Reuse the same name every time so it can be counted.
- Person (`distinct_id`, text, required): The distinct ID of the person this happened to - your user ID, or their email. PostHog creates the person the first time it sees one.
- Properties (`properties`, object): Extra fields to record with the event, which you can then filter and break down by in PostHog.
- When it happened (`timestamp`, date and time): When the event happened. Leave blank for now. Use it when you are recording something that already happened, so it lands in the right place on a chart.

**Outputs**

- `distinct_id` (text)
- `event` (text)
- `project_id` (number)
- `properties` (object)
- `status` (text)
- `timestamp` (text)

**Example output**

```json
{
  "distinct_id": "user_1042",
  "event": "signed up",
  "project_id": 12345,
  "properties": {
    "plan": "pro"
  },
  "status": "queued",
  "timestamp": "2026-09-08T09:15:00+00:00"
}
```

### Create annotation

Mark a moment on this project's charts with a note, so a step in a graph has an explanation beside it - a deploy, a campaign, an outage. Shows across the whole project by default; you can pin it to one dashboard or one insight instead.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Note (`content`, text, required): What happened, shown on the chart at this moment - 'Deployed v2.4', 'Pricing page changed'.
- When it happened (`date_marker`, date and time): The moment to mark on the chart. Defaults to now on a new annotation.
- Show on (`scope`, text): Which charts carry the marker. Defaults to the whole project. One of: `project` (The whole project), `organization` (Every project in the organisation), `dashboard` (One dashboard), `dashboard_item` (One insight).
- Dashboard (`dashboard_id`, text): The dashboard to attach it to. Only used when 'Show on' is set to one dashboard.
- Insight ID (`insight_id`, text): The insight to attach it to, as its numeric ID. 'List insights' returns it as 'id'. Only used when 'Show on' is set to one insight.
- Emoji (`emoji`, text): Shown on the chart instead of the default marker, such as 🚀.
- Hide in PostHog (`hidden_in_user_interface`, true/false): Keep the annotation out of PostHog's charts and lists while leaving it readable over the API. For high-frequency markers that would otherwise crowd a chart.
- Created by (`creation_type`, text): Whether PostHog should show this as written by a person or by a bot. Defaults to a person. One of: `USR` (A person), `GIT` (A bot or deployment).

**Outputs**

- `content` (text)
- `created_at` (text)
- `created_by` (object)
- `creation_type` (text)
- `dashboard_id` (number)
- `dashboard_item` (number)
- `dashboard_name` (text)
- `date_marker` (text)
- `deleted` (true/false)
- `emoji` (text)
- `hidden_in_user_interface` (true/false)
- `id` (number)
- `insight_derived_name` (text)
- `insight_name` (text)
- `insight_short_id` (text)
- `scope` (text)
- `updated_at` (text)

**Example output**

```json
{
  "content": "Deployed the rebuilt checkout",
  "created_at": "2026-09-05T16:01:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "creation_type": "USR",
  "dashboard_id": null,
  "dashboard_item": null,
  "date_marker": "2026-09-05T16:00:00+00:00",
  "deleted": false,
  "emoji": "\ud83d\ude80",
  "hidden_in_user_interface": false,
  "id": 3390,
  "scope": "project",
  "updated_at": "2026-09-05T16:01:00+00:00"
}
```

### Create dashboard

Create a dashboard in this project. A new one starts empty; name an existing dashboard to duplicate and PostHog copies its charts across, which is how to stand up a per-customer or per-release board from a template you keep by hand.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Name (`name`, text, required): What to call the dashboard.
- Description (`description`, text): What the dashboard is for.
- Pinned (`pinned`, true/false): Pin it to the top of the dashboard list and into PostHog's sidebar.
- Tags (`tags`, list): Labels to file the dashboard under.
- Copy from (`duplicate_of_dashboard_id`, text): An existing dashboard to copy the charts from. Leave blank for an empty one.

**Outputs**

- `created_at` (text)
- `created_by` (object)
- `creation_mode` (text)
- `deleted` (true/false)
- `description` (text)
- `effective_privilege_level` (number)
- `file_system_path` (text)
- `filters` (object)
- `folder` (text)
- `id` (number)
- `is_shared` (true/false)
- `last_accessed_at` (text)
- `last_refresh` (text)
- `name` (text)
- `pinned` (true/false)
- `restriction_level` (number)
- `tags` (list)
- `team_id` (number)
- `tiles` (list)
- `user_access_level` (text)

**Example output**

```json
{
  "created_at": "2026-07-20T09:00:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "creation_mode": "default",
  "deleted": false,
  "description": "How the new checkout is doing.",
  "folder": "Unfiled/Dashboards",
  "id": 4102,
  "is_shared": false,
  "name": "Checkout health",
  "pinned": true,
  "restriction_level": 21,
  "tags": [
    "checkout"
  ],
  "team_id": 12345,
  "tiles": []
}
```

### Create feature flag

Add a feature flag your code can check by key. Give it a rollout percentage to release it to a share of people, or a list of variants to split them between versions. With no targeting it is created for everyone. Anything more elaborate - property filters, cohort targeting - goes in the advanced Targeting field as PostHog's own filters object.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Key (`key`, text, required): The identifier your code checks, such as 'new-checkout'. This is what a PostHog SDK asks for by name.
- Description (`name`, text): What the flag is for, shown beside it in PostHog. Stored in PostHog's 'name' field, which is where it keeps a flag's description.
- Enabled (`active`, true/false): Whether the flag evaluates at all. A disabled flag is off for everyone regardless of its targeting.
- Rollout percentage (`rollout_percentage`, number): What share of people the flag is on for, 0-100. Leave blank on a new flag for everyone. Cannot be combined with the advanced 'Targeting' field below. From 0.0 to 100.0.
- Variants (`variants`, list): Turns this into a multivariate flag. A list of objects, each with "key", an optional "name" and a "rollout_percentage". The percentages have to add up to 100.
- Targeting (advanced) (`filters`, object): PostHog's whole targeting object - release condition groups with property filters, and any variant configuration. Use this to carry targeting over from another flag or from PostHog's own API. Cannot be combined with the rollout percentage and variants fields above.
- Tags (`tags`, list): Labels to file the flag under in PostHog.
- Evaluate in (`evaluation_runtime`, text): Where PostHog will let this flag be read. Defaults to anywhere. One of: `all` (Anywhere), `server` (Server-side SDKs only), `client` (Client-side SDKs only).
- Roll out by (`bucketing_identifier`, text): What the rollout percentage is measured against. Device ID cannot be combined with 'Keep the same value after sign-in'. One of: `distinct_id` (User ID), `device_id` (Device ID).
- Keep the same value after sign-in (`ensure_experience_continuity`, true/false): Hold a person's flag value steady as they go from anonymous to identified, so a feature does not appear or disappear when they log in.

**Outputs**

- `active` (true/false)
- `analytics_dashboards` (list)
- `archived` (true/false)
- `bucketing_identifier` (text)
- `can_edit` (true/false)
- `created_at` (text)
- `created_by` (object)
- `deleted` (true/false)
- `ensure_experience_continuity` (true/false)
- `evaluation_contexts` (list)
- `evaluation_runtime` (text)
- `experiment_set` (list)
- `filters` (object)
- `has_encrypted_payloads` (true/false)
- `id` (number)
- `is_eligible_for_experiment` (true/false)
- `is_remote_configuration` (true/false)
- `is_used_in_replay_settings` (true/false)
- `key` (text)
- `last_called_at` (text)
- `last_modified_by` (object)
- `name` (text)
- `status` (text)
- `tags` (list)
- `updated_at` (text)
- `usage_dashboard` (number)
- `version` (number)

**Example output**

```json
{
  "active": true,
  "archived": false,
  "bucketing_identifier": "distinct_id",
  "can_edit": true,
  "created_at": "2026-07-19T13:45:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "deleted": false,
  "ensure_experience_continuity": false,
  "evaluation_runtime": "all",
  "experiment_set": [],
  "filters": {
    "groups": [
      {
        "properties": [],
        "rollout_percentage": 25
      }
    ]
  },
  "id": 6120,
  "is_eligible_for_experiment": false,
  "key": "new-checkout",
  "name": "The rebuilt checkout flow",
  "status": "ACTIVE",
  "tags": [
    "checkout"
  ],
  "updated_at": "2026-09-05T16:02:00+00:00",
  "version": 3
}
```

### Delete annotation

Delete an annotation, taking its marker off every chart it showed on. PostHog does not erase annotations - it marks them deleted. Returns the annotation as it was.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Annotation ID (`annotation_id`, text, required): The annotation's numeric ID. 'List annotations' returns it as 'id'.

**Outputs**

- `content` (text)
- `created_at` (text)
- `created_by` (object)
- `creation_type` (text)
- `dashboard_id` (number)
- `dashboard_item` (number)
- `dashboard_name` (text)
- `date_marker` (text)
- `deleted` (true/false)
- `emoji` (text)
- `hidden_in_user_interface` (true/false)
- `id` (number)
- `insight_derived_name` (text)
- `insight_name` (text)
- `insight_short_id` (text)
- `scope` (text)
- `updated_at` (text)

**Example output**

```json
{
  "content": "Deployed the rebuilt checkout",
  "created_at": "2026-09-05T16:01:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "creation_type": "USR",
  "dashboard_id": null,
  "dashboard_item": null,
  "date_marker": "2026-09-05T16:00:00+00:00",
  "deleted": true,
  "emoji": "\ud83d\ude80",
  "hidden_in_user_interface": false,
  "id": 3390,
  "scope": "project",
  "updated_at": "2026-09-05T16:01:00+00:00"
}
```

### Delete dashboard

Delete a dashboard. PostHog does not erase dashboards - it marks them deleted. The charts on it survive by default and stay findable in the insight list; turn on 'Delete its charts too' to remove the ones that were only on this dashboard. Returns the dashboard as it was.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Dashboard (`dashboard_id`, text, required): The dashboard to delete. 'List dashboards' returns its ID as 'id'.
- Delete its charts too (`delete_insights`, true/false): Also delete the insights that were only on this dashboard. Off by default, so the charts survive it. Default: `false`.

**Outputs**

- `created_at` (text)
- `created_by` (object)
- `creation_mode` (text)
- `deleted` (true/false)
- `description` (text)
- `effective_privilege_level` (number)
- `file_system_path` (text)
- `filters` (object)
- `folder` (text)
- `id` (number)
- `is_shared` (true/false)
- `last_accessed_at` (text)
- `last_refresh` (text)
- `name` (text)
- `pinned` (true/false)
- `restriction_level` (number)
- `tags` (list)
- `team_id` (number)
- `tiles` (list)
- `user_access_level` (text)

**Example output**

```json
{
  "created_at": "2026-07-20T09:00:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "creation_mode": "default",
  "deleted": true,
  "description": "How the new checkout is doing.",
  "folder": "Unfiled/Dashboards",
  "id": 4102,
  "is_shared": false,
  "name": "Checkout health",
  "pinned": true,
  "restriction_level": 21,
  "tags": [
    "checkout"
  ],
  "team_id": 12345,
  "tiles": []
}
```

### Delete feature flag

Delete a feature flag. PostHog does not erase flags - it marks them deleted, which stops them being evaluated and takes them out of the flag list, and frees the key for reuse. Returns the flag as it was.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Feature flag (`feature_flag_id`, text, required): The flag's numeric ID. 'List feature flags' returns it as 'id'. You can also paste the PostHog URL of the flag.

**Outputs**

- `active` (true/false)
- `analytics_dashboards` (list)
- `archived` (true/false)
- `bucketing_identifier` (text)
- `can_edit` (true/false)
- `created_at` (text)
- `created_by` (object)
- `deleted` (true/false)
- `ensure_experience_continuity` (true/false)
- `evaluation_contexts` (list)
- `evaluation_runtime` (text)
- `experiment_set` (list)
- `filters` (object)
- `has_encrypted_payloads` (true/false)
- `id` (number)
- `is_eligible_for_experiment` (true/false)
- `is_remote_configuration` (true/false)
- `is_used_in_replay_settings` (true/false)
- `key` (text)
- `last_called_at` (text)
- `last_modified_by` (object)
- `name` (text)
- `status` (text)
- `tags` (list)
- `updated_at` (text)
- `usage_dashboard` (number)
- `version` (number)

**Example output**

```json
{
  "active": true,
  "archived": false,
  "bucketing_identifier": "distinct_id",
  "can_edit": true,
  "created_at": "2026-07-19T13:45:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "deleted": true,
  "ensure_experience_continuity": false,
  "evaluation_runtime": "all",
  "experiment_set": [],
  "filters": {
    "groups": [
      {
        "properties": [],
        "rollout_percentage": 25
      }
    ]
  },
  "id": 6120,
  "is_eligible_for_experiment": false,
  "key": "new-checkout",
  "name": "The rebuilt checkout flow",
  "status": "ACTIVE",
  "tags": [
    "checkout"
  ],
  "updated_at": "2026-09-05T16:02:00+00:00",
  "version": 3
}
```

### Enable or disable feature flag

Turn a feature flag on or off and change nothing else - targeting, variants, payloads and tags are all left as they are. PostHog refuses to enable an archived flag, and refuses to disable one that another active flag depends on. Turning a flag off stops it evaluating for everyone, including any experiment or session replay setting attached to it.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Feature flag (`feature_flag_id`, text, required): The flag's numeric ID. 'List feature flags' returns it as 'id'. You can also paste the PostHog URL of the flag.
- Enabled (`enabled`, true/false, required): On to enable the flag, off to disable it.

**Outputs**

- `active` (true/false)
- `analytics_dashboards` (list)
- `archived` (true/false)
- `bucketing_identifier` (text)
- `can_edit` (true/false)
- `created_at` (text)
- `created_by` (object)
- `deleted` (true/false)
- `ensure_experience_continuity` (true/false)
- `evaluation_contexts` (list)
- `evaluation_runtime` (text)
- `experiment_set` (list)
- `filters` (object)
- `has_encrypted_payloads` (true/false)
- `id` (number)
- `is_eligible_for_experiment` (true/false)
- `is_remote_configuration` (true/false)
- `is_used_in_replay_settings` (true/false)
- `key` (text)
- `last_called_at` (text)
- `last_modified_by` (object)
- `name` (text)
- `status` (text)
- `tags` (list)
- `updated_at` (text)
- `usage_dashboard` (number)
- `version` (number)

**Example output**

```json
{
  "active": true,
  "archived": false,
  "bucketing_identifier": "distinct_id",
  "can_edit": true,
  "created_at": "2026-07-19T13:45:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "deleted": false,
  "ensure_experience_continuity": false,
  "evaluation_runtime": "all",
  "experiment_set": [],
  "filters": {
    "groups": [
      {
        "properties": [],
        "rollout_percentage": 25
      }
    ]
  },
  "id": 6120,
  "is_eligible_for_experiment": false,
  "key": "new-checkout",
  "name": "The rebuilt checkout flow",
  "status": "ACTIVE",
  "tags": [
    "checkout"
  ],
  "updated_at": "2026-09-05T16:02:00+00:00",
  "version": 3
}
```

### Get feature flag

Read one feature flag by its ID: its key and description, whether it is on, its full targeting - release conditions, rollout percentages and variants - its tags, and whether anything else in PostHog depends on it, such as an experiment or a session replay setting.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Feature flag (`feature_flag_id`, text, required): The flag's numeric ID. 'List feature flags' returns it as 'id'. You can also paste the PostHog URL of the flag.

**Outputs**

- `active` (true/false)
- `analytics_dashboards` (list)
- `archived` (true/false)
- `bucketing_identifier` (text)
- `can_edit` (true/false)
- `created_at` (text)
- `created_by` (object)
- `deleted` (true/false)
- `ensure_experience_continuity` (true/false)
- `evaluation_contexts` (list)
- `evaluation_runtime` (text)
- `experiment_set` (list)
- `filters` (object)
- `has_encrypted_payloads` (true/false)
- `id` (number)
- `is_eligible_for_experiment` (true/false)
- `is_remote_configuration` (true/false)
- `is_used_in_replay_settings` (true/false)
- `key` (text)
- `last_called_at` (text)
- `last_modified_by` (object)
- `name` (text)
- `status` (text)
- `tags` (list)
- `updated_at` (text)
- `usage_dashboard` (number)
- `version` (number)

**Example output**

```json
{
  "active": true,
  "archived": false,
  "bucketing_identifier": "distinct_id",
  "can_edit": true,
  "created_at": "2026-07-19T13:45:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "deleted": false,
  "ensure_experience_continuity": false,
  "evaluation_runtime": "all",
  "experiment_set": [],
  "filters": {
    "groups": [
      {
        "properties": [],
        "rollout_percentage": 25
      }
    ]
  },
  "id": 6120,
  "is_eligible_for_experiment": false,
  "key": "new-checkout",
  "name": "The rebuilt checkout flow",
  "status": "ACTIVE",
  "tags": [
    "checkout"
  ],
  "updated_at": "2026-09-05T16:02:00+00:00",
  "version": 3
}
```

### List annotations

List the notes pinned to moments on this project's charts - releases, incidents, pricing changes - with what each says, the moment it marks, and which charts it shows on.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Search (`search`, text): Only annotations whose text matches matching this text.
- How many (`limit`, number): How many annotations to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many annotations before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `annotations` (list): The annotations on this page
- `count` (number): How many records this page holds.
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "annotations": [
    {
      "content": "Deployed the rebuilt checkout",
      "created_at": "2026-09-05T16:01:00+00:00",
      "created_by": {
        "email": "sam@example.com",
        "first_name": "Sam",
        "id": 42,
        "uuid": "0192f0aa-0000-7000-8000-000000000042"
      },
      "creation_type": "USR",
      "dashboard_id": null,
      "dashboard_item": null,
      "date_marker": "2026-09-05T16:00:00+00:00",
      "deleted": false,
      "emoji": "\ud83d\ude80",
      "hidden_in_user_interface": false,
      "id": 3390,
      "scope": "project",
      "updated_at": "2026-09-05T16:01:00+00:00"
    }
  ],
  "count": 1,
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "total": 52
}
```

### List dashboards

List this project's dashboards with their names, descriptions, tags and whether each is pinned. Use it to find the ID of the dashboard an annotation or an insight filter should point at.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Search (`search`, text): Only dashboards whose name, description or tags match matching this text.
- How many (`limit`, number): How many dashboards to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many dashboards before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `dashboards` (list): The dashboards on this page
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "dashboards": [
    {
      "created_at": "2026-07-20T09:00:00+00:00",
      "created_by": {
        "email": "sam@example.com",
        "first_name": "Sam",
        "id": 42,
        "uuid": "0192f0aa-0000-7000-8000-000000000042"
      },
      "creation_mode": "default",
      "deleted": false,
      "description": "How the new checkout is doing.",
      "folder": "Unfiled/Dashboards",
      "id": 4102,
      "is_shared": false,
      "name": "Checkout health",
      "pinned": true,
      "restriction_level": 21,
      "tags": [
        "checkout"
      ],
      "team_id": 12345,
      "tiles": []
    }
  ],
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "total": 9
}
```

### List events

Read recent raw events, newest first, optionally narrowed to one event name, one person, or a time window. PostHog looks at the last 24 hours unless you give it one. This is the quick way to see what is arriving; for counting, grouping or joining anything, use 'Run a query' instead - PostHog considers this endpoint superseded by it.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Event name (`event`, text): Only events with this exact name, such as '$pageview' or 'signed up'.
- Person (`distinct_id`, text): Only events from this distinct ID.
- Person ID (`person_id`, text): Only events from this person's numeric ID. 'List people' returns it as 'id'.
- After (`after`, date and time): Only events from after this moment. Defaults to 24 hours ago.
- Before (`before`, date and time): Only events from before this moment.
- Include the person (`include_person`, true/false): Return each event's person alongside it. Slower, so off unless you need it.
- How many (`limit`, number): How many events to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many events before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `events` (list): The events on this page
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "events": [
    {
      "distinct_id": "user_1042",
      "elements": [],
      "elements_chain": "",
      "event": "signed up",
      "id": "0192f0aa-1111-7000-8000-00000000abcd",
      "person": {
        "distinct_ids": [
          "user_1042"
        ],
        "properties": {
          "email": "a@example.com"
        }
      },
      "properties": {
        "$browser": "Chrome",
        "plan": "pro"
      },
      "timestamp": "2026-09-08T09:15:00+00:00"
    }
  ],
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "total": 4821
}
```

### List feature flags

List the project's feature flags with their keys, targeting and whether each is on. Filter by keyword, by exact key, by kind, or by tag. 'State' also offers Stale, which is PostHog's own judgement about a flag that has been fully rolled out or unused long enough to be worth removing. Archived flags are left out unless you ask for them.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Search (`search`, text): Only flags whose key or description matches matching this text.
- Key (`key`, text): Only the flag with this exact key.
- State (`active`, text): Only flags in this state. One of: `true` (Enabled), `false` (Disabled), `STALE`.
- Kind (`flag_type`, text): Only flags of this kind. One of: `boolean` (Boolean (on/off)), `multivariant` (Multivariate), `experiment` (Backing an experiment), `remote_config` (Remote config).
- Archived only (`archived`, true/false): Return archived flags instead of active ones. Off by default, which is why an archived flag goes missing from an ordinary list.
- Tags (`tags`, list): Only flags carrying any of these tags.
- How many (`limit`, number): How many flags to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many flags before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `feature_flags` (list): The feature flags on this page
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "feature_flags": [
    {
      "active": true,
      "archived": false,
      "bucketing_identifier": "distinct_id",
      "can_edit": true,
      "created_at": "2026-07-19T13:45:00+00:00",
      "created_by": {
        "email": "sam@example.com",
        "first_name": "Sam",
        "id": 42,
        "uuid": "0192f0aa-0000-7000-8000-000000000042"
      },
      "deleted": false,
      "ensure_experience_continuity": false,
      "evaluation_runtime": "all",
      "experiment_set": [],
      "filters": {
        "groups": [
          {
            "properties": [],
            "rollout_percentage": 25
          }
        ]
      },
      "id": 6120,
      "is_eligible_for_experiment": false,
      "key": "new-checkout",
      "name": "The rebuilt checkout flow",
      "status": "ACTIVE",
      "tags": [
        "checkout"
      ],
      "updated_at": "2026-09-05T16:02:00+00:00",
      "version": 3
    }
  ],
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "total": 37
}
```

### List insights

List the saved charts in this project - their names, descriptions, tags and which dashboards they sit on. Filter by kind, by dashboard, by tag, or to your favourites. Returns each insight's definition rather than its numbers; use 'Run a query' to compute a figure.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Search (`search`, text): Only insights whose name, description or tags match matching this text.
- Kind (`insight_type`, text): Only insights of this kind. One of: `TRENDS`, `FUNNELS`, `RETENTION`, `PATHS`, `STICKINESS`, `LIFECYCLE`, `JOURNEYS`, `SQL` (SQL (HogQL)), `JSON` (Other query).
- On dashboards (`dashboard_ids`, list): Only insights shown on every one of these dashboards.
- Tags (`tags`, list): Only insights carrying any of these tags.
- Favourites only (`favorited`, true/false): Only insights you have marked as favourites.
- How many (`limit`, number): How many insights to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many insights before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `has_more` (true/false): Whether another page follows this one.
- `insights` (list): The insights on this page
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "has_more": true,
  "insights": [
    {
      "created_at": "2026-05-02T14:20:00+00:00",
      "created_by": {
        "email": "sam@example.com",
        "first_name": "Sam",
        "id": 42,
        "uuid": "0192f0aa-0000-7000-8000-000000000042"
      },
      "dashboard_tiles": [
        {
          "dashboard_id": 4102,
          "id": 3311
        }
      ],
      "deleted": false,
      "description": "Distinct users with any event, by week.",
      "favorited": true,
      "id": 9021,
      "last_modified_at": "2026-09-01T08:05:00+00:00",
      "name": "Weekly active users",
      "short_id": "aBcD1234",
      "tags": [
        "growth"
      ]
    }
  ],
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "total": 63
}
```

### List people

Find the people PostHog has seen in this project, with the properties saved against each one and every distinct ID they have been seen under. Search by email, by distinct ID, or by any text across their name, email and IDs.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Search (`search`, text): Only people whose name, email or distinct ID matches matching this text.
- Email (`email`, text): Only the person with this exact email.
- Distinct ID (`distinct_id`, text): Only the person with this exact distinct ID.
- How many (`limit`, number): How many people to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many people before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `persons` (list): The people on this page
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "persons": [
    {
      "created_at": "2026-08-01T11:00:00+00:00",
      "distinct_ids": [
        "user_1042"
      ],
      "id": 5150,
      "last_seen_at": "2026-09-08T09:15:00+00:00",
      "name": "a@example.com",
      "properties": {
        "email": "a@example.com",
        "plan": "pro"
      },
      "uuid": "0192f0aa-2222-7000-8000-000000005150"
    }
  ],
  "total": 1284
}
```

### List projects

List the PostHog projects this connection can see, with the numeric ID every other PostHog action needs. PostHog does not show that ID anywhere in its own settings screens, so this is how a workflow finds one - and the only action here that does not itself take a project. The project's write key is deliberately left out of the result: this integration uses it internally when it captures an event, and a workflow has no reason to carry a credential around.

**Inputs**

- How many (`limit`, number): How many projects to return, 1-200. Defaults to 20. From 1 to 200.
- Skip (`offset`, number): Skip this many projects before the page begins. Read 'next_offset' from the result to get the next page. From 0 to 100000.

**Outputs**

- `count` (number): How many records this page holds.
- `has_more` (true/false): Whether another page follows this one.
- `limit` (number): The page size that was asked for.
- `next_offset` (number): The offset to ask for next, or null when this is the last page.
- `offset` (number): The offset this page started at.
- `projects` (list): The projects on this page
- `total` (number): How many records match in total, when PostHog reported it.

**Example output**

```json
{
  "count": 1,
  "has_more": true,
  "limit": 20,
  "next_offset": 1,
  "offset": 0,
  "projects": [
    {
      "access_control": false,
      "completed_snippet_onboarding": true,
      "id": 12345,
      "ingested_event": true,
      "is_demo": false,
      "name": "Production",
      "organization": "0192f0aa-4444-7000-8000-000000000001",
      "project_id": 12345,
      "tags": [],
      "timezone": "UTC",
      "uuid": "0192f0aa-3333-7000-8000-000000012345"
    }
  ],
  "total": 1
}
```

### Run a query

Run SQL (HogQL) over your PostHog data and get the rows back: counts, funnels, joins between events and people, anything the fixed list actions cannot express. Returns 'results' as a list of rows with 'columns' naming what is in each position. Use {placeholders} with the Values field rather than pasting a value into the SQL, so text carried over from an earlier step cannot be read as query syntax.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- SQL (`query`, text, required): The HogQL query to run. PostHog's tables include events, persons, sessions and any data warehouse tables you have connected.
- Values (`values`, object): Values for the {placeholders} in the query, as fields and values. A query saying "WHERE event = {name}" takes a "name" here.
- Cache (`refresh`, text): How much to rely on PostHog's cached results. Defaults to reusing very fresh ones. One of: `blocking` (Wait for results, reusing very fresh cached ones), `force_blocking` (Wait for results, ignoring the cache), `force_cache` (Cached results only, never recalculate).

**Outputs**

- `columns` (list)
- `count` (number)
- `has_more` (true/false)
- `hogql` (text)
- `query` (text)
- `results` (list)
- `types` (list)

**Example output**

```json
{
  "columns": [
    "event",
    "total"
  ],
  "count": 2,
  "has_more": false,
  "hogql": "SELECT event, count() AS total FROM events GROUP BY event",
  "query": "SELECT event, count() AS total FROM events GROUP BY event",
  "results": [
    [
      "signed up",
      412
    ],
    [
      "$pageview",
      90210
    ]
  ],
  "types": [
    "String",
    "UInt64"
  ]
}
```

### Set person properties

Save details onto a person's profile in PostHog - their email, plan, company, anything you want to segment by later. Sent as PostHog's '$identify' event, which is how its own documentation says to write person properties. 'Properties' overwrite what is already there; 'Set once properties' fill in only what is still missing, so a signup date set on the first run is not overwritten on the second. Like any capture, this is queued rather than applied on the spot.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Person (`distinct_id`, text, required): The distinct ID of the person to update - your user ID, or their email. PostHog creates the person if it has not seen this ID before.
- Properties (`properties`, object): Details to save on the person, overwriting whatever was there before.
- Set once properties (`set_once_properties`, object): Details to save only if the person does not have them yet, such as the date they signed up or where they came from.

**Outputs**

- `distinct_id` (text)
- `event` (text)
- `project_id` (number)
- `properties` (object)
- `set_once_properties` (object)
- `set_properties` (object)
- `status` (text)
- `timestamp` (text)

**Example output**

```json
{
  "distinct_id": "user_1042",
  "event": "$identify",
  "project_id": 12345,
  "properties": {
    "$set": {
      "plan": "pro"
    }
  },
  "set_once_properties": {
    "signup_source": "docs"
  },
  "set_properties": {
    "plan": "pro"
  },
  "status": "queued",
  "timestamp": "2026-09-08T09:15:00+00:00"
}
```

### Update annotation

Change an annotation's text, the moment it marks, where it shows, or its emoji. Anything left blank keeps the value it already had.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Annotation ID (`annotation_id`, text, required): The annotation's numeric ID. 'List annotations' returns it as 'id'.
- Note (`content`, text): What happened, shown on the chart at this moment - 'Deployed v2.4', 'Pricing page changed'.
- When it happened (`date_marker`, date and time): The moment to mark on the chart. Defaults to now on a new annotation.
- Show on (`scope`, text): Which charts carry the marker. Defaults to the whole project. One of: `project` (The whole project), `organization` (Every project in the organisation), `dashboard` (One dashboard), `dashboard_item` (One insight).
- Dashboard (`dashboard_id`, text): The dashboard to attach it to. Only used when 'Show on' is set to one dashboard.
- Insight ID (`insight_id`, text): The insight to attach it to, as its numeric ID. 'List insights' returns it as 'id'. Only used when 'Show on' is set to one insight.
- Emoji (`emoji`, text): Shown on the chart instead of the default marker, such as 🚀.
- Hide in PostHog (`hidden_in_user_interface`, true/false): Keep the annotation out of PostHog's charts and lists while leaving it readable over the API. For high-frequency markers that would otherwise crowd a chart.

**Outputs**

- `content` (text)
- `created_at` (text)
- `created_by` (object)
- `creation_type` (text)
- `dashboard_id` (number)
- `dashboard_item` (number)
- `dashboard_name` (text)
- `date_marker` (text)
- `deleted` (true/false)
- `emoji` (text)
- `hidden_in_user_interface` (true/false)
- `id` (number)
- `insight_derived_name` (text)
- `insight_name` (text)
- `insight_short_id` (text)
- `scope` (text)
- `updated_at` (text)

**Example output**

```json
{
  "content": "Deployed the rebuilt checkout",
  "created_at": "2026-09-05T16:01:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "creation_type": "USR",
  "dashboard_id": null,
  "dashboard_item": null,
  "date_marker": "2026-09-05T16:00:00+00:00",
  "deleted": false,
  "emoji": "\ud83d\ude80",
  "hidden_in_user_interface": false,
  "id": 3390,
  "scope": "project",
  "updated_at": "2026-09-05T16:01:00+00:00"
}
```

### Update feature flag

Change a feature flag: its key or description, its rollout percentage or variants, its tags, or whether it is archived. Anything left blank keeps the value it already had. To turn a flag on or off without touching anything else, use 'Enable or disable feature flag' instead.

**Inputs**

- Project (`project_id`, text, required): The PostHog project to work in. Pick one from the list, or paste a project ID or the PostHog URL of a page inside it.
- Feature flag (`feature_flag_id`, text, required): The flag's numeric ID. 'List feature flags' returns it as 'id'. You can also paste the PostHog URL of the flag.
- Key (`key`, text): A new key for the flag. Changing it will stop any code still asking for the old one from matching.
- Description (`name`, text): What the flag is for, shown beside it in PostHog. Stored in PostHog's 'name' field, which is where it keeps a flag's description.
- Enabled (`active`, true/false): Whether the flag evaluates at all. A disabled flag is off for everyone regardless of its targeting.
- Rollout percentage (`rollout_percentage`, number): What share of people the flag is on for, 0-100. Leave blank on a new flag for everyone. Cannot be combined with the advanced 'Targeting' field below. From 0.0 to 100.0.
- Variants (`variants`, list): Turns this into a multivariate flag. A list of objects, each with "key", an optional "name" and a "rollout_percentage". The percentages have to add up to 100.
- Targeting (advanced) (`filters`, object): PostHog's whole targeting object - release condition groups with property filters, and any variant configuration. Use this to carry targeting over from another flag or from PostHog's own API. Cannot be combined with the rollout percentage and variants fields above.
- Tags (`tags`, list): Labels to file the flag under in PostHog.
- Evaluate in (`evaluation_runtime`, text): Where PostHog will let this flag be read. Defaults to anywhere. One of: `all` (Anywhere), `server` (Server-side SDKs only), `client` (Client-side SDKs only).
- Roll out by (`bucketing_identifier`, text): What the rollout percentage is measured against. Device ID cannot be combined with 'Keep the same value after sign-in'. One of: `distinct_id` (User ID), `device_id` (Device ID).
- Keep the same value after sign-in (`ensure_experience_continuity`, true/false): Hold a person's flag value steady as they go from anonymous to identified, so a feature does not appear or disappear when they log in.
- Archived (`archived`, true/false): Put the flag away without deleting it. PostHog will not archive a flag that is still enabled, so disable it first.

**Outputs**

- `active` (true/false)
- `analytics_dashboards` (list)
- `archived` (true/false)
- `bucketing_identifier` (text)
- `can_edit` (true/false)
- `created_at` (text)
- `created_by` (object)
- `deleted` (true/false)
- `ensure_experience_continuity` (true/false)
- `evaluation_contexts` (list)
- `evaluation_runtime` (text)
- `experiment_set` (list)
- `filters` (object)
- `has_encrypted_payloads` (true/false)
- `id` (number)
- `is_eligible_for_experiment` (true/false)
- `is_remote_configuration` (true/false)
- `is_used_in_replay_settings` (true/false)
- `key` (text)
- `last_called_at` (text)
- `last_modified_by` (object)
- `name` (text)
- `status` (text)
- `tags` (list)
- `updated_at` (text)
- `usage_dashboard` (number)
- `version` (number)

**Example output**

```json
{
  "active": true,
  "archived": false,
  "bucketing_identifier": "distinct_id",
  "can_edit": true,
  "created_at": "2026-07-19T13:45:00+00:00",
  "created_by": {
    "email": "sam@example.com",
    "first_name": "Sam",
    "id": 42,
    "uuid": "0192f0aa-0000-7000-8000-000000000042"
  },
  "deleted": false,
  "ensure_experience_continuity": false,
  "evaluation_runtime": "all",
  "experiment_set": [],
  "filters": {
    "groups": [
      {
        "properties": [],
        "rollout_percentage": 25
      }
    ]
  },
  "id": 6120,
  "is_eligible_for_experiment": false,
  "key": "new-checkout",
  "name": "The rebuilt checkout flow",
  "status": "ACTIVE",
  "tags": [
    "checkout"
  ],
  "updated_at": "2026-09-05T16:02:00+00:00",
  "version": 3
}
```
