PostHog ExecModule
Overview
PostHogModule connects ValkyrAI workflows to PostHog Cloud through the native map I/O ExecModule ABI. Workflow Studio discovers it as PostHogModule; the scoped personal API key and project token are resolved only from a bound encrypted IntegrationAccount.
The initial production operation set supports the product-feedback loop on both PostHog US and EU Cloud:
- capture a custom event, identify a person, or create an alias;
- capture
$pageviewand$screenevents with typed reserved properties; - list or get events and persons;
- list or get feature flags.
Management reads use PostHog's paginated REST API. The module extracts only validated offset or cursor values from provider next URLs and always rebuilds the next request on the configured fixed regional host. Read-only requests retry conservatively. Event ingestion is always single-attempt because a network timeout can leave the write outcome ambiguous.
Usage
- Choose the PostHog Cloud region used by the project:
usoreu. - Create a scoped personal API key with read access only to the selected project resources.
- Copy the project's event-ingestion token from PostHog project settings.
- Store the personal key in the encrypted
apiKeySecureField, the project token in the encryptedpasswordSecureField, and the numeric project ID inIntegrationAccount.accountId. - Set the account status to
READYand bind it throughExecModuleConfig.authConfig.integrationAccount. - Use capture operations only after the workflow has a stable
distinctId, an approved event taxonomy, and no sensitive properties. - Use list/get operations to verify analytics evidence or feature-flag definitions without exposing credentials to workflow input or output.
Workflow input cannot supply a credential, project token, arbitrary PostHog host, or authorization header. The module builds requests only for PostHog US/EU API and ingestion origins.
Inputs
| Name | Type | Requirement | Default | Description and constraints |
|---|---|---|---|---|
operation | string | Required | None | One of the eleven documented operations. |
region | string | Optional | us | us or eu; selects fixed API and ingestion hosts. |
projectId | string | Management reads | IntegrationAccount.accountId | Numeric project ID, up to 20 digits. |
resourceId | string | Get operations | None | Bounded event, person, or feature-flag ID. |
eventName | string | capture_event; optional list_events filter | None | Bounded custom event name, up to 200 characters. |
distinctId | string | Every capture operation; optional list filter | None | Stable user or anonymous ID, up to 200 characters. |
alias | string | create_alias | None | New PostHog alias, up to 200 characters. |
currentUrl | string | capture_pageview | None | HTTPS URL without embedded credentials. |
screenName | string | capture_screen | None | Application screen name, up to 200 characters. |
properties | object or JSON string | Optional capture payload | {} | Custom properties, capped at 512 KiB. Reserved credential fields are rejected. |
personProperties | object or JSON string | identify_person | None | Properties emitted as $set. |
setOnce | object or JSON string | Optional identify_person | None | First-touch properties emitted as $set_once. At least one identify property object must be non-empty. |
timestamp | string | Optional capture field | Provider receive time | ISO-8601 timestamp with offset. |
eventUuid | UUID string | Optional capture field | None | Caller-owned PostHog event UUID for provider deduplication. |
after / before | string | Optional list_events filters | None | ISO-8601 timestamps with offsets. |
cursor | string | Optional list continuation | None | Opaque offset=... or cursor=... value emitted by this module. |
limit | integer | Optional | 100 | Maximum returned resources, 1–10,000. |
returnAll | boolean | Optional | false | Continue through provider pages up to the 10,000-result cap. |
requestId | string | Optional | None | Caller correlation value sent as X-Request-Id, up to 128 characters. |
The module injects distinct_id, $current_url, $screen_name, $set, $set_once, and alias from typed inputs. It injects the project token as api_key only after validation. properties cannot override credential-bearing fields such as api_key, authorization, token, or password.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation name. |
attempts | integer | Always | Total provider attempts across pages. |
httpStatus | integer | Provider responded | Last PostHog HTTP status. |
data | object | Capture/get success | Sanitized ingestion receipt or provider resource. |
id, uuid, name, key, distinct_id | string | Provider returns field | Safe convenience identity fields. |
items / count | array / integer | List success | Bounded provider resources and emitted count. |
hasMore / nextCursor | boolean / string | List success | Provider continuation state and opaque fixed-host resume token. |
requestId | string | Provider supplies one | Safe provider trace reference. |
error | object | Failure | Safe {code, message, httpStatus?, retryable} details. |
Personal keys, project tokens, request authorization, and credential-bearing provider text are redacted from outputs and workflow events.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | PostHog Cloud US or EU project |
accountName | Human-readable automation identity |
accountId | Numeric PostHog project ID for REST reads |
apiKey | Encrypted SecureField containing a scoped personal API key (phx_...) |
password | Encrypted SecureField containing the project event-ingestion token (phc_...) |
status | READY or legacy unset status; CLOSED and ERROR fail closed |
Capture-only workflows require the project token. Management read operations require the personal API key and project ID. Store both when a workflow uses both capability families. Grant the personal key only event, person, and feature-flag read scopes required by the selected operations. Token rotation belongs to the platform IntegrationAccount lifecycle, not workflow input.
Configuration
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:posthog-product-analytics"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000,
"jitter": false
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"operation\":\"capture_event\",\"region\":\"us\",\"eventName\":\"workspace_activated\",\"distinctId\":\"customer-42\",\"eventUuid\":\"0f87f78c-a05d-457d-9c0a-b71892afb647\"}"
}
}
The integration-account value is symbolic. Persisted workflows use the generated relationship and never plaintext credentials.
Operations
| Operation | PostHog behavior | Side effect |
|---|---|---|
capture_event | Captures one caller-named event with bounded custom properties. | Event write; single attempt. |
identify_person | Captures $identify with typed $set and optional $set_once. | Person/event write; single attempt. |
create_alias | Captures $create_alias for one current distinct ID and alias. | Identity-link write; single attempt. |
capture_pageview | Captures $pageview with typed HTTPS $current_url. | Event write; single attempt. |
capture_screen | Captures $screen with typed $screen_name. | Event write; single attempt. |
list_events | Lists project events with optional event, distinct-ID, and time filters. | Read-only; safe retries. |
get_event | Reads one project event by ID. | Read-only; safe retries. |
list_persons | Lists project persons with an optional distinct-ID filter. | Read-only; safe retries. |
get_person | Reads one person by ID. | Read-only; safe retries. |
list_feature_flags | Lists project feature-flag definitions. | Read-only; safe retries. |
get_feature_flag | Reads one feature-flag definition by ID. | Read-only; safe retries. |
Errors and Failure Modes
| Code | Typical cause | Retryable | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Missing/invalid credential, project ID, identifier, URL, timestamp, event UUID, property object, cursor, or region. | No | Correct input; no unsafe request was sent. |
UNSUPPORTED_OPERATION | Unknown operation. | No | Select a documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No bound account. | No | Bind a PostHog IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | Account is closed or in error. | No | Repair or reconnect the account. |
POSTHOG_HTTP_400 | PostHog rejected an event, filter, or project resource request. | No | Correct the bounded request and event taxonomy. |
POSTHOG_HTTP_401 / 403 | Personal key invalid/expired or missing scope. | No | Rotate the key or grant minimum read permissions. |
POSTHOG_HTTP_404 | Project resource is absent or invisible. | No | Re-run discovery with the same account and project ID. |
POSTHOG_HTTP_429 / 5xx | Rate limit or transient provider failure. | Yes for reads | Honor Retry-After; reconcile capture state before repeating writes. |
NETWORK_ERROR | Timeout, DNS, TLS, or connectivity failure. | Yes for reads | Verify connectivity; do not blindly repeat an ambiguous event write. |
RESPONSE_TOO_LARGE | Response exceeded 5 MiB. | No | Narrow filters or lower the result limit. |
INVALID_PROVIDER_RESPONSE | A list lacked results, or pagination repeated/used an unsupported token. | No | Inspect the request ID and verify API compatibility. |
Example
Capture one activation milestone after onboarding completes:
{
"operation": "capture_event",
"region": "us",
"eventName": "workspace_activated",
"distinctId": "customer-42",
"eventUuid": "0f87f78c-a05d-457d-9c0a-b71892afb647",
"properties": {
"plan": "enterprise",
"activation_path": "guided"
}
}
Expected result:
{
"status": "success",
"operation": "capture_event",
"httpStatus": 200,
"attempts": 1,
"data": {"status": "Ok"}
}
Notes
- Pagination: PostHog list responses contain a
nextURL. The module extracts only a boundedoffsetorcursor, never follows the absolute URL, rebuilds the request on the fixed regional API host, rejects repeated tokens, and stops at the requested limit or 10,000 results. - Rate limits: GET operations retry HTTP 408, 429, 500, 502, 503, and 504 according to
RetryPolicy, honoring integerRetry-After. Capture operations never retry automatically. - API limits: provider responses are capped at 5 MiB; property objects and final event payloads are capped at 512 KiB; strings, identifiers, timestamps, cursors, and result counts are bounded before request construction.
- Idempotency: supply a stable caller-owned
eventUuidfor capture deduplication. A timeout is still ambiguous, so reconcile PostHog before manually repeating the same event UUID. - Destructive behavior: this version exposes no event, person, feature-flag, project, or organization deletion and no feature-flag mutation. Alias and identify events can affect identity analytics and require deliberate caller approval.
- Privacy: never send passwords, auth tokens, raw payment data, regulated identifiers, or unrelated customer payloads as event properties. PostHog retention and data-residency settings remain provider-side responsibilities.
- Regional routing:
ususesus.posthog.comandus.i.posthog.com;euuseseu.posthog.comandeu.i.posthog.com. Arbitrary/self-hosted endpoints are intentionally deferred to prevent workflow-controlled routing. - External verification: request construction, pagination, validation, retry safety, redaction, response mapping, and metadata discovery are deterministic local tests. Live PostHog scopes, regional ingestion, deduplication, rate limits, and data availability require separately authorized provider credentials and are not exercised in repository tests.
- Deferred operations: feature-flag create/update/delete, cohort and insight management, batch ingestion, group analytics, annotations, experiments, actions, dashboards, HogQL queries, webhooks/triggers, self-hosted routing, OAuth lifecycle, and arbitrary raw requests.
- Functional references: n8n PostHog node source and PostHog API schema.