From 8bb85489b436eb6ccdd53fc781c4edf7669853d1 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 4 Nov 2026 14:38:45 -0500 Subject: [PATCH 1/9] docs: generate the 7.x Markdown reference Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 5350 ++++++++++++++++++++++++++++++++ 1 file changed, 5350 insertions(+) create mode 100644 references/posthog-python-7.md diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md new file mode 100644 index 000000000..83a8806ca --- /dev/null +++ b/references/posthog-python-7.md @@ -0,0 +1,5350 @@ +--- +title: PostHog Python SDK +sdk: python +version: 7.83.1 +major: 7 +status: current +--- + +## Getting started + +The Python SDK captures events, evaluates feature flags and reports errors from Python 3.10 or later. + +### Install + +```bash +pip install posthog +``` + +### Initialize + +Create one client for your app with your project token and host. Your project token and host are in your [project settings](https://app.posthog.com/project/settings). Keep the token in an environment variable rather than in code. + +```python +from posthog import Posthog + +posthog = Posthog("", host="") +``` + +### Capture an event + +```python +posthog.capture("user_signed_up", distinct_id="user_123", properties={"plan": "free"}) +``` + +`capture` queues the event and returns right away. A background thread sends it. + +### Shut down + +Call `shutdown()` before your process exits, so queued events are sent. + +```python +posthog.shutdown() +``` + +In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [AsyncClient](#asyncclient). + +## Traces + +### `Client.start_span` + +Start a span for distributed tracing. Alpha. + +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on +the way out); or call `end()` yourself for a span that cannot wrap a +block. Spans started inside the block nest under it automatically. +Always returns a usable handle, even when tracing is off, so calling +code never branches. + +```python +start_span( + name: str, + kind: Optional[str] = None, + attributes: Optional[Mapping[str, Any]] = None, + parent: Union[Span, str, None] = None, + tracestate: Optional[str] = None, + start_time: Union[datetime, float, None] = None, +) -> Span +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | +| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | +| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | +| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | +| `start_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +posthog = Posthog("", traces={"service_name": "checkout-api"}) + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2794) + +### `Client.get_active_span` + +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes +it active; a span started manually is not. Use it to propagate the +trace to the next service: `span.traceparent()` is the header value. + +```python +get_active_span() -> Optional[Span] +``` + +**Returns** `Optional[Span]` + +**Correct example.** + +```python +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2853) + +## Alias + +### `Client.alias` + +Create an alias between two distinct IDs. + +Note: This method will not raise exceptions. Errors are logged. + +```python +alias( + previous_id: ID_TYPES, + distinct_id: Optional[str], + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required**
The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | +| `distinct_id`
**Type:** `Optional[str]` · **Required**
The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.alias(previous_id='distinct_id', distinct_id='alias_id') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2168) + +## Capture + +### `Client.capture` + +Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name to capture. | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to include with the event. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
A dictionary of group information. | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Anonymous event +posthog.capture('some-anon-event') +``` + +**Correct example.** + +```python +# Context usage +from posthog import identify_context, new_context +with new_context(): + identify_context('distinct_id_of_the_user') + posthog.capture('user_signed_up') + posthog.capture('user_logged_in') + posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +``` + +**Correct example.** + +```python +# Set event properties +posthog.capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` + +**Correct example.** + +```python +# Page view event +posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1738) + +## Capture AI + +### `Client.capture_ai` + +Capture an AI event on the dedicated AI capture endpoint. + +Beta: the signature is stable; operational limits (per-event size +cap, batching, endpoint) may change without notice. + +Takes the same arguments and returns the same value as `capture()`: +the event UUID, or None when the event was not admitted (disabled +client, or dropped by `before_send`). The event is queued on an +isolated AI lane with its own consumer pool and a higher per-event +size cap, posting to the dedicated AI ingestion endpoint. The payload +is sent as given — no redaction or truncation is applied here. + +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1797) + +## Capture exception + +### `Client.capture_exception` + +Capture an exception for error tracking. + +When OpenTelemetry is installed and a valid span is active, its trace and +span IDs are added as `$trace_id` and `$span_id` event properties. + +```python +capture_exception( + exception: Optional[ExceptionArg], + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Required**
The exception to capture. | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Pass `flags` from `evaluate_flags()` instead. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +try: + # Some code that might fail + pass +except Exception as e: + posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2234) + +## Emails + +### `Client.emails` + +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. + +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope. Sends go to `app_host`, or to the PostHog Cloud app host of +`host`. `email_request_timeout_seconds` and `email_request_max_retries` +configure each send. A disabled or shut-down client sends nothing. See +`posthog.emails` for setup. + +```python +Client.emails: Emails +``` + +**Correct example.** + +```python +client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1256) + +## Flush + +### `Client.flush` + +Attempt immediate delivery of queued events, ended spans and autocaptured metrics, keeping the client reusable. + +For a client shared across requests or serverless invocations (including +the module-level client), call `flush()` before a short-lived invocation +returns. Use `shutdown()` instead only for final process cleanup or when +disposing of a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. + +Returning does not guarantee server receipt: pending work can remain after +a timeout or span export failure, and failed events may be dropped by the +consumers. Calls made directly from SDK callbacks such as `on_error` are +deferred rather than blocking the worker that invoked the callback. + +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the shared client open. +posthog.flush(timeout_seconds=10) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2872) + +## Get feature flag + +### `Client.get_feature_flag` + +Get multivariate feature flag value for a user. + +```python +get_feature_flag( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FlagValue] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[FlagValue]` + +**Correct example.** + +```python +enabled_variant = posthog.get_feature_flag('flag-key', 'distinct_id_of_your_user') +if enabled_variant == 'variant-key': # replace 'variant-key' with the key of your variant + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4324) + +## Get feature flag payload + +### `Client.get_feature_flag_payload` + +Get the payload for a feature flag. + +```python +get_feature_flag_payload( + key: str, + distinct_id: ID_TYPES, + match_value: Optional[FlagValue] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[object] +``` + +
+Parameters (10) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
The specific flag value to get payload for. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `False`
Deprecated. Use get_feature_flag() instead if you need events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. + +**Correct example.** + +```python +is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') + +if is_my_flag_enabled: + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4424) + +## Get feature flag result + +### `Client.get_feature_flag_result` + +Get a FeatureFlagResult object which contains the flag result and payload for a key by evaluating locally or remotely +depending on whether local evaluation is enabled and the flag can be locally evaluated. +This also captures the `$feature_flag_called` event unless `send_feature_flag_events` is `False`. + +```python +get_feature_flag_result( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FeatureFlagResult] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[FeatureFlagResult]`. Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. + +**Correct example.** + +```python +flag_result = posthog.get_feature_flag_result('flag-key', 'distinct_id_of_your_user') +if flag_result and flag_result.get_value() == 'variant-key': + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = flag_result.payload +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4269) + +## Get feature flags + +### `Client.get_feature_variants` + +Get feature flag variants for a user. + +```python +get_feature_variants( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> dict[str, Union[bool, str]] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `dict[str, Union[bool, str]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1499) + +### `Client.get_all_flags` + +Get all feature flags for a user. + +```python +get_all_flags( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> Optional[dict[str, Union[bool, str]]] +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[dict[str, Union[bool, str]]]` + +**Correct example.** + +```python +posthog.get_all_flags('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4744) + +## Get feature flags and payloads + +### `Client.get_feature_flags_and_payloads` + +Get feature flags and payloads for a user. + +```python +get_feature_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsAndPayloads` + +**Correct example.** + +```python +result = posthog.get_feature_flags_and_payloads('') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1580) + +### `Client.get_all_flags_and_payloads` + +Get all feature flags and their payloads for a user. + +```python +get_all_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsAndPayloads` + +**Correct example.** + +```python +posthog.get_all_flags_and_payloads('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4790) + +## Evaluate flags + +### `Client.evaluate_flags` + +Evaluate all feature flags for a user in a single call and return a +`FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / +`.get_flag()` and pass the same snapshot to `capture` via the +`flags` option so events carry the exact flag values the code branched on. + +Prefer this over repeated `get_feature_flag()` calls and over +`capture(send_feature_flags=True)` — it consolidates flag evaluation into +a single `/flags` request per incoming request. + +Local evaluation is transparent: when the poller resolves a flag, the +snapshot's `$feature_flag_called` events are tagged `locally_evaluated=True` +and reason `"Evaluated locally"`. + +```python +evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[List[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `flag_keys`
**Type:** `Optional[List[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | + +
+ +**Returns** `FeatureFlagEvaluations`. class:`FeatureFlagEvaluations` snapshot. + +**Correct example.** + +```python +flags = posthog.evaluate_flags( + "user_123", + person_properties={"plan": "enterprise"}, +) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id="user_123", flags=flags) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4875) + +## Group identify + +### `Client.group_identify` + +Identify a group and set its properties. + +Note: This method will not raise exceptions. Errors are logged. + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[Union[str, UUID]] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required**
The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | +| `group_key`
**Type:** `str` · **Required**
The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of properties to set on the group. | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user performing the action. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2093) + +## Identify + +### `Client.set` + +Set properties on a person profile. + +Note: This method will not raise exceptions. Errors are logged. + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Set with distinct id +posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1995) + +### `Client.set_once` + +Set properties on a person profile only if they haven't been set before. + +Note: This method will not raise exceptions. Errors are logged. + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set once. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2045) + +## Is feature enabled + +### `Client.feature_enabled` + +Check if a feature flag is enabled for a user. + +```python +feature_enabled( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[bool] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[bool]` + +**Correct example.** + +```python +is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3982) + +## Setup + +### `Client(...)` + +Initialize a new PostHog client instance. + +```python +Client( + project_api_key: str, + host = None, + debug = False, + max_queue_size = 10000, + send = True, + on_error = None, + flush_at = 100, + flush_interval = 5.0, + gzip = False, + max_retries = 3, + sync_mode = False, + timeout: float = 15, + thread = 1, + poll_interval = 30, + personal_api_key = None, + disabled = False, + disable_geoip = True, + is_server = True, + historical_migration = False, + feature_flags_request_timeout_seconds: float = 3, + feature_flags_request_max_retries = 1, + super_properties = None, + enable_exception_autocapture = False, + log_captured_exceptions = False, + project_root = None, + privacy_mode = False, + before_send = None, + flag_fallback_cache_url = None, + enable_local_evaluation = True, + flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, + capture_exception_code_variables = False, + code_variables_mask_patterns = None, + code_variables_ignore_patterns = None, + code_variables_mask_url_credentials = None, + code_variables_detect_secrets = None, + in_app_modules: list[str] | None = None, + enable_exception_autocapture_rate_limiting = False, + exception_autocapture_bucket_size = ExceptionCapture.DEFAULT_BUCKET_SIZE, + exception_autocapture_refill_rate = ExceptionCapture.DEFAULT_REFILL_RATE, + exception_autocapture_refill_interval_seconds = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, + capture_mode: Optional[Union[CaptureMode, str]] = None, + capture_compression: Optional[Union[CaptureCompression, str]] = None, + secret_key = None, + metrics: Optional[dict] = None, + enable_full_ai_capture = False, + capture_trace_context = False, + traces: Optional[dict] = None, + app_host: Optional[str] = None, + email_request_timeout_seconds: float = 15, + email_request_max_retries: int = 2, +) +``` + +
+Parameters (50) + +| Parameter | +| --- | +| `project_api_key`
**Type:** `str` · **Required**
PostHog project API key/token. | +| `host`
**Default:** `None`
PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | +| `debug`
**Default:** `False`
Enable verbose SDK logging and re-raise errors from public API methods. | +| `max_queue_size`
**Default:** `10000`
Maximum number of events buffered before upload. | +| `send`
**Default:** `True`
If False, queueing succeeds but events are not sent. | +| `on_error`
**Default:** `None`
Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | +| `flush_at`
**Default:** `100`
Number of queued events that triggers a batch upload. | +| `flush_interval`
**Default:** `5.0`
Maximum seconds a background consumer waits before flushing a partial batch. | +| `gzip`
**Default:** `False`
Whether to gzip event upload payloads. | +| `max_retries`
**Default:** `3`
Number of upload retries. Values below 0 are treated as 0. | +| `sync_mode`
**Default:** `False`
If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | +| `timeout`
**Type:** `float` · **Default:** `15`
HTTP request timeout in seconds for event uploads. | +| `thread`
**Default:** `1`
Number of background consumer threads. | +| `poll_interval`
**Default:** `30`
Seconds between local feature flag definition refreshes. | +| `personal_api_key`
**Default:** `None`
Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | +| `disabled`
**Default:** `False`
If True, disable captures and API requests. Useful in tests. | +| `disable_geoip`
**Default:** `True`
Whether to disable server-side GeoIP enrichment. Defaults to True. | +| `is_server`
**Default:** `True`
Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | +| `historical_migration`
**Default:** `False`
Mark events as historical migration imports. | +| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3`
Timeout in seconds for feature flag and remote config requests. | +| `feature_flags_request_max_retries`
**Default:** `1`
Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | +| `super_properties`
**Default:** `None`
Properties merged into every captured event. | +| `enable_exception_autocapture`
**Default:** `False`
Automatically capture uncaught exceptions. | +| `log_captured_exceptions`
**Default:** `False`
Also log exceptions captured by error tracking. | +| `project_root`
**Default:** `None`
Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | +| `privacy_mode`
**Default:** `False`
For AI observability, capture usage metadata without prompt inputs or outputs. | +| `before_send`
**Default:** `None`
Optional callback that can modify or drop events before upload. Return `None` to drop an event. | +| `flag_fallback_cache_url`
**Default:** `None`
Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | +| `enable_local_evaluation`
**Default:** `True`
Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | +| `flag_definition_cache_provider`
**Type:** `Optional[FlagDefinitionCacheProvider]` · **Default:** `None`
Optional external cache provider for sharing feature flag definitions across workers. | +| `capture_exception_code_variables`
**Default:** `False`
Capture local variable values on exception stack frames. | +| `code_variables_mask_patterns`
**Default:** `None`
Variable-name patterns to mask when capturing code variables. | +| `code_variables_ignore_patterns`
**Default:** `None`
Variable-name patterns to omit when capturing code variables. | +| `code_variables_mask_url_credentials`
**Default:** `None`
Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | +| `code_variables_detect_secrets`
**Default:** `None`
Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | +| `in_app_modules`
**Type:** `list[str]` \| `None` · **Default:** `None`
Module/package prefixes treated as in-app frames in captured exceptions. | +| `enable_exception_autocapture_rate_limiting`
**Default:** `False`
Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | +| `exception_autocapture_bucket_size`
**Default:** `ExceptionCapture.DEFAULT_BUCKET_SIZE`
Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | +| `exception_autocapture_refill_rate`
**Default:** `ExceptionCapture.DEFAULT_REFILL_RATE`
Tokens restored per refill interval for each exception type's bucket. | +| `exception_autocapture_refill_interval_seconds`
**Default:** `ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS`
Seconds between token refills for autocaptured exception rate limiting. | +| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None`
Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | +| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None`
Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | +| `secret_key`
**Default:** `None`
A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:
`posthog.Client(project_api_key, secret_key="phx_...")` | +| `metrics`
**Type:** `Optional[dict]` · **Default:** `None` | +| `enable_full_ai_capture`
**Default:** `False`
Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | +| `capture_trace_context`
**Default:** `False`
When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | +| `traces`
**Type:** `Optional[dict]` · **Default:** `None`
Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | +| `app_host`
**Type:** `Optional[str]` · **Default:** `None`
Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | +| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15`
Timeout in seconds for each email send request. Defaults to 15. | +| `email_request_max_retries`
**Type:** `int` · **Default:** `2`
Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | + +
+ +**Correct example.** + +```python +from posthog import Posthog + +posthog = Posthog('', host='') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L684) + +## Shutdown + +### `Client.join` + +Attempt to process queued events and end the consumer threads. Do not use directly, call `shutdown()` instead. + +Failed or undrainable events may be dropped and reported through logging +or `on_error`; returning does not guarantee server receipt. Lifecycle +cleanup is attempted once, and cleanup failures are logged without retry. + +```python +join() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +posthog.join() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3342) + +### `Client.shutdown` + +Attempt final delivery and permanently shut down the client. + +Call this for final process cleanup or when disposing of a client that +will not be reused. It closes capture lanes, stops background workers and +the feature flag poller, and tears down integrations. Do not call it at the +end of each request or serverless invocation when the client is shared; +call `flush()` before returning instead. A shut-down client cannot be +reused; create a new client if needed. + +Normally this method blocks until queued events have been attempted and +cleanup finishes. Failed or undrainable events may be dropped and +reported through logging or `on_error`; returning does not guarantee +server receipt. Event draining has no timeout. Queued spans get one final +flush with up to 30 seconds waiting for an in-flight flush, then a fresh +30-second drain budget; the last HTTP request is not cut short. Any spans +it cannot send are discarded with a warning, as are spans still open. +Lifecycle cleanup is attempted once, and cleanup failures +are logged without retry. When called directly from an SDK callback such as +`on_error`, shutdown is deferred to avoid blocking the worker that +invoked the callback. If the callback must coordinate a blocking +shutdown, have it signal an +application-owned thread and return before that thread calls shutdown. +Do not wait inside the callback for another thread or task that calls a +lifecycle method. + +```python +shutdown() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +posthog.shutdown() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3364) + +## Flag definition loader + +### `Client.load_feature_flags` + +Load feature flags for local evaluation. + +```python +load_feature_flags() +``` + +**Correct example.** + +```python +posthog.load_feature_flags() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3825) + +### `Client.feature_flag_definitions` + +Return feature flag definitions loaded for local evaluation. + +```python +feature_flag_definitions() +``` + +**Returns** . The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5252) + +## SDK utils + +### Other + +#### `Client.queue` + +The analytics lane's queue (kept for backwards compatibility). + +```python +Client.queue: Queue +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1293) + +#### `Client.consumers` + +Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). + +```python +Client.consumers: Optional[List[Consumer]] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1298) + +#### `Client.feature_flags` + +Get the local evaluation feature flags. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1478) + +#### `Client.metrics` + +The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. + +Samples fold into per-series aggregates in memory and flush as one OTLP +data point per series per window, so recording from hot paths is cheap. +Configure via the `metrics` client option; pending metrics flush on +`shutdown()`. + +```python +Client.metrics: PostHogMetrics +``` + +**Correct example.** + +```python +client = Posthog("", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2718) + +### Contexts + +#### `Client.new_context` + +Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). + +```python +new_context(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | + +
+ +**Correct example.** + +```python +with client.new_context(): + client.identify_context('') + client.capture('event_name') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1378) + +#### `Client.scoped` + +Decorator that creates a new context for the wrapped function using this client. + +```python +scoped(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1400) + +#### `Client.tag` + +Add a tag to the current context. + +```python +tag(name: str, value: Any) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The tag key. | +| `value`
**Type:** `Any` · **Required**
The tag value. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1416) + +#### `Client.get_tags` + +Get all tags from the current context. + +```python +get_tags() -> Dict[str, Any] +``` + +**Returns** `Dict[str, Any]`. Dict of all tags in the current context. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1429) + +#### `Client.identify_context` + +Identify the current context with a distinct ID. + +```python +identify_context(distinct_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1441) + +#### `Client.set_context_session` + +Set the session ID for the current context. + +```python +set_context_session(session_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1453) + +#### `Client.set_context_device_id` + +Set the device ID for the current context. + +```python +set_context_device_id(device_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1465) + +### Feature flags + +#### `Client.get_feature_payloads` + +Get feature flag payloads for a user, preserving valid serialized JSON. + +```python +get_feature_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> dict[str, Optional[str]] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `dict[str, Optional[str]]` + +**Correct example.** + +```python +payloads = posthog.get_feature_payloads('') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1535) + +#### `Client.get_flags_decision` + +Get feature flags decision. + +```python +get_flags_decision( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsResponse +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsResponse` + +**Correct example.** + +```python +decision = posthog.get_flags_decision('user123') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1628) + +#### `Client.get_remote_config_payload` + +Get the payload for a remote config feature flag. + +```python +get_remote_config_payload(key: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The remote config feature flag key. | + +
+ +**Returns** . The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned. + +**Note.** Requires `secret_key` for authentication. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4670) + +#### `Client.get_feature_flag_evaluation_runtime` + +Return where a locally loaded feature flag is meant to be evaluated. + +```python +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | + +
+ +**Returns** `Optional[FeatureFlagEvaluationRuntime]`. The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime + +runtime = posthog.get_feature_flag_evaluation_runtime("my-flag") +if runtime is FeatureFlagEvaluationRuntime.SERVER: + ... +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5264) + +#### `Client.get_feature_flag_keys_by_evaluation_runtime` + +Return the keys of locally loaded flags that a runtime can evaluate. + +A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, +so it is returned for `CLIENT` and for `SERVER`, and asking for +`ALL` returns every loaded flag. Use this to decide which flags to hand +to a browser when a backend serves flags to its own frontend. + +```python +get_feature_flag_keys_by_evaluation_runtime( + evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], +) -> list[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required**
The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | + +
+ +**Returns** `list[str]`. The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime + +client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( + FeatureFlagEvaluationRuntime.CLIENT +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5298) + +### Framework integrations + +#### `posthog.integrations.django.PosthogContextMiddleware` + +**Available in:** Django apps + +Middleware to automatically track Django requests. + +This middleware wraps all calls with a posthog context. It attempts to extract the following from the request: +- Session ID, (extracted from `X-POSTHOG-SESSION-ID`) +- Distinct ID, (extracted from `X-POSTHOG-DISTINCT-ID`, falling back to the authenticated request user ID) +- Authenticated user email as `email` +- Request URL as `$current_url` +- Request method as `$request_method` +- Request path as `$request_path` +- Forwarded IP address as `$ip` +- User agent as `$user_agent` + +Configure the integration with these Django settings: +- `POSTHOG_MW_CLIENT`: client used for automatic exception capture, or the global client. + This does not redirect events explicitly captured through other clients. +- `POSTHOG_MW_CAPTURE_EXCEPTIONS`: `False` enables context enrichment only; + `True` enables automatic exception capture; `None` inherits the effective client's + `enable_exception_autocapture`. When omitted, the legacy default is `True`. +- `POSTHOG_MW_REQUEST_FILTER`: a callback receiving the request. Returning `False` + disables both enrichment and automatic exception capture for that request. +- `POSTHOG_MW_EXTRA_PROPERTIES`: a callback returning additional event properties. +- `POSTHOG_MW_CAPTURE_TRACING_HEADERS`: read PostHog identity and session headers + as request-scoped analytics context (default: `True`). Explicit capture IDs and + event properties take precedence. These values are never authentication or + authorization. Authenticated Django user identity remains the fallback when no + usable header ID is available or header capture is disabled. +- `POSTHOG_MW_TRUST_TRACING_HEADERS`: deprecated alias for + `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. +- `POSTHOG_MW_PROPERTIES_MAP`: an optional callback transforming request properties. + +The old `POSTHOG_MW_EXTRA_TAGS` and `POSTHOG_MW_TAG_MAP` settings remain aliases; +the property-named settings take precedence when both are configured. + +Request properties are included on all events captured within the active context, +including when automatic exception capture is disabled. +See the context documentation for more information. The extracted distinct ID and session ID, +if found, are used to associate all events captured in the middleware context with the same distinct ID +and session as currently active on the frontend. See the documentation for `set_context_session` +and `identify_context` for more details. + +This middleware is hybrid-capable: it supports both WSGI (sync) and ASGI (async) Django applications. The middleware +detects at initialization whether the next middleware in the chain is async or sync, and adapts its behavior accordingly. +This ensures compatibility with both pure sync and pure async middleware chains, as well as mixed chains in ASGI mode. + +```python +PosthogContextMiddleware(get_response) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `get_response`
**Required**
The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L31) + +#### `PosthogContextMiddleware.trust_tracing_headers` + +**Available in:** Django apps + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogContextMiddleware.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L158) + +#### `PosthogContextMiddleware.extra_tags` + +**Available in:** Django apps + +Compatibility alias for `extra_properties`. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L167) + +#### `PosthogContextMiddleware.tag_map` + +**Available in:** Django apps + +Compatibility alias for `properties_map`. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L176) + +#### `PosthogContextMiddleware.extract_tags` + +**Available in:** Django apps + +Compatibility alias for `extract_properties`. + +```python +extract_tags(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L184) + +#### `PosthogContextMiddleware.extract_properties` + +**Available in:** Django apps + +Extract event properties and identity from a synchronous request. + +```python +extract_properties(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L189) + +#### `PosthogContextMiddleware.extract_request_user` + +**Available in:** Django apps + +Extract user ID and email from request in sync context. + +```python +extract_request_user(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L250) + +#### `PosthogContextMiddleware.aextract_tags` + +**Available in:** Django apps + +Compatibility alias for `aextract_properties`. + +```python +async aextract_tags(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L256) + +#### `PosthogContextMiddleware.aextract_properties` + +**Available in:** Django apps + +Async version of extract_properties for use in async request handling. + +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. + +Follows Django's naming convention for async methods (auser, asave, etc.). + +```python +async aextract_properties(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L261) + +#### `PosthogContextMiddleware.aextract_request_user` + +**Available in:** Django apps + +Async version of extract_request_user for use in async request handling. + +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. + +Follows Django's naming convention for async methods (auser, asave, etc.). + +```python +async aextract_request_user(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L274) + +#### `PosthogContextMiddleware.process_exception` + +**Available in:** Django apps + +Process exceptions from views and downstream middleware. + +Django calls this WHILE still inside the context created by __call__, +so request tags have already been extracted and set. This method just +needs to capture the exception directly. + +Django converts view exceptions into responses before they propagate through +the middleware stack, so the context manager in __call__/__acall__ never sees them. + +Note: Django's process_exception is always synchronous, even for async views. + +```python +process_exception(request, exception) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `request`
**Required** | +| `exception`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L376) + +#### `posthog.integrations.flask.PosthogFlaskIntegration` + +**Available in:** Flask apps + +Add PostHog request context and exception tracking to a Flask app. + +The integration intentionally does not capture exceptions handled by an +application error handler, expected HTTP exceptions, request or response +bodies, query strings, cookies, authorization headers, or arbitrary headers. +Call `capture_exception` explicitly from a custom error handler if a +handled exception should be reported. + +```python +PosthogFlaskIntegration( + app: Optional[Flask] = None, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + request_filter: Optional[Callable[[Request], bool]] = None, + extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, + trust_tracing_headers: Optional[bool] = None, + capture_tracing_headers: Optional[bool] = None, +) +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `app`
**Type:** `Optional[Flask]` · **Default:** `None`
An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | +| `request_filter`
**Type:** `Optional[Callable[[Request], bool]]` · **Default:** `None`
Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | +| `extra_properties`
**Type:** `Optional[Callable[[Request], Mapping[str, Any]]]` · **Default:** `None`
Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | +| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | +| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L91) + +#### `PosthogFlaskIntegration.trust_tracing_headers` + +**Available in:** Flask apps + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogFlaskIntegration.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L146) + +#### `PosthogFlaskIntegration.init_app` + +**Available in:** Flask apps + +Register the integration with a Flask application once. + +```python +init_app(app: Flask) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `app`
**Type:** `Flask` · **Required** | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L154) + +#### `posthog.integrations.asgi.PosthogASGIMiddleware` + +**Available in:** ASGI apps, such as FastAPI and Starlette + +Add PostHog context and automatic exception capture to an ASGI app. + +```python +PosthogASGIMiddleware( + app: _ASGIApp, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + request_filter: Optional[_RequestFilter] = None, + extra_properties: Optional[_ExtraProperties] = None, + trust_tracing_headers: Optional[bool] = None, + capture_tracing_headers: Optional[bool] = None, +) +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `app`
**Type:** `_ASGIApp` · **Required**
The downstream ASGI application. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | +| `request_filter`
**Type:** `Optional[_RequestFilter]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | +| `extra_properties`
**Type:** `Optional[_ExtraProperties]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope and returning additional event properties. | +| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | +| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L182) + +#### `PosthogASGIMiddleware.trust_tracing_headers` + +**Available in:** ASGI apps, such as FastAPI and Starlette + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogASGIMiddleware.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L225) + +#### `posthog.integrations.celery.PosthogCeleryIntegration` + +**Available in:** Celery workers + +Celery integration that captures task lifecycle events and exceptions. + +```python +PosthogCeleryIntegration( + client: Optional[Client] = None, + capture_exceptions: bool = True, + capture_task_lifecycle_events: bool = True, + propagate_context: bool = True, + task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None, +) +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | +| `capture_exceptions`
**Type:** `bool` · **Default:** `True`
Whether to capture task exceptions via `capture_exception` (default `True`). | +| `capture_task_lifecycle_events`
**Type:** `bool` · **Default:** `True`
Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | +| `propagate_context`
**Type:** `bool` · **Default:** `True`
Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | +| `task_filter`
**Type:** `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` · **Default:** `None`
Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L89) + +#### `PosthogCeleryIntegration.instrument` + +**Available in:** Celery workers + +Connect Celery signal handlers to capture task events and exceptions. +Call this after initializing the PostHog client and this integration. + +If Celery runs on a single host, reinstrumenting in worker children is +not strictly necessary because the PostHog client and this integration +are fork-safe. If Celery workers run across multiple hosts, each worker +process must initialize PostHog, this integration, and call +`instrument()`. Celery provides `worker_process_init` signal to help +with this. + +```python +instrument() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L129) + +#### `PosthogCeleryIntegration.uninstrument` + +**Available in:** Celery workers + +Disconnect Celery signal handlers and unregister exit cleanup. + +Do not use directly, call `shutdown()` instead. + +```python +uninstrument() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L182) + +#### `PosthogCeleryIntegration.shutdown` + +**Available in:** Celery workers + +Disconnect all signal handlers registered by `instrument()`, flush all pending events +and cleanly shutdown the integration. + +`shutdown()` is also registered on `worker_process_shutdown` and `atexit` signals, +but there is no guarantee those will always be called, so we strongly recommend calling +it manually when the integration is no longer needed to avoid data loss. + +```python +shutdown() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L190) + +#### `posthog.integrations.drf.create_exception_handler` + +**Available in:** Django REST framework apps + +Create a PostHog-instrumented DRF exception handler. + +When `POSTHOG_MW_REQUEST_FILTER` is configured, it is also applied to the +underlying Django request before capture so handled errors cannot bypass the +middleware's per-request exclusion. + +The delegated handler is called first. A `None` response is never +captured here because DRF will re-raise that exception, allowing Django's +middleware to capture it as unhandled. + +```python +create_exception_handler( + handler: Optional[Callable[[Exception, Mapping[str, Any]], Any]] = None, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + capture_4xx: bool = False, + exception_filter: Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]] = None, +) -> Callable[[Exception, Mapping[str, Any]], Any] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `handler`
**Type:** `Optional[Callable[[Exception, Mapping[str, Any]], Any]]` · **Default:** `None`
Handler to delegate to. Defaults to DRF's standard exception handler. Its return value and raised exceptions are preserved. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional PostHog client. Client precedence is this argument, the legacy `POSTHOG_DRF_CLIENT` alias, `POSTHOG_MW_CLIENT`, then the global PostHog client. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture handled DRF exceptions. An explicit value takes precedence over `POSTHOG_MW_CAPTURE_EXCEPTIONS`. A boolean setting is used directly; an explicit `None` setting inherits the effective client's `enable_exception_autocapture`. An omitted or malformed setting preserves the legacy `True` default. | +| `capture_4xx`
**Type:** `bool` · **Default:** `False`
Also capture handled 4xx responses. Disabled by default to avoid reporting expected API errors. | +| `exception_filter`
**Type:** `Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]]` · **Default:** `None`
Optional final filter called with `(exception, response, context)`. Returning `False` suppresses capture. | + +
+ +**Returns** `Callable[[Exception, Mapping[str, Any]], Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/drf.py#L140) + +#### `posthog.integrations.otel.PostHogContextSpanProcessor` + +**Available in:** the `otel` extra, `posthog[otel]` + +Add PostHog request IDs to application-owned OpenTelemetry SDK spans. + +Add this processor to the application's existing TracerProvider before +starting requests. It snapshots child span context at span start, without +changing exporters, sampling or providers. Request integrations must also +enrich an incoming span that started before request context was available. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L20) + +#### `PostHogContextSpanProcessor.on_start` + +**Available in:** the `otel` extra, `posthog[otel]` + +```python +on_start(span: Span, parent_context: Optional[Context] = None) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `span`
**Type:** `Span` · **Required** | +| `parent_context`
**Type:** `Optional[Context]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L29) + +#### `posthog.integrations.otel.enrich_current_span` + +**Available in:** the `otel` extra, `posthog[otel]` + +Add request IDs to an existing recording span after request context is set. + +Explicit span attributes take precedence. Missing OpenTelemetry support and +context lookup failures do not interrupt request handling. + +```python +enrich_current_span() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L11) + +### HTTP connection + +#### `posthog.request.set_socket_options` + +Configure socket options for all SDK HTTP connections. + +Call this during initialization, before making API requests. Pass `None` +to reset to the default socket behavior. + +```python +set_socket_options(socket_options: Optional[SocketOptions]) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `socket_options`
**Type:** `Optional[SocketOptions]` · **Required**
A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +from posthog import set_socket_options +set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L143) + +#### `posthog.request.enable_keep_alive` + +Enable TCP keepalive for SDK HTTP connections. + +This helps prevent idle pooled connections from being dropped by network +infrastructure. Call during initialization, before making API requests. + +```python +enable_keep_alive() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L166) + +#### `posthog.request.disable_connection_reuse` + +Disable HTTP connection reuse for SDK requests. + +Each request will create a fresh connection. This can avoid issues with +environments that terminate pooled connections, but adds per-request +overhead. Call during initialization, before making API requests. + +```python +disable_connection_reuse() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L176) + +### AI wrapper clients + +#### `posthog.ai.openai` + +**Available in:** apps with the `openai` package + +Exports `OpenAI`, `AsyncOpenAI`, `AsyncAzureOpenAI`, `AzureOpenAI`. + +#### `posthog.ai.anthropic` + +**Available in:** apps with the `anthropic` package + +Exports `Anthropic`, `AsyncAnthropic`, `AnthropicBedrock`, `AnthropicVertex`, `AsyncAnthropicBedrock`, `AsyncAnthropicVertex`. + +#### `posthog.ai.gemini` + +**Available in:** apps with the Google Gen AI package + +Exports `Client`, `AsyncClient`. + +#### `posthog.ai.langchain` + +**Available in:** the `langchain` extra, `posthog[langchain]` + +Exports `CallbackHandler`. + +#### `posthog.ai.openai_agents` + +**Available in:** apps with the `openai-agents` package + +Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `Trace`, `Client`, `PostHogTracingProcessor`. + +#### `posthog.ai.claude_agent_sdk` + +**Available in:** apps with the `claude-agent-sdk` package + +Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `ClaudeAgentOptions`, `ResultMessage`, `Client`, `PostHogClaudeSDKClient`, `PostHogClaudeAgentProcessor`. + +## AsyncClient + +### `AsyncClient.alias` + +**Available in:** the `async` extra, `posthog[async]` + +```python +alias( + previous_id: ID_TYPES, + distinct_id: Optional[str], + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required** | +| `distinct_id`
**Type:** `Optional[str]` · **Required** | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L772) + +### `AsyncClient.capture` + +**Available in:** the `async` extra, `posthog[async]` + +Queue an event without blocking for network delivery. + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L570) + +### `AsyncClient.capture_immediate` + +**Available in:** the `async` extra, `posthog[async]` + +Capture one event and wait until its delivery attempt completes. + +```python +async capture_immediate( + event: str, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L613) + +### `AsyncClient.capture_exception` + +**Available in:** the `async` extra, `posthog[async]` + +Capture an exception. This method never raises, including in debug mode. + +```python +capture_exception( + exception: Optional[ExceptionArg] = None, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L823) + +### `AsyncClient.emails` + +**Available in:** the `async` extra, `posthog[async]` + +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. + +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog +Cloud app host of `host`. `email_request_timeout_seconds` and +`email_request_max_retries` configure each send. A disabled or shut-down +client sends nothing. See `posthog.emails` for setup. + +```python +AsyncClient.emails: AsyncEmails +``` + +**Correct example.** + +```python +await client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L268) + +### `AsyncClient.flush` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1204) + +### `AsyncClient.evaluate_flags` + +**Available in:** the `async` extra, `posthog[async]` + +Evaluate flags remotely without blocking the event loop. + +The returned snapshot has synchronous in-memory accessors. Pass it to +`capture(flags=...)` to attach the exact values used for branching. +This client does not evaluate flags locally, so the snapshot's +`unresolved_flags` is always empty. + +```python +async evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None` | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None` | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None` | + +
+ +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L959) + +### `AsyncClient.group_identify` + +**Available in:** the `async` extra, `posthog[async]` + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[Union[str, UUID]] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required** | +| `group_key`
**Type:** `str` · **Required** | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | +| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L727) + +### `AsyncClient.set` + +**Available in:** the `async` extra, `posthog[async]` + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L701) + +### `AsyncClient.set_once` + +**Available in:** the `async` extra, `posthog[async]` + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L714) + +### `AsyncClient(...)` + +**Available in:** the `async` extra, `posthog[async]` + +```python +AsyncClient( + project_api_key: str, + host: Optional[str] = None, + debug: bool = False, + max_queue_size: int = 10000, + send: bool = True, + on_error = None, + flush_at: int = 100, + flush_interval: float = 5.0, + gzip: bool = False, + max_retries: int = 3, + timeout: float = 15, + thread: int = 1, + disabled: bool = False, + disable_geoip: bool = True, + is_server: bool = True, + historical_migration: bool = False, + super_properties: Optional[dict[str, Any]] = None, + before_send = None, + log_captured_exceptions: bool = False, + project_root: Optional[str] = None, + capture_exception_code_variables: bool = False, + code_variables_mask_patterns = None, + code_variables_ignore_patterns = None, + code_variables_mask_url_credentials = None, + code_variables_detect_secrets = None, + in_app_modules: Optional[list[str]] = None, + capture_mode: Optional[Union[CaptureMode, str]] = None, + capture_compression: Optional[Union[CaptureCompression, str]] = None, + capture_trace_context: bool = False, + secret_key: Optional[str] = None, + personal_api_key: Optional[str] = None, + feature_flags_request_timeout_seconds: float = 3, + feature_flags_request_max_retries: int = 1, + app_host: Optional[str] = None, + email_request_timeout_seconds: float = 15, + email_request_max_retries: int = 2, +) +``` + +
+Parameters (36) + +| Parameter | +| --- | +| `project_api_key`
**Type:** `str` · **Required** | +| `host`
**Type:** `Optional[str]` · **Default:** `None` | +| `debug`
**Type:** `bool` · **Default:** `False` | +| `max_queue_size`
**Type:** `int` · **Default:** `10000` | +| `send`
**Type:** `bool` · **Default:** `True` | +| `on_error`
**Default:** `None` | +| `flush_at`
**Type:** `int` · **Default:** `100` | +| `flush_interval`
**Type:** `float` · **Default:** `5.0` | +| `gzip`
**Type:** `bool` · **Default:** `False` | +| `max_retries`
**Type:** `int` · **Default:** `3` | +| `timeout`
**Type:** `float` · **Default:** `15` | +| `thread`
**Type:** `int` · **Default:** `1` | +| `disabled`
**Type:** `bool` · **Default:** `False` | +| `disable_geoip`
**Type:** `bool` · **Default:** `True` | +| `is_server`
**Type:** `bool` · **Default:** `True` | +| `historical_migration`
**Type:** `bool` · **Default:** `False` | +| `super_properties`
**Type:** `Optional[dict[str, Any]]` · **Default:** `None` | +| `before_send`
**Default:** `None` | +| `log_captured_exceptions`
**Type:** `bool` · **Default:** `False` | +| `project_root`
**Type:** `Optional[str]` · **Default:** `None` | +| `capture_exception_code_variables`
**Type:** `bool` · **Default:** `False` | +| `code_variables_mask_patterns`
**Default:** `None` | +| `code_variables_ignore_patterns`
**Default:** `None` | +| `code_variables_mask_url_credentials`
**Default:** `None` | +| `code_variables_detect_secrets`
**Default:** `None` | +| `in_app_modules`
**Type:** `Optional[list[str]]` · **Default:** `None` | +| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None` | +| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None` | +| `capture_trace_context`
**Type:** `bool` · **Default:** `False` | +| `secret_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `personal_api_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3` | +| `feature_flags_request_max_retries`
**Type:** `int` · **Default:** `1` | +| `app_host`
**Type:** `Optional[str]` · **Default:** `None` | +| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15` | +| `email_request_max_retries`
**Type:** `int` · **Default:** `2` | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L102) + +### `AsyncClient.shutdown` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async shutdown() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1235) + +### `AsyncClient.join` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async join() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1305) + +### `AsyncClient.get_remote_config_payload` + +**Available in:** the `async` extra, `posthog[async]` + +Fetch and decrypt a remote-config payload without blocking the loop. + +```python +async get_remote_config_payload(key: str) -> Optional[Any] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1064) + +## Module functions + +### `posthog.start_span` + +Start a span for distributed tracing. Alpha. + +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on the +way out); or call `end()` yourself for a span that cannot wrap a block. +Spans started inside the block nest under it automatically. Always returns +a usable handle, even when tracing is off, so calling code never branches. + +```python +start_span( + name: str, + kind: Optional[str] = None, + attributes: Optional[Mapping[str, Any]] = None, + parent: Union[Span, str, None] = None, + tracestate: Optional[str] = None, + start_time: Union[datetime.datetime, float, None] = None, +) -> Span +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | +| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | +| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | +| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | +| `start_time`
**Type:** `Union[datetime.datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +import posthog +posthog.traces = {"service_name": "checkout-api"} + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1284) + +### `posthog.get_active_span` + +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes it +active; a span started manually is not. Use it to propagate the trace to +the next service: `span.traceparent()` is the header value. + +```python +get_active_span() -> Optional[Span] +``` + +**Returns** `Optional[Span]` + +**Correct example.** + +```python +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1339) + +### `posthog.alias` + +Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. + +```python +alias( + previous_id: ID_TYPES, + distinct_id: str, + timestamp: Optional[Union[datetime.datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required**
The unique ID of the user before | +| `distinct_id`
**Type:** `str` · **Required**
The current unique id | +| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | + +
+ +**Returns** `Optional[str]` + +**Details.** To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action. + +**Correct example.** + +```python +# Alias user +from posthog import alias +alias(previous_id='distinct_id', distinct_id='alias_id') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L685) + +### `posthog.capture` + +Capture anything a user does within your system. + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name to specify the event | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | + +
+ +**Returns** `Optional[str]` + +**Details.** Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. + +**Correct example.** + +```python +# Context and capture usage +from posthog import new_context, identify_context, tag_context, capture +# Enter a new context (e.g. a request/response cycle, an instance of a background job, etc) +with new_context(): + # Associate this context with some user, by distinct_id + identify_context('some user') + + # Capture an event, associated with the context-level distinct ID ('some user') + capture('movie started') + + # Capture an event associated with some other user (overriding the context-level distinct ID) + capture('movie joined', distinct_id='some-other-user') + + # Capture an event with some properties + capture('movie played', properties={'movie_id': '123', 'category': 'romcom'}) + + # Capture an event with some properties + capture('purchase', properties={'product_id': '123', 'category': 'romcom'}) + # Capture an event with some associated group + capture('purchase', groups={'company': 'id:5'}) + + # Adding a tag to the current context will cause it to appear on all subsequent events + tag_context('some-tag', 'some-value') + + capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict +``` + +**Correct example.** + +```python +# Set event properties +from posthog import capture +capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L466) + +### `posthog.capture_ai` + +Capture an AI event on the dedicated AI capture endpoint. + +Beta: the signature is stable; operational limits (per-event size cap, +batching, endpoint) may change without notice. + +Takes the same arguments and returns the same value as `capture()`: the +event UUID, or None when the event was not admitted (disabled client, or +dropped by `before_send`). The event is delivered on an isolated queue +with its own consumer pool and a higher per-event size cap, posting to +the dedicated AI ingestion endpoint. The payload is sent as given — no +redaction or truncation is applied here. + +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name, normally one of the `$ai_*` event names. | +| `**kwargs`
Same optional arguments as `capture()`. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +from posthog import capture_ai + +uuid = capture_ai( + "$ai_generation", + distinct_id="user_123", + properties={"$ai_model": "gpt-5"}, +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L539) + +### `posthog.capture_exception` + +Capture exceptions that happen in your code. + +```python +capture_exception( + exception: Optional[ExceptionArg] = None, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None`
The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | +| `**kwargs`
Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | + +
+ +**Returns** `Optional[str]` + +**Details.** Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. + +**Correct example.** + +```python +# Capture exception +from posthog import capture_exception +try: + risky_operation() +except Exception as e: + capture_exception(e) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L725) + +### `posthog.flush` + +Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. + +Call `flush()` before a short-lived request or serverless invocation returns +when using the shared module-level client. Use `shutdown()` only for final +process cleanup or a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. + +Returning does not guarantee server receipt: pending work can remain after a +timeout or span export failure, and failed events may be dropped by consumers. +Calls made directly from SDK callbacks such as `on_error` are deferred +rather than blocking the worker that invoked the callback. + +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +import posthog +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the global client open. +posthog.flush(timeout_seconds=10) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1223) + +### `posthog.get_feature_flag` + +Get feature flag variant for users. Used with experiments. + +```python +get_feature_flag( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FlagValue] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping from group type to group key | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties in format { group_type_name: { group_properties } } | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | + +
+ +**Returns** `Optional[FlagValue]` + +**Details.** `groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. + +**Correct example.** + +```python +# Multivariate feature flag +from posthog import get_feature_flag, get_feature_flag_payload +enabled_variant = get_feature_flag('flag-key', 'distinct_id_of_your_user') +if enabled_variant == 'variant-key': + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L809) + +### `posthog.get_feature_flag_payload` + +Get the payload associated with a feature flag value. + +Deprecated for new code. Prefer `evaluate_flags()` and +`flags.get_flag_payload(key)` so flag evaluation happens once per request. + +```python +get_feature_flag_payload( + key: str, + distinct_id: ID_TYPES, + match_value: Optional[FlagValue] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[object] +``` + +
+Parameters (10) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
Optional flag value to use when selecting a payload. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | + +
+ +**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L965) + +### `posthog.get_feature_flag_result` + +Get a FeatureFlagResult object which contains the flag result and payload. + +This method evaluates a feature flag and returns a FeatureFlagResult object containing: +- enabled: Whether the flag is enabled +- variant: The variant value if the flag has variants +- payload: The payload associated with the flag (automatically deserialized from JSON) +- key: The flag key +- reason: Why the flag was enabled/disabled + +Example: +``python +result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') +if result and result.enabled: + # Use the variant and payload + print(f"Variant: {result.variant}") + print(f"Payload: {result.payload}") +`` + +```python +get_feature_flag_result( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FeatureFlagResult] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | + +
+ +**Returns** `Optional[FeatureFlagResult]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L908) + +### `posthog.get_all_flags` + +Get all flags for a given user. + +```python +get_all_flags( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, +) -> Optional[dict[str, FlagValue]] +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate (evaluates all if None) | + +
+ +**Returns** `Optional[dict[str, FlagValue]]` + +**Details.** Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False. + +**Correct example.** + +```python +# All flags for user +from posthog import get_all_flags +get_all_flags('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L861) + +### `posthog.get_all_flags_and_payloads` + +Get all feature flag values and payloads for a user. + +```python +get_all_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate. Evaluates all flags when omitted. | + +
+ +**Returns** `FlagsAndPayloads`. A dict with `featureFlags` and `featureFlagPayloads` entries. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1037) + +### `posthog.evaluate_flags` + +Evaluate all feature flags for a user in a single call and return a +`FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / +`.get_flag()` and pass the same snapshot to `capture()` via the +`flags` option so events carry the exact flag values the code branched on. + +Prefer this over repeated `get_feature_flag()` calls and over +`capture(send_feature_flags=True)` — it consolidates flag evaluation into +a single `/flags` request per incoming request. + +```python +evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | + +
+ +**Returns** `FeatureFlagEvaluations` + +**Correct example.** + +```python +from posthog import evaluate_flags, capture +flags = evaluate_flags("user_123", person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +capture("page_viewed", distinct_id="user_123", flags=flags) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1079) + +### `posthog.group_identify` + +Set properties on a group. + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime.datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required**
Type of your group. Required - the call is dropped with a warning if it is missing or empty. | +| `group_key`
**Type:** `str` · **Required**
Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Properties to set on the group | +| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
Optional distinct ID of the user performing the action | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Group identify +from posthog import group_identify +group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L637) + +### `posthog.set` + +Set properties on a user record. + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | + +
+ +**Returns** `Optional[str]` + +**Details.** This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). + +**Correct example.** + +```python +# Set person properties +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L573) + +### `posthog.set_once` + +Set properties on a user record, only if they do not yet exist. + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | + +
+ +**Returns** `Optional[str]` + +**Details.** This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. + +**Correct example.** + +```python +# Set property once +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L605) + +### `posthog.feature_enabled` + +Use feature flags to enable or disable features for users. + +```python +feature_enabled( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[bool] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | + +
+ +**Returns** `Optional[bool]` + +**Details.** You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. + +**Correct example.** + +```python +# Boolean feature flag +from posthog import feature_enabled, get_feature_flag_payload +is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L757) + +### `posthog.setup` + +Create or return the global PostHog client configured by module settings. + +Most applications should either instantiate `Posthog` directly or set +`posthog.api_key`/other module settings before calling top-level helpers. +`setup()` is called automatically by global APIs such as `capture()`. + +```python +setup() -> Client +``` + +**Returns** `Client`. The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1394) + +### `posthog.join` + +Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. + +Failed or undrainable events may be dropped and reported through logging or +`on_error`; returning does not guarantee server receipt. Lifecycle cleanup +is attempted once, and cleanup failures are logged without retry. + +```python +join() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +from posthog import join +join() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1265) + +### `posthog.shutdown` + +Attempt final delivery and permanently shut down the global client. + +Call this for final process cleanup, not at the end of each request or +serverless invocation that shares the module-level client. Use `flush()` +before returning from those invocations instead. Shutdown closes capture +lanes, stops background workers and the feature flag poller, and tears down +integrations. The global client is not recreated automatically after shutdown. + +This normally blocks until queued events have been attempted and cleanup +finishes. Failed or undrainable events may be dropped and reported through +logging or `on_error`; returning does not guarantee server receipt. Event +draining has no timeout. Queued spans get a final flush with up to 30 seconds +waiting for an in-flight flush, then a fresh 30-second drain budget; the last +HTTP request is not cut short. Unsent queued spans and still-open spans are +discarded with a warning. +Lifecycle cleanup is attempted once, and cleanup failures are logged without +retry. Calls made directly from SDK callbacks such as `on_error` are deferred +to avoid deadlocking the worker. If blocking completion is required, signal an application-owned +thread, return from the callback, and call `shutdown()` from that thread. +Do not wait inside a callback for another thread or task calling a lifecycle +method. + +```python +shutdown() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +from posthog import shutdown +shutdown() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1359) + +### `posthog.feature_flag_definitions` + +Returns loaded feature flags. + +```python +feature_flag_definitions() +``` + +**Details.** Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. + +**Correct example.** + +```python +from posthog import feature_flag_definitions +definitions = feature_flag_definitions() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1142) + +### `posthog.load_feature_flags` + +Load feature flag definitions from PostHog. + +```python +load_feature_flags() +``` + +**Correct example.** + +```python +from posthog import load_feature_flags +load_feature_flags() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1208) + +### `posthog.new_context` + +Create a new context scope that will be active for the duration of the with block. + +```python +new_context( + fresh: bool = False, + capture_exceptions: Optional[bool] = None, + client: Optional[Client] = None, +) +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `fresh`
**Type:** `bool` · **Default:** `False`
Whether to start with a fresh context (default: False) | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional Posthog client instance to use for this context (default: None) | + +
+ +**Correct example.** + +```python +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L98) + +### `posthog.scoped` + +Decorator that creates a new context for the function. + +```python +scoped(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to start with a fresh context (default: False) | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | + +
+ +**Correct example.** + +```python +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L127) + +### `posthog.set_context_session` + +Set the session ID for the current context. + +```python +set_context_session(session_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import set_context_session +set_context_session("session_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L150) + +### `posthog.set_context_device_id` + +Set the device ID for the current context, associating all feature flag requests +in this or child contexts with the given device ID. + +```python +set_context_device_id(device_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import set_context_device_id +set_context_device_id("device_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L169) + +### `posthog.identify_context` + +Identify the current context with a distinct ID. + +```python +identify_context(distinct_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import identify_context +identify_context("user_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L189) + +### `posthog.set_capture_exception_code_variables_context` + +Override code-variable capture for exceptions in the current context. + +```python +set_capture_exception_code_variables_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required**
Whether exceptions captured in this context should include local variable values from stack frames. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L208) + +### `posthog.set_code_variables_mask_patterns_context` + +Override code-variable mask patterns for exceptions in the current context. + +```python +set_code_variables_mask_patterns_context(mask_patterns: list[str]) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `mask_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns whose values should be replaced with `***` when code variables are captured. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L222) + +### `posthog.set_code_variables_ignore_patterns_context` + +Override code-variable ignore patterns for exceptions in the current context. + +```python +set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `ignore_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns that should be omitted entirely when code variables are captured. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L236) + +### `posthog.set_code_variables_mask_url_credentials_context` + +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from +captured code variables for the current context. + +```python +set_code_variables_mask_url_credentials_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L250) + +### `posthog.set_code_variables_detect_secrets_context` + +Whether to apply entropy-based secret detection as a last-resort redaction of +high-entropy values (API keys, tokens, strong passwords) in captured code +variables for the current context. + +```python +set_code_variables_detect_secrets_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L258) + +### `posthog.tag` + +Add a tag to the current context. + +```python +tag(name: str, value: Any) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The tag key | +| `value`
**Type:** `Any` · **Required**
The tag value | + +
+ +**Correct example.** + +```python +from posthog import tag +tag("user_id", "123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L270) + +### `posthog.get_tags` + +Get all tags from the current context. + +```python +get_tags() -> Dict[str, Any] +``` + +**Returns** `Dict[str, Any]`. Dict of all tags in the current context + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L290) + +### `posthog.get_remote_config_payload` + +Get the payload for a remote config feature flag. + +```python +get_remote_config_payload(key: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The key of the feature flag | + +
+ +**Returns** . The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted + +**Note.** Requires secret_key to be set for authentication + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1017) + +### `posthog.get_feature_flag_evaluation_runtime` + +Return where a locally loaded feature flag is meant to be evaluated. + +```python +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[FeatureFlagEvaluationRuntime]` + +**Details.** Reads the `evaluation_runtime` each flag definition carries, so no extra +request is made. Returns `None` when local evaluation has not loaded a +definition for this key. A definition that carries no runtime reports +`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime +runtime = get_feature_flag_evaluation_runtime("my-flag") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1160) + +### `posthog.get_feature_flag_keys_by_evaluation_runtime` + +Return the keys of locally loaded flags that a runtime can evaluate. + +```python +get_feature_flag_keys_by_evaluation_runtime( + evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], +) -> list[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required** | + +
+ +**Returns** `list[str]` + +**Details.** A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so +it is returned for `CLIENT` and for `SERVER`. Use this to decide which +flags to hand to a browser when a backend serves flags to its own +frontend. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime +client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1184) + +## Configs + +
+Settings (7) + +| Setting | +| --- | +| `POSTHOG_MW_CLIENT`
**Where:** Django settings
client used for automatic exception capture, or the global client. This does not redirect events explicitly captured through other clients. | +| `POSTHOG_MW_CAPTURE_EXCEPTIONS`
**Where:** Django settings
`False` enables context enrichment only; `True` enables automatic exception capture; `None` inherits the effective client's `enable_exception_autocapture`. When omitted, the legacy default is `True`. | +| `POSTHOG_MW_REQUEST_FILTER`
**Where:** Django settings
a callback receiving the request. Returning `False` disables both enrichment and automatic exception capture for that request. | +| `POSTHOG_MW_EXTRA_PROPERTIES`
**Where:** Django settings
a callback returning additional event properties. | +| `POSTHOG_MW_CAPTURE_TRACING_HEADERS`
**Where:** Django settings
read PostHog identity and session headers as request-scoped analytics context (default: `True`). Explicit capture IDs and event properties take precedence. These values are never authentication or authorization. Authenticated Django user identity remains the fallback when no usable header ID is available or header capture is disabled. | +| `POSTHOG_MW_TRUST_TRACING_HEADERS`
**Where:** Django settings
deprecated alias for `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. | +| `POSTHOG_MW_PROPERTIES_MAP`
**Where:** Django settings
an optional callback transforming request properties. | + +
+ +## Types + +### `OptionalCaptureArgs` + +Optional arguments for the capture method. + +
+Fields (8) + +| Field | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to track with the event | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
Group identifiers to associate with this event (format: {group_type: group_key}) | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this event. Defaults to False. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L26) + +### `OptionalSetArgs` + +Optional arguments for the set method. + +
+Fields (5) + +| Field | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to set on the person | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this operation. Defaults to False. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L70) + +### `FeatureFlagEvaluations` + +A point-in-time snapshot of feature flag evaluations for a single distinct_id. + +Returned by `Client.evaluate_flags` — branch on `is_enabled` / +`get_flag` and pass the same object to `Client.capture` via the +`flags` option so the captured event carries the exact flag values the code +branched on. + +Example: + +```python +flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +``` + +To narrow the set of flags that get attached to a captured event, use the in-memory +helpers `only` and `only_accessed`. To narrow the set of flags requested +from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. + +#### `FeatureFlagEvaluations.is_enabled` + +Return whether the flag is enabled. Fires `$feature_flag_called` on the +first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. + +A flag that has a value always wins over `default_value`, including a +disabled flag, which returns `False` even when `default_value=True`. + +```python +is_enabled( + key: str, + default_value: bool = False, + send_feature_flag_events: bool = True, +) -> bool +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `default_value`
**Type:** `bool` · **Default:** `False`
Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | + +
+ +**Returns** `bool` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L164) + +#### `FeatureFlagEvaluations.get_flag` + +Return the flag value. Fires `$feature_flag_called` on first access. + +Returns the variant string for multivariate flags, `True` for enabled flags +without a variant, `False` for disabled flags, and `None` for flags that +were not returned by the evaluation. + +Pass `send_feature_flag_events=False` to skip the event for this read, as +with `is_enabled`. + +```python +get_flag(key: str, send_feature_flag_events: bool = True) -> Optional[FlagValue] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True` | + +
+ +**Returns** `Optional[FlagValue]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L191) + +#### `FeatureFlagEvaluations.get_flag_payload` + +Return the payload associated with a flag. + +Does not count as an access for `only_accessed` and does not fire any event. + +```python +get_flag_payload(key: str) -> Optional[Any] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L211) + +#### `FeatureFlagEvaluations.only_accessed` + +Return a filtered copy containing only flags accessed via `is_enabled` +or `get_flag` before this call. + +Order-dependent: if nothing has been accessed yet, the returned snapshot is +empty. The method honors its name — pre-access if you want a populated result. + +```python +only_accessed() -> FeatureFlagEvaluations +``` + +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L219) + +#### `FeatureFlagEvaluations.only` + +Return a filtered copy containing only flags with the given keys. Keys that +are not present in the evaluation are dropped and logged as a warning. + +```python +only(keys: List[str]) -> FeatureFlagEvaluations +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `keys`
**Type:** `List[str]` · **Required** | + +
+ +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L229) + +#### `FeatureFlagEvaluations.keys` + +Return the flag keys that are part of this evaluation. + +```python +FeatureFlagEvaluations.keys: List[str] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L249) + +#### `FeatureFlagEvaluations.unresolved_flags` + +Return a read-only mapping of flag key to the reason local evaluation +left it without a value. + +A flag is listed when it has a loaded local definition, was in the requested +scope, was inconclusive locally, and no remote value filled the gap. Listed +flags are not part of `keys`, and reading one reports the +`local_evaluation_inconclusive` error instead of `flag_missing`. Reading +this mapping does not count as an access and does not fire any event. +Snapshots returned by `only` and `only_accessed`, and by +`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no +entries. + +```python +FeatureFlagEvaluations.unresolved_flags: Mapping[str, UnresolvedFlagReason] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L254) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L110) + +### `FeatureFlagResult` + +The result of calling a feature flag which includes the flag result, variant, and payload. + +
+Fields (5) + +| Field | +| --- | +| `key`
**Type:** `str`
The unique identifier of the feature flag. | +| `enabled`
**Type:** `bool`
Whether the feature flag is enabled for the current context. | +| `variant`
**Type:** `Optional[str]`
The variant value if the flag is enabled and has variants, None otherwise. | +| `payload`
**Type:** `Optional[Any]`
Additional data associated with the feature flag, if any. | +| `reason`
**Type:** `Optional[str]`
A description of why the flag was enabled or disabled, if available. | + +
+ +#### `FeatureFlagResult.get_value` + +Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. + +```python +get_value() -> FlagValue +``` + +**Returns** `FlagValue`. Either a string variant or boolean value representing the flag's state. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L582) + +#### `FeatureFlagResult.from_value_and_payload` + +Creates a FeatureFlagResult from a flag value and payload. + +```python +from_value_and_payload( + key: str, + value: Union[FlagValue, None], + payload: Any, +) -> Union[FeatureFlagResult, None] +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The unique identifier of the feature flag. | +| `value`
**Type:** `Union[FlagValue, None]` · **Required**
The value of the flag (string variant or boolean). | +| `payload`
**Type:** `Any` · **Required**
Additional data associated with the feature flag. | + +
+ +**Returns** `Union[FeatureFlagResult, None]`. Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L592) + +#### `FeatureFlagResult.from_flag_details` + +Create a FeatureFlagResult from a FeatureFlag object. + +```python +from_flag_details( + details: Union[FeatureFlag, None], + override_match_value: Optional[FlagValue] = None, +) -> FeatureFlagResult | None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `details`
**Type:** `Union[FeatureFlag, None]` · **Required**
The FeatureFlag object to convert. | +| `override_match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | + +
+ +**Returns** `FeatureFlagResult | None`. FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L618) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L563) + +### `FeatureFlag` + +Detailed feature flag evaluation returned by the flags API. + +`enabled`, `variant` and `metadata.payload` are the value rendered the way +responses before `/flags?v=4` carried it, which the legacy getters return. + +
+Fields (5) + +| Field | +| --- | +| `key`
**Type:** `str`
Feature flag key. | +| `enabled`
**Type:** `bool`
Whether the flag is enabled for the evaluated user or group. | +| `variant`
**Type:** `Optional[str]`
Variant key for multivariate flags, otherwise `None`. | +| `reason`
**Type:** `Optional[FlagReason]`
Optional reason metadata explaining the result. | +| `metadata`
**Type:** `Union[FlagMetadata, LegacyFlagMetadata]`
Payload and other metadata returned by the API. | + +
+ +#### `FeatureFlag.get_value` + +Return the variant for a multivariate flag, otherwise whether the flag is enabled. + +```python +get_value() -> FlagValue +``` + +**Returns** `FlagValue` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L285) + +#### `FeatureFlag.from_json` + +Parse one flag record of a `/flags` response. + +A record with a `value` member is a `/flags?v=4` record. A record +without one comes from an older server: its value is `variant`, or +`enabled` when there is no variant, and its config version is `1`. + +```python +from_json(resp: Any) -> FeatureFlag +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `resp`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlag` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L289) + +#### `FeatureFlag.from_value_and_payload` + +Build a flag from its value and payload. A string value is a variant, so the flag is enabled. + +```python +from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `value`
**Type:** `FlagValue` · **Required** | +| `payload`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlag` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L299) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L245) + +### `FlagsAndPayloads` + +Feature flag values and payloads keyed by feature flag key. + +
+Fields (2) + +| Field | +| --- | +| `featureFlags`
**Type:** `Optional[dict[str, FlagValue]]`
Each flag's value, keyed by flag key. | +| `featureFlagPayloads`
**Type:** `Optional[dict[str, Any]]`
Each flag's payload, keyed by flag key. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L551) + +### `FeatureFlagEvaluationRuntime` + +Where a feature flag is meant to be evaluated. + +Set per flag in PostHog and carried on every locally cached flag definition. +`ALL` means the flag suits both client-side and server-side evaluation, so +it matches either runtime. Inheriting from `str` keeps the members directly +comparable to their `"all"` / `"client"` / `"server"` values. + +
+Fields (3) + +| Field | +| --- | +| `ALL`
**Value:** `'all'`
The flag suits both client-side and server-side evaluation. | +| `CLIENT`
**Value:** `'client'`
The flag is meant for client-side evaluation. | +| `SERVER`
**Value:** `'server'`
The flag is meant for server-side evaluation. | + +
+ +#### `FeatureFlagEvaluationRuntime.from_value` + +Coerce a raw `evaluation_runtime` value to a member. + +A missing, null or unrecognized value becomes `ALL`, which is the +default PostHog applies to a flag that does not set a runtime. + +```python +from_value(value: Any) -> FeatureFlagEvaluationRuntime +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `value`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlagEvaluationRuntime` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L98) + +#### `FeatureFlagEvaluationRuntime.matches` + +Whether a flag set to one of these runtimes suits the other runtime. + +`ALL` matches every runtime, so the check is symmetric. + +```python +matches(other: FeatureFlagEvaluationRuntime) -> bool +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `other`
**Type:** `FeatureFlagEvaluationRuntime` · **Required** | + +
+ +**Returns** `bool` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L112) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L80) + +### `UnresolvedFlagReason` + +Why local evaluation left a flag without a value. + +Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from +`str` keeps the members directly comparable to their string values. When more +than one cause applies, the first reason in the order below is reported. + +
+Fields (4) + +| Field | +| --- | +| `EXPERIENCE_CONTINUITY`
**Value:** `'experience_continuity'`
The flag has experience continuity enabled, which local evaluation never resolves. Change the flag to fix it. | +| `UNSUPPORTED_DEFINITION`
**Value:** `'unsupported_definition'`
The flag uses something the local evaluator does not support, such as a static cohort, an unknown operator, a malformed value, a dependency with no loaded definition or a circular dependency. Change the flag or upgrade the SDK to fix it. | +| `UNRESOLVED_DEPENDENCY`
**Value:** `'unresolved_dependency'`
A flag this flag depends on has a loaded definition but was unresolved. | +| `MISSING_CONTEXT`
**Value:** `'missing_context'`
The call did not pass a property, group property or device id the flag needs, or passed it in an unusable form. Pass it to fix it. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L120) + +### `FlagDefinitionCacheProvider` + +Interface for external caching of feature flag definitions. + +Enables multi-worker environments to share flag definitions, reducing API +calls while ensuring all workers have consistent data. + +Methods may be implemented as either synchronous functions or async +functions. If a method returns an awaitable, the SDK runs it to completion +before continuing. + +The four methods handle the complete lifecycle of flag definition caching: + +1. `should_fetch_flag_definitions()` - Called before each poll to determine + if this worker should fetch new definitions. Use for distributed lock + coordination to ensure only one worker fetches at a time. + +2. `get_flag_definitions()` - Called when `should_fetch_flag_definitions()` + returns False. Returns cached definitions if available. + +3. `on_flag_definitions_received()` - Called after successfully fetching + new definitions from the API. Store the data in your external cache + and release any locks. + +4. `shutdown()` - Called when the PostHog client shuts down. Release any + distributed locks and clean up resources. + +#### `FlagDefinitionCacheProvider.get_flag_definitions` + +Retrieve cached flag definitions. + +```python +get_flag_definitions( +) -> Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]] +``` + +**Returns** `Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]]`. Cached flag definitions if available and valid, None otherwise. May return an awaitable resolving to the same value. Returning None will trigger a fetch from the API if this worker has no flags loaded yet. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L93) + +#### `FlagDefinitionCacheProvider.should_fetch_flag_definitions` + +Determine whether this instance should fetch new flag definitions. + +Use this for distributed lock coordination. Only one worker should +return True to avoid thundering herd problems. A typical implementation +uses a distributed lock (e.g., Redis SETNX) that expires after the +poll interval. + +```python +should_fetch_flag_definitions() -> Union[bool, Awaitable[bool]] +``` + +**Returns** `Union[bool, Awaitable[bool]]`. True if this instance should fetch from the API, False otherwise. May return an awaitable resolving to the same value. When False, the client will call `get_flag_definitions()` to retrieve cached data instead. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L109) + +#### `FlagDefinitionCacheProvider.on_flag_definitions_received` + +Called after successfully receiving new flag definitions from PostHog. + +Use this to store the data in your external cache and release any +distributed locks acquired in `should_fetch_flag_definitions()`. + +```python +on_flag_definitions_received(data: FlagDefinitionCacheData) -> Optional[Awaitable[None]] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `data`
**Type:** `FlagDefinitionCacheData` · **Required**
The flag definitions to cache, containing flags, group_type_mapping, and cohorts. | + +
+ +**Returns** `Optional[Awaitable[None]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L126) + +#### `FlagDefinitionCacheProvider.shutdown` + +Called when the PostHog client shuts down. + +Use this to release any distributed locks and clean up resources. +This method is called even if `should_fetch_flag_definitions()` +returned False, so implementations should handle the case where +no lock was acquired. + +```python +shutdown() -> Optional[Awaitable[None]] +``` + +**Returns** `Optional[Awaitable[None]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L141) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L56) + +### `FlagDefinitionCacheData` + +Data structure for cached flag definitions. + +
+Fields (5) + +| Field | +| --- | +| `flags`
**Type:** `Required[List[Dict[str, Any]]]`
List of feature flag definition dictionaries from the API. | +| `group_type_mapping`
**Type:** `Required[Dict[str, str]]`
Mapping of group type indices to group names. | +| `cohorts`
**Type:** `Required[Dict[str, Any]]`
Dictionary of cohort definitions for local evaluation. | +| `minimal_flag_called_events`
**Type:** `NotRequired[bool]`
Server-controlled gate for minimal `$feature_flag_called` events. Treated as False when absent. | +| `property_matching_version`
**Type:** `NotRequired[int]`
Exact/is_not matching selector. Missing means legacy; only version 2 enables explicit matching. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L35) + +### `InconclusiveMatchError` + +Raised when local evaluation can't determine a flag's value. `reason` says +why, as reported by `FeatureFlagEvaluations.unresolved_flags`. + +
+Fields (1) + +| Field | +| --- | +| `reason`
**Type:** `UnresolvedFlagReason`
Why local evaluation couldn't resolve the flag. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L98) + +### `RequiresServerEvaluation` + +Raised when feature flag evaluation requires server-side data that is not +available locally (e.g., static cohorts). + +This error should propagate immediately to trigger API fallback, unlike +InconclusiveMatchError which allows trying other conditions. + +
+Fields (1) + +| Field | +| --- | +| `reason`
**Type:** `UnresolvedFlagReason`
Why the flag needs server-side evaluation. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L115) + +### `CaptureCompression` + +Selects the request-body compression for capture-v1 uploads. + +Only honored when `capture_mode` is `V1`; the legacy `/batch/` path +keeps using its own `gzip` flag. `NONE` sends the body uncompressed. +`GZIP` and `DEFLATE` (zlib, RFC 1950) are both stdlib / zero-dependency; +`ZSTD` is faster and compresses better but needs the optional zstandard +package (`pip install posthog[zstd]`) until stdlib support lands in +Python 3.14. Each maps to the matching `Content-Encoding` token the v1 +server decodes (`br` is accepted by the server too but is intentionally +left out for now). Inheriting from `str` keeps the members comparable to +and serializable as their token values. + +
+Fields (4) + +| Field | +| --- | +| `NONE`
**Value:** `'none'`
Sends the body uncompressed. | +| `GZIP`
**Value:** `'gzip'`
gzip, from the standard library. | +| `DEFLATE`
**Value:** `'deflate'`
zlib (RFC 1950), from the standard library. | +| `ZSTD`
**Value:** `'zstd'`
Faster and smaller, but needs `pip install posthog[zstd]`. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/capture_compression.py#L21) + +### `Span` + +A handle to a span. + +Every method is safe to call on any handle, including after `end()` and +on the inert handles returned when tracing is off, so calling code never +branches on whether tracing is running. Entering a handle (`with span:`) +makes it the active span for the block and ends it on exit, recording an +`Exception` raised inside it. A `BaseException` that is not an +`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) +still ends the span but is not recorded as a failure. + +#### `Span.set_attribute` + +Set one attribute on the span; last write wins. Ignored after `end()`. + +Returns the span, so calls chain. Prefer primitive values: strings, +booleans, integers and floats keep their type. Lists and mappings are +sent as OTLP arrays and maps, but PostHog stores them as serialized +strings. `None` removes the key; anything else is stringified. + +```python +set_attribute(key: str, value: Any) -> Span +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `value`
**Type:** `Any` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L21) + +#### `Span.set_attributes` + +Set several attributes at once; last write wins per key. Ignored after `end()`. + +Returns the span, so calls chain. Same encoding as `set_attribute()`. + +```python +set_attributes(attributes: Mapping[str, Any]) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `attributes`
**Type:** `Mapping[str, Any]` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_attributes({"db.system": "postgresql", "db.rows": 12}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L36) + +#### `Span.add_event` + +Add a timestamped event to the span. Ignored after `end()`. + +`timestamp` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`. Returns the span, so calls +chain. + +```python +add_event( + name: str, + attributes: Optional[Mapping[str, Any]] = None, + timestamp: Union[datetime, float, None] = None, +) -> Span +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | +| `timestamp`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.add_event("cache.miss", {"key": "user:42"}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L48) + +#### `Span.set_status` + +Set the span status to `"ok"` or `"error"`. Ignored after `end()`. + +Unset by default. Any other `code` is ignored. `ok` is final for the +scoped form: an `Exception` raised inside `with span:` does not override +it. Returns the span, so calls chain. + +```python +set_status(code: str, message: Optional[str] = None) -> Span +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `code`
**Type:** `str` · **Required** | +| `message`
**Type:** `Optional[str]` · **Default:** `None` | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_status("error", "upstream timed out") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L67) + +#### `Span.record_exception` + +Record an exception as an `exception` event and mark the span `error`. + +Ignored after `end()`. The event carries `exception.type`, +`exception.message` and, for a raised exception, +`exception.stacktrace` (its last `max_attribute_value_length` +characters, so a chained traceback keeps the outermost exception and +may lose its cause). Returns the span, so calls chain. Inside +`with span:` a raised `Exception` is recorded automatically, so +this is for exceptions that are caught and handled. + +```python +record_exception(exception: BaseException) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `exception`
**Type:** `BaseException` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +try: + charge(card) +except PaymentError as e: + span.record_exception(e) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L81) + +#### `Span.update_name` + +Rename the span, for a name only known after it started. Ignored after `end()`. + +Returns the span, so calls chain. + +```python +update_name(name: str) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span = posthog.start_span("http.request") +span.update_name(f"{request.method} {route.pattern}") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L102) + +#### `Span.traceparent` + +The W3C `traceparent` header value to propagate, or `None`. + +```python +traceparent() -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L115) + +#### `Span.tracestate` + +The W3C `tracestate` header value to propagate, or `None`. + +```python +tracestate() -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L119) + +#### `Span.end` + +End the span and queue it for export. Idempotent. + +`end_time` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`, and is never earlier than +the start. Later calls, and later mutations, no-op. `with span:` +ends the span on exit, so call this only for spans started manually. + +```python +end(end_time: Union[datetime, float, None] = None) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `end_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | + +
+ +**Returns** `None` + +**Correct example.** + +```python +span = posthog.start_span("job") +try: + run_job() +finally: + span.end() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L123) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L9) + +### `PostHogMetrics` + +The `client.metrics` API: `count`, `gauge`, `histogram`, `flush`. + +Thread-safe; safe to call from hot paths. Configure via the `metrics` +client option (`flush_interval` is in seconds, matching the client's own +`flush_interval` — unlike posthog-js, whose `flushIntervalMs` is milliseconds): + +```python +client = Client("phc_...", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +#### `PostHogMetrics.count` + +Record an increment for a monotonic counter (things that only go up). + +```python +count( + name: str, + value: float = 1, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Default:** `1` | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L374) + +#### `PostHogMetrics.gauge` + +Record the current value of something that goes up and down. + +```python +gauge( + name: str, + value: float, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Required** | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L384) + +#### `PostHogMetrics.histogram` + +Record one observation of a distribution (durations, sizes). + +```python +histogram( + name: str, + value: float, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Required** | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L394) + +#### `PostHogMetrics.flush` + +Sends everything aggregated so far without waiting for the flush interval. + +```python +flush() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L404) + +#### `PostHogMetrics.reset` + +Clears the flush timer and drops the current window. + +```python +reset() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L409) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L297) + +### `Emails` + +Sends transactional email from PostHog email templates. + +`host` is your PostHog app host. PostHog Cloud ingestion hosts map to the +app host, so `us.i.posthog.com` sends to `us.posthog.com`. Any other +host is used as given. + +Each send retries network errors, rate limits and an unavailable service up +to `max_retries` times, with the same idempotency key. Set +`max_retries=0` when a job runner already retries the send. `timeout` +is in seconds, per request. Pass `session` to send through your own +`requests.Session`, for example a test double. + +#### `Emails.send` + +Queue one email from a transactional email template. + +```python +send( + to: str, + template_id: Union[str, UUID], + template_data: Optional[Mapping[str, Any]] = None, + distinct_id: Optional[str] = None, + idempotency_key: Optional[str] = None, + max_retries: Optional[int] = None, +) -> SendEmailResult +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `to`
**Type:** `str` · **Required**
One recipient email address. | +| `template_id`
**Type:** `Union[str, UUID]` · **Required**
The UUID of a template made transactional in PostHog. | +| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | +| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None`
The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | +| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None`
1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | +| `max_retries`
**Type:** `Optional[int]` · **Default:** `None`
Overrides the client's maximum number of retries for this send. `0` turns retries off. | + +
+ +**Returns** `SendEmailResult`. The queued email. A result means PostHog queued the email, not that it was delivered. + +**Raises** `EmailError`. PostHog did not queue the email, or the client could +not tell whether it did. + +**Raises** `(TypeError, ValueError)`. An argument has the wrong type or format. + +**Correct example.** + +```python +emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", + idempotency_key="welcome:user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L588) + +#### `Emails.get` + +Read what happened to an email that `send` queued. + +```python +get(message_id: Union[str, UUID]) -> EmailStatus +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `message_id`
**Type:** `Union[str, UUID]` · **Required**
The `id` of the `SendEmailResult` that `send` returned. | + +
+ +**Returns** `EmailStatus`. The email's latest status, for 30 days after the send. + +**Raises** `EmailError`. PostHog did not answer with a status. `code` is +`not_found` for an unknown ID, an email older than 30 days, +or for a few seconds after the send. + +**Raises** `ValueError`. `message_id` is not a message ID. + +**Correct example.** + +```python +result = emails.send(to="user@example.com", template_id="...") +status = emails.get(result.id) +if status.status == "bounced": + print(status.reason) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L659) + +#### `Emails.close` + +Close the HTTP connections this client opened. A `session` you passed in stays open. + +```python +close() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L737) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L553) + +### `AsyncEmails` + +The async counterpart of `Emails`. Needs `posthog[async]`. + +Pass `http_client` to send through your own `httpx.AsyncClient`, for +example one with an `httpx.MockTransport` in tests. + +#### `AsyncEmails.send` + +Queue one email from a transactional email template. + +Takes the same arguments and raises the same errors as +`Emails.send`. + +```python +async send( + to: str, + template_id: Union[str, UUID], + template_data: Optional[Mapping[str, Any]] = None, + distinct_id: Optional[str] = None, + idempotency_key: Optional[str] = None, + max_retries: Optional[int] = None, +) -> SendEmailResult +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `to`
**Type:** `str` · **Required** | +| `template_id`
**Type:** `Union[str, UUID]` · **Required** | +| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | +| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None` | +| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `max_retries`
**Type:** `Optional[int]` · **Default:** `None` | + +
+ +**Returns** `SendEmailResult` + +**Correct example.** + +```python +await emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L792) + +#### `AsyncEmails.get` + +Read what happened to an email that `send` queued. + +Takes the same argument and raises the same errors as +`Emails.get`. + +```python +async get(message_id: Union[str, UUID]) -> EmailStatus +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `message_id`
**Type:** `Union[str, UUID]` · **Required** | + +
+ +**Returns** `EmailStatus` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L838) + +#### `AsyncEmails.aclose` + +Close the HTTP connections this client opened. An `http_client` you passed in stays open. + +```python +async aclose() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L899) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L765) + +### `EmailError` + +PostHog did not queue the email, or the client could not tell whether it did. + +Branch on `code`, PostHog's stable error code, or on `name`, a coarse +category of the failure. The message never contains the secret key or the +request body. + +
+Fields (9) + +| Field | +| --- | +| `name`
A coarse category of the failure. | +| `code`
PostHog's stable error code. | +| `message`
What went wrong. It never contains the secret key or the request body. | +| `status_code`
The HTTP status of the response, or `None` when none arrived. | +| `why`
PostHog's explanation of the failure, when it gave one. | +| `fix`
What to change to fix it, when PostHog said. | +| `docs_url`
A docs page about the error, when PostHog gave one. | +| `field`
The request field the error is about, when there is one. | +| `retry_after`
Seconds to wait before retrying, when PostHog said. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L122) + +### `EmailStatus` + +What happened to an email that `send()` queued. + +`status` is one of: + +- `queued`: the email waits to go out. +- `sent`: PostHog handed the email to the email provider. +- `failed`: the email was not sent, and `reason` says why. +- `delivered`: the recipient's mail server accepted the email. +- `bounced` and `complained`: the recipient's mail provider reported + them after delivery. + +Later SDK versions can see values this list does not have yet. +`reason` says why a failed email was not sent, such as +`provider_error` or `recipient_suppressed`, or gives the bounce type of +a bounced email: `hard`, `soft` or `unknown`. It is `None` otherwise. + +
+Fields (5) + +| Field | +| --- | +| `id`
**Type:** `str`
The email's message ID. | +| `status`
**Type:** `str`
Where the email is now, one of the values above. | +| `created_at`
**Type:** `datetime`
When PostHog queued the email. | +| `status_at`
**Type:** `datetime`
When the email reached its current status. | +| `reason`
**Type:** `Optional[str]` · **Default:** `None`
Why a failed email was not sent, or a bounced email's bounce type. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L189) + +### `SendEmailResult` + +The queued email. `id` is its message ID. + +
+Fields (3) + +| Field | +| --- | +| `id`
**Type:** `str`
The email's message ID. | +| `replayed`
**Type:** `bool` · **Default:** `False`
`True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. | +| `warnings`
**Type:** `tuple[EmailWarning, ...]` · **Default:** `()`
Warnings PostHog returned about the request. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L173) + +### `Prompts` + +Fetch and compile LLM prompts from PostHog. + +Can be initialized with a PostHog client or with direct options. + +#### `Prompts.get` + +Fetch a prompt by name from the PostHog API. + +When `with_metadata` is `True`, returns a `PromptResult` +with `source`, `name`, `version`, and `config` metadata. When +omitted or `False`, returns a plain string (deprecated -- will be +removed in a future major version). + +```python +get( + name: str, + with_metadata: Optional[bool] = None, + cache_ttl_seconds: Optional[int] = None, + fallback: Optional[str] = None, + version: Optional[int] = None, + label: Optional[str] = None, +) -> Union[str, PromptResult] +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The name of the prompt to fetch | +| `with_metadata`
**Type:** `Optional[bool]` · **Default:** `None`
If True, returns a PromptResult with source info. Omitting this parameter is deprecated. | +| `cache_ttl_seconds`
**Type:** `Optional[int]` · **Default:** `None`
Cache TTL in seconds (defaults to instance default) | +| `fallback`
**Type:** `Optional[str]` · **Default:** `None`
Fallback prompt to use if fetch fails and no cache available | +| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to fetch. Mutually exclusive with label. If neither is given, fetches the latest version | +| `label`
**Type:** `Optional[str]` · **Default:** `None`
Fetch the version this label currently points to, e.g. 'production'. Mutually exclusive with version | + +
+ +**Returns** `Union[str, PromptResult]`. str if with_metadata is False/omitted, PromptResult if True + +**Raises** `ValueError`. If both version and label are provided + +**Raises** `Exception`. If the prompt cannot be fetched and no fallback is available + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L359) + +#### `Prompts.get_all` + +Fetch every prompt in one batch. + +Returns a dict mapping prompt name to `PromptResult`. With a +label, each prompt is at the version the label points to, and prompts +without the label are not included. Without a label, every prompt is +included at its latest version, matching what `get(name)` returns. + +Each fetched prompt is stored in the cache, so later +`get(name, label=...)` (or plain `get(name)`) calls are served +from cache within the TTL. An app with many prompts can call this once +per cache cycle instead of making one `get()` request per prompt. + +```python +get_all(label: Optional[str] = None) -> Dict[str, PromptResult] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `label`
**Type:** `Optional[str]` · **Default:** `None`
The label to resolve, e.g. 'production'. Omit to fetch latest versions. | + +
+ +**Returns** `Dict[str, PromptResult]`. Dict of prompt name to PromptResult. + +**Raises** `Exception`. If the request fails, or a label was passed and the +server does not support fetching prompts by label on the list +endpoint (PostHog releases from before September 2026). + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L433) + +#### `Prompts.compile` + +Replace {{variableName}} placeholders with values. + +Unmatched variables are left unchanged. +Supports variable names with hyphens and dots (e.g., user-id, company.name). + +```python +compile(prompt: str, variables: PromptVariables) -> str +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `prompt`
**Type:** `str` · **Required**
The prompt template string | +| `variables`
**Type:** `PromptVariables` · **Required**
Object containing variable values | + +
+ +**Returns** `str`. The compiled prompt string + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L720) + +#### `Prompts.clear_cache` + +Clear cached prompts. + +```python +clear_cache(name: Optional[str] = None, version: Optional[int] = None) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `Optional[str]` · **Default:** `None`
Specific prompt name to clear. If None, clears all cached prompts. | +| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to clear. Requires name. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L745) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L227) From 16c4895bc2903c4270aca5bbc096882ad6abfe4c Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 4 Nov 2026 17:00:43 -0500 Subject: [PATCH 2/9] docs: regenerate the 7.x reference and its latest file Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 87 +- references/posthog-python-reference.md | 5426 ++++++++++++++++++++++++ 2 files changed, 5508 insertions(+), 5 deletions(-) create mode 100644 references/posthog-python-reference.md diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index 83a8806ca..4594ed985 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -1,9 +1,86 @@ --- -title: PostHog Python SDK -sdk: python -version: 7.83.1 -major: 7 -status: current +title: "PostHog Python SDK 7.x" +sidebar: Docs +showTitle: true +contentMaxWidthClass: max-w-full +platformLogo: python +noindex: true +tableOfContents: + - value: "Getting started" + url: getting-started + depth: 0 + - value: "Traces" + url: traces + depth: 0 + - value: "Alias" + url: alias + depth: 0 + - value: "Capture" + url: capture + depth: 0 + - value: "Capture AI" + url: capture-ai + depth: 0 + - value: "Capture exception" + url: capture-exception + depth: 0 + - value: "Emails" + url: emails + depth: 0 + - value: "Flush" + url: flush + depth: 0 + - value: "Get feature flag" + url: get-feature-flag + depth: 0 + - value: "Get feature flag payload" + url: get-feature-flag-payload + depth: 0 + - value: "Get feature flag result" + url: get-feature-flag-result + depth: 0 + - value: "Get feature flags" + url: get-feature-flags + depth: 0 + - value: "Get feature flags and payloads" + url: get-feature-flags-and-payloads + depth: 0 + - value: "Evaluate flags" + url: evaluate-flags + depth: 0 + - value: "Group identify" + url: group-identify + depth: 0 + - value: "Identify" + url: identify + depth: 0 + - value: "Is feature enabled" + url: is-feature-enabled + depth: 0 + - value: "Setup" + url: setup + depth: 0 + - value: "Shutdown" + url: shutdown + depth: 0 + - value: "Flag definition loader" + url: flag-definition-loader + depth: 0 + - value: "SDK utils" + url: sdk-utils + depth: 0 + - value: "AsyncClient" + url: asyncclient + depth: 0 + - value: "Module functions" + url: module-functions + depth: 0 + - value: "Configs" + url: configs + depth: 0 + - value: "Types" + url: types + depth: 0 --- ## Getting started diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md new file mode 100644 index 000000000..daeb05fe0 --- /dev/null +++ b/references/posthog-python-reference.md @@ -0,0 +1,5426 @@ +--- +title: "PostHog Python SDK" +sidebar: Docs +showTitle: true +contentMaxWidthClass: max-w-full +platformLogo: python +tableOfContents: + - value: "Getting started" + url: getting-started + depth: 0 + - value: "Traces" + url: traces + depth: 0 + - value: "Alias" + url: alias + depth: 0 + - value: "Capture" + url: capture + depth: 0 + - value: "Capture AI" + url: capture-ai + depth: 0 + - value: "Capture exception" + url: capture-exception + depth: 0 + - value: "Emails" + url: emails + depth: 0 + - value: "Flush" + url: flush + depth: 0 + - value: "Get feature flag" + url: get-feature-flag + depth: 0 + - value: "Get feature flag payload" + url: get-feature-flag-payload + depth: 0 + - value: "Get feature flag result" + url: get-feature-flag-result + depth: 0 + - value: "Get feature flags" + url: get-feature-flags + depth: 0 + - value: "Get feature flags and payloads" + url: get-feature-flags-and-payloads + depth: 0 + - value: "Evaluate flags" + url: evaluate-flags + depth: 0 + - value: "Group identify" + url: group-identify + depth: 0 + - value: "Identify" + url: identify + depth: 0 + - value: "Is feature enabled" + url: is-feature-enabled + depth: 0 + - value: "Setup" + url: setup + depth: 0 + - value: "Shutdown" + url: shutdown + depth: 0 + - value: "Flag definition loader" + url: flag-definition-loader + depth: 0 + - value: "SDK utils" + url: sdk-utils + depth: 0 + - value: "AsyncClient" + url: asyncclient + depth: 0 + - value: "Module functions" + url: module-functions + depth: 0 + - value: "Configs" + url: configs + depth: 0 + - value: "Types" + url: types + depth: 0 +--- + +## Getting started + +The Python SDK captures events, evaluates feature flags and reports errors from Python 3.10 or later. + +### Install + +```bash +pip install posthog +``` + +### Initialize + +Create one client for your app with your project token and host. Your project token and host are in your [project settings](https://app.posthog.com/project/settings). Keep the token in an environment variable rather than in code. + +```python +from posthog import Posthog + +posthog = Posthog("", host="") +``` + +### Capture an event + +```python +posthog.capture("user_signed_up", distinct_id="user_123", properties={"plan": "free"}) +``` + +`capture` queues the event and returns right away. A background thread sends it. + +### Shut down + +Call `shutdown()` before your process exits, so queued events are sent. + +```python +posthog.shutdown() +``` + +In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [AsyncClient](#asyncclient). + +## Traces + +### `Client.start_span` + +Start a span for distributed tracing. Alpha. + +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on +the way out); or call `end()` yourself for a span that cannot wrap a +block. Spans started inside the block nest under it automatically. +Always returns a usable handle, even when tracing is off, so calling +code never branches. + +```python +start_span( + name: str, + kind: Optional[str] = None, + attributes: Optional[Mapping[str, Any]] = None, + parent: Union[Span, str, None] = None, + tracestate: Optional[str] = None, + start_time: Union[datetime, float, None] = None, +) -> Span +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | +| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | +| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | +| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | +| `start_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +posthog = Posthog("", traces={"service_name": "checkout-api"}) + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2794) + +### `Client.get_active_span` + +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes +it active; a span started manually is not. Use it to propagate the +trace to the next service: `span.traceparent()` is the header value. + +```python +get_active_span() -> Optional[Span] +``` + +**Returns** `Optional[Span]` + +**Correct example.** + +```python +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2853) + +## Alias + +### `Client.alias` + +Create an alias between two distinct IDs. + +Note: This method will not raise exceptions. Errors are logged. + +```python +alias( + previous_id: ID_TYPES, + distinct_id: Optional[str], + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required**
The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | +| `distinct_id`
**Type:** `Optional[str]` · **Required**
The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.alias(previous_id='distinct_id', distinct_id='alias_id') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2168) + +## Capture + +### `Client.capture` + +Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name to capture. | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to include with the event. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
A dictionary of group information. | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Anonymous event +posthog.capture('some-anon-event') +``` + +**Correct example.** + +```python +# Context usage +from posthog import identify_context, new_context +with new_context(): + identify_context('distinct_id_of_the_user') + posthog.capture('user_signed_up') + posthog.capture('user_logged_in') + posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +``` + +**Correct example.** + +```python +# Set event properties +posthog.capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` + +**Correct example.** + +```python +# Page view event +posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1738) + +## Capture AI + +### `Client.capture_ai` + +Capture an AI event on the dedicated AI capture endpoint. + +Beta: the signature is stable; operational limits (per-event size +cap, batching, endpoint) may change without notice. + +Takes the same arguments and returns the same value as `capture()`: +the event UUID, or None when the event was not admitted (disabled +client, or dropped by `before_send`). The event is queued on an +isolated AI lane with its own consumer pool and a higher per-event +size cap, posting to the dedicated AI ingestion endpoint. The payload +is sent as given — no redaction or truncation is applied here. + +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1797) + +## Capture exception + +### `Client.capture_exception` + +Capture an exception for error tracking. + +When OpenTelemetry is installed and a valid span is active, its trace and +span IDs are added as `$trace_id` and `$span_id` event properties. + +```python +capture_exception( + exception: Optional[ExceptionArg], + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Required**
The exception to capture. | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Pass `flags` from `evaluate_flags()` instead. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +try: + # Some code that might fail + pass +except Exception as e: + posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2234) + +## Emails + +### `Client.emails` + +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. + +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope. Sends go to `app_host`, or to the PostHog Cloud app host of +`host`. `email_request_timeout_seconds` and `email_request_max_retries` +configure each send. A disabled or shut-down client sends nothing. See +`posthog.emails` for setup. + +```python +Client.emails: Emails +``` + +**Correct example.** + +```python +client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1256) + +## Flush + +### `Client.flush` + +Attempt immediate delivery of queued events, ended spans and autocaptured metrics, keeping the client reusable. + +For a client shared across requests or serverless invocations (including +the module-level client), call `flush()` before a short-lived invocation +returns. Use `shutdown()` instead only for final process cleanup or when +disposing of a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. + +Returning does not guarantee server receipt: pending work can remain after +a timeout or span export failure, and failed events may be dropped by the +consumers. Calls made directly from SDK callbacks such as `on_error` are +deferred rather than blocking the worker that invoked the callback. + +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the shared client open. +posthog.flush(timeout_seconds=10) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2872) + +## Get feature flag + +### `Client.get_feature_flag` + +Get multivariate feature flag value for a user. + +```python +get_feature_flag( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FlagValue] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[FlagValue]` + +**Correct example.** + +```python +enabled_variant = posthog.get_feature_flag('flag-key', 'distinct_id_of_your_user') +if enabled_variant == 'variant-key': # replace 'variant-key' with the key of your variant + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4324) + +## Get feature flag payload + +### `Client.get_feature_flag_payload` + +Get the payload for a feature flag. + +```python +get_feature_flag_payload( + key: str, + distinct_id: ID_TYPES, + match_value: Optional[FlagValue] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[object] +``` + +
+Parameters (10) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
The specific flag value to get payload for. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `False`
Deprecated. Use get_feature_flag() instead if you need events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. + +**Correct example.** + +```python +is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') + +if is_my_flag_enabled: + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4424) + +## Get feature flag result + +### `Client.get_feature_flag_result` + +Get a FeatureFlagResult object which contains the flag result and payload for a key by evaluating locally or remotely +depending on whether local evaluation is enabled and the flag can be locally evaluated. +This also captures the `$feature_flag_called` event unless `send_feature_flag_events` is `False`. + +```python +get_feature_flag_result( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FeatureFlagResult] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[FeatureFlagResult]`. Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. + +**Correct example.** + +```python +flag_result = posthog.get_feature_flag_result('flag-key', 'distinct_id_of_your_user') +if flag_result and flag_result.get_value() == 'variant-key': + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = flag_result.payload +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4269) + +## Get feature flags + +### `Client.get_feature_variants` + +Get feature flag variants for a user. + +```python +get_feature_variants( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> dict[str, Union[bool, str]] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `dict[str, Union[bool, str]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1499) + +### `Client.get_all_flags` + +Get all feature flags for a user. + +```python +get_all_flags( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> Optional[dict[str, Union[bool, str]]] +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[dict[str, Union[bool, str]]]` + +**Correct example.** + +```python +posthog.get_all_flags('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4744) + +## Get feature flags and payloads + +### `Client.get_feature_flags_and_payloads` + +Get feature flags and payloads for a user. + +```python +get_feature_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsAndPayloads` + +**Correct example.** + +```python +result = posthog.get_feature_flags_and_payloads('') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1580) + +### `Client.get_all_flags_and_payloads` + +Get all feature flags and their payloads for a user. + +```python +get_all_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsAndPayloads` + +**Correct example.** + +```python +posthog.get_all_flags_and_payloads('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4790) + +## Evaluate flags + +### `Client.evaluate_flags` + +Evaluate all feature flags for a user in a single call and return a +`FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / +`.get_flag()` and pass the same snapshot to `capture` via the +`flags` option so events carry the exact flag values the code branched on. + +Prefer this over repeated `get_feature_flag()` calls and over +`capture(send_feature_flags=True)` — it consolidates flag evaluation into +a single `/flags` request per incoming request. + +Local evaluation is transparent: when the poller resolves a flag, the +snapshot's `$feature_flag_called` events are tagged `locally_evaluated=True` +and reason `"Evaluated locally"`. + +```python +evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[List[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `flag_keys`
**Type:** `Optional[List[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | + +
+ +**Returns** `FeatureFlagEvaluations`. class:`FeatureFlagEvaluations` snapshot. + +**Correct example.** + +```python +flags = posthog.evaluate_flags( + "user_123", + person_properties={"plan": "enterprise"}, +) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id="user_123", flags=flags) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4875) + +## Group identify + +### `Client.group_identify` + +Identify a group and set its properties. + +Note: This method will not raise exceptions. Errors are logged. + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[Union[str, UUID]] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required**
The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | +| `group_key`
**Type:** `str` · **Required**
The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of properties to set on the group. | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user performing the action. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2093) + +## Identify + +### `Client.set` + +Set properties on a person profile. + +Note: This method will not raise exceptions. Errors are logged. + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Set with distinct id +posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1995) + +### `Client.set_once` + +Set properties on a person profile only if they haven't been set before. + +Note: This method will not raise exceptions. Errors are logged. + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set once. | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2045) + +## Is feature enabled + +### `Client.feature_enabled` + +Check if a feature flag is enabled for a user. + +```python +feature_enabled( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[bool] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `Optional[bool]` + +**Correct example.** + +```python +is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + # Do something differently for this user + # Optional: fetch the payload + matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3982) + +## Setup + +### `Client(...)` + +Initialize a new PostHog client instance. + +```python +Client( + project_api_key: str, + host = None, + debug = False, + max_queue_size = 10000, + send = True, + on_error = None, + flush_at = 100, + flush_interval = 5.0, + gzip = False, + max_retries = 3, + sync_mode = False, + timeout: float = 15, + thread = 1, + poll_interval = 30, + personal_api_key = None, + disabled = False, + disable_geoip = True, + is_server = True, + historical_migration = False, + feature_flags_request_timeout_seconds: float = 3, + feature_flags_request_max_retries = 1, + super_properties = None, + enable_exception_autocapture = False, + log_captured_exceptions = False, + project_root = None, + privacy_mode = False, + before_send = None, + flag_fallback_cache_url = None, + enable_local_evaluation = True, + flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, + capture_exception_code_variables = False, + code_variables_mask_patterns = None, + code_variables_ignore_patterns = None, + code_variables_mask_url_credentials = None, + code_variables_detect_secrets = None, + in_app_modules: list[str] | None = None, + enable_exception_autocapture_rate_limiting = False, + exception_autocapture_bucket_size = ExceptionCapture.DEFAULT_BUCKET_SIZE, + exception_autocapture_refill_rate = ExceptionCapture.DEFAULT_REFILL_RATE, + exception_autocapture_refill_interval_seconds = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, + capture_mode: Optional[Union[CaptureMode, str]] = None, + capture_compression: Optional[Union[CaptureCompression, str]] = None, + secret_key = None, + metrics: Optional[dict] = None, + enable_full_ai_capture = False, + capture_trace_context = False, + traces: Optional[dict] = None, + app_host: Optional[str] = None, + email_request_timeout_seconds: float = 15, + email_request_max_retries: int = 2, +) +``` + +
+Parameters (50) + +| Parameter | +| --- | +| `project_api_key`
**Type:** `str` · **Required**
PostHog project API key/token. | +| `host`
**Default:** `None`
PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | +| `debug`
**Default:** `False`
Enable verbose SDK logging and re-raise errors from public API methods. | +| `max_queue_size`
**Default:** `10000`
Maximum number of events buffered before upload. | +| `send`
**Default:** `True`
If False, queueing succeeds but events are not sent. | +| `on_error`
**Default:** `None`
Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | +| `flush_at`
**Default:** `100`
Number of queued events that triggers a batch upload. | +| `flush_interval`
**Default:** `5.0`
Maximum seconds a background consumer waits before flushing a partial batch. | +| `gzip`
**Default:** `False`
Whether to gzip event upload payloads. | +| `max_retries`
**Default:** `3`
Number of upload retries. Values below 0 are treated as 0. | +| `sync_mode`
**Default:** `False`
If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | +| `timeout`
**Type:** `float` · **Default:** `15`
HTTP request timeout in seconds for event uploads. | +| `thread`
**Default:** `1`
Number of background consumer threads. | +| `poll_interval`
**Default:** `30`
Seconds between local feature flag definition refreshes. | +| `personal_api_key`
**Default:** `None`
Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | +| `disabled`
**Default:** `False`
If True, disable captures and API requests. Useful in tests. | +| `disable_geoip`
**Default:** `True`
Whether to disable server-side GeoIP enrichment. Defaults to True. | +| `is_server`
**Default:** `True`
Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | +| `historical_migration`
**Default:** `False`
Mark events as historical migration imports. | +| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3`
Timeout in seconds for feature flag and remote config requests. | +| `feature_flags_request_max_retries`
**Default:** `1`
Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | +| `super_properties`
**Default:** `None`
Properties merged into every captured event. | +| `enable_exception_autocapture`
**Default:** `False`
Automatically capture uncaught exceptions. | +| `log_captured_exceptions`
**Default:** `False`
Also log exceptions captured by error tracking. | +| `project_root`
**Default:** `None`
Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | +| `privacy_mode`
**Default:** `False`
For AI observability, capture usage metadata without prompt inputs or outputs. | +| `before_send`
**Default:** `None`
Optional callback that can modify or drop events before upload. Return `None` to drop an event. | +| `flag_fallback_cache_url`
**Default:** `None`
Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | +| `enable_local_evaluation`
**Default:** `True`
Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | +| `flag_definition_cache_provider`
**Type:** `Optional[FlagDefinitionCacheProvider]` · **Default:** `None`
Optional external cache provider for sharing feature flag definitions across workers. | +| `capture_exception_code_variables`
**Default:** `False`
Capture local variable values on exception stack frames. | +| `code_variables_mask_patterns`
**Default:** `None`
Variable-name patterns to mask when capturing code variables. | +| `code_variables_ignore_patterns`
**Default:** `None`
Variable-name patterns to omit when capturing code variables. | +| `code_variables_mask_url_credentials`
**Default:** `None`
Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | +| `code_variables_detect_secrets`
**Default:** `None`
Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | +| `in_app_modules`
**Type:** `list[str]` \| `None` · **Default:** `None`
Module/package prefixes treated as in-app frames in captured exceptions. | +| `enable_exception_autocapture_rate_limiting`
**Default:** `False`
Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | +| `exception_autocapture_bucket_size`
**Default:** `ExceptionCapture.DEFAULT_BUCKET_SIZE`
Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | +| `exception_autocapture_refill_rate`
**Default:** `ExceptionCapture.DEFAULT_REFILL_RATE`
Tokens restored per refill interval for each exception type's bucket. | +| `exception_autocapture_refill_interval_seconds`
**Default:** `ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS`
Seconds between token refills for autocaptured exception rate limiting. | +| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None`
Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | +| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None`
Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | +| `secret_key`
**Default:** `None`
A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:
`posthog.Client(project_api_key, secret_key="phx_...")` | +| `metrics`
**Type:** `Optional[dict]` · **Default:** `None` | +| `enable_full_ai_capture`
**Default:** `False`
Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | +| `capture_trace_context`
**Default:** `False`
When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | +| `traces`
**Type:** `Optional[dict]` · **Default:** `None`
Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | +| `app_host`
**Type:** `Optional[str]` · **Default:** `None`
Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | +| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15`
Timeout in seconds for each email send request. Defaults to 15. | +| `email_request_max_retries`
**Type:** `int` · **Default:** `2`
Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | + +
+ +**Correct example.** + +```python +from posthog import Posthog + +posthog = Posthog('', host='') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L684) + +## Shutdown + +### `Client.join` + +Attempt to process queued events and end the consumer threads. Do not use directly, call `shutdown()` instead. + +Failed or undrainable events may be dropped and reported through logging +or `on_error`; returning does not guarantee server receipt. Lifecycle +cleanup is attempted once, and cleanup failures are logged without retry. + +```python +join() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +posthog.join() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3342) + +### `Client.shutdown` + +Attempt final delivery and permanently shut down the client. + +Call this for final process cleanup or when disposing of a client that +will not be reused. It closes capture lanes, stops background workers and +the feature flag poller, and tears down integrations. Do not call it at the +end of each request or serverless invocation when the client is shared; +call `flush()` before returning instead. A shut-down client cannot be +reused; create a new client if needed. + +Normally this method blocks until queued events have been attempted and +cleanup finishes. Failed or undrainable events may be dropped and +reported through logging or `on_error`; returning does not guarantee +server receipt. Event draining has no timeout. Queued spans get one final +flush with up to 30 seconds waiting for an in-flight flush, then a fresh +30-second drain budget; the last HTTP request is not cut short. Any spans +it cannot send are discarded with a warning, as are spans still open. +Lifecycle cleanup is attempted once, and cleanup failures +are logged without retry. When called directly from an SDK callback such as +`on_error`, shutdown is deferred to avoid blocking the worker that +invoked the callback. If the callback must coordinate a blocking +shutdown, have it signal an +application-owned thread and return before that thread calls shutdown. +Do not wait inside the callback for another thread or task that calls a +lifecycle method. + +```python +shutdown() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +posthog.shutdown() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3364) + +## Flag definition loader + +### `Client.load_feature_flags` + +Load feature flags for local evaluation. + +```python +load_feature_flags() +``` + +**Correct example.** + +```python +posthog.load_feature_flags() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3825) + +### `Client.feature_flag_definitions` + +Return feature flag definitions loaded for local evaluation. + +```python +feature_flag_definitions() +``` + +**Returns** . The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5252) + +## SDK utils + +### Other + +#### `Client.queue` + +The analytics lane's queue (kept for backwards compatibility). + +```python +Client.queue: Queue +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1293) + +#### `Client.consumers` + +Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). + +```python +Client.consumers: Optional[List[Consumer]] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1298) + +#### `Client.feature_flags` + +Get the local evaluation feature flags. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1478) + +#### `Client.metrics` + +The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. + +Samples fold into per-series aggregates in memory and flush as one OTLP +data point per series per window, so recording from hot paths is cheap. +Configure via the `metrics` client option; pending metrics flush on +`shutdown()`. + +```python +Client.metrics: PostHogMetrics +``` + +**Correct example.** + +```python +client = Posthog("", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2718) + +### Contexts + +#### `Client.new_context` + +Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). + +```python +new_context(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | + +
+ +**Correct example.** + +```python +with client.new_context(): + client.identify_context('') + client.capture('event_name') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1378) + +#### `Client.scoped` + +Decorator that creates a new context for the wrapped function using this client. + +```python +scoped(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1400) + +#### `Client.tag` + +Add a tag to the current context. + +```python +tag(name: str, value: Any) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The tag key. | +| `value`
**Type:** `Any` · **Required**
The tag value. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1416) + +#### `Client.get_tags` + +Get all tags from the current context. + +```python +get_tags() -> Dict[str, Any] +``` + +**Returns** `Dict[str, Any]`. Dict of all tags in the current context. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1429) + +#### `Client.identify_context` + +Identify the current context with a distinct ID. + +```python +identify_context(distinct_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1441) + +#### `Client.set_context_session` + +Set the session ID for the current context. + +```python +set_context_session(session_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1453) + +#### `Client.set_context_device_id` + +Set the device ID for the current context. + +```python +set_context_device_id(device_id: str) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1465) + +### Feature flags + +#### `Client.get_feature_payloads` + +Get feature flag payloads for a user, preserving valid serialized JSON. + +```python +get_feature_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> dict[str, Optional[str]] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `dict[str, Optional[str]]` + +**Correct example.** + +```python +payloads = posthog.get_feature_payloads('') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1535) + +#### `Client.get_flags_decision` + +Get feature flags decision. + +```python +get_flags_decision( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FlagsResponse +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | + +
+ +**Returns** `FlagsResponse` + +**Correct example.** + +```python +decision = posthog.get_flags_decision('user123') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1628) + +#### `Client.get_remote_config_payload` + +Get the payload for a remote config feature flag. + +```python +get_remote_config_payload(key: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The remote config feature flag key. | + +
+ +**Returns** . The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned. + +**Note.** Requires `secret_key` for authentication. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4670) + +#### `Client.get_feature_flag_evaluation_runtime` + +Return where a locally loaded feature flag is meant to be evaluated. + +```python +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | + +
+ +**Returns** `Optional[FeatureFlagEvaluationRuntime]`. The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime + +runtime = posthog.get_feature_flag_evaluation_runtime("my-flag") +if runtime is FeatureFlagEvaluationRuntime.SERVER: + ... +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5264) + +#### `Client.get_feature_flag_keys_by_evaluation_runtime` + +Return the keys of locally loaded flags that a runtime can evaluate. + +A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, +so it is returned for `CLIENT` and for `SERVER`, and asking for +`ALL` returns every loaded flag. Use this to decide which flags to hand +to a browser when a backend serves flags to its own frontend. + +```python +get_feature_flag_keys_by_evaluation_runtime( + evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], +) -> list[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required**
The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | + +
+ +**Returns** `list[str]`. The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime + +client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( + FeatureFlagEvaluationRuntime.CLIENT +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5298) + +### Framework integrations + +#### `posthog.integrations.django.PosthogContextMiddleware` + +**Available in:** Django apps + +Middleware to automatically track Django requests. + +This middleware wraps all calls with a posthog context. It attempts to extract the following from the request: +- Session ID, (extracted from `X-POSTHOG-SESSION-ID`) +- Distinct ID, (extracted from `X-POSTHOG-DISTINCT-ID`, falling back to the authenticated request user ID) +- Authenticated user email as `email` +- Request URL as `$current_url` +- Request method as `$request_method` +- Request path as `$request_path` +- Forwarded IP address as `$ip` +- User agent as `$user_agent` + +Configure the integration with these Django settings: +- `POSTHOG_MW_CLIENT`: client used for automatic exception capture, or the global client. + This does not redirect events explicitly captured through other clients. +- `POSTHOG_MW_CAPTURE_EXCEPTIONS`: `False` enables context enrichment only; + `True` enables automatic exception capture; `None` inherits the effective client's + `enable_exception_autocapture`. When omitted, the legacy default is `True`. +- `POSTHOG_MW_REQUEST_FILTER`: a callback receiving the request. Returning `False` + disables both enrichment and automatic exception capture for that request. +- `POSTHOG_MW_EXTRA_PROPERTIES`: a callback returning additional event properties. +- `POSTHOG_MW_CAPTURE_TRACING_HEADERS`: read PostHog identity and session headers + as request-scoped analytics context (default: `True`). Explicit capture IDs and + event properties take precedence. These values are never authentication or + authorization. Authenticated Django user identity remains the fallback when no + usable header ID is available or header capture is disabled. +- `POSTHOG_MW_TRUST_TRACING_HEADERS`: deprecated alias for + `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. +- `POSTHOG_MW_PROPERTIES_MAP`: an optional callback transforming request properties. + +The old `POSTHOG_MW_EXTRA_TAGS` and `POSTHOG_MW_TAG_MAP` settings remain aliases; +the property-named settings take precedence when both are configured. + +Request properties are included on all events captured within the active context, +including when automatic exception capture is disabled. +See the context documentation for more information. The extracted distinct ID and session ID, +if found, are used to associate all events captured in the middleware context with the same distinct ID +and session as currently active on the frontend. See the documentation for `set_context_session` +and `identify_context` for more details. + +This middleware is hybrid-capable: it supports both WSGI (sync) and ASGI (async) Django applications. The middleware +detects at initialization whether the next middleware in the chain is async or sync, and adapts its behavior accordingly. +This ensures compatibility with both pure sync and pure async middleware chains, as well as mixed chains in ASGI mode. + +```python +PosthogContextMiddleware(get_response) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `get_response`
**Required**
The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L31) + +#### `PosthogContextMiddleware.trust_tracing_headers` + +**Available in:** Django apps + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogContextMiddleware.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L158) + +#### `PosthogContextMiddleware.extra_tags` + +**Available in:** Django apps + +Compatibility alias for `extra_properties`. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L167) + +#### `PosthogContextMiddleware.tag_map` + +**Available in:** Django apps + +Compatibility alias for `properties_map`. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L176) + +#### `PosthogContextMiddleware.extract_tags` + +**Available in:** Django apps + +Compatibility alias for `extract_properties`. + +```python +extract_tags(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L184) + +#### `PosthogContextMiddleware.extract_properties` + +**Available in:** Django apps + +Extract event properties and identity from a synchronous request. + +```python +extract_properties(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L189) + +#### `PosthogContextMiddleware.extract_request_user` + +**Available in:** Django apps + +Extract user ID and email from request in sync context. + +```python +extract_request_user(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L250) + +#### `PosthogContextMiddleware.aextract_tags` + +**Available in:** Django apps + +Compatibility alias for `aextract_properties`. + +```python +async aextract_tags(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L256) + +#### `PosthogContextMiddleware.aextract_properties` + +**Available in:** Django apps + +Async version of extract_properties for use in async request handling. + +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. + +Follows Django's naming convention for async methods (auser, asave, etc.). + +```python +async aextract_properties(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L261) + +#### `PosthogContextMiddleware.aextract_request_user` + +**Available in:** Django apps + +Async version of extract_request_user for use in async request handling. + +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. + +Follows Django's naming convention for async methods (auser, asave, etc.). + +```python +async aextract_request_user(request) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `request`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L274) + +#### `PosthogContextMiddleware.process_exception` + +**Available in:** Django apps + +Process exceptions from views and downstream middleware. + +Django calls this WHILE still inside the context created by __call__, +so request tags have already been extracted and set. This method just +needs to capture the exception directly. + +Django converts view exceptions into responses before they propagate through +the middleware stack, so the context manager in __call__/__acall__ never sees them. + +Note: Django's process_exception is always synchronous, even for async views. + +```python +process_exception(request, exception) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `request`
**Required** | +| `exception`
**Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L376) + +#### `posthog.integrations.flask.PosthogFlaskIntegration` + +**Available in:** Flask apps + +Add PostHog request context and exception tracking to a Flask app. + +The integration intentionally does not capture exceptions handled by an +application error handler, expected HTTP exceptions, request or response +bodies, query strings, cookies, authorization headers, or arbitrary headers. +Call `capture_exception` explicitly from a custom error handler if a +handled exception should be reported. + +```python +PosthogFlaskIntegration( + app: Optional[Flask] = None, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + request_filter: Optional[Callable[[Request], bool]] = None, + extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, + trust_tracing_headers: Optional[bool] = None, + capture_tracing_headers: Optional[bool] = None, +) +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `app`
**Type:** `Optional[Flask]` · **Default:** `None`
An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | +| `request_filter`
**Type:** `Optional[Callable[[Request], bool]]` · **Default:** `None`
Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | +| `extra_properties`
**Type:** `Optional[Callable[[Request], Mapping[str, Any]]]` · **Default:** `None`
Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | +| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | +| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L91) + +#### `PosthogFlaskIntegration.trust_tracing_headers` + +**Available in:** Flask apps + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogFlaskIntegration.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L146) + +#### `PosthogFlaskIntegration.init_app` + +**Available in:** Flask apps + +Register the integration with a Flask application once. + +```python +init_app(app: Flask) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `app`
**Type:** `Flask` · **Required** | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L154) + +#### `posthog.integrations.asgi.PosthogASGIMiddleware` + +**Available in:** ASGI apps, such as FastAPI and Starlette + +Add PostHog context and automatic exception capture to an ASGI app. + +```python +PosthogASGIMiddleware( + app: _ASGIApp, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + request_filter: Optional[_RequestFilter] = None, + extra_properties: Optional[_ExtraProperties] = None, + trust_tracing_headers: Optional[bool] = None, + capture_tracing_headers: Optional[bool] = None, +) +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `app`
**Type:** `_ASGIApp` · **Required**
The downstream ASGI application. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | +| `request_filter`
**Type:** `Optional[_RequestFilter]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | +| `extra_properties`
**Type:** `Optional[_ExtraProperties]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope and returning additional event properties. | +| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | +| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L182) + +#### `PosthogASGIMiddleware.trust_tracing_headers` + +**Available in:** ASGI apps, such as FastAPI and Starlette + +Deprecated alias for `capture_tracing_headers`. + +```python +PosthogASGIMiddleware.trust_tracing_headers: bool +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L225) + +#### `posthog.integrations.celery.PosthogCeleryIntegration` + +**Available in:** Celery workers + +Celery integration that captures task lifecycle events and exceptions. + +```python +PosthogCeleryIntegration( + client: Optional[Client] = None, + capture_exceptions: bool = True, + capture_task_lifecycle_events: bool = True, + propagate_context: bool = True, + task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None, +) +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | +| `capture_exceptions`
**Type:** `bool` · **Default:** `True`
Whether to capture task exceptions via `capture_exception` (default `True`). | +| `capture_task_lifecycle_events`
**Type:** `bool` · **Default:** `True`
Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | +| `propagate_context`
**Type:** `bool` · **Default:** `True`
Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | +| `task_filter`
**Type:** `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` · **Default:** `None`
Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L89) + +#### `PosthogCeleryIntegration.instrument` + +**Available in:** Celery workers + +Connect Celery signal handlers to capture task events and exceptions. +Call this after initializing the PostHog client and this integration. + +If Celery runs on a single host, reinstrumenting in worker children is +not strictly necessary because the PostHog client and this integration +are fork-safe. If Celery workers run across multiple hosts, each worker +process must initialize PostHog, this integration, and call +`instrument()`. Celery provides `worker_process_init` signal to help +with this. + +```python +instrument() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L129) + +#### `PosthogCeleryIntegration.uninstrument` + +**Available in:** Celery workers + +Disconnect Celery signal handlers and unregister exit cleanup. + +Do not use directly, call `shutdown()` instead. + +```python +uninstrument() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L182) + +#### `PosthogCeleryIntegration.shutdown` + +**Available in:** Celery workers + +Disconnect all signal handlers registered by `instrument()`, flush all pending events +and cleanly shutdown the integration. + +`shutdown()` is also registered on `worker_process_shutdown` and `atexit` signals, +but there is no guarantee those will always be called, so we strongly recommend calling +it manually when the integration is no longer needed to avoid data loss. + +```python +shutdown() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L190) + +#### `posthog.integrations.drf.create_exception_handler` + +**Available in:** Django REST framework apps + +Create a PostHog-instrumented DRF exception handler. + +When `POSTHOG_MW_REQUEST_FILTER` is configured, it is also applied to the +underlying Django request before capture so handled errors cannot bypass the +middleware's per-request exclusion. + +The delegated handler is called first. A `None` response is never +captured here because DRF will re-raise that exception, allowing Django's +middleware to capture it as unhandled. + +```python +create_exception_handler( + handler: Optional[Callable[[Exception, Mapping[str, Any]], Any]] = None, + client: Optional[Client] = None, + capture_exceptions: Optional[bool] = None, + capture_4xx: bool = False, + exception_filter: Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]] = None, +) -> Callable[[Exception, Mapping[str, Any]], Any] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `handler`
**Type:** `Optional[Callable[[Exception, Mapping[str, Any]], Any]]` · **Default:** `None`
Handler to delegate to. Defaults to DRF's standard exception handler. Its return value and raised exceptions are preserved. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional PostHog client. Client precedence is this argument, the legacy `POSTHOG_DRF_CLIENT` alias, `POSTHOG_MW_CLIENT`, then the global PostHog client. | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture handled DRF exceptions. An explicit value takes precedence over `POSTHOG_MW_CAPTURE_EXCEPTIONS`. A boolean setting is used directly; an explicit `None` setting inherits the effective client's `enable_exception_autocapture`. An omitted or malformed setting preserves the legacy `True` default. | +| `capture_4xx`
**Type:** `bool` · **Default:** `False`
Also capture handled 4xx responses. Disabled by default to avoid reporting expected API errors. | +| `exception_filter`
**Type:** `Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]]` · **Default:** `None`
Optional final filter called with `(exception, response, context)`. Returning `False` suppresses capture. | + +
+ +**Returns** `Callable[[Exception, Mapping[str, Any]], Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/drf.py#L140) + +#### `posthog.integrations.otel.PostHogContextSpanProcessor` + +**Available in:** the `otel` extra, `posthog[otel]` + +Add PostHog request IDs to application-owned OpenTelemetry SDK spans. + +Add this processor to the application's existing TracerProvider before +starting requests. It snapshots child span context at span start, without +changing exporters, sampling or providers. Request integrations must also +enrich an incoming span that started before request context was available. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L20) + +#### `PostHogContextSpanProcessor.on_start` + +**Available in:** the `otel` extra, `posthog[otel]` + +```python +on_start(span: Span, parent_context: Optional[Context] = None) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `span`
**Type:** `Span` · **Required** | +| `parent_context`
**Type:** `Optional[Context]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L29) + +#### `posthog.integrations.otel.enrich_current_span` + +**Available in:** the `otel` extra, `posthog[otel]` + +Add request IDs to an existing recording span after request context is set. + +Explicit span attributes take precedence. Missing OpenTelemetry support and +context lookup failures do not interrupt request handling. + +```python +enrich_current_span() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L11) + +### HTTP connection + +#### `posthog.request.set_socket_options` + +Configure socket options for all SDK HTTP connections. + +Call this during initialization, before making API requests. Pass `None` +to reset to the default socket behavior. + +```python +set_socket_options(socket_options: Optional[SocketOptions]) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `socket_options`
**Type:** `Optional[SocketOptions]` · **Required**
A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +from posthog import set_socket_options +set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L143) + +#### `posthog.request.enable_keep_alive` + +Enable TCP keepalive for SDK HTTP connections. + +This helps prevent idle pooled connections from being dropped by network +infrastructure. Call during initialization, before making API requests. + +```python +enable_keep_alive() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L166) + +#### `posthog.request.disable_connection_reuse` + +Disable HTTP connection reuse for SDK requests. + +Each request will create a fresh connection. This can avoid issues with +environments that terminate pooled connections, but adds per-request +overhead. Call during initialization, before making API requests. + +```python +disable_connection_reuse() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L176) + +### AI wrapper clients + +#### `posthog.ai.openai` + +**Available in:** apps with the `openai` package + +Exports `OpenAI`, `AsyncOpenAI`, `AsyncAzureOpenAI`, `AzureOpenAI`. + +#### `posthog.ai.anthropic` + +**Available in:** apps with the `anthropic` package + +Exports `Anthropic`, `AsyncAnthropic`, `AnthropicBedrock`, `AnthropicVertex`, `AsyncAnthropicBedrock`, `AsyncAnthropicVertex`. + +#### `posthog.ai.gemini` + +**Available in:** apps with the Google Gen AI package + +Exports `Client`, `AsyncClient`. + +#### `posthog.ai.langchain` + +**Available in:** the `langchain` extra, `posthog[langchain]` + +Exports `CallbackHandler`. + +#### `posthog.ai.openai_agents` + +**Available in:** apps with the `openai-agents` package + +Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `Trace`, `Client`, `PostHogTracingProcessor`. + +#### `posthog.ai.claude_agent_sdk` + +**Available in:** apps with the `claude-agent-sdk` package + +Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `ClaudeAgentOptions`, `ResultMessage`, `Client`, `PostHogClaudeSDKClient`, `PostHogClaudeAgentProcessor`. + +## AsyncClient + +### `AsyncClient.alias` + +**Available in:** the `async` extra, `posthog[async]` + +```python +alias( + previous_id: ID_TYPES, + distinct_id: Optional[str], + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required** | +| `distinct_id`
**Type:** `Optional[str]` · **Required** | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L772) + +### `AsyncClient.capture` + +**Available in:** the `async` extra, `posthog[async]` + +Queue an event without blocking for network delivery. + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L570) + +### `AsyncClient.capture_immediate` + +**Available in:** the `async` extra, `posthog[async]` + +Capture one event and wait until its delivery attempt completes. + +```python +async capture_immediate( + event: str, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L613) + +### `AsyncClient.capture_exception` + +**Available in:** the `async` extra, `posthog[async]` + +Capture an exception. This method never raises, including in debug mode. + +```python +capture_exception( + exception: Optional[ExceptionArg] = None, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L823) + +### `AsyncClient.emails` + +**Available in:** the `async` extra, `posthog[async]` + +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. + +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog +Cloud app host of `host`. `email_request_timeout_seconds` and +`email_request_max_retries` configure each send. A disabled or shut-down +client sends nothing. See `posthog.emails` for setup. + +```python +AsyncClient.emails: AsyncEmails +``` + +**Correct example.** + +```python +await client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L268) + +### `AsyncClient.flush` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1204) + +### `AsyncClient.evaluate_flags` + +**Available in:** the `async` extra, `posthog[async]` + +Evaluate flags remotely without blocking the event loop. + +The returned snapshot has synchronous in-memory accessors. Pass it to +`capture(flags=...)` to attach the exact values used for branching. +This client does not evaluate flags locally, so the snapshot's +`unresolved_flags` is always empty. + +```python +async evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None` | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None` | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None` | + +
+ +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L959) + +### `AsyncClient.group_identify` + +**Available in:** the `async` extra, `posthog[async]` + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime, str]] = None, + uuid: Optional[Union[str, UUID]] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required** | +| `group_key`
**Type:** `str` · **Required** | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | +| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | +| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None` | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | + +
+ +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L727) + +### `AsyncClient.set` + +**Available in:** the `async` extra, `posthog[async]` + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L701) + +### `AsyncClient.set_once` + +**Available in:** the `async` extra, `posthog[async]` + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L714) + +### `AsyncClient(...)` + +**Available in:** the `async` extra, `posthog[async]` + +```python +AsyncClient( + project_api_key: str, + host: Optional[str] = None, + debug: bool = False, + max_queue_size: int = 10000, + send: bool = True, + on_error = None, + flush_at: int = 100, + flush_interval: float = 5.0, + gzip: bool = False, + max_retries: int = 3, + timeout: float = 15, + thread: int = 1, + disabled: bool = False, + disable_geoip: bool = True, + is_server: bool = True, + historical_migration: bool = False, + super_properties: Optional[dict[str, Any]] = None, + before_send = None, + log_captured_exceptions: bool = False, + project_root: Optional[str] = None, + capture_exception_code_variables: bool = False, + code_variables_mask_patterns = None, + code_variables_ignore_patterns = None, + code_variables_mask_url_credentials = None, + code_variables_detect_secrets = None, + in_app_modules: Optional[list[str]] = None, + capture_mode: Optional[Union[CaptureMode, str]] = None, + capture_compression: Optional[Union[CaptureCompression, str]] = None, + capture_trace_context: bool = False, + secret_key: Optional[str] = None, + personal_api_key: Optional[str] = None, + feature_flags_request_timeout_seconds: float = 3, + feature_flags_request_max_retries: int = 1, + app_host: Optional[str] = None, + email_request_timeout_seconds: float = 15, + email_request_max_retries: int = 2, +) +``` + +
+Parameters (36) + +| Parameter | +| --- | +| `project_api_key`
**Type:** `str` · **Required** | +| `host`
**Type:** `Optional[str]` · **Default:** `None` | +| `debug`
**Type:** `bool` · **Default:** `False` | +| `max_queue_size`
**Type:** `int` · **Default:** `10000` | +| `send`
**Type:** `bool` · **Default:** `True` | +| `on_error`
**Default:** `None` | +| `flush_at`
**Type:** `int` · **Default:** `100` | +| `flush_interval`
**Type:** `float` · **Default:** `5.0` | +| `gzip`
**Type:** `bool` · **Default:** `False` | +| `max_retries`
**Type:** `int` · **Default:** `3` | +| `timeout`
**Type:** `float` · **Default:** `15` | +| `thread`
**Type:** `int` · **Default:** `1` | +| `disabled`
**Type:** `bool` · **Default:** `False` | +| `disable_geoip`
**Type:** `bool` · **Default:** `True` | +| `is_server`
**Type:** `bool` · **Default:** `True` | +| `historical_migration`
**Type:** `bool` · **Default:** `False` | +| `super_properties`
**Type:** `Optional[dict[str, Any]]` · **Default:** `None` | +| `before_send`
**Default:** `None` | +| `log_captured_exceptions`
**Type:** `bool` · **Default:** `False` | +| `project_root`
**Type:** `Optional[str]` · **Default:** `None` | +| `capture_exception_code_variables`
**Type:** `bool` · **Default:** `False` | +| `code_variables_mask_patterns`
**Default:** `None` | +| `code_variables_ignore_patterns`
**Default:** `None` | +| `code_variables_mask_url_credentials`
**Default:** `None` | +| `code_variables_detect_secrets`
**Default:** `None` | +| `in_app_modules`
**Type:** `Optional[list[str]]` · **Default:** `None` | +| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None` | +| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None` | +| `capture_trace_context`
**Type:** `bool` · **Default:** `False` | +| `secret_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `personal_api_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3` | +| `feature_flags_request_max_retries`
**Type:** `int` · **Default:** `1` | +| `app_host`
**Type:** `Optional[str]` · **Default:** `None` | +| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15` | +| `email_request_max_retries`
**Type:** `int` · **Default:** `2` | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L102) + +### `AsyncClient.shutdown` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async shutdown() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1235) + +### `AsyncClient.join` + +**Available in:** the `async` extra, `posthog[async]` + +```python +async join() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1305) + +### `AsyncClient.get_remote_config_payload` + +**Available in:** the `async` extra, `posthog[async]` + +Fetch and decrypt a remote-config payload without blocking the loop. + +```python +async get_remote_config_payload(key: str) -> Optional[Any] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1064) + +## Module functions + +### `posthog.start_span` + +Start a span for distributed tracing. Alpha. + +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on the +way out); or call `end()` yourself for a span that cannot wrap a block. +Spans started inside the block nest under it automatically. Always returns +a usable handle, even when tracing is off, so calling code never branches. + +```python +start_span( + name: str, + kind: Optional[str] = None, + attributes: Optional[Mapping[str, Any]] = None, + parent: Union[Span, str, None] = None, + tracestate: Optional[str] = None, + start_time: Union[datetime.datetime, float, None] = None, +) -> Span +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | +| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | +| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | +| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | +| `start_time`
**Type:** `Union[datetime.datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +import posthog +posthog.traces = {"service_name": "checkout-api"} + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1284) + +### `posthog.get_active_span` + +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes it +active; a span started manually is not. Use it to propagate the trace to +the next service: `span.traceparent()` is the header value. + +```python +get_active_span() -> Optional[Span] +``` + +**Returns** `Optional[Span]` + +**Correct example.** + +```python +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1339) + +### `posthog.alias` + +Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. + +```python +alias( + previous_id: ID_TYPES, + distinct_id: str, + timestamp: Optional[Union[datetime.datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, +) -> Optional[str] +``` + +
+Parameters (5) + +| Parameter | +| --- | +| `previous_id`
**Type:** `ID_TYPES` · **Required**
The unique ID of the user before | +| `distinct_id`
**Type:** `str` · **Required**
The current unique id | +| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | + +
+ +**Returns** `Optional[str]` + +**Details.** To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action. + +**Correct example.** + +```python +# Alias user +from posthog import alias +alias(previous_id='distinct_id', distinct_id='alias_id') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L685) + +### `posthog.capture` + +Capture anything a user does within your system. + +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name to specify the event | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | + +
+ +**Returns** `Optional[str]` + +**Details.** Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. + +**Correct example.** + +```python +# Context and capture usage +from posthog import new_context, identify_context, tag_context, capture +# Enter a new context (e.g. a request/response cycle, an instance of a background job, etc) +with new_context(): + # Associate this context with some user, by distinct_id + identify_context('some user') + + # Capture an event, associated with the context-level distinct ID ('some user') + capture('movie started') + + # Capture an event associated with some other user (overriding the context-level distinct ID) + capture('movie joined', distinct_id='some-other-user') + + # Capture an event with some properties + capture('movie played', properties={'movie_id': '123', 'category': 'romcom'}) + + # Capture an event with some properties + capture('purchase', properties={'product_id': '123', 'category': 'romcom'}) + # Capture an event with some associated group + capture('purchase', groups={'company': 'id:5'}) + + # Adding a tag to the current context will cause it to appear on all subsequent events + tag_context('some-tag', 'some-value') + + capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict +``` + +**Correct example.** + +```python +# Set event properties +from posthog import capture +capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L466) + +### `posthog.capture_ai` + +Capture an AI event on the dedicated AI capture endpoint. + +Beta: the signature is stable; operational limits (per-event size cap, +batching, endpoint) may change without notice. + +Takes the same arguments and returns the same value as `capture()`: the +event UUID, or None when the event was not admitted (disabled client, or +dropped by `before_send`). The event is delivered on an isolated queue +with its own consumer pool and a higher per-event size cap, posting to +the dedicated AI ingestion endpoint. The payload is sent as given — no +redaction or truncation is applied here. + +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `event`
**Type:** `str` · **Required**
The event name, normally one of the `$ai_*` event names. | +| `**kwargs`
Same optional arguments as `capture()`. | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +from posthog import capture_ai + +uuid = capture_ai( + "$ai_generation", + distinct_id="user_123", + properties={"$ai_model": "gpt-5"}, +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L539) + +### `posthog.capture_exception` + +Capture exceptions that happen in your code. + +```python +capture_exception( + exception: Optional[ExceptionArg] = None, + **kwargs: Unpack[OptionalCaptureArgs], +) -> Optional[str] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None`
The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | +| `**kwargs`
Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | + +
+ +**Returns** `Optional[str]` + +**Details.** Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. + +**Correct example.** + +```python +# Capture exception +from posthog import capture_exception +try: + risky_operation() +except Exception as e: + capture_exception(e) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L725) + +### `posthog.flush` + +Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. + +Call `flush()` before a short-lived request or serverless invocation returns +when using the shared module-level client. Use `shutdown()` only for final +process cleanup or a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. + +Returning does not guarantee server receipt: pending work can remain after a +timeout or span export failure, and failed events may be dropped by consumers. +Calls made directly from SDK callbacks such as `on_error` are deferred +rather than blocking the worker that invoked the callback. + +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | + +
+ +**Returns** `None` + +**Correct example.** + +```python +import posthog +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the global client open. +posthog.flush(timeout_seconds=10) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1223) + +### `posthog.get_feature_flag` + +Get feature flag variant for users. Used with experiments. + +```python +get_feature_flag( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FlagValue] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping from group type to group key | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties in format { group_type_name: { group_properties } } | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | + +
+ +**Returns** `Optional[FlagValue]` + +**Details.** `groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. + +**Correct example.** + +```python +# Multivariate feature flag +from posthog import get_feature_flag, get_feature_flag_payload +enabled_variant = get_feature_flag('flag-key', 'distinct_id_of_your_user') +if enabled_variant == 'variant-key': + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L809) + +### `posthog.get_feature_flag_payload` + +Get the payload associated with a feature flag value. + +Deprecated for new code. Prefer `evaluate_flags()` and +`flags.get_flag_payload(key)` so flag evaluation happens once per request. + +```python +get_feature_flag_payload( + key: str, + distinct_id: ID_TYPES, + match_value: Optional[FlagValue] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[object] +``` + +
+Parameters (10) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
Optional flag value to use when selecting a payload. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | + +
+ +**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L965) + +### `posthog.get_feature_flag_result` + +Get a FeatureFlagResult object which contains the flag result and payload. + +This method evaluates a feature flag and returns a FeatureFlagResult object containing: +- enabled: Whether the flag is enabled +- variant: The variant value if the flag has variants +- payload: The payload associated with the flag (automatically deserialized from JSON) +- key: The flag key +- reason: Why the flag was enabled/disabled + +Example: +``python +result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') +if result and result.enabled: + # Use the variant and payload + print(f"Variant: {result.variant}") + print(f"Payload: {result.payload}") +`` + +```python +get_feature_flag_result( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[FeatureFlagResult] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | + +
+ +**Returns** `Optional[FeatureFlagResult]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L908) + +### `posthog.get_all_flags` + +Get all flags for a given user. + +```python +get_all_flags( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, +) -> Optional[dict[str, FlagValue]] +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate (evaluates all if None) | + +
+ +**Returns** `Optional[dict[str, FlagValue]]` + +**Details.** Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False. + +**Correct example.** + +```python +# All flags for user +from posthog import get_all_flags +get_all_flags('distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L861) + +### `posthog.get_all_flags_and_payloads` + +Get all feature flag values and payloads for a user. + +```python +get_all_flags_and_payloads( + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, + flag_keys_to_evaluate: Optional[list[str]] = None, +) -> FlagsAndPayloads +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate. Evaluates all flags when omitted. | + +
+ +**Returns** `FlagsAndPayloads`. A dict with `featureFlags` and `featureFlagPayloads` entries. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1037) + +### `posthog.evaluate_flags` + +Evaluate all feature flags for a user in a single call and return a +`FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / +`.get_flag()` and pass the same snapshot to `capture()` via the +`flags` option so events carry the exact flag values the code branched on. + +Prefer this over repeated `get_feature_flag()` calls and over +`capture(send_feature_flags=True)` — it consolidates flag evaluation into +a single `/flags` request per incoming request. + +```python +evaluate_flags( + distinct_id: Optional[ID_TYPES] = None, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + disable_geoip: Optional[bool] = None, + flag_keys: Optional[list[str]] = None, + device_id: Optional[str] = None, +) -> FeatureFlagEvaluations +``` + +
+Parameters (8) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | +| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | + +
+ +**Returns** `FeatureFlagEvaluations` + +**Correct example.** + +```python +from posthog import evaluate_flags, capture +flags = evaluate_flags("user_123", person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +capture("page_viewed", distinct_id="user_123", flags=flags) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1079) + +### `posthog.group_identify` + +Set properties on a group. + +```python +group_identify( + group_type: str, + group_key: str, + properties: Optional[Dict[str, Any]] = None, + timestamp: Optional[Union[datetime.datetime, str]] = None, + uuid: Optional[str] = None, + disable_geoip: Optional[bool] = None, + distinct_id: Optional[ID_TYPES] = None, +) -> Optional[str] +``` + +
+Parameters (7) + +| Parameter | +| --- | +| `group_type`
**Type:** `str` · **Required**
Type of your group. Required - the call is dropped with a warning if it is missing or empty. | +| `group_key`
**Type:** `str` · **Required**
Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | +| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Properties to set on the group | +| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
Optional distinct ID of the user performing the action | + +
+ +**Returns** `Optional[str]` + +**Correct example.** + +```python +# Group identify +from posthog import group_identify +group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L637) + +### `posthog.set` + +Set properties on a user record. + +```python +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | + +
+ +**Returns** `Optional[str]` + +**Details.** This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). + +**Correct example.** + +```python +# Set person properties +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L573) + +### `posthog.set_once` + +Set properties on a user record, only if they do not yet exist. + +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | + +
+ +**Returns** `Optional[str]` + +**Details.** This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. + +**Correct example.** + +```python +# Set property once +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L605) + +### `posthog.feature_enabled` + +Use feature flags to enable or disable features for users. + +```python +feature_enabled( + key: str, + distinct_id: ID_TYPES, + groups: Optional[Mapping[str, Union[str, int]]] = None, + person_properties: Optional[Dict[str, Any]] = None, + group_properties: Optional[Dict[str, Dict[str, Any]]] = None, + only_evaluate_locally: bool = False, + send_feature_flag_events: bool = True, + disable_geoip: Optional[bool] = None, + device_id: Optional[str] = None, +) -> Optional[bool] +``` + +
+Parameters (9) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key | +| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | +| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | +| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | +| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | +| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | +| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | +| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | + +
+ +**Returns** `Optional[bool]` + +**Details.** You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. + +**Correct example.** + +```python +# Boolean feature flag +from posthog import feature_enabled, get_feature_flag_payload +is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L757) + +### `posthog.setup` + +Create or return the global PostHog client configured by module settings. + +Most applications should either instantiate `Posthog` directly or set +`posthog.api_key`/other module settings before calling top-level helpers. +`setup()` is called automatically by global APIs such as `capture()`. + +```python +setup() -> Client +``` + +**Returns** `Client`. The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1394) + +### `posthog.join` + +Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. + +Failed or undrainable events may be dropped and reported through logging or +`on_error`; returning does not guarantee server receipt. Lifecycle cleanup +is attempted once, and cleanup failures are logged without retry. + +```python +join() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +from posthog import join +join() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1265) + +### `posthog.shutdown` + +Attempt final delivery and permanently shut down the global client. + +Call this for final process cleanup, not at the end of each request or +serverless invocation that shares the module-level client. Use `flush()` +before returning from those invocations instead. Shutdown closes capture +lanes, stops background workers and the feature flag poller, and tears down +integrations. The global client is not recreated automatically after shutdown. + +This normally blocks until queued events have been attempted and cleanup +finishes. Failed or undrainable events may be dropped and reported through +logging or `on_error`; returning does not guarantee server receipt. Event +draining has no timeout. Queued spans get a final flush with up to 30 seconds +waiting for an in-flight flush, then a fresh 30-second drain budget; the last +HTTP request is not cut short. Unsent queued spans and still-open spans are +discarded with a warning. +Lifecycle cleanup is attempted once, and cleanup failures are logged without +retry. Calls made directly from SDK callbacks such as `on_error` are deferred +to avoid deadlocking the worker. If blocking completion is required, signal an application-owned +thread, return from the callback, and call `shutdown()` from that thread. +Do not wait inside a callback for another thread or task calling a lifecycle +method. + +```python +shutdown() -> None +``` + +**Returns** `None` + +**Correct example.** + +```python +from posthog import shutdown +shutdown() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1359) + +### `posthog.feature_flag_definitions` + +Returns loaded feature flags. + +```python +feature_flag_definitions() +``` + +**Details.** Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. + +**Correct example.** + +```python +from posthog import feature_flag_definitions +definitions = feature_flag_definitions() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1142) + +### `posthog.load_feature_flags` + +Load feature flag definitions from PostHog. + +```python +load_feature_flags() +``` + +**Correct example.** + +```python +from posthog import load_feature_flags +load_feature_flags() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1208) + +### `posthog.new_context` + +Create a new context scope that will be active for the duration of the with block. + +```python +new_context( + fresh: bool = False, + capture_exceptions: Optional[bool] = None, + client: Optional[Client] = None, +) +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `fresh`
**Type:** `bool` · **Default:** `False`
Whether to start with a fresh context (default: False) | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | +| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional Posthog client instance to use for this context (default: None) | + +
+ +**Correct example.** + +```python +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L98) + +### `posthog.scoped` + +Decorator that creates a new context for the function. + +```python +scoped(fresh = False, capture_exceptions: Optional[bool] = None) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `fresh`
**Default:** `False`
Whether to start with a fresh context (default: False) | +| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | + +
+ +**Correct example.** + +```python +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L127) + +### `posthog.set_context_session` + +Set the session ID for the current context. + +```python +set_context_session(session_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import set_context_session +set_context_session("session_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L150) + +### `posthog.set_context_device_id` + +Set the device ID for the current context, associating all feature flag requests +in this or child contexts with the given device ID. + +```python +set_context_device_id(device_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import set_context_device_id +set_context_device_id("device_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L169) + +### `posthog.identify_context` + +Identify the current context with a distinct ID. + +```python +identify_context(distinct_id: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children | + +
+ +**Correct example.** + +```python +from posthog import identify_context +identify_context("user_123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L189) + +### `posthog.set_capture_exception_code_variables_context` + +Override code-variable capture for exceptions in the current context. + +```python +set_capture_exception_code_variables_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required**
Whether exceptions captured in this context should include local variable values from stack frames. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L208) + +### `posthog.set_code_variables_mask_patterns_context` + +Override code-variable mask patterns for exceptions in the current context. + +```python +set_code_variables_mask_patterns_context(mask_patterns: list[str]) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `mask_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns whose values should be replaced with `***` when code variables are captured. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L222) + +### `posthog.set_code_variables_ignore_patterns_context` + +Override code-variable ignore patterns for exceptions in the current context. + +```python +set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `ignore_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns that should be omitted entirely when code variables are captured. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L236) + +### `posthog.set_code_variables_mask_url_credentials_context` + +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from +captured code variables for the current context. + +```python +set_code_variables_mask_url_credentials_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L250) + +### `posthog.set_code_variables_detect_secrets_context` + +Whether to apply entropy-based secret detection as a last-resort redaction of +high-entropy values (API keys, tokens, strong passwords) in captured code +variables for the current context. + +```python +set_code_variables_detect_secrets_context(enabled: bool) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `enabled`
**Type:** `bool` · **Required** | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L258) + +### `posthog.tag` + +Add a tag to the current context. + +```python +tag(name: str, value: Any) +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The tag key | +| `value`
**Type:** `Any` · **Required**
The tag value | + +
+ +**Correct example.** + +```python +from posthog import tag +tag("user_id", "123") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L270) + +### `posthog.get_tags` + +Get all tags from the current context. + +```python +get_tags() -> Dict[str, Any] +``` + +**Returns** `Dict[str, Any]`. Dict of all tags in the current context + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L290) + +### `posthog.get_remote_config_payload` + +Get the payload for a remote config feature flag. + +```python +get_remote_config_payload(key: str) +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The key of the feature flag | + +
+ +**Returns** . The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted + +**Note.** Requires secret_key to be set for authentication + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1017) + +### `posthog.get_feature_flag_evaluation_runtime` + +Return where a locally loaded feature flag is meant to be evaluated. + +```python +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[FeatureFlagEvaluationRuntime]` + +**Details.** Reads the `evaluation_runtime` each flag definition carries, so no extra +request is made. Returns `None` when local evaluation has not loaded a +definition for this key. A definition that carries no runtime reports +`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime +runtime = get_feature_flag_evaluation_runtime("my-flag") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1160) + +### `posthog.get_feature_flag_keys_by_evaluation_runtime` + +Return the keys of locally loaded flags that a runtime can evaluate. + +```python +get_feature_flag_keys_by_evaluation_runtime( + evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], +) -> list[str] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required** | + +
+ +**Returns** `list[str]` + +**Details.** A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so +it is returned for `CLIENT` and for `SERVER`. Use this to decide which +flags to hand to a browser when a backend serves flags to its own +frontend. + +**Correct example.** + +```python +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime +client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1184) + +## Configs + +
+Settings (7) + +| Setting | +| --- | +| `POSTHOG_MW_CLIENT`
**Where:** Django settings
client used for automatic exception capture, or the global client. This does not redirect events explicitly captured through other clients. | +| `POSTHOG_MW_CAPTURE_EXCEPTIONS`
**Where:** Django settings
`False` enables context enrichment only; `True` enables automatic exception capture; `None` inherits the effective client's `enable_exception_autocapture`. When omitted, the legacy default is `True`. | +| `POSTHOG_MW_REQUEST_FILTER`
**Where:** Django settings
a callback receiving the request. Returning `False` disables both enrichment and automatic exception capture for that request. | +| `POSTHOG_MW_EXTRA_PROPERTIES`
**Where:** Django settings
a callback returning additional event properties. | +| `POSTHOG_MW_CAPTURE_TRACING_HEADERS`
**Where:** Django settings
read PostHog identity and session headers as request-scoped analytics context (default: `True`). Explicit capture IDs and event properties take precedence. These values are never authentication or authorization. Authenticated Django user identity remains the fallback when no usable header ID is available or header capture is disabled. | +| `POSTHOG_MW_TRUST_TRACING_HEADERS`
**Where:** Django settings
deprecated alias for `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. | +| `POSTHOG_MW_PROPERTIES_MAP`
**Where:** Django settings
an optional callback transforming request properties. | + +
+ +## Types + +### `OptionalCaptureArgs` + +Optional arguments for the capture method. + +
+Fields (8) + +| Field | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to track with the event | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
Group identifiers to associate with this event (format: {group_type: group_key}) | +| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | +| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this event. Defaults to False. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L26) + +### `OptionalSetArgs` + +Optional arguments for the set method. + +
+Fields (5) + +| Field | +| --- | +| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | +| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to set on the person | +| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this operation. Defaults to False. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L70) + +### `FeatureFlagEvaluations` + +A point-in-time snapshot of feature flag evaluations for a single distinct_id. + +Returned by `Client.evaluate_flags` — branch on `is_enabled` / +`get_flag` and pass the same object to `Client.capture` via the +`flags` option so the captured event carries the exact flag values the code +branched on. + +Example: + +```python +flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +``` + +To narrow the set of flags that get attached to a captured event, use the in-memory +helpers `only` and `only_accessed`. To narrow the set of flags requested +from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. + +#### `FeatureFlagEvaluations.is_enabled` + +Return whether the flag is enabled. Fires `$feature_flag_called` on the +first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. + +A flag that has a value always wins over `default_value`, including a +disabled flag, which returns `False` even when `default_value=True`. + +```python +is_enabled( + key: str, + default_value: bool = False, + send_feature_flag_events: bool = True, +) -> bool +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The feature flag key. | +| `default_value`
**Type:** `bool` · **Default:** `False`
Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | + +
+ +**Returns** `bool` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L164) + +#### `FeatureFlagEvaluations.get_flag` + +Return the flag value. Fires `$feature_flag_called` on first access. + +Returns the variant string for multivariate flags, `True` for enabled flags +without a variant, `False` for disabled flags, and `None` for flags that +were not returned by the evaluation. + +Pass `send_feature_flag_events=False` to skip the event for this read, as +with `is_enabled`. + +```python +get_flag(key: str, send_feature_flag_events: bool = True) -> Optional[FlagValue] +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True` | + +
+ +**Returns** `Optional[FlagValue]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L191) + +#### `FeatureFlagEvaluations.get_flag_payload` + +Return the payload associated with a flag. + +Does not count as an access for `only_accessed` and does not fire any event. + +```python +get_flag_payload(key: str) -> Optional[Any] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | + +
+ +**Returns** `Optional[Any]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L211) + +#### `FeatureFlagEvaluations.only_accessed` + +Return a filtered copy containing only flags accessed via `is_enabled` +or `get_flag` before this call. + +Order-dependent: if nothing has been accessed yet, the returned snapshot is +empty. The method honors its name — pre-access if you want a populated result. + +```python +only_accessed() -> FeatureFlagEvaluations +``` + +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L219) + +#### `FeatureFlagEvaluations.only` + +Return a filtered copy containing only flags with the given keys. Keys that +are not present in the evaluation are dropped and logged as a warning. + +```python +only(keys: List[str]) -> FeatureFlagEvaluations +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `keys`
**Type:** `List[str]` · **Required** | + +
+ +**Returns** `FeatureFlagEvaluations` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L229) + +#### `FeatureFlagEvaluations.keys` + +Return the flag keys that are part of this evaluation. + +```python +FeatureFlagEvaluations.keys: List[str] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L249) + +#### `FeatureFlagEvaluations.unresolved_flags` + +Return a read-only mapping of flag key to the reason local evaluation +left it without a value. + +A flag is listed when it has a loaded local definition, was in the requested +scope, was inconclusive locally, and no remote value filled the gap. Listed +flags are not part of `keys`, and reading one reports the +`local_evaluation_inconclusive` error instead of `flag_missing`. Reading +this mapping does not count as an access and does not fire any event. +Snapshots returned by `only` and `only_accessed`, and by +`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no +entries. + +```python +FeatureFlagEvaluations.unresolved_flags: Mapping[str, UnresolvedFlagReason] +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L254) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L110) + +### `FeatureFlagResult` + +The result of calling a feature flag which includes the flag result, variant, and payload. + +
+Fields (5) + +| Field | +| --- | +| `key`
**Type:** `str`
The unique identifier of the feature flag. | +| `enabled`
**Type:** `bool`
Whether the feature flag is enabled for the current context. | +| `variant`
**Type:** `Optional[str]`
The variant value if the flag is enabled and has variants, None otherwise. | +| `payload`
**Type:** `Optional[Any]`
Additional data associated with the feature flag, if any. | +| `reason`
**Type:** `Optional[str]`
A description of why the flag was enabled or disabled, if available. | + +
+ +#### `FeatureFlagResult.get_value` + +Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. + +```python +get_value() -> FlagValue +``` + +**Returns** `FlagValue`. Either a string variant or boolean value representing the flag's state. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L582) + +#### `FeatureFlagResult.from_value_and_payload` + +Creates a FeatureFlagResult from a flag value and payload. + +```python +from_value_and_payload( + key: str, + value: Union[FlagValue, None], + payload: Any, +) -> Union[FeatureFlagResult, None] +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required**
The unique identifier of the feature flag. | +| `value`
**Type:** `Union[FlagValue, None]` · **Required**
The value of the flag (string variant or boolean). | +| `payload`
**Type:** `Any` · **Required**
Additional data associated with the feature flag. | + +
+ +**Returns** `Union[FeatureFlagResult, None]`. Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L592) + +#### `FeatureFlagResult.from_flag_details` + +Create a FeatureFlagResult from a FeatureFlag object. + +```python +from_flag_details( + details: Union[FeatureFlag, None], + override_match_value: Optional[FlagValue] = None, +) -> FeatureFlagResult | None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `details`
**Type:** `Union[FeatureFlag, None]` · **Required**
The FeatureFlag object to convert. | +| `override_match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | + +
+ +**Returns** `FeatureFlagResult | None`. FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L618) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L563) + +### `FeatureFlag` + +Detailed feature flag evaluation returned by the flags API. + +`enabled`, `variant` and `metadata.payload` are the value rendered the way +responses before `/flags?v=4` carried it, which the legacy getters return. + +
+Fields (5) + +| Field | +| --- | +| `key`
**Type:** `str`
Feature flag key. | +| `enabled`
**Type:** `bool`
Whether the flag is enabled for the evaluated user or group. | +| `variant`
**Type:** `Optional[str]`
Variant key for multivariate flags, otherwise `None`. | +| `reason`
**Type:** `Optional[FlagReason]`
Optional reason metadata explaining the result. | +| `metadata`
**Type:** `Union[FlagMetadata, LegacyFlagMetadata]`
Payload and other metadata returned by the API. | + +
+ +#### `FeatureFlag.get_value` + +Return the variant for a multivariate flag, otherwise whether the flag is enabled. + +```python +get_value() -> FlagValue +``` + +**Returns** `FlagValue` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L285) + +#### `FeatureFlag.from_json` + +Parse one flag record of a `/flags` response. + +A record with a `value` member is a `/flags?v=4` record. A record +without one comes from an older server: its value is `variant`, or +`enabled` when there is no variant, and its config version is `1`. + +```python +from_json(resp: Any) -> FeatureFlag +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `resp`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlag` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L289) + +#### `FeatureFlag.from_value_and_payload` + +Build a flag from its value and payload. A string value is a variant, so the flag is enabled. + +```python +from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `value`
**Type:** `FlagValue` · **Required** | +| `payload`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlag` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L299) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L245) + +### `FlagsAndPayloads` + +Feature flag values and payloads keyed by feature flag key. + +
+Fields (2) + +| Field | +| --- | +| `featureFlags`
**Type:** `Optional[dict[str, FlagValue]]`
Each flag's value, keyed by flag key. | +| `featureFlagPayloads`
**Type:** `Optional[dict[str, Any]]`
Each flag's payload, keyed by flag key. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L551) + +### `FeatureFlagEvaluationRuntime` + +Where a feature flag is meant to be evaluated. + +Set per flag in PostHog and carried on every locally cached flag definition. +`ALL` means the flag suits both client-side and server-side evaluation, so +it matches either runtime. Inheriting from `str` keeps the members directly +comparable to their `"all"` / `"client"` / `"server"` values. + +
+Fields (3) + +| Field | +| --- | +| `ALL`
**Value:** `'all'`
The flag suits both client-side and server-side evaluation. | +| `CLIENT`
**Value:** `'client'`
The flag is meant for client-side evaluation. | +| `SERVER`
**Value:** `'server'`
The flag is meant for server-side evaluation. | + +
+ +#### `FeatureFlagEvaluationRuntime.from_value` + +Coerce a raw `evaluation_runtime` value to a member. + +A missing, null or unrecognized value becomes `ALL`, which is the +default PostHog applies to a flag that does not set a runtime. + +```python +from_value(value: Any) -> FeatureFlagEvaluationRuntime +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `value`
**Type:** `Any` · **Required** | + +
+ +**Returns** `FeatureFlagEvaluationRuntime` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L98) + +#### `FeatureFlagEvaluationRuntime.matches` + +Whether a flag set to one of these runtimes suits the other runtime. + +`ALL` matches every runtime, so the check is symmetric. + +```python +matches(other: FeatureFlagEvaluationRuntime) -> bool +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `other`
**Type:** `FeatureFlagEvaluationRuntime` · **Required** | + +
+ +**Returns** `bool` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L112) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L80) + +### `UnresolvedFlagReason` + +Why local evaluation left a flag without a value. + +Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from +`str` keeps the members directly comparable to their string values. When more +than one cause applies, the first reason in the order below is reported. + +
+Fields (4) + +| Field | +| --- | +| `EXPERIENCE_CONTINUITY`
**Value:** `'experience_continuity'`
The flag has experience continuity enabled, which local evaluation never resolves. Change the flag to fix it. | +| `UNSUPPORTED_DEFINITION`
**Value:** `'unsupported_definition'`
The flag uses something the local evaluator does not support, such as a static cohort, an unknown operator, a malformed value, a dependency with no loaded definition or a circular dependency. Change the flag or upgrade the SDK to fix it. | +| `UNRESOLVED_DEPENDENCY`
**Value:** `'unresolved_dependency'`
A flag this flag depends on has a loaded definition but was unresolved. | +| `MISSING_CONTEXT`
**Value:** `'missing_context'`
The call did not pass a property, group property or device id the flag needs, or passed it in an unusable form. Pass it to fix it. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L120) + +### `FlagDefinitionCacheProvider` + +Interface for external caching of feature flag definitions. + +Enables multi-worker environments to share flag definitions, reducing API +calls while ensuring all workers have consistent data. + +Methods may be implemented as either synchronous functions or async +functions. If a method returns an awaitable, the SDK runs it to completion +before continuing. + +The four methods handle the complete lifecycle of flag definition caching: + +1. `should_fetch_flag_definitions()` - Called before each poll to determine + if this worker should fetch new definitions. Use for distributed lock + coordination to ensure only one worker fetches at a time. + +2. `get_flag_definitions()` - Called when `should_fetch_flag_definitions()` + returns False. Returns cached definitions if available. + +3. `on_flag_definitions_received()` - Called after successfully fetching + new definitions from the API. Store the data in your external cache + and release any locks. + +4. `shutdown()` - Called when the PostHog client shuts down. Release any + distributed locks and clean up resources. + +#### `FlagDefinitionCacheProvider.get_flag_definitions` + +Retrieve cached flag definitions. + +```python +get_flag_definitions( +) -> Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]] +``` + +**Returns** `Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]]`. Cached flag definitions if available and valid, None otherwise. May return an awaitable resolving to the same value. Returning None will trigger a fetch from the API if this worker has no flags loaded yet. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L93) + +#### `FlagDefinitionCacheProvider.should_fetch_flag_definitions` + +Determine whether this instance should fetch new flag definitions. + +Use this for distributed lock coordination. Only one worker should +return True to avoid thundering herd problems. A typical implementation +uses a distributed lock (e.g., Redis SETNX) that expires after the +poll interval. + +```python +should_fetch_flag_definitions() -> Union[bool, Awaitable[bool]] +``` + +**Returns** `Union[bool, Awaitable[bool]]`. True if this instance should fetch from the API, False otherwise. May return an awaitable resolving to the same value. When False, the client will call `get_flag_definitions()` to retrieve cached data instead. + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L109) + +#### `FlagDefinitionCacheProvider.on_flag_definitions_received` + +Called after successfully receiving new flag definitions from PostHog. + +Use this to store the data in your external cache and release any +distributed locks acquired in `should_fetch_flag_definitions()`. + +```python +on_flag_definitions_received(data: FlagDefinitionCacheData) -> Optional[Awaitable[None]] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `data`
**Type:** `FlagDefinitionCacheData` · **Required**
The flag definitions to cache, containing flags, group_type_mapping, and cohorts. | + +
+ +**Returns** `Optional[Awaitable[None]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L126) + +#### `FlagDefinitionCacheProvider.shutdown` + +Called when the PostHog client shuts down. + +Use this to release any distributed locks and clean up resources. +This method is called even if `should_fetch_flag_definitions()` +returned False, so implementations should handle the case where +no lock was acquired. + +```python +shutdown() -> Optional[Awaitable[None]] +``` + +**Returns** `Optional[Awaitable[None]]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L141) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L56) + +### `FlagDefinitionCacheData` + +Data structure for cached flag definitions. + +
+Fields (5) + +| Field | +| --- | +| `flags`
**Type:** `Required[List[Dict[str, Any]]]`
List of feature flag definition dictionaries from the API. | +| `group_type_mapping`
**Type:** `Required[Dict[str, str]]`
Mapping of group type indices to group names. | +| `cohorts`
**Type:** `Required[Dict[str, Any]]`
Dictionary of cohort definitions for local evaluation. | +| `minimal_flag_called_events`
**Type:** `NotRequired[bool]`
Server-controlled gate for minimal `$feature_flag_called` events. Treated as False when absent. | +| `property_matching_version`
**Type:** `NotRequired[int]`
Exact/is_not matching selector. Missing means legacy; only version 2 enables explicit matching. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L35) + +### `InconclusiveMatchError` + +Raised when local evaluation can't determine a flag's value. `reason` says +why, as reported by `FeatureFlagEvaluations.unresolved_flags`. + +
+Fields (1) + +| Field | +| --- | +| `reason`
**Type:** `UnresolvedFlagReason`
Why local evaluation couldn't resolve the flag. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L98) + +### `RequiresServerEvaluation` + +Raised when feature flag evaluation requires server-side data that is not +available locally (e.g., static cohorts). + +This error should propagate immediately to trigger API fallback, unlike +InconclusiveMatchError which allows trying other conditions. + +
+Fields (1) + +| Field | +| --- | +| `reason`
**Type:** `UnresolvedFlagReason`
Why the flag needs server-side evaluation. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L115) + +### `CaptureCompression` + +Selects the request-body compression for capture-v1 uploads. + +Only honored when `capture_mode` is `V1`; the legacy `/batch/` path +keeps using its own `gzip` flag. `NONE` sends the body uncompressed. +`GZIP` and `DEFLATE` (zlib, RFC 1950) are both stdlib / zero-dependency; +`ZSTD` is faster and compresses better but needs the optional zstandard +package (`pip install posthog[zstd]`) until stdlib support lands in +Python 3.14. Each maps to the matching `Content-Encoding` token the v1 +server decodes (`br` is accepted by the server too but is intentionally +left out for now). Inheriting from `str` keeps the members comparable to +and serializable as their token values. + +
+Fields (4) + +| Field | +| --- | +| `NONE`
**Value:** `'none'`
Sends the body uncompressed. | +| `GZIP`
**Value:** `'gzip'`
gzip, from the standard library. | +| `DEFLATE`
**Value:** `'deflate'`
zlib (RFC 1950), from the standard library. | +| `ZSTD`
**Value:** `'zstd'`
Faster and smaller, but needs `pip install posthog[zstd]`. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/capture_compression.py#L21) + +### `Span` + +A handle to a span. + +Every method is safe to call on any handle, including after `end()` and +on the inert handles returned when tracing is off, so calling code never +branches on whether tracing is running. Entering a handle (`with span:`) +makes it the active span for the block and ends it on exit, recording an +`Exception` raised inside it. A `BaseException` that is not an +`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) +still ends the span but is not recorded as a failure. + +#### `Span.set_attribute` + +Set one attribute on the span; last write wins. Ignored after `end()`. + +Returns the span, so calls chain. Prefer primitive values: strings, +booleans, integers and floats keep their type. Lists and mappings are +sent as OTLP arrays and maps, but PostHog stores them as serialized +strings. `None` removes the key; anything else is stringified. + +```python +set_attribute(key: str, value: Any) -> Span +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `key`
**Type:** `str` · **Required** | +| `value`
**Type:** `Any` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L21) + +#### `Span.set_attributes` + +Set several attributes at once; last write wins per key. Ignored after `end()`. + +Returns the span, so calls chain. Same encoding as `set_attribute()`. + +```python +set_attributes(attributes: Mapping[str, Any]) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `attributes`
**Type:** `Mapping[str, Any]` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_attributes({"db.system": "postgresql", "db.rows": 12}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L36) + +#### `Span.add_event` + +Add a timestamped event to the span. Ignored after `end()`. + +`timestamp` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`. Returns the span, so calls +chain. + +```python +add_event( + name: str, + attributes: Optional[Mapping[str, Any]] = None, + timestamp: Union[datetime, float, None] = None, +) -> Span +``` + +
+Parameters (3) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | +| `timestamp`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.add_event("cache.miss", {"key": "user:42"}) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L48) + +#### `Span.set_status` + +Set the span status to `"ok"` or `"error"`. Ignored after `end()`. + +Unset by default. Any other `code` is ignored. `ok` is final for the +scoped form: an `Exception` raised inside `with span:` does not override +it. Returns the span, so calls chain. + +```python +set_status(code: str, message: Optional[str] = None) -> Span +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `code`
**Type:** `str` · **Required** | +| `message`
**Type:** `Optional[str]` · **Default:** `None` | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span.set_status("error", "upstream timed out") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L67) + +#### `Span.record_exception` + +Record an exception as an `exception` event and mark the span `error`. + +Ignored after `end()`. The event carries `exception.type`, +`exception.message` and, for a raised exception, +`exception.stacktrace` (its last `max_attribute_value_length` +characters, so a chained traceback keeps the outermost exception and +may lose its cause). Returns the span, so calls chain. Inside +`with span:` a raised `Exception` is recorded automatically, so +this is for exceptions that are caught and handled. + +```python +record_exception(exception: BaseException) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `exception`
**Type:** `BaseException` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +try: + charge(card) +except PaymentError as e: + span.record_exception(e) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L81) + +#### `Span.update_name` + +Rename the span, for a name only known after it started. Ignored after `end()`. + +Returns the span, so calls chain. + +```python +update_name(name: str) -> Span +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | + +
+ +**Returns** `Span` + +**Correct example.** + +```python +span = posthog.start_span("http.request") +span.update_name(f"{request.method} {route.pattern}") +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L102) + +#### `Span.traceparent` + +The W3C `traceparent` header value to propagate, or `None`. + +```python +traceparent() -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L115) + +#### `Span.tracestate` + +The W3C `tracestate` header value to propagate, or `None`. + +```python +tracestate() -> Optional[str] +``` + +**Returns** `Optional[str]` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L119) + +#### `Span.end` + +End the span and queue it for export. Idempotent. + +`end_time` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`, and is never earlier than +the start. Later calls, and later mutations, no-op. `with span:` +ends the span on exit, so call this only for spans started manually. + +```python +end(end_time: Union[datetime, float, None] = None) -> None +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `end_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | + +
+ +**Returns** `None` + +**Correct example.** + +```python +span = posthog.start_span("job") +try: + run_job() +finally: + span.end() +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L123) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L9) + +### `PostHogMetrics` + +The `client.metrics` API: `count`, `gauge`, `histogram`, `flush`. + +Thread-safe; safe to call from hot paths. Configure via the `metrics` +client option (`flush_interval` is in seconds, matching the client's own +`flush_interval` — unlike posthog-js, whose `flushIntervalMs` is milliseconds): + +```python +client = Client("phc_...", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +#### `PostHogMetrics.count` + +Record an increment for a monotonic counter (things that only go up). + +```python +count( + name: str, + value: float = 1, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Default:** `1` | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L374) + +#### `PostHogMetrics.gauge` + +Record the current value of something that goes up and down. + +```python +gauge( + name: str, + value: float, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Required** | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L384) + +#### `PostHogMetrics.histogram` + +Record one observation of a distribution (durations, sizes). + +```python +histogram( + name: str, + value: float, + unit: Optional[str] = None, + attributes: Optional[dict] = None, +) -> None +``` + +
+Parameters (4) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required** | +| `value`
**Type:** `float` · **Required** | +| `unit`
**Type:** `Optional[str]` · **Default:** `None` | +| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L394) + +#### `PostHogMetrics.flush` + +Sends everything aggregated so far without waiting for the flush interval. + +```python +flush() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L404) + +#### `PostHogMetrics.reset` + +Clears the flush timer and drops the current window. + +```python +reset() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L409) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L297) + +### `Emails` + +Sends transactional email from PostHog email templates. + +`host` is your PostHog app host. PostHog Cloud ingestion hosts map to the +app host, so `us.i.posthog.com` sends to `us.posthog.com`. Any other +host is used as given. + +Each send retries network errors, rate limits and an unavailable service up +to `max_retries` times, with the same idempotency key. Set +`max_retries=0` when a job runner already retries the send. `timeout` +is in seconds, per request. Pass `session` to send through your own +`requests.Session`, for example a test double. + +#### `Emails.send` + +Queue one email from a transactional email template. + +```python +send( + to: str, + template_id: Union[str, UUID], + template_data: Optional[Mapping[str, Any]] = None, + distinct_id: Optional[str] = None, + idempotency_key: Optional[str] = None, + max_retries: Optional[int] = None, +) -> SendEmailResult +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `to`
**Type:** `str` · **Required**
One recipient email address. | +| `template_id`
**Type:** `Union[str, UUID]` · **Required**
The UUID of a template made transactional in PostHog. | +| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | +| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None`
The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | +| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None`
1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | +| `max_retries`
**Type:** `Optional[int]` · **Default:** `None`
Overrides the client's maximum number of retries for this send. `0` turns retries off. | + +
+ +**Returns** `SendEmailResult`. The queued email. A result means PostHog queued the email, not that it was delivered. + +**Raises** `EmailError`. PostHog did not queue the email, or the client could +not tell whether it did. + +**Raises** `(TypeError, ValueError)`. An argument has the wrong type or format. + +**Correct example.** + +```python +emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", + idempotency_key="welcome:user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L588) + +#### `Emails.get` + +Read what happened to an email that `send` queued. + +```python +get(message_id: Union[str, UUID]) -> EmailStatus +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `message_id`
**Type:** `Union[str, UUID]` · **Required**
The `id` of the `SendEmailResult` that `send` returned. | + +
+ +**Returns** `EmailStatus`. The email's latest status, for 30 days after the send. + +**Raises** `EmailError`. PostHog did not answer with a status. `code` is +`not_found` for an unknown ID, an email older than 30 days, +or for a few seconds after the send. + +**Raises** `ValueError`. `message_id` is not a message ID. + +**Correct example.** + +```python +result = emails.send(to="user@example.com", template_id="...") +status = emails.get(result.id) +if status.status == "bounced": + print(status.reason) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L659) + +#### `Emails.close` + +Close the HTTP connections this client opened. A `session` you passed in stays open. + +```python +close() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L737) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L553) + +### `AsyncEmails` + +The async counterpart of `Emails`. Needs `posthog[async]`. + +Pass `http_client` to send through your own `httpx.AsyncClient`, for +example one with an `httpx.MockTransport` in tests. + +#### `AsyncEmails.send` + +Queue one email from a transactional email template. + +Takes the same arguments and raises the same errors as +`Emails.send`. + +```python +async send( + to: str, + template_id: Union[str, UUID], + template_data: Optional[Mapping[str, Any]] = None, + distinct_id: Optional[str] = None, + idempotency_key: Optional[str] = None, + max_retries: Optional[int] = None, +) -> SendEmailResult +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `to`
**Type:** `str` · **Required** | +| `template_id`
**Type:** `Union[str, UUID]` · **Required** | +| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | +| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None` | +| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None` | +| `max_retries`
**Type:** `Optional[int]` · **Default:** `None` | + +
+ +**Returns** `SendEmailResult` + +**Correct example.** + +```python +await emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + template_data={"name": "Ada"}, + distinct_id="user_123", +) +``` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L792) + +#### `AsyncEmails.get` + +Read what happened to an email that `send` queued. + +Takes the same argument and raises the same errors as +`Emails.get`. + +```python +async get(message_id: Union[str, UUID]) -> EmailStatus +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `message_id`
**Type:** `Union[str, UUID]` · **Required** | + +
+ +**Returns** `EmailStatus` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L838) + +#### `AsyncEmails.aclose` + +Close the HTTP connections this client opened. An `http_client` you passed in stays open. + +```python +async aclose() -> None +``` + +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L899) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L765) + +### `EmailError` + +PostHog did not queue the email, or the client could not tell whether it did. + +Branch on `code`, PostHog's stable error code, or on `name`, a coarse +category of the failure. The message never contains the secret key or the +request body. + +
+Fields (9) + +| Field | +| --- | +| `name`
A coarse category of the failure. | +| `code`
PostHog's stable error code. | +| `message`
What went wrong. It never contains the secret key or the request body. | +| `status_code`
The HTTP status of the response, or `None` when none arrived. | +| `why`
PostHog's explanation of the failure, when it gave one. | +| `fix`
What to change to fix it, when PostHog said. | +| `docs_url`
A docs page about the error, when PostHog gave one. | +| `field`
The request field the error is about, when there is one. | +| `retry_after`
Seconds to wait before retrying, when PostHog said. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L122) + +### `EmailStatus` + +What happened to an email that `send()` queued. + +`status` is one of: + +- `queued`: the email waits to go out. +- `sent`: PostHog handed the email to the email provider. +- `failed`: the email was not sent, and `reason` says why. +- `delivered`: the recipient's mail server accepted the email. +- `bounced` and `complained`: the recipient's mail provider reported + them after delivery. + +Later SDK versions can see values this list does not have yet. +`reason` says why a failed email was not sent, such as +`provider_error` or `recipient_suppressed`, or gives the bounce type of +a bounced email: `hard`, `soft` or `unknown`. It is `None` otherwise. + +
+Fields (5) + +| Field | +| --- | +| `id`
**Type:** `str`
The email's message ID. | +| `status`
**Type:** `str`
Where the email is now, one of the values above. | +| `created_at`
**Type:** `datetime`
When PostHog queued the email. | +| `status_at`
**Type:** `datetime`
When the email reached its current status. | +| `reason`
**Type:** `Optional[str]` · **Default:** `None`
Why a failed email was not sent, or a bounced email's bounce type. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L189) + +### `SendEmailResult` + +The queued email. `id` is its message ID. + +
+Fields (3) + +| Field | +| --- | +| `id`
**Type:** `str`
The email's message ID. | +| `replayed`
**Type:** `bool` · **Default:** `False`
`True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. | +| `warnings`
**Type:** `tuple[EmailWarning, ...]` · **Default:** `()`
Warnings PostHog returned about the request. | + +
+ +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L173) + +### `Prompts` + +Fetch and compile LLM prompts from PostHog. + +Can be initialized with a PostHog client or with direct options. + +#### `Prompts.get` + +Fetch a prompt by name from the PostHog API. + +When `with_metadata` is `True`, returns a `PromptResult` +with `source`, `name`, `version`, and `config` metadata. When +omitted or `False`, returns a plain string (deprecated -- will be +removed in a future major version). + +```python +get( + name: str, + with_metadata: Optional[bool] = None, + cache_ttl_seconds: Optional[int] = None, + fallback: Optional[str] = None, + version: Optional[int] = None, + label: Optional[str] = None, +) -> Union[str, PromptResult] +``` + +
+Parameters (6) + +| Parameter | +| --- | +| `name`
**Type:** `str` · **Required**
The name of the prompt to fetch | +| `with_metadata`
**Type:** `Optional[bool]` · **Default:** `None`
If True, returns a PromptResult with source info. Omitting this parameter is deprecated. | +| `cache_ttl_seconds`
**Type:** `Optional[int]` · **Default:** `None`
Cache TTL in seconds (defaults to instance default) | +| `fallback`
**Type:** `Optional[str]` · **Default:** `None`
Fallback prompt to use if fetch fails and no cache available | +| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to fetch. Mutually exclusive with label. If neither is given, fetches the latest version | +| `label`
**Type:** `Optional[str]` · **Default:** `None`
Fetch the version this label currently points to, e.g. 'production'. Mutually exclusive with version | + +
+ +**Returns** `Union[str, PromptResult]`. str if with_metadata is False/omitted, PromptResult if True + +**Raises** `ValueError`. If both version and label are provided + +**Raises** `Exception`. If the prompt cannot be fetched and no fallback is available + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L359) + +#### `Prompts.get_all` + +Fetch every prompt in one batch. + +Returns a dict mapping prompt name to `PromptResult`. With a +label, each prompt is at the version the label points to, and prompts +without the label are not included. Without a label, every prompt is +included at its latest version, matching what `get(name)` returns. + +Each fetched prompt is stored in the cache, so later +`get(name, label=...)` (or plain `get(name)`) calls are served +from cache within the TTL. An app with many prompts can call this once +per cache cycle instead of making one `get()` request per prompt. + +```python +get_all(label: Optional[str] = None) -> Dict[str, PromptResult] +``` + +
+Parameters (1) + +| Parameter | +| --- | +| `label`
**Type:** `Optional[str]` · **Default:** `None`
The label to resolve, e.g. 'production'. Omit to fetch latest versions. | + +
+ +**Returns** `Dict[str, PromptResult]`. Dict of prompt name to PromptResult. + +**Raises** `Exception`. If the request fails, or a label was passed and the +server does not support fetching prompts by label on the list +endpoint (PostHog releases from before September 2026). + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L433) + +#### `Prompts.compile` + +Replace {{variableName}} placeholders with values. + +Unmatched variables are left unchanged. +Supports variable names with hyphens and dots (e.g., user-id, company.name). + +```python +compile(prompt: str, variables: PromptVariables) -> str +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `prompt`
**Type:** `str` · **Required**
The prompt template string | +| `variables`
**Type:** `PromptVariables` · **Required**
Object containing variable values | + +
+ +**Returns** `str`. The compiled prompt string + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L720) + +#### `Prompts.clear_cache` + +Clear cached prompts. + +```python +clear_cache(name: Optional[str] = None, version: Optional[int] = None) -> None +``` + +
+Parameters (2) + +| Parameter | +| --- | +| `name`
**Type:** `Optional[str]` · **Default:** `None`
Specific prompt name to clear. If None, clears all cached prompts. | +| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to clear. Requires name. | + +
+ +**Returns** `None` + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L745) + +[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L227) From d1b4eb0eb24a90e32b3cb85600fbfd8304de2d93 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 4 Nov 2026 17:16:39 -0500 Subject: [PATCH 3/9] docs: regenerate the 7.x pages Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 1 - 1 file changed, 1 deletion(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index 4594ed985..a71bd22b7 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -4,7 +4,6 @@ sidebar: Docs showTitle: true contentMaxWidthClass: max-w-full platformLogo: python -noindex: true tableOfContents: - value: "Getting started" url: getting-started From 187527b4877d60b93a247899edd8d5a71db7f9e6 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 4 Nov 2026 18:07:35 -0500 Subject: [PATCH 4/9] docs: regenerate the 7.x pages with griffe2md Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 5866 +++++++++--------------- references/posthog-python-reference.md | 5866 +++++++++--------------- 2 files changed, 4542 insertions(+), 7190 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index a71bd22b7..fbe09b77a 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -8,15 +8,21 @@ tableOfContents: - value: "Getting started" url: getting-started depth: 0 + - value: "Setup" + url: setup + depth: 0 + - value: "Capture" + url: capture + depth: 0 + - value: "Identify" + url: identify + depth: 0 - value: "Traces" url: traces depth: 0 - value: "Alias" url: alias depth: 0 - - value: "Capture" - url: capture - depth: 0 - value: "Capture AI" url: capture-ai depth: 0 @@ -50,15 +56,9 @@ tableOfContents: - value: "Group identify" url: group-identify depth: 0 - - value: "Identify" - url: identify - depth: 0 - value: "Is feature enabled" url: is-feature-enabled depth: 0 - - value: "Setup" - url: setup - depth: 0 - value: "Shutdown" url: shutdown depth: 0 @@ -74,9 +74,6 @@ tableOfContents: - value: "Module functions" url: module-functions depth: 0 - - value: "Configs" - url: configs - depth: 0 - value: "Types" url: types depth: 0 @@ -84,6 +81,7 @@ tableOfContents: ## Getting started + The Python SDK captures events, evaluates feature flags and reports errors from Python 3.10 or later. ### Install @@ -120,200 +118,284 @@ posthog.shutdown() In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [AsyncClient](#asyncclient). -## Traces - -### `Client.start_span` - -Start a span for distributed tracing. Alpha. +## Setup -Returns a span handle. Use it as a context manager to make it the active -span for the block and end it on exit (recording a raised exception on -the way out); or call `end()` yourself for a span that cannot wrap a -block. Spans started inside the block nest under it automatically. -Always returns a usable handle, even when tracing is off, so calling -code never branches. +### `Client(...)` ```python -start_span( - name: str, - kind: Optional[str] = None, - attributes: Optional[Mapping[str, Any]] = None, - parent: Union[Span, str, None] = None, - tracestate: Optional[str] = None, - start_time: Union[datetime, float, None] = None, -) -> Span +__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) ``` -
-Parameters (6) +Initialize a new PostHog client instance. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | -| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | -| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | -| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | -| `start_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`project_api_key` | `str` | PostHog project API key/token. | *required* +`host` | | PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | `None` +`debug` | | Enable verbose SDK logging and re-raise errors from public API methods. | `False` +`max_queue_size` | | Maximum number of events buffered before upload. | `10000` +`send` | | If False, queueing succeeds but events are not sent. | `True` +`on_error` | | Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | `None` +`flush_at` | | Number of queued events that triggers a batch upload. | `100` +`flush_interval` | | Maximum seconds a background consumer waits before flushing a partial batch. | `5.0` +`gzip` | | Whether to gzip event upload payloads. | `False` +`max_retries` | | Number of upload retries. Values below 0 are treated as 0. | `3` +`sync_mode` | | If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | `False` +`timeout` | `float` | HTTP request timeout in seconds for event uploads. | `15` +`thread` | | Number of background consumer threads. | `1` +`poll_interval` | | Seconds between local feature flag definition refreshes. | `30` +`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example::
posthog.Client(project_api_key, secret_key="phx_...") | `None` +`personal_api_key` | | Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | `None` +`disabled` | | If True, disable captures and API requests. Useful in tests. | `False` +`disable_geoip` | | Whether to disable server-side GeoIP enrichment. Defaults to True. | `True` +`is_server` | | Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | `True` +`historical_migration` | | Mark events as historical migration imports. | `False` +`feature_flags_request_timeout_seconds` | `float` | Timeout in seconds for feature flag and remote config requests. | `3` +`feature_flags_request_max_retries` | | Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | `1` +`app_host` | `Optional[str]` | Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | `None` +`email_request_timeout_seconds` | `float` | Timeout in seconds for each email send request. Defaults to 15. | `15` +`email_request_max_retries` | `int` | Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | `2` +`super_properties` | | Properties merged into every captured event. | `None` +`enable_exception_autocapture` | | Automatically capture uncaught exceptions. | `False` +`log_captured_exceptions` | | Also log exceptions captured by error tracking. | `False` +`project_root` | | Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | `None` +`privacy_mode` | | For AI observability, capture usage metadata without prompt inputs or outputs. | `False` +`enable_full_ai_capture` | | Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | `False` +`before_send` | | Optional callback that can modify or drop events before upload. Return `None` to drop an event. | `None` +`flag_fallback_cache_url` | | Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | `None` +`enable_local_evaluation` | | Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | `True` +`flag_definition_cache_provider` | `Optional[FlagDefinitionCacheProvider]` | Optional external cache provider for sharing feature flag definitions across workers. | `None` +`capture_exception_code_variables` | | Capture local variable values on exception stack frames. | `False` +`capture_trace_context` | | When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | `False` +`traces` | `Optional[dict]` | Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | `None` +`code_variables_mask_patterns` | | Variable-name patterns to mask when capturing code variables. | `None` +`code_variables_ignore_patterns` | | Variable-name patterns to omit when capturing code variables. | `None` +`code_variables_mask_url_credentials` | | Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | `None` +`code_variables_detect_secrets` | | Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | `None` +`in_app_modules` | `list[str] \| None` | Module/package prefixes treated as in-app frames in captured exceptions. | `None` +`enable_exception_autocapture_rate_limiting` | | Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | `False` +`exception_autocapture_bucket_size` | | Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | `DEFAULT_BUCKET_SIZE` +`exception_autocapture_refill_rate` | | Tokens restored per refill interval for each exception type's bucket. | `DEFAULT_REFILL_RATE` +`exception_autocapture_refill_interval_seconds` | | Seconds between token refills for autocaptured exception rate limiting. | `DEFAULT_REFILL_INTERVAL_SECONDS` +`capture_mode` | `Optional[Union[CaptureMode, str]]` | Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | `None` +`capture_compression` | `Optional[Union[CaptureCompression, str]]` | Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | `None` + +**Examples:** -
+```python +from posthog import Posthog -**Returns** `Span` +posthog = Posthog('', host='') +``` -**Correct example.** +## Capture -```python -posthog = Posthog("", traces={"service_name": "checkout-api"}) +### `Client.capture` -with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: - span.set_attribute("plan", user.plan) - with posthog.start_span("db.query", kind="client"): - ... - outgoing_headers = {"traceparent": span.traceparent()} +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2794) +Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) -### `Client.get_active_span` +**Parameters:** -The span that is active in the current context, or `None`. Alpha. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name to capture. | *required* +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to include with the event. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`groups` | | A dictionary of group information. | +`flags` | | A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | +`send_feature_flags` | | Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -Only entering a span (`with posthog.start_span(...) as span:`) makes -it active; a span started manually is not. Use it to propagate the -trace to the next service: `span.traceparent()` is the header value. +**Examples:** ```python -get_active_span() -> Optional[Span] +# Anonymous event +posthog.capture('some-anon-event') +``` +```python +# Context usage +from posthog import identify_context, new_context +with new_context(): + identify_context('distinct_id_of_the_user') + posthog.capture('user_signed_up') + posthog.capture('user_logged_in') + posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +``` +```python +# Set event properties +posthog.capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` +```python +# Page view event +posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) ``` -**Returns** `Optional[Span]` +## Identify -**Correct example.** +### `Client.set` ```python -span = posthog.get_active_span() -if span is not None: - headers["traceparent"] = span.traceparent() +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2853) +Set properties on a person profile. -## Alias +**Parameters:** -### `Client.alias` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to set. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -Create an alias between two distinct IDs. +**Examples:** + +```python +# Set with distinct id +posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) +``` Note: This method will not raise exceptions. Errors are logged. +### `Client.set_once` + ```python -alias( - previous_id: ID_TYPES, - distinct_id: Optional[str], - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (5) - -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required**
The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | -| `distinct_id`
**Type:** `Optional[str]` · **Required**
The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | +Set properties on a person profile only if they haven't been set before. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to set once. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -**Correct example.** +**Examples:** ```python -posthog.alias(previous_id='distinct_id', distinct_id='alias_id') +posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2168) - -## Capture +Note: This method will not raise exceptions. Errors are logged. -### `Client.capture` +## Traces -Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) +### `Client.start_span` ```python -capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +start_span(name: str, *, kind: Optional[str] = None, attributes: Optional[Mapping[str, Any]] = None, parent: Union[Span, str, None] = None, tracestate: Optional[str] = None, start_time: Union[datetime, float, None] = None) -> Span ``` -
-Parameters (9) +Start a span for distributed tracing. Alpha. -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name to capture. | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to include with the event. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
A dictionary of group information. | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on +the way out); or call `end()` yourself for a span that cannot wrap a +block. Spans started inside the block nest under it automatically. +Always returns a usable handle, even when tracing is off, so calling +code never branches. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | *required* +`kind` | `Optional[str]` | `internal` (default), `server`, `client`, `producer` or `consumer`. | `None` +`attributes` | `Optional[Mapping[str, Any]]` | Initial attributes. | `None` +`parent` | `Union[Span, str, None]` | A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | `None` +`tracestate` | `Optional[str]` | The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | `None` +`start_time` | `Union[datetime, float, None]` | A `datetime` or epoch seconds, to backdate the span. | `None` -**Correct example.** +**Examples:** ```python -# Anonymous event -posthog.capture('some-anon-event') +posthog = Posthog("", traces={"service_name": "checkout-api"}) + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} ``` -**Correct example.** +### `Client.get_active_span` ```python -# Context usage -from posthog import identify_context, new_context -with new_context(): - identify_context('distinct_id_of_the_user') - posthog.capture('user_signed_up') - posthog.capture('user_logged_in') - posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +get_active_span() -> Optional[Span] ``` -**Correct example.** +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes +it active; a span started manually is not. Use it to propagate the +trace to the next service: `span.traceparent()` is the header value. + +**Examples:** ```python -# Set event properties -posthog.capture( - "user_signed_up", - distinct_id="distinct_id_of_the_user", - properties={ - "login_type": "email", - "is_free_trial": "true" - } -) +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +## Alias + +### `Client.alias` + +```python +alias(previous_id: ID_TYPES, distinct_id: Optional[str], timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -**Correct example.** +Create an alias between two distinct IDs. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`previous_id` | `ID_TYPES` | The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | *required* +`distinct_id` | `Optional[str]` | The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | *required* +`timestamp` | `Optional[Union[datetime, str]]` | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this event. | `None` + +**Examples:** ```python -# Page view event -posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) +posthog.alias(previous_id='distinct_id', distinct_id='alias_id') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1738) +Note: This method will not raise exceptions. Errors are logged. ## Capture AI ### `Client.capture_ai` +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + Capture an AI event on the dedicated AI capture endpoint. Beta: the signature is stable; operational limits (per-event size @@ -326,56 +408,31 @@ isolated AI lane with its own consumer pool and a higher per-event size cap, posting to the dedicated AI ingestion endpoint. The payload is sent as given — no redaction or truncation is applied here. -```python -capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1797) - ## Capture exception ### `Client.capture_exception` -Capture an exception for error tracking. - -When OpenTelemetry is installed and a valid span is active, its trace and -span IDs are added as `$trace_id` and `$span_id` event properties. - ```python -capture_exception( - exception: Optional[ExceptionArg], - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +capture_exception(exception: Optional[ExceptionArg], **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -
-Parameters (6) +Capture an exception for error tracking. -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Required**
The exception to capture. | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Pass `flags` from `evaluate_flags()` instead. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | +When OpenTelemetry is installed and a valid span is active, its trace and +span IDs are added as `$trace_id` and `$span_id` event properties. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`exception` | `Optional[ExceptionArg]` | The exception to capture. | *required* +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | +`flags` | | A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | +`send_feature_flags` | | Deprecated. Pass `flags` from `evaluate_flags()` instead. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -**Correct example.** +**Examples:** ```python try: @@ -385,12 +442,14 @@ except Exception as e: posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2234) - ## Emails ### `Client.emails` +```python +emails: Emails +``` + Send transactional email from PostHog email templates, and read the status of each email sent with `get`. @@ -400,11 +459,7 @@ scope. Sends go to `app_host`, or to the PostHog Cloud app host of configure each send. A disabled or shut-down client sends nothing. See `posthog.emails` for setup. -```python -Client.emails: Emails -``` - -**Correct example.** +**Examples:** ```python client.emails.send( @@ -415,12 +470,14 @@ client.emails.send( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1256) - ## Flush ### `Client.flush` +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + Attempt immediate delivery of queued events, ended spans and autocaptured metrics, keeping the client reusable. For a client shared across requests or serverless invocations (including @@ -434,22 +491,13 @@ a timeout or span export failure, and failed events may be dropped by the consumers. Calls made directly from SDK callbacks such as `on_error` are deferred rather than blocking the worker that invoked the callback. -```python -flush(timeout_seconds: Optional[float] = 10) -> None -``` - -
-Parameters (1) +**Parameters:** -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`timeout_seconds` | `Optional[float]` | Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | `10` -
- -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.capture('event_name', distinct_id='user_id') @@ -457,48 +505,31 @@ posthog.capture('event_name', distinct_id='user_id') posthog.flush(timeout_seconds=10) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2872) - ## Get feature flag ### `Client.get_feature_flag` -Get multivariate feature flag value for a user. - ```python -get_feature_flag( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FlagValue] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_feature_flag(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FlagValue] +``` -
+Get multivariate feature flag value for a user. + +**Parameters:** -**Returns** `Optional[FlagValue]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python enabled_variant = posthog.get_feature_flag('flag-key', 'distinct_id_of_your_user') @@ -508,50 +539,40 @@ if enabled_variant == 'variant-key': # replace 'variant-key' with the key of you matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4324) - ## Get feature flag payload ### `Client.get_feature_flag_payload` +```python +get_feature_flag_payload(key: str, distinct_id: ID_TYPES, *, match_value: Optional[FlagValue] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[object] +``` + Get the payload for a feature flag. -```python -get_feature_flag_payload( - key: str, - distinct_id: ID_TYPES, - match_value: Optional[FlagValue] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[object] -``` - -
-Parameters (10) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
The specific flag value to get payload for. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `False`
Deprecated. Use get_feature_flag() instead if you need events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`match_value` | `Optional[FlagValue]` | The specific flag value to get payload for. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Deprecated. Use get_feature_flag() instead if you need events. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. +**Returns:** -**Correct example.** +Type | Description +---- | ----------- +`Optional[object]` | The payload associated with the matched feature flag value, or None. +`Optional[object]` | This method returns the payload only, not the FeatureFlagResult wrapper +`Optional[object]` | used internally to compute it. + +**Examples:** ```python is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') @@ -562,50 +583,19 @@ if is_my_flag_enabled: matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4424) - ## Get feature flag result ### `Client.get_feature_flag_result` +```python +get_feature_flag_result(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FeatureFlagResult] +``` + Get a FeatureFlagResult object which contains the flag result and payload for a key by evaluating locally or remotely depending on whether local evaluation is enabled and the flag can be locally evaluated. This also captures the `$feature_flag_called` event unless `send_feature_flag_events` is `False`. -```python -get_feature_flag_result( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FeatureFlagResult] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
- -**Returns** `Optional[FeatureFlagResult]`. Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. - -**Correct example.** +**Examples:** ```python flag_result = posthog.get_feature_flag_result('flag-key', 'distinct_id_of_your_user') @@ -615,178 +605,138 @@ if flag_result and flag_result.get_value() == 'variant-key': matched_flag_payload = flag_result.payload ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4269) +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Returns:** + +Type | Description +---- | ----------- +`Optional[FeatureFlagResult]` | Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. ## Get feature flags ### `Client.get_feature_variants` -Get feature flag variants for a user. - ```python -get_feature_variants( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> dict[str, Union[bool, str]] +get_feature_variants(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> dict[str, Union[bool, str]] ``` -
-Parameters (7) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
+Get feature flag variants for a user. -**Returns** `dict[str, Union[bool, str]]` +**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1499) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` ### `Client.get_all_flags` -Get all feature flags for a user. - ```python -get_all_flags( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> Optional[dict[str, Union[bool, str]]] -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_all_flags(distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> Optional[dict[str, Union[bool, str]]] +``` -
+Get all feature flags for a user. -**Returns** `Optional[dict[str, Union[bool, str]]]` +**Parameters:** -**Correct example.** +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** ```python posthog.get_all_flags('distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4744) - ## Get feature flags and payloads ### `Client.get_feature_flags_and_payloads` -Get feature flags and payloads for a user. - ```python -get_feature_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsAndPayloads +get_feature_flags_and_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsAndPayloads ``` -
-Parameters (7) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Get feature flags and payloads for a user. -
+**Parameters:** -**Returns** `FlagsAndPayloads` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python result = posthog.get_feature_flags_and_payloads('') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1580) - ### `Client.get_all_flags_and_payloads` -Get all feature flags and their payloads for a user. - ```python -get_all_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsAndPayloads -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_all_flags_and_payloads(distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsAndPayloads +``` -
+Get all feature flags and their payloads for a user. + +**Parameters:** -**Returns** `FlagsAndPayloads` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python posthog.get_all_flags_and_payloads('distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4790) - ## Evaluate flags ### `Client.evaluate_flags` +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys: Optional[List[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` + Evaluate all feature flags for a user in a single call and return a `FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / `.get_flag()` and pass the same snapshot to `capture` via the @@ -800,38 +750,26 @@ Local evaluation is transparent: when the poller resolves a flag, the snapshot's `$feature_flag_called` events are tagged `locally_evaluated=True` and reason `"Evaluated locally"`. -```python -evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[List[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `flag_keys`
**Type:** `Optional[List[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`flag_keys` | `Optional[List[str]]` | Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | `None` +`device_id` | `Optional[str]` | Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | `None` -**Returns** `FeatureFlagEvaluations`. class:`FeatureFlagEvaluations` snapshot. +**Returns:** -**Correct example.** +Type | Description +---- | ----------- +`FeatureFlagEvaluations` | A `FeatureFlagEvaluations` snapshot. + +**Examples:** ```python flags = posthog.evaluate_flags( @@ -843,46 +781,29 @@ if flags.is_enabled("new-dashboard"): posthog.capture("page_viewed", distinct_id="user_123", flags=flags) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4875) - ## Group identify ### `Client.group_identify` -Identify a group and set its properties. - -Note: This method will not raise exceptions. Errors are logged. - ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[Union[str, UUID]] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[Union[str, UUID]] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] ``` -
-Parameters (7) - -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required**
The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | -| `group_key`
**Type:** `str` · **Required**
The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of properties to set on the group. | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user performing the action. | +Identify a group and set its properties. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`group_type` | `str` | The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | *required* +`group_key` | `str` | The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`properties` | `Optional[Dict[str, Any]]` | A dictionary of properties to set on the group. | `None` +`timestamp` | `Optional[Union[datetime, str]]` | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[Union[str, UUID]]` | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this event. | `None` +`distinct_id` | `Optional[ID_TYPES]` | The distinct ID of the user performing the action. | `None` -**Correct example.** +**Examples:** ```python posthog.group_identify('company', 'company_id_in_your_db', { @@ -891,117 +812,33 @@ posthog.group_identify('company', 'company_id_in_your_db', { }) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2093) - -## Identify - -### `Client.set` - -Set properties on a person profile. - -Note: This method will not raise exceptions. Errors are logged. - -```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] -``` - -
-Parameters (5) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | - -
- -**Returns** `Optional[str]` - -**Correct example.** - -```python -# Set with distinct id -posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1995) - -### `Client.set_once` - -Set properties on a person profile only if they haven't been set before. - Note: This method will not raise exceptions. Errors are logged. -```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] -``` - -
-Parameters (5) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set once. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | - -
- -**Returns** `Optional[str]` +## Is feature enabled -**Correct example.** +### `Client.feature_enabled` ```python -posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) +feature_enabled(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[bool] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2045) - -## Is feature enabled - -### `Client.feature_enabled` - Check if a feature flag is enabled for a user. -```python -feature_enabled( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[bool] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
+**Parameters:** -**Returns** `Optional[bool]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') @@ -1011,163 +848,32 @@ if is_my_flag_enabled: matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3982) - -## Setup - -### `Client(...)` - -Initialize a new PostHog client instance. - -```python -Client( - project_api_key: str, - host = None, - debug = False, - max_queue_size = 10000, - send = True, - on_error = None, - flush_at = 100, - flush_interval = 5.0, - gzip = False, - max_retries = 3, - sync_mode = False, - timeout: float = 15, - thread = 1, - poll_interval = 30, - personal_api_key = None, - disabled = False, - disable_geoip = True, - is_server = True, - historical_migration = False, - feature_flags_request_timeout_seconds: float = 3, - feature_flags_request_max_retries = 1, - super_properties = None, - enable_exception_autocapture = False, - log_captured_exceptions = False, - project_root = None, - privacy_mode = False, - before_send = None, - flag_fallback_cache_url = None, - enable_local_evaluation = True, - flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, - capture_exception_code_variables = False, - code_variables_mask_patterns = None, - code_variables_ignore_patterns = None, - code_variables_mask_url_credentials = None, - code_variables_detect_secrets = None, - in_app_modules: list[str] | None = None, - enable_exception_autocapture_rate_limiting = False, - exception_autocapture_bucket_size = ExceptionCapture.DEFAULT_BUCKET_SIZE, - exception_autocapture_refill_rate = ExceptionCapture.DEFAULT_REFILL_RATE, - exception_autocapture_refill_interval_seconds = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, - capture_mode: Optional[Union[CaptureMode, str]] = None, - capture_compression: Optional[Union[CaptureCompression, str]] = None, - secret_key = None, - metrics: Optional[dict] = None, - enable_full_ai_capture = False, - capture_trace_context = False, - traces: Optional[dict] = None, - app_host: Optional[str] = None, - email_request_timeout_seconds: float = 15, - email_request_max_retries: int = 2, -) -``` - -
-Parameters (50) - -| Parameter | -| --- | -| `project_api_key`
**Type:** `str` · **Required**
PostHog project API key/token. | -| `host`
**Default:** `None`
PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | -| `debug`
**Default:** `False`
Enable verbose SDK logging and re-raise errors from public API methods. | -| `max_queue_size`
**Default:** `10000`
Maximum number of events buffered before upload. | -| `send`
**Default:** `True`
If False, queueing succeeds but events are not sent. | -| `on_error`
**Default:** `None`
Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | -| `flush_at`
**Default:** `100`
Number of queued events that triggers a batch upload. | -| `flush_interval`
**Default:** `5.0`
Maximum seconds a background consumer waits before flushing a partial batch. | -| `gzip`
**Default:** `False`
Whether to gzip event upload payloads. | -| `max_retries`
**Default:** `3`
Number of upload retries. Values below 0 are treated as 0. | -| `sync_mode`
**Default:** `False`
If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | -| `timeout`
**Type:** `float` · **Default:** `15`
HTTP request timeout in seconds for event uploads. | -| `thread`
**Default:** `1`
Number of background consumer threads. | -| `poll_interval`
**Default:** `30`
Seconds between local feature flag definition refreshes. | -| `personal_api_key`
**Default:** `None`
Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | -| `disabled`
**Default:** `False`
If True, disable captures and API requests. Useful in tests. | -| `disable_geoip`
**Default:** `True`
Whether to disable server-side GeoIP enrichment. Defaults to True. | -| `is_server`
**Default:** `True`
Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | -| `historical_migration`
**Default:** `False`
Mark events as historical migration imports. | -| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3`
Timeout in seconds for feature flag and remote config requests. | -| `feature_flags_request_max_retries`
**Default:** `1`
Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | -| `super_properties`
**Default:** `None`
Properties merged into every captured event. | -| `enable_exception_autocapture`
**Default:** `False`
Automatically capture uncaught exceptions. | -| `log_captured_exceptions`
**Default:** `False`
Also log exceptions captured by error tracking. | -| `project_root`
**Default:** `None`
Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | -| `privacy_mode`
**Default:** `False`
For AI observability, capture usage metadata without prompt inputs or outputs. | -| `before_send`
**Default:** `None`
Optional callback that can modify or drop events before upload. Return `None` to drop an event. | -| `flag_fallback_cache_url`
**Default:** `None`
Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | -| `enable_local_evaluation`
**Default:** `True`
Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | -| `flag_definition_cache_provider`
**Type:** `Optional[FlagDefinitionCacheProvider]` · **Default:** `None`
Optional external cache provider for sharing feature flag definitions across workers. | -| `capture_exception_code_variables`
**Default:** `False`
Capture local variable values on exception stack frames. | -| `code_variables_mask_patterns`
**Default:** `None`
Variable-name patterns to mask when capturing code variables. | -| `code_variables_ignore_patterns`
**Default:** `None`
Variable-name patterns to omit when capturing code variables. | -| `code_variables_mask_url_credentials`
**Default:** `None`
Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | -| `code_variables_detect_secrets`
**Default:** `None`
Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | -| `in_app_modules`
**Type:** `list[str]` \| `None` · **Default:** `None`
Module/package prefixes treated as in-app frames in captured exceptions. | -| `enable_exception_autocapture_rate_limiting`
**Default:** `False`
Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | -| `exception_autocapture_bucket_size`
**Default:** `ExceptionCapture.DEFAULT_BUCKET_SIZE`
Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | -| `exception_autocapture_refill_rate`
**Default:** `ExceptionCapture.DEFAULT_REFILL_RATE`
Tokens restored per refill interval for each exception type's bucket. | -| `exception_autocapture_refill_interval_seconds`
**Default:** `ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS`
Seconds between token refills for autocaptured exception rate limiting. | -| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None`
Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | -| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None`
Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | -| `secret_key`
**Default:** `None`
A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:
`posthog.Client(project_api_key, secret_key="phx_...")` | -| `metrics`
**Type:** `Optional[dict]` · **Default:** `None` | -| `enable_full_ai_capture`
**Default:** `False`
Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | -| `capture_trace_context`
**Default:** `False`
When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | -| `traces`
**Type:** `Optional[dict]` · **Default:** `None`
Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | -| `app_host`
**Type:** `Optional[str]` · **Default:** `None`
Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | -| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15`
Timeout in seconds for each email send request. Defaults to 15. | -| `email_request_max_retries`
**Type:** `int` · **Default:** `2`
Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | - -
+## Shutdown -**Correct example.** +### `Client.join` ```python -from posthog import Posthog - -posthog = Posthog('', host='') +join() -> None ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L684) - -## Shutdown - -### `Client.join` - Attempt to process queued events and end the consumer threads. Do not use directly, call `shutdown()` instead. Failed or undrainable events may be dropped and reported through logging or `on_error`; returning does not guarantee server receipt. Lifecycle cleanup is attempted once, and cleanup failures are logged without retry. -```python -join() -> None -``` - -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.join() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3342) - ### `Client.shutdown` +```python +shutdown() -> None +``` + Attempt final delivery and permanently shut down the client. Call this for final process cleanup or when disposing of a client that @@ -1193,125 +899,77 @@ application-owned thread and return before that thread calls shutdown. Do not wait inside the callback for another thread or task that calls a lifecycle method. -```python -shutdown() -> None -``` - -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.shutdown() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3364) - ## Flag definition loader ### `Client.load_feature_flags` -Load feature flags for local evaluation. - ```python load_feature_flags() ``` -**Correct example.** +Load feature flags for local evaluation. + +**Examples:** ```python posthog.load_feature_flags() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3825) - ### `Client.feature_flag_definitions` -Return feature flag definitions loaded for local evaluation. - ```python feature_flag_definitions() ``` -**Returns** . The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5252) - -## SDK utils - -### Other - -#### `Client.queue` - -The analytics lane's queue (kept for backwards compatibility). +Return feature flag definitions loaded for local evaluation. -```python -Client.queue: Queue -``` +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1293) +Type | Description +---- | ----------- + | The currently loaded feature flag definitions, or `None` before + | local evaluation has loaded definitions. -#### `Client.consumers` +## SDK utils -Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). +### `Client.queue` ```python -Client.consumers: Optional[List[Consumer]] +queue: Queue ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1298) - -#### `Client.feature_flags` - -Get the local evaluation feature flags. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1478) - -#### `Client.metrics` - -The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. - -Samples fold into per-series aggregates in memory and flush as one OTLP -data point per series per window, so recording from hot paths is cheap. -Configure via the `metrics` client option; pending metrics flush on -`shutdown()`. - -```python -Client.metrics: PostHogMetrics -``` +The analytics lane's queue (kept for backwards compatibility). -**Correct example.** +### `Client.consumers` ```python -client = Posthog("", metrics={"service_name": "billing-worker"}) -client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) -client.metrics.gauge("queue.depth", 42) -client.metrics.histogram("job.duration", 187, unit="ms") +consumers: Optional[List[Consumer]] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2718) - -### Contexts - -#### `Client.new_context` +Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). -Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). +### `Client.new_context` ```python new_context(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (2) +Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` +`capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -**Correct example.** +**Examples:** ```python with client.new_context(): @@ -1319,252 +977,298 @@ with client.new_context(): client.capture('event_name') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1378) +
+Category -#### `Client.scoped` +Contexts -Decorator that creates a new context for the wrapped function using this client. +
+ +### `Client.scoped` ```python scoped(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (2) +Decorator that creates a new context for the wrapped function using this client. -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` +`capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1400) +
+Category -#### `Client.tag` +Contexts -Add a tag to the current context. +
+ +### `Client.tag` ```python tag(name: str, value: Any) -> None ``` -
-Parameters (2) +Add a tag to the current context. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The tag key. | -| `value`
**Type:** `Any` · **Required**
The tag value. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | The tag key. | *required* +`value` | `Any` | The tag value. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1416) +Contexts -#### `Client.get_tags` +
-Get all tags from the current context. +### `Client.get_tags` ```python get_tags() -> Dict[str, Any] ``` -**Returns** `Dict[str, Any]`. Dict of all tags in the current context. +Get all tags from the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1429) +**Returns:** -#### `Client.identify_context` +Type | Description +---- | ----------- +`Dict[str, Any]` | Dict of all tags in the current context. -Identify the current context with a distinct ID. +
+Category + +Contexts + +
+ +### `Client.identify_context` ```python identify_context(distinct_id: str) -> None ``` -
-Parameters (1) +Identify the current context with a distinct ID. -| Parameter | -| --- | -| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `str` | The distinct ID to associate with the current context and its children. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1441) +Contexts -#### `Client.set_context_session` +
-Set the session ID for the current context. +### `Client.set_context_session` ```python set_context_session(session_id: str) -> None ``` -
-Parameters (1) +Set the session ID for the current context. -| Parameter | -| --- | -| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`session_id` | `str` | The session ID to associate with the current context and its children. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1453) +Contexts -#### `Client.set_context_device_id` +
-Set the device ID for the current context. +### `Client.set_context_device_id` ```python set_context_device_id(device_id: str) -> None ``` -
-Parameters (1) +Set the device ID for the current context. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`device_id` | `str` | The device ID to associate with the current context and its children. | *required* + +
+Category -| Parameter | -| --- | -| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children. | +Contexts
-**Returns** `None` +### `Client.feature_flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1465) +```python +feature_flags +``` + +Get the local evaluation feature flags. -### Feature flags +### `Client.get_feature_payloads` -#### `Client.get_feature_payloads` +```python +get_feature_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> dict[str, Optional[str]] +``` Get feature flag payloads for a user, preserving valid serialized JSON. +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** + ```python -get_feature_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> dict[str, Optional[str]] +payloads = posthog.get_feature_payloads('') ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Feature flags
-**Returns** `dict[str, Optional[str]]` - -**Correct example.** +### `Client.get_flags_decision` ```python -payloads = posthog.get_feature_payloads('') +get_flags_decision(distinct_id: Optional[ID_TYPES] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsResponse ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1535) +Get feature flags decision. -#### `Client.get_flags_decision` +**Parameters:** -Get feature flags decision. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The distinct ID of the user. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** ```python -get_flags_decision( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsResponse +decision = posthog.get_flags_decision('user123') ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Feature flags
-**Returns** `FlagsResponse` - -**Correct example.** +### `Client.metrics` ```python -decision = posthog.get_flags_decision('user123') +metrics: PostHogMetrics ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1628) +The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. + +Samples fold into per-series aggregates in memory and flush as one OTLP +data point per series per window, so recording from hot paths is cheap. +Configure via the `metrics` client option; pending metrics flush on +`shutdown()`. -#### `Client.get_remote_config_payload` +**Examples:** -Get the payload for a remote config feature flag. +```python +client = Posthog("", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +### `Client.get_remote_config_payload` ```python get_remote_config_payload(key: str) ``` -
-Parameters (1) +Get the payload for a remote config feature flag. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The remote config feature flag key. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The remote config feature flag key. | *required* -**Returns** . The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned. +**Returns:** -**Note.** Requires `secret_key` for authentication. +Type | Description +---- | ----------- + | The payload associated with the feature flag, or `None` if the + | client is disabled, no personal API key is configured, or the request + | fails. Encrypted payloads are decrypted by PostHog before being + | returned. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4670) +
+Note -#### `Client.get_feature_flag_evaluation_runtime` +Requires `secret_key` for authentication. -Return where a locally loaded feature flag is meant to be evaluated. +
+ +
+Category + +Feature flags + +
+ +### `Client.get_feature_flag_evaluation_runtime` ```python get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] ``` -
-Parameters (1) +Return where a locally loaded feature flag is meant to be evaluated. + +**Parameters:** -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* -
+**Returns:** -**Returns** `Optional[FeatureFlagEvaluationRuntime]`. The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. +Type | Description +---- | ----------- +`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has +`Optional[FeatureFlagEvaluationRuntime]` | not loaded a definition for this key. A definition that carries no +`Optional[FeatureFlagEvaluationRuntime]` | runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default +`Optional[FeatureFlagEvaluationRuntime]` | PostHog applies. -**Correct example.** +**Examples:** ```python from posthog import FeatureFlagEvaluationRuntime @@ -1574,9 +1278,18 @@ if runtime is FeatureFlagEvaluationRuntime.SERVER: ... ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5264) +
+Category -#### `Client.get_feature_flag_keys_by_evaluation_runtime` +Feature flags + +
+ +### `Client.get_feature_flag_keys_by_evaluation_runtime` + +```python +get_feature_flag_keys_by_evaluation_runtime(evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str]) -> list[str] +``` Return the keys of locally loaded flags that a runtime can evaluate. @@ -1585,24 +1298,20 @@ so it is returned for `CLIENT` and for `SERVER`, and asking for `ALL` returns every loaded flag. Use this to decide which flags to hand to a browser when a backend serves flags to its own frontend. -```python -get_feature_flag_keys_by_evaluation_runtime( - evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], -) -> list[str] -``` - -
-Parameters (1) +**Parameters:** -| Parameter | -| --- | -| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required**
The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`evaluation_runtime` | `Union[FeatureFlagEvaluationRuntime, str]` | The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | *required* -
+**Returns:** -**Returns** `list[str]`. The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. +Type | Description +---- | ----------- +`list[str]` | The matching flag keys, in the order local evaluation loaded them. +`list[str]` | Empty when no definitions are loaded. -**Correct example.** +**Examples:** ```python from posthog import FeatureFlagEvaluationRuntime @@ -1612,13 +1321,18 @@ client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5298) +
+Category -### Framework integrations +Feature flags + +
-#### `posthog.integrations.django.PosthogContextMiddleware` +### `posthog.integrations.django.PosthogContextMiddleware` -**Available in:** Django apps +```python +PosthogContextMiddleware(get_response) +``` Middleware to automatically track Django requests. @@ -1664,373 +1378,420 @@ This middleware is hybrid-capable: it supports both WSGI (sync) and ASGI (async) detects at initialization whether the next middleware in the chain is async or sync, and adapts its behavior accordingly. This ensures compatibility with both pure sync and pure async middleware chains, as well as mixed chains in ASGI mode. -```python -PosthogContextMiddleware(get_response) -``` +**Functions:** -
-Parameters (1) +Name | Description +---- | ----------- +`aextract_properties` | Async version of extract_properties for use in async request handling. +`aextract_request_user` | Async version of extract_request_user for use in async request handling. +`aextract_tags` | Compatibility alias for `aextract_properties`. +`extract_properties` | Extract event properties and identity from a synchronous request. +`extract_request_user` | Extract user ID and email from request in sync context. +`extract_tags` | Compatibility alias for `extract_properties`. +`process_exception` | Process exceptions from views and downstream middleware. -| Parameter | -| --- | -| `get_response`
**Required**
The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | +**Attributes:** -
+Name | Type | Description +---- | ---- | ----------- +`async_capable` | | +`capture_exceptions` | `Optional[bool]` | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`extra_tags` | | Compatibility alias for `extra_properties`. +`get_response` | | +`properties_map` | | +`request_filter` | | +`sync_capable` | | +`tag_map` | | Compatibility alias for `properties_map`. +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L31) +Initialize the middleware with Django's next handler. -#### `PosthogContextMiddleware.trust_tracing_headers` +**Parameters:** -**Available in:** Django apps +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`get_response` | | The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | -Deprecated alias for `capture_tracing_headers`. +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_properties` ```python -PosthogContextMiddleware.trust_tracing_headers: bool +aextract_properties(request) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L158) +Async version of extract_properties for use in async request handling. -#### `PosthogContextMiddleware.extra_tags` +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. -**Available in:** Django apps +Follows Django's naming convention for async methods (auser, asave, etc.). -Compatibility alias for `extra_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_request_user` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L167) +```python +aextract_request_user(request) +``` -#### `PosthogContextMiddleware.tag_map` +Async version of extract_request_user for use in async request handling. -**Available in:** Django apps +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. -Compatibility alias for `properties_map`. +Follows Django's naming convention for async methods (auser, asave, etc.). -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L176) +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_tags` -#### `PosthogContextMiddleware.extract_tags` +```python +aextract_tags(request) +``` -**Available in:** Django apps +Compatibility alias for `aextract_properties`. -Compatibility alias for `extract_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.async_capable` ```python -extract_tags(request) +async_capable = True ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.capture_exceptions` -| Parameter | -| --- | -| `request`
**Required** | +```python +capture_exceptions: Optional[bool] = capture_exceptions if (capture_exceptions is None or isinstance(capture_exceptions, bool)) else True +``` -
+#### `posthog.integrations.django.PosthogContextMiddleware.capture_tracing_headers` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L184) +```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers, canonical_name='POSTHOG_MW_CAPTURE_TRACING_HEADERS', deprecated_name='POSTHOG_MW_TRUST_TRACING_HEADERS') +``` -#### `PosthogContextMiddleware.extract_properties` +#### `posthog.integrations.django.PosthogContextMiddleware.client` -**Available in:** Django apps +```python +client = cast('Optional[Client]', settings.POSTHOG_MW_CLIENT) +``` -Extract event properties and identity from a synchronous request. +#### `posthog.integrations.django.PosthogContextMiddleware.extra_properties` ```python -extract_properties(request) +extra_properties = cast('Callable[[HttpRequest], Dict[str, Any]]', extra_properties) if callable(extra_properties) else None ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.extra_tags` -| Parameter | -| --- | -| `request`
**Required** | +```python +extra_tags +``` -
+Compatibility alias for `extra_properties`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L189) +#### `posthog.integrations.django.PosthogContextMiddleware.extract_properties` -#### `PosthogContextMiddleware.extract_request_user` +```python +extract_properties(request) +``` -**Available in:** Django apps +Extract event properties and identity from a synchronous request. -Extract user ID and email from request in sync context. +#### `posthog.integrations.django.PosthogContextMiddleware.extract_request_user` ```python extract_request_user(request) ``` -
-Parameters (1) - -| Parameter | -| --- | -| `request`
**Required** | - -
+Extract user ID and email from request in sync context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L250) +#### `posthog.integrations.django.PosthogContextMiddleware.extract_tags` -#### `PosthogContextMiddleware.aextract_tags` +```python +extract_tags(request) +``` -**Available in:** Django apps +Compatibility alias for `extract_properties`. -Compatibility alias for `aextract_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.get_response` ```python -async aextract_tags(request) +get_response = get_response ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.process_exception` -| Parameter | -| --- | -| `request`
**Required** | +```python +process_exception(request, exception) +``` -
+Process exceptions from views and downstream middleware. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L256) +Django calls this WHILE still inside the context created by __call__, +so request tags have already been extracted and set. This method just +needs to capture the exception directly. -#### `PosthogContextMiddleware.aextract_properties` +Django converts view exceptions into responses before they propagate through +the middleware stack, so the context manager in __call__/__acall__ never sees them. -**Available in:** Django apps +Note: Django's process_exception is always synchronous, even for async views. -Async version of extract_properties for use in async request handling. +#### `posthog.integrations.django.PosthogContextMiddleware.properties_map` -Uses await request.auser() instead of request.user to avoid -SynchronousOnlyOperation in async context. +```python +properties_map = cast('Callable[[Dict[str, Any]], Dict[str, Any]]', properties_map) if callable(properties_map) else None +``` -Follows Django's naming convention for async methods (auser, asave, etc.). +#### `posthog.integrations.django.PosthogContextMiddleware.request_filter` ```python -async aextract_properties(request) +request_filter = cast('Optional[Callable[[HttpRequest], bool]]', settings.POSTHOG_MW_REQUEST_FILTER) ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.sync_capable` -| Parameter | -| --- | -| `request`
**Required** | +```python +sync_capable = True +``` -
+#### `posthog.integrations.django.PosthogContextMiddleware.tag_map` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L261) +```python +tag_map +``` -#### `PosthogContextMiddleware.aextract_request_user` +Compatibility alias for `properties_map`. -**Available in:** Django apps +#### `posthog.integrations.django.PosthogContextMiddleware.trust_tracing_headers` -Async version of extract_request_user for use in async request handling. +```python +trust_tracing_headers: bool +``` -Uses await request.auser() instead of request.user to avoid -SynchronousOnlyOperation in async context. +Deprecated alias for `capture_tracing_headers`. -Follows Django's naming convention for async methods (auser, asave, etc.). +### `posthog.integrations.flask.PosthogFlaskIntegration` ```python -async aextract_request_user(request) +PosthogFlaskIntegration(app: Optional[Flask] = None, *, client: Optional[Client] = None, capture_exceptions: Optional[bool] = None, request_filter: Optional[Callable[[Request], bool]] = None, extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, trust_tracing_headers: Optional[bool] = None, capture_tracing_headers: Optional[bool] = None) -> None ``` -
-Parameters (1) - -| Parameter | -| --- | -| `request`
**Required** | +Add PostHog request context and exception tracking to a Flask app. -
+**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L274) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`app` | `Optional[Flask]` | An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | `None` +`client` | `Optional[Client]` | Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | `None` +`capture_exceptions` | `Optional[bool]` | Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | `None` +`request_filter` | `Optional[Callable[[Request], bool]]` | Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | `None` +`extra_properties` | `Optional[Callable[[Request], Mapping[str, Any]]]` | Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | `None` +`capture_tracing_headers` | `Optional[bool]` | Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | `None` +`trust_tracing_headers` | `Optional[bool]` | Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | `None` -#### `PosthogContextMiddleware.process_exception` +The integration intentionally does not capture exceptions handled by an +application error handler, expected HTTP exceptions, request or response +bodies, query strings, cookies, authorization headers, or arbitrary headers. +Call `capture_exception` explicitly from a custom error handler if a +handled exception should be reported. -**Available in:** Django apps +**Functions:** -Process exceptions from views and downstream middleware. +Name | Description +---- | ----------- +`init_app` | Register the integration with a Flask application once. -Django calls this WHILE still inside the context created by __call__, -so request tags have already been extracted and set. This method just -needs to capture the exception directly. +**Attributes:** -Django converts view exceptions into responses before they propagate through -the middleware stack, so the context manager in __call__/__acall__ never sees them. +Name | Type | Description +---- | ---- | ----------- +`capture_exceptions` | | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`request_filter` | | +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -Note: Django's process_exception is always synchronous, even for async views. +#### `posthog.integrations.flask.PosthogFlaskIntegration.capture_exceptions` ```python -process_exception(request, exception) +capture_exceptions = capture_exceptions ``` -
-Parameters (2) +#### `posthog.integrations.flask.PosthogFlaskIntegration.capture_tracing_headers` -| Parameter | -| --- | -| `request`
**Required** | -| `exception`
**Required** | - -
+```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers) +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L376) +#### `posthog.integrations.flask.PosthogFlaskIntegration.client` -#### `posthog.integrations.flask.PosthogFlaskIntegration` +```python +client = client +``` -**Available in:** Flask apps +#### `posthog.integrations.flask.PosthogFlaskIntegration.extra_properties` -Add PostHog request context and exception tracking to a Flask app. +```python +extra_properties = extra_properties +``` -The integration intentionally does not capture exceptions handled by an -application error handler, expected HTTP exceptions, request or response -bodies, query strings, cookies, authorization headers, or arbitrary headers. -Call `capture_exception` explicitly from a custom error handler if a -handled exception should be reported. +#### `posthog.integrations.flask.PosthogFlaskIntegration.init_app` ```python -PosthogFlaskIntegration( - app: Optional[Flask] = None, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - request_filter: Optional[Callable[[Request], bool]] = None, - extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, - trust_tracing_headers: Optional[bool] = None, - capture_tracing_headers: Optional[bool] = None, -) +init_app(app: Flask) -> None ``` -
-Parameters (7) - -| Parameter | -| --- | -| `app`
**Type:** `Optional[Flask]` · **Default:** `None`
An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | -| `request_filter`
**Type:** `Optional[Callable[[Request], bool]]` · **Default:** `None`
Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | -| `extra_properties`
**Type:** `Optional[Callable[[Request], Mapping[str, Any]]]` · **Default:** `None`
Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | -| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | -| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | +Register the integration with a Flask application once. -
+#### `posthog.integrations.flask.PosthogFlaskIntegration.request_filter` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L91) +```python +request_filter = request_filter +``` -#### `PosthogFlaskIntegration.trust_tracing_headers` +#### `posthog.integrations.flask.PosthogFlaskIntegration.trust_tracing_headers` -**Available in:** Flask apps +```python +trust_tracing_headers: bool +``` Deprecated alias for `capture_tracing_headers`. +### `posthog.integrations.asgi.PosthogASGIMiddleware` + ```python -PosthogFlaskIntegration.trust_tracing_headers: bool +PosthogASGIMiddleware(app: _ASGIApp, client: Optional[Client] = None, capture_exceptions: Optional[bool] = None, request_filter: Optional[_RequestFilter] = None, extra_properties: Optional[_ExtraProperties] = None, trust_tracing_headers: Optional[bool] = None, *, capture_tracing_headers: Optional[bool] = None) -> None ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L146) - -#### `PosthogFlaskIntegration.init_app` +Add PostHog context and automatic exception capture to an ASGI app. -**Available in:** Flask apps +**Parameters:** -Register the integration with a Flask application once. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`app` | `_ASGIApp` | The downstream ASGI application. | *required* +`client` | `Optional[Client]` | Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | `None` +`capture_exceptions` | `Optional[bool]` | Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | `None` +`request_filter` | `Optional[_RequestFilter]` | Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | `None` +`extra_properties` | `Optional[_ExtraProperties]` | Optional sync or async callback receiving the ASGI scope and returning additional event properties. | `None` +`capture_tracing_headers` | `Optional[bool]` | Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | `None` +`trust_tracing_headers` | `Optional[bool]` | Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | `None` -```python -init_app(app: Flask) -> None -``` +**Attributes:** -
-Parameters (1) +Name | Type | Description +---- | ---- | ----------- +`app` | | +`capture_exceptions` | | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`request_filter` | | +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -| Parameter | -| --- | -| `app`
**Type:** `Flask` · **Required** | +#### `posthog.integrations.asgi.PosthogASGIMiddleware.app` -
+```python +app = app +``` -**Returns** `None` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.capture_exceptions` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L154) +```python +capture_exceptions = capture_exceptions +``` -#### `posthog.integrations.asgi.PosthogASGIMiddleware` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.capture_tracing_headers` -**Available in:** ASGI apps, such as FastAPI and Starlette +```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers) +``` -Add PostHog context and automatic exception capture to an ASGI app. +#### `posthog.integrations.asgi.PosthogASGIMiddleware.client` ```python -PosthogASGIMiddleware( - app: _ASGIApp, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - request_filter: Optional[_RequestFilter] = None, - extra_properties: Optional[_ExtraProperties] = None, - trust_tracing_headers: Optional[bool] = None, - capture_tracing_headers: Optional[bool] = None, -) +client = client ``` -
-Parameters (7) +#### `posthog.integrations.asgi.PosthogASGIMiddleware.extra_properties` -| Parameter | -| --- | -| `app`
**Type:** `_ASGIApp` · **Required**
The downstream ASGI application. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | -| `request_filter`
**Type:** `Optional[_RequestFilter]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | -| `extra_properties`
**Type:** `Optional[_ExtraProperties]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope and returning additional event properties. | -| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | -| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | +```python +extra_properties = extra_properties +``` -
+#### `posthog.integrations.asgi.PosthogASGIMiddleware.request_filter` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L182) +```python +request_filter = request_filter +``` -#### `PosthogASGIMiddleware.trust_tracing_headers` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.trust_tracing_headers` -**Available in:** ASGI apps, such as FastAPI and Starlette +```python +trust_tracing_headers: bool +``` Deprecated alias for `capture_tracing_headers`. +### `posthog.integrations.celery.PosthogCeleryIntegration` + ```python -PosthogASGIMiddleware.trust_tracing_headers: bool +PosthogCeleryIntegration(client: Optional[Client] = None, capture_exceptions: bool = True, capture_task_lifecycle_events: bool = True, propagate_context: bool = True, task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L225) +Celery integration that captures task lifecycle events and exceptions. + +**Parameters:** -#### `posthog.integrations.celery.PosthogCeleryIntegration` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`client` | `Optional[Client]` | Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | `None` +`capture_exceptions` | `bool` | Whether to capture task exceptions via `capture_exception` (default `True`). | `True` +`capture_task_lifecycle_events` | `bool` | Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | `True` +`propagate_context` | `bool` | Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | `True` +`task_filter` | `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` | Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | `None` -**Available in:** Celery workers +**Functions:** -Celery integration that captures task lifecycle events and exceptions. +Name | Description +---- | ----------- +`instrument` | Connect Celery signal handlers to capture task events and exceptions. +`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events +`uninstrument` | Disconnect Celery signal handlers and unregister exit cleanup. + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`capture_exceptions` | | +`capture_task_lifecycle_events` | | +`client` | | +`propagate_context` | | +`task_filter` | | + +#### `posthog.integrations.celery.PosthogCeleryIntegration.capture_exceptions` ```python -PosthogCeleryIntegration( - client: Optional[Client] = None, - capture_exceptions: bool = True, - capture_task_lifecycle_events: bool = True, - propagate_context: bool = True, - task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None, -) +capture_exceptions = capture_exceptions ``` -
-Parameters (5) +#### `posthog.integrations.celery.PosthogCeleryIntegration.capture_task_lifecycle_events` -| Parameter | -| --- | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | -| `capture_exceptions`
**Type:** `bool` · **Default:** `True`
Whether to capture task exceptions via `capture_exception` (default `True`). | -| `capture_task_lifecycle_events`
**Type:** `bool` · **Default:** `True`
Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | -| `propagate_context`
**Type:** `bool` · **Default:** `True`
Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | -| `task_filter`
**Type:** `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` · **Default:** `None`
Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | +```python +capture_task_lifecycle_events = capture_task_lifecycle_events +``` -
+#### `posthog.integrations.celery.PosthogCeleryIntegration.client` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L89) +```python +client = client +``` -#### `PosthogCeleryIntegration.instrument` +#### `posthog.integrations.celery.PosthogCeleryIntegration.instrument` -**Available in:** Celery workers +```python +instrument() -> None +``` Connect Celery signal handlers to capture task events and exceptions. Call this after initializing the PostHog client and this integration. @@ -2042,34 +1803,18 @@ process must initialize PostHog, this integration, and call `instrument()`. Celery provides `worker_process_init` signal to help with this. +#### `posthog.integrations.celery.PosthogCeleryIntegration.propagate_context` + ```python -instrument() -> None +propagate_context = propagate_context ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L129) - -#### `PosthogCeleryIntegration.uninstrument` - -**Available in:** Celery workers - -Disconnect Celery signal handlers and unregister exit cleanup. - -Do not use directly, call `shutdown()` instead. +#### `posthog.integrations.celery.PosthogCeleryIntegration.shutdown` ```python -uninstrument() -> None +shutdown() -> None ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L182) - -#### `PosthogCeleryIntegration.shutdown` - -**Available in:** Celery workers - Disconnect all signal handlers registered by `instrument()`, flush all pending events and cleanly shutdown the integration. @@ -2077,748 +1822,505 @@ and cleanly shutdown the integration. but there is no guarantee those will always be called, so we strongly recommend calling it manually when the integration is no longer needed to avoid data loss. +#### `posthog.integrations.celery.PosthogCeleryIntegration.task_filter` + ```python -shutdown() -> None +task_filter = task_filter ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L190) +#### `posthog.integrations.celery.PosthogCeleryIntegration.uninstrument` -#### `posthog.integrations.drf.create_exception_handler` - -**Available in:** Django REST framework apps +```python +uninstrument() -> None +``` -Create a PostHog-instrumented DRF exception handler. +Disconnect Celery signal handlers and unregister exit cleanup. -When `POSTHOG_MW_REQUEST_FILTER` is configured, it is also applied to the -underlying Django request before capture so handled errors cannot bypass the -middleware's per-request exclusion. +Do not use directly, call `shutdown()` instead. -The delegated handler is called first. A `None` response is never -captured here because DRF will re-raise that exception, allowing Django's -middleware to capture it as unhandled. +### `posthog.request.set_socket_options` ```python -create_exception_handler( - handler: Optional[Callable[[Exception, Mapping[str, Any]], Any]] = None, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - capture_4xx: bool = False, - exception_filter: Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]] = None, -) -> Callable[[Exception, Mapping[str, Any]], Any] +set_socket_options(socket_options: Optional[SocketOptions]) -> None ``` -
-Parameters (5) +Configure socket options for all SDK HTTP connections. -| Parameter | -| --- | -| `handler`
**Type:** `Optional[Callable[[Exception, Mapping[str, Any]], Any]]` · **Default:** `None`
Handler to delegate to. Defaults to DRF's standard exception handler. Its return value and raised exceptions are preserved. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional PostHog client. Client precedence is this argument, the legacy `POSTHOG_DRF_CLIENT` alias, `POSTHOG_MW_CLIENT`, then the global PostHog client. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture handled DRF exceptions. An explicit value takes precedence over `POSTHOG_MW_CAPTURE_EXCEPTIONS`. A boolean setting is used directly; an explicit `None` setting inherits the effective client's `enable_exception_autocapture`. An omitted or malformed setting preserves the legacy `True` default. | -| `capture_4xx`
**Type:** `bool` · **Default:** `False`
Also capture handled 4xx responses. Disabled by default to avoid reporting expected API errors. | -| `exception_filter`
**Type:** `Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]]` · **Default:** `None`
Optional final filter called with `(exception, response, context)`. Returning `False` suppresses capture. | +Call this during initialization, before making API requests. Pass `None` +to reset to the default socket behavior. -
+**Parameters:** -**Returns** `Callable[[Exception, Mapping[str, Any]], Any]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`socket_options` | `Optional[SocketOptions]` | A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | *required* -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/drf.py#L140) +
+Example -#### `posthog.integrations.otel.PostHogContextSpanProcessor` +from posthog import set_socket_options +set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) -**Available in:** the `otel` extra, `posthog[otel]` +
-Add PostHog request IDs to application-owned OpenTelemetry SDK spans. +### `posthog.request.enable_keep_alive` -Add this processor to the application's existing TracerProvider before -starting requests. It snapshots child span context at span start, without -changing exporters, sampling or providers. Request integrations must also -enrich an incoming span that started before request context was available. +```python +enable_keep_alive() -> None +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L20) +Enable TCP keepalive for SDK HTTP connections. -#### `PostHogContextSpanProcessor.on_start` +This helps prevent idle pooled connections from being dropped by network +infrastructure. Call during initialization, before making API requests. -**Available in:** the `otel` extra, `posthog[otel]` +### `posthog.request.disable_connection_reuse` ```python -on_start(span: Span, parent_context: Optional[Context] = None) -> None +disable_connection_reuse() -> None ``` -
-Parameters (2) - -| Parameter | -| --- | -| `span`
**Type:** `Span` · **Required** | -| `parent_context`
**Type:** `Optional[Context]` · **Default:** `None` | - -
+Disable HTTP connection reuse for SDK requests. -**Returns** `None` +Each request will create a fresh connection. This can avoid issues with +environments that terminate pooled connections, but adds per-request +overhead. Call during initialization, before making API requests. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L29) +## AsyncClient -#### `posthog.integrations.otel.enrich_current_span` +Needs the `async` extra, `posthog[async]`. -**Available in:** the `otel` extra, `posthog[otel]` +### `AsyncClient(...)` -Add request IDs to an existing recording span after request context is set. +```python +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) -> None +``` -Explicit span attributes take precedence. Missing OpenTelemetry support and -context lookup failures do not interrupt request handling. +### `AsyncClient.capture` ```python -enrich_current_span() -> None +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L11) +Queue an event without blocking for network delivery. -### HTTP connection +### `AsyncClient.capture_immediate` -#### `posthog.request.set_socket_options` +```python +capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` -Configure socket options for all SDK HTTP connections. +Capture one event and wait until its delivery attempt completes. -Call this during initialization, before making API requests. Pass `None` -to reset to the default socket behavior. +### `AsyncClient.set` ```python -set_socket_options(socket_options: Optional[SocketOptions]) -> None +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `socket_options`
**Type:** `Optional[SocketOptions]` · **Required**
A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | - -
+### `AsyncClient.set_once` -**Returns** `None` +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` -**Correct example.** +### `AsyncClient.alias` ```python -from posthog import set_socket_options -set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) +alias(previous_id: ID_TYPES, distinct_id: Optional[str], timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L143) +### `AsyncClient.capture_exception` -#### `posthog.request.enable_keep_alive` +```python +capture_exception(exception: Optional[ExceptionArg] = None, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` -Enable TCP keepalive for SDK HTTP connections. +Capture an exception. This method never raises, including in debug mode. -This helps prevent idle pooled connections from being dropped by network -infrastructure. Call during initialization, before making API requests. +### `AsyncClient.emails` ```python -enable_keep_alive() -> None +emails: AsyncEmails ``` -**Returns** `None` +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L166) +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog +Cloud app host of `host`. `email_request_timeout_seconds` and +`email_request_max_retries` configure each send. A disabled or shut-down +client sends nothing. See `posthog.emails` for setup. -#### `posthog.request.disable_connection_reuse` +**Examples:** -Disable HTTP connection reuse for SDK requests. +```python +await client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + distinct_id="user_123", +) +``` -Each request will create a fresh connection. This can avoid issues with -environments that terminate pooled connections, but adds per-request -overhead. Call during initialization, before making API requests. +### `AsyncClient.flush` ```python -disable_connection_reuse() -> None +flush(timeout_seconds: Optional[float] = 10) -> None ``` -**Returns** `None` +### `AsyncClient.evaluate_flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L176) +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` -### AI wrapper clients +Evaluate flags remotely without blocking the event loop. -#### `posthog.ai.openai` - -**Available in:** apps with the `openai` package - -Exports `OpenAI`, `AsyncOpenAI`, `AsyncAzureOpenAI`, `AzureOpenAI`. - -#### `posthog.ai.anthropic` - -**Available in:** apps with the `anthropic` package - -Exports `Anthropic`, `AsyncAnthropic`, `AnthropicBedrock`, `AnthropicVertex`, `AsyncAnthropicBedrock`, `AsyncAnthropicVertex`. - -#### `posthog.ai.gemini` - -**Available in:** apps with the Google Gen AI package - -Exports `Client`, `AsyncClient`. - -#### `posthog.ai.langchain` - -**Available in:** the `langchain` extra, `posthog[langchain]` - -Exports `CallbackHandler`. - -#### `posthog.ai.openai_agents` - -**Available in:** apps with the `openai-agents` package +The returned snapshot has synchronous in-memory accessors. Pass it to +`capture(flags=...)` to attach the exact values used for branching. +This client does not evaluate flags locally, so the snapshot's +`unresolved_flags` is always empty. -Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `Trace`, `Client`, `PostHogTracingProcessor`. +### `AsyncClient.group_identify` -#### `posthog.ai.claude_agent_sdk` +```python +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[Union[str, UUID]] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] +``` -**Available in:** apps with the `claude-agent-sdk` package +### `AsyncClient.shutdown` -Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `ClaudeAgentOptions`, `ResultMessage`, `Client`, `PostHogClaudeSDKClient`, `PostHogClaudeAgentProcessor`. +```python +shutdown() -> None +``` -## AsyncClient +### `AsyncClient.join` -### `AsyncClient.alias` +```python +join() -> None +``` -**Available in:** the `async` extra, `posthog[async]` +### `AsyncClient.get_remote_config_payload` ```python -alias( - previous_id: ID_TYPES, - distinct_id: Optional[str], - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +get_remote_config_payload(key: str) -> Optional[Any] ``` -
-Parameters (5) +Fetch and decrypt a remote-config payload without blocking the loop. -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required** | -| `distinct_id`
**Type:** `Optional[str]` · **Required** | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +## Module functions -
+### `posthog.new_context` -**Returns** `Optional[str]` +```python +new_context(fresh: bool = False, capture_exceptions: Optional[bool] = None, client: Optional[Client] = None) +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L772) +Create a new context scope that will be active for the duration of the with block. -### `AsyncClient.capture` +**Parameters:** -**Available in:** the `async` extra, `posthog[async]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | `bool` | Whether to start with a fresh context (default: False) | `False` +`capture_exceptions` | `Optional[bool]` | Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | `None` +`client` | `Optional[Client]` | Optional Posthog client instance to use for this context (default: None) | `None` -Queue an event without blocking for network delivery. +**Examples:** ```python -capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | +Contexts
-**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L570) - -### `AsyncClient.capture_immediate` - -**Available in:** the `async` extra, `posthog[async]` - -Capture one event and wait until its delivery attempt completes. +### `posthog.scoped` ```python -async capture_immediate( - event: str, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +scoped(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (1) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L613) +Decorator that creates a new context for the function. -### `AsyncClient.capture_exception` +**Parameters:** -**Available in:** the `async` extra, `posthog[async]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to start with a fresh context (default: False) | `False` +`capture_exceptions` | `Optional[bool]` | Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | `None` -Capture an exception. This method never raises, including in debug mode. +**Examples:** ```python -capture_exception( - exception: Optional[ExceptionArg] = None, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None` | +Contexts
-**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L823) - -### `AsyncClient.emails` - -**Available in:** the `async` extra, `posthog[async]` - -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. - -Needs `secret_key`, a project secret API key with the `hog_flow:write` -scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog -Cloud app host of `host`. `email_request_timeout_seconds` and -`email_request_max_retries` configure each send. A disabled or shut-down -client sends nothing. See `posthog.emails` for setup. +### `posthog.set_context_session` ```python -AsyncClient.emails: AsyncEmails +set_context_session(session_id: str) ``` -**Correct example.** - -```python -await client.emails.send( - to="user@example.com", - template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", - distinct_id="user_123", -) -``` +Set the session ID for the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L268) +**Parameters:** -### `AsyncClient.flush` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`session_id` | `str` | The session ID to associate with the current context and its children | *required* -**Available in:** the `async` extra, `posthog[async]` +**Examples:** ```python -async flush(timeout_seconds: Optional[float] = 10) -> None +from posthog import set_context_session +set_context_session("session_123") ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10` | +Contexts
-**Returns** `None` +### `posthog.set_context_device_id` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1204) +```python +set_context_device_id(device_id: str) +``` -### `AsyncClient.evaluate_flags` +Set the device ID for the current context, associating all feature flag requests +in this or child contexts with the given device ID. -**Available in:** the `async` extra, `posthog[async]` +**Parameters:** -Evaluate flags remotely without blocking the event loop. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`device_id` | `str` | The device ID to associate with the current context and its children | *required* -The returned snapshot has synchronous in-memory accessors. Pass it to -`capture(flags=...)` to attach the exact values used for branching. -This client does not evaluate flags locally, so the snapshot's -`unresolved_flags` is always empty. +**Examples:** ```python -async evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations +from posthog import set_context_device_id +set_context_device_id("device_123") ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None` | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | -| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None` | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None` | +Contexts
-**Returns** `FeatureFlagEvaluations` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L959) - -### `AsyncClient.group_identify` - -**Available in:** the `async` extra, `posthog[async]` +### `posthog.identify_context` ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[Union[str, UUID]] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +identify_context(distinct_id: str) ``` -
-Parameters (7) - -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required** | -| `group_key`
**Type:** `str` · **Required** | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | -| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | - -
- -**Returns** `Optional[str]` +Identify the current context with a distinct ID. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L727) +**Parameters:** -### `AsyncClient.set` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `str` | The distinct ID to associate with the current context and its children | *required* -**Available in:** the `async` extra, `posthog[async]` +**Examples:** ```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +from posthog import identify_context +identify_context("user_123") ``` -**Returns** `Optional[str]` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L701) +Identification -### `AsyncClient.set_once` +
-**Available in:** the `async` extra, `posthog[async]` +### `posthog.set_capture_exception_code_variables_context` ```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +set_capture_exception_code_variables_context(enabled: bool) ``` -**Returns** `Optional[str]` +Override code-variable capture for exceptions in the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L714) +**Parameters:** -### `AsyncClient(...)` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`enabled` | `bool` | Whether exceptions captured in this context should include local variable values from stack frames. | *required* -**Available in:** the `async` extra, `posthog[async]` - -```python -AsyncClient( - project_api_key: str, - host: Optional[str] = None, - debug: bool = False, - max_queue_size: int = 10000, - send: bool = True, - on_error = None, - flush_at: int = 100, - flush_interval: float = 5.0, - gzip: bool = False, - max_retries: int = 3, - timeout: float = 15, - thread: int = 1, - disabled: bool = False, - disable_geoip: bool = True, - is_server: bool = True, - historical_migration: bool = False, - super_properties: Optional[dict[str, Any]] = None, - before_send = None, - log_captured_exceptions: bool = False, - project_root: Optional[str] = None, - capture_exception_code_variables: bool = False, - code_variables_mask_patterns = None, - code_variables_ignore_patterns = None, - code_variables_mask_url_credentials = None, - code_variables_detect_secrets = None, - in_app_modules: Optional[list[str]] = None, - capture_mode: Optional[Union[CaptureMode, str]] = None, - capture_compression: Optional[Union[CaptureCompression, str]] = None, - capture_trace_context: bool = False, - secret_key: Optional[str] = None, - personal_api_key: Optional[str] = None, - feature_flags_request_timeout_seconds: float = 3, - feature_flags_request_max_retries: int = 1, - app_host: Optional[str] = None, - email_request_timeout_seconds: float = 15, - email_request_max_retries: int = 2, -) -``` +
+Category -
-Parameters (36) - -| Parameter | -| --- | -| `project_api_key`
**Type:** `str` · **Required** | -| `host`
**Type:** `Optional[str]` · **Default:** `None` | -| `debug`
**Type:** `bool` · **Default:** `False` | -| `max_queue_size`
**Type:** `int` · **Default:** `10000` | -| `send`
**Type:** `bool` · **Default:** `True` | -| `on_error`
**Default:** `None` | -| `flush_at`
**Type:** `int` · **Default:** `100` | -| `flush_interval`
**Type:** `float` · **Default:** `5.0` | -| `gzip`
**Type:** `bool` · **Default:** `False` | -| `max_retries`
**Type:** `int` · **Default:** `3` | -| `timeout`
**Type:** `float` · **Default:** `15` | -| `thread`
**Type:** `int` · **Default:** `1` | -| `disabled`
**Type:** `bool` · **Default:** `False` | -| `disable_geoip`
**Type:** `bool` · **Default:** `True` | -| `is_server`
**Type:** `bool` · **Default:** `True` | -| `historical_migration`
**Type:** `bool` · **Default:** `False` | -| `super_properties`
**Type:** `Optional[dict[str, Any]]` · **Default:** `None` | -| `before_send`
**Default:** `None` | -| `log_captured_exceptions`
**Type:** `bool` · **Default:** `False` | -| `project_root`
**Type:** `Optional[str]` · **Default:** `None` | -| `capture_exception_code_variables`
**Type:** `bool` · **Default:** `False` | -| `code_variables_mask_patterns`
**Default:** `None` | -| `code_variables_ignore_patterns`
**Default:** `None` | -| `code_variables_mask_url_credentials`
**Default:** `None` | -| `code_variables_detect_secrets`
**Default:** `None` | -| `in_app_modules`
**Type:** `Optional[list[str]]` · **Default:** `None` | -| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None` | -| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None` | -| `capture_trace_context`
**Type:** `bool` · **Default:** `False` | -| `secret_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `personal_api_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3` | -| `feature_flags_request_max_retries`
**Type:** `int` · **Default:** `1` | -| `app_host`
**Type:** `Optional[str]` · **Default:** `None` | -| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15` | -| `email_request_max_retries`
**Type:** `int` · **Default:** `2` | +Contexts
-[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L102) - -### `AsyncClient.shutdown` - -**Available in:** the `async` extra, `posthog[async]` +### `posthog.set_code_variables_mask_patterns_context` ```python -async shutdown() -> None +set_code_variables_mask_patterns_context(mask_patterns: list[str]) ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1235) - -### `AsyncClient.join` - -**Available in:** the `async` extra, `posthog[async]` +Override code-variable mask patterns for exceptions in the current context. -```python -async join() -> None -``` +**Parameters:** -**Returns** `None` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`mask_patterns` | `list[str]` | Variable-name patterns whose values should be replaced with `***` when code variables are captured. | *required* -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1305) +
+Category -### `AsyncClient.get_remote_config_payload` +Contexts -**Available in:** the `async` extra, `posthog[async]` +
-Fetch and decrypt a remote-config payload without blocking the loop. +### `posthog.set_code_variables_ignore_patterns_context` ```python -async get_remote_config_payload(key: str) -> Optional[Any] +set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) ``` -
-Parameters (1) +Override code-variable ignore patterns for exceptions in the current context. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`ignore_patterns` | `list[str]` | Variable-name patterns that should be omitted entirely when code variables are captured. | *required* -**Returns** `Optional[Any]` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1064) +Contexts -## Module functions +
-### `posthog.start_span` +### `posthog.set_code_variables_mask_url_credentials_context` -Start a span for distributed tracing. Alpha. +```python +set_code_variables_mask_url_credentials_context(enabled: bool) +``` -Returns a span handle. Use it as a context manager to make it the active -span for the block and end it on exit (recording a raised exception on the -way out); or call `end()` yourself for a span that cannot wrap a block. -Spans started inside the block nest under it automatically. Always returns -a usable handle, even when tracing is off, so calling code never branches. +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from +captured code variables for the current context. + +### `posthog.set_code_variables_detect_secrets_context` ```python -start_span( - name: str, - kind: Optional[str] = None, - attributes: Optional[Mapping[str, Any]] = None, - parent: Union[Span, str, None] = None, - tracestate: Optional[str] = None, - start_time: Union[datetime.datetime, float, None] = None, -) -> Span +set_code_variables_detect_secrets_context(enabled: bool) ``` -
-Parameters (6) +Whether to apply entropy-based secret detection as a last-resort redaction of +high-entropy values (API keys, tokens, strong passwords) in captured code +variables for the current context. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | -| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | -| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | -| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | -| `start_time`
**Type:** `Union[datetime.datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | +
+Category -
+Contexts -**Returns** `Span` +
-**Correct example.** +### `posthog.tag` ```python -import posthog -posthog.traces = {"service_name": "checkout-api"} - -with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: - span.set_attribute("plan", user.plan) - with posthog.start_span("db.query", kind="client"): - ... - outgoing_headers = {"traceparent": span.traceparent()} +tag(name: str, value: Any) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1284) +Add a tag to the current context. -### `posthog.get_active_span` +**Parameters:** -The span that is active in the current context, or `None`. Alpha. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | The tag key | *required* +`value` | `Any` | The tag value | *required* -Only entering a span (`with posthog.start_span(...) as span:`) makes it -active; a span started manually is not. Use it to propagate the trace to -the next service: `span.traceparent()` is the header value. +**Examples:** ```python -get_active_span() -> Optional[Span] +from posthog import tag +tag("user_id", "123") ``` -**Returns** `Optional[Span]` +
+Category -**Correct example.** +Contexts -```python -span = posthog.get_active_span() -if span is not None: - headers["traceparent"] = span.traceparent() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1339) - -### `posthog.alias` +
-Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. +### `posthog.get_tags` ```python -alias( - previous_id: ID_TYPES, - distinct_id: str, - timestamp: Optional[Union[datetime.datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +get_tags() -> Dict[str, Any] ``` -
-Parameters (5) - -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required**
The unique ID of the user before | -| `distinct_id`
**Type:** `str` · **Required**
The current unique id | -| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | - -
+Get all tags from the current context. -**Returns** `Optional[str]` +**Returns:** -**Details.** To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action. +Type | Description +---- | ----------- +`Dict[str, Any]` | Dict of all tags in the current context -**Correct example.** +
+Category -```python -# Alias user -from posthog import alias -alias(previous_id='distinct_id', distinct_id='alias_id') -``` +Contexts -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L685) +
### `posthog.capture` -Capture anything a user does within your system. - ```python capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -
-Parameters (2) +Capture anything a user does within your system. -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name to specify the event | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name to specify the event | *required* +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | `{}` -**Returns** `Optional[str]` +
+Details -**Details.** Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. +Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. + +
-**Correct example.** +**Examples:** ```python # Context and capture usage @@ -2847,9 +2349,6 @@ with new_context(): capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict ``` - -**Correct example.** - ```python # Set event properties from posthog import capture @@ -2863,10 +2362,12 @@ capture( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L466) - ### `posthog.capture_ai` +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + Capture an AI event on the dedicated AI capture endpoint. Beta: the signature is stable; operational limits (per-event size cap, @@ -2879,23 +2380,14 @@ with its own consumer pool and a higher per-event size cap, posting to the dedicated AI ingestion endpoint. The payload is sent as given — no redaction or truncation is applied here. -```python -capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name, normally one of the `$ai_*` event names. | -| `**kwargs`
Same optional arguments as `capture()`. | +**Parameters:** -
- -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name, normally one of the `$ai_*` event names. | *required* +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Same optional arguments as `capture()`. | `{}` -**Correct example.** +**Examples:** ```python from posthog import capture_ai @@ -2907,126 +2399,231 @@ uuid = capture_ai( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L539) - -### `posthog.capture_exception` - -Capture exceptions that happen in your code. +### `posthog.set` ```python -capture_exception( - exception: Optional[ExceptionArg] = None, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (2) +Set properties on a user record. -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None`
The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | -| `**kwargs`
Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`**kwargs` | `Unpack[OptionalSetArgs]` | Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | `{}` -**Returns** `Optional[str]` +
+Details -**Details.** Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. +This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). + +
-**Correct example.** +**Examples:** ```python -# Capture exception -from posthog import capture_exception -try: - risky_operation() -except Exception as e: - capture_exception(e) +# Set person properties +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L725) - -### `posthog.flush` +### `posthog.set_once` -Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` -Call `flush()` before a short-lived request or serverless invocation returns -when using the shared module-level client. Use `shutdown()` only for final -process cleanup or a client that will not be reused. Flush does not stop the -background workers or feature flag poller, and does not end open spans. +Set properties on a user record, only if they do not yet exist. -Returning does not guarantee server receipt: pending work can remain after a -timeout or span export failure, and failed events may be dropped by consumers. -Calls made directly from SDK callbacks such as `on_error` are deferred -rather than blocking the worker that invoked the callback. +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`**kwargs` | `Unpack[OptionalSetArgs]` | Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | `{}` + +
+Details + +This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. + +
+ +**Examples:** ```python -flush(timeout_seconds: Optional[float] = 10) -> None +# Set property once +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) + +``` + +### `posthog.group_identify` + +```python +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime.datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] +``` + +Set properties on a group. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`group_type` | `str` | Type of your group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`group_key` | `str` | Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`properties` | `Optional[Dict[str, Any]]` | Properties to set on the group | `None` +`timestamp` | `Optional[Union[datetime, str]]` | Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | Optional UUID for the event | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`distinct_id` | `Optional[ID_TYPES]` | Optional distinct ID of the user performing the action | `None` + +**Examples:** + +```python +# Group identify +from posthog import group_identify +group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +### `posthog.alias` + +```python +alias(previous_id: ID_TYPES, distinct_id: str, timestamp: Optional[Union[datetime.datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -
-Parameters (1) +Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`previous_id` | `ID_TYPES` | The unique ID of the user before | *required* +`distinct_id` | `str` | The current unique id | *required* +`timestamp` | `Optional[Union[datetime, str]]` | Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | Optional UUID for the event | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` + +
+Details -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | +To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action.
-**Returns** `None` +**Examples:** + +```python +# Alias user +from posthog import alias +alias(previous_id='distinct_id', distinct_id='alias_id') +``` -**Correct example.** +### `posthog.capture_exception` ```python -import posthog -posthog.capture('event_name', distinct_id='user_id') -# Before a serverless invocation returns; keep the global client open. -posthog.flush(timeout_seconds=10) +capture_exception(exception: Optional[ExceptionArg] = None, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +Capture exceptions that happen in your code. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`exception` | `Optional[ExceptionArg]` | The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | `None` +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | `{}` + +
+Details + +Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. + +
+ +**Examples:** + +```python +# Capture exception +from posthog import capture_exception +try: + risky_operation() +except Exception as e: + capture_exception(e) +``` + +### `posthog.feature_enabled` + +```python +feature_enabled(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[bool] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1223) +Use feature flags to enable or disable features for users. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` + +
+Details + +You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. + +
+ +**Examples:** + +```python +# Boolean feature flag +from posthog import feature_enabled, get_feature_flag_payload +is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` ### `posthog.get_feature_flag` +```python +get_feature_flag(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FlagValue] +``` + Get feature flag variant for users. Used with experiments. -```python -get_feature_flag( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FlagValue] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping from group type to group key | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties in format { group_type_name: { group_properties } } | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping from group type to group key | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties in format { group_type_name: { group_properties } } | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` + +
+Details -**Returns** `Optional[FlagValue]` +`groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. -**Details.** `groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. +
-**Correct example.** +**Examples:** ```python # Multivariate feature flag @@ -3036,54 +2633,48 @@ if enabled_variant == 'variant-key': matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L809) +### `posthog.get_all_flags` -### `posthog.get_feature_flag_payload` +```python +get_all_flags(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None, flag_keys_to_evaluate: Optional[list[str]] = None) -> Optional[dict[str, FlagValue]] +``` -Get the payload associated with a feature flag value. +Get all flags for a given user. -Deprecated for new code. Prefer `evaluate_flags()` and -`flags.get_flag_payload(key)` so flag evaluation happens once per request. +**Parameters:** -```python -get_feature_flag_payload( - key: str, - distinct_id: ID_TYPES, - match_value: Optional[FlagValue] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[object] -``` - -
-Parameters (10) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
Optional flag value to use when selecting a payload. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | Optional list of flag keys to evaluate (evaluates all if None) | `None` + +
+Details + +Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False.
-**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. +**Examples:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L965) +```python +# All flags for user +from posthog import get_all_flags +get_all_flags('distinct_id_of_your_user') +``` ### `posthog.get_feature_flag_result` +```python +get_feature_flag_result(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FeatureFlagResult] +``` + Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: @@ -3093,136 +2684,123 @@ This method evaluates a feature flag and returns a FeatureFlagResult object cont - key: The flag key - reason: Why the flag was enabled/disabled +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send a $feature_flag_called event. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` + Example: -``python +```python result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') if result and result.enabled: # Use the variant and payload print(f"Variant: {result.variant}") print(f"Payload: {result.payload}") -`` - -```python -get_feature_flag_result( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FeatureFlagResult] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +``` -
+### `posthog.get_feature_flag_payload` + +```python +get_feature_flag_payload(key: str, distinct_id: ID_TYPES, match_value: Optional[FlagValue] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[object] +``` -**Returns** `Optional[FeatureFlagResult]` +Get the payload associated with a feature flag value. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L908) +Deprecated for new code. Prefer `evaluate_flags()` and +`flags.get_flag_payload(key)` so flag evaluation happens once per request. -### `posthog.get_all_flags` +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`match_value` | `Optional[FlagValue]` | Optional flag value to use when selecting a payload. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send a $feature_flag_called event. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` + +**Returns:** + +Type | Description +---- | ----------- +`Optional[object]` | The payload associated with the matched feature flag value, or None. +`Optional[object]` | This function returns the payload only, not the FeatureFlagResult wrapper +`Optional[object]` | used internally to compute it. -Get all flags for a given user. +### `posthog.get_remote_config_payload` ```python -get_all_flags( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, -) -> Optional[dict[str, FlagValue]] -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate (evaluates all if None) | +get_remote_config_payload(key: str) +``` -
+Get the payload for a remote config feature flag. -**Returns** `Optional[dict[str, FlagValue]]` +**Parameters:** -**Details.** Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The key of the feature flag | *required* -**Correct example.** +**Returns:** -```python -# All flags for user -from posthog import get_all_flags -get_all_flags('distinct_id_of_your_user') -``` +Type | Description +---- | ----------- + | The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L861) +
+Note + +Requires secret_key to be set for authentication + +
### `posthog.get_all_flags_and_payloads` +```python +get_all_flags_and_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None, flag_keys_to_evaluate: Optional[list[str]] = None) -> FlagsAndPayloads +``` + Get all feature flag values and payloads for a user. -```python -get_all_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, -) -> FlagsAndPayloads -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate. Evaluates all flags when omitted. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | Optional list of flag keys to evaluate. Evaluates all flags when omitted. | `None` -**Returns** `FlagsAndPayloads`. A dict with `featureFlags` and `featureFlagPayloads` entries. +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1037) +Type | Description +---- | ----------- +`FlagsAndPayloads` | A dict with `featureFlags` and `featureFlagPayloads` entries. ### `posthog.evaluate_flags` +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` + Evaluate all feature flags for a user in a single call and return a `FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / `.get_flag()` and pass the same snapshot to `capture()` via the @@ -3232,38 +2810,20 @@ Prefer this over repeated `get_feature_flag()` calls and over `capture(send_feature_flags=True)` — it consolidates flag evaluation into a single `/flags` request per incoming request. -```python -evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | - -
+**Parameters:** -**Returns** `FeatureFlagEvaluations` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`flag_keys` | `Optional[list[str]]` | Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | `None` +`device_id` | `Optional[str]` | Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | `None` -**Correct example.** +**Examples:** ```python from posthog import evaluate_flags, capture @@ -3273,1578 +2833,872 @@ if flags.is_enabled("new-dashboard"): capture("page_viewed", distinct_id="user_123", flags=flags) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1079) - -### `posthog.group_identify` - -Set properties on a group. +### `posthog.feature_flag_definitions` ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime.datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +feature_flag_definitions() ``` -
-Parameters (7) +Returns loaded feature flags. -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required**
Type of your group. Required - the call is dropped with a warning if it is missing or empty. | -| `group_key`
**Type:** `str` · **Required**
Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Properties to set on the group | -| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
Optional distinct ID of the user performing the action | +
+Details -
+Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. -**Returns** `Optional[str]` +
-**Correct example.** +**Examples:** ```python -# Group identify -from posthog import group_identify -group_identify('company', 'company_id_in_your_db', { - 'name': 'Awesome Inc.', - 'employees': 11 -}) +from posthog import feature_flag_definitions +definitions = feature_flag_definitions() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L637) - -### `posthog.set` - -Set properties on a user record. +### `posthog.get_feature_flag_evaluation_runtime` ```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | +Return where a locally loaded feature flag is meant to be evaluated. -
+
+Details -**Returns** `Optional[str]` +Reads the `evaluation_runtime` each flag definition carries, so no extra +request is made. Returns `None` when local evaluation has not loaded a +definition for this key. A definition that carries no runtime reports +`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. -**Details.** This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). +
-**Correct example.** +**Examples:** ```python -# Set person properties -from posthog import set -set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime +runtime = get_feature_flag_evaluation_runtime("my-flag") ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L573) +
+Category -### `posthog.set_once` +Feature flags -Set properties on a user record, only if they do not yet exist. +
+ +### `posthog.get_feature_flag_keys_by_evaluation_runtime` ```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +get_feature_flag_keys_by_evaluation_runtime(evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str]) -> list[str] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | +Return the keys of locally loaded flags that a runtime can evaluate. -
+
+Details -**Returns** `Optional[str]` +A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so +it is returned for `CLIENT` and for `SERVER`. Use this to decide which +flags to hand to a browser when a backend serves flags to its own +frontend. -**Details.** This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. +
-**Correct example.** +**Examples:** ```python -# Set property once -from posthog import set_once -set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime +client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L605) - -### `posthog.feature_enabled` - -Use feature flags to enable or disable features for users. +
+Category -```python -feature_enabled( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[bool] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +Feature flags
-**Returns** `Optional[bool]` - -**Details.** You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. - -**Correct example.** +### `posthog.load_feature_flags` ```python -# Boolean feature flag -from posthog import feature_enabled, get_feature_flag_payload -is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') -if is_my_flag_enabled: - matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +load_feature_flags() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L757) - -### `posthog.setup` - -Create or return the global PostHog client configured by module settings. +Load feature flag definitions from PostHog. -Most applications should either instantiate `Posthog` directly or set -`posthog.api_key`/other module settings before calling top-level helpers. -`setup()` is called automatically by global APIs such as `capture()`. +**Examples:** ```python -setup() -> Client +from posthog import load_feature_flags +load_feature_flags() ``` -**Returns** `Client`. The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. +### `posthog.flush` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1394) +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` -### `posthog.join` +Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. -Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. +Call `flush()` before a short-lived request or serverless invocation returns +when using the shared module-level client. Use `shutdown()` only for final +process cleanup or a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. -Failed or undrainable events may be dropped and reported through logging or -`on_error`; returning does not guarantee server receipt. Lifecycle cleanup -is attempted once, and cleanup failures are logged without retry. - -```python -join() -> None -``` - -**Returns** `None` - -**Correct example.** - -```python -from posthog import join -join() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1265) - -### `posthog.shutdown` - -Attempt final delivery and permanently shut down the global client. - -Call this for final process cleanup, not at the end of each request or -serverless invocation that shares the module-level client. Use `flush()` -before returning from those invocations instead. Shutdown closes capture -lanes, stops background workers and the feature flag poller, and tears down -integrations. The global client is not recreated automatically after shutdown. - -This normally blocks until queued events have been attempted and cleanup -finishes. Failed or undrainable events may be dropped and reported through -logging or `on_error`; returning does not guarantee server receipt. Event -draining has no timeout. Queued spans get a final flush with up to 30 seconds -waiting for an in-flight flush, then a fresh 30-second drain budget; the last -HTTP request is not cut short. Unsent queued spans and still-open spans are -discarded with a warning. -Lifecycle cleanup is attempted once, and cleanup failures are logged without -retry. Calls made directly from SDK callbacks such as `on_error` are deferred -to avoid deadlocking the worker. If blocking completion is required, signal an application-owned -thread, return from the callback, and call `shutdown()` from that thread. -Do not wait inside a callback for another thread or task calling a lifecycle -method. - -```python -shutdown() -> None -``` - -**Returns** `None` - -**Correct example.** - -```python -from posthog import shutdown -shutdown() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1359) - -### `posthog.feature_flag_definitions` - -Returns loaded feature flags. - -```python -feature_flag_definitions() -``` - -**Details.** Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. - -**Correct example.** - -```python -from posthog import feature_flag_definitions -definitions = feature_flag_definitions() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1142) - -### `posthog.load_feature_flags` - -Load feature flag definitions from PostHog. - -```python -load_feature_flags() -``` - -**Correct example.** - -```python -from posthog import load_feature_flags -load_feature_flags() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1208) - -### `posthog.new_context` - -Create a new context scope that will be active for the duration of the with block. - -```python -new_context( - fresh: bool = False, - capture_exceptions: Optional[bool] = None, - client: Optional[Client] = None, -) -``` - -
-Parameters (3) - -| Parameter | -| --- | -| `fresh`
**Type:** `bool` · **Default:** `False`
Whether to start with a fresh context (default: False) | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional Posthog client instance to use for this context (default: None) | - -
- -**Correct example.** - -```python -from posthog import new_context, tag, capture -with new_context(): - tag("request_id", "123") - capture("event_name", properties={"property": "value"}) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L98) - -### `posthog.scoped` - -Decorator that creates a new context for the function. - -```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to start with a fresh context (default: False) | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | - -
- -**Correct example.** - -```python -from posthog import scoped, tag, capture -@scoped() -def process_payment(payment_id): - tag("payment_id", payment_id) - capture("payment_started") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L127) - -### `posthog.set_context_session` - -Set the session ID for the current context. - -```python -set_context_session(session_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import set_context_session -set_context_session("session_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L150) - -### `posthog.set_context_device_id` - -Set the device ID for the current context, associating all feature flag requests -in this or child contexts with the given device ID. - -```python -set_context_device_id(device_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import set_context_device_id -set_context_device_id("device_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L169) - -### `posthog.identify_context` - -Identify the current context with a distinct ID. - -```python -identify_context(distinct_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import identify_context -identify_context("user_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L189) - -### `posthog.set_capture_exception_code_variables_context` - -Override code-variable capture for exceptions in the current context. - -```python -set_capture_exception_code_variables_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required**
Whether exceptions captured in this context should include local variable values from stack frames. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L208) - -### `posthog.set_code_variables_mask_patterns_context` - -Override code-variable mask patterns for exceptions in the current context. - -```python -set_code_variables_mask_patterns_context(mask_patterns: list[str]) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `mask_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns whose values should be replaced with `***` when code variables are captured. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L222) - -### `posthog.set_code_variables_ignore_patterns_context` - -Override code-variable ignore patterns for exceptions in the current context. - -```python -set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `ignore_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns that should be omitted entirely when code variables are captured. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L236) - -### `posthog.set_code_variables_mask_url_credentials_context` - -Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from -captured code variables for the current context. - -```python -set_code_variables_mask_url_credentials_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required** | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L250) - -### `posthog.set_code_variables_detect_secrets_context` - -Whether to apply entropy-based secret detection as a last-resort redaction of -high-entropy values (API keys, tokens, strong passwords) in captured code -variables for the current context. - -```python -set_code_variables_detect_secrets_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required** | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L258) - -### `posthog.tag` - -Add a tag to the current context. - -```python -tag(name: str, value: Any) -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The tag key | -| `value`
**Type:** `Any` · **Required**
The tag value | - -
- -**Correct example.** - -```python -from posthog import tag -tag("user_id", "123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L270) - -### `posthog.get_tags` - -Get all tags from the current context. - -```python -get_tags() -> Dict[str, Any] -``` - -**Returns** `Dict[str, Any]`. Dict of all tags in the current context - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L290) - -### `posthog.get_remote_config_payload` - -Get the payload for a remote config feature flag. - -```python -get_remote_config_payload(key: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The key of the feature flag | - -
- -**Returns** . The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted - -**Note.** Requires secret_key to be set for authentication - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1017) - -### `posthog.get_feature_flag_evaluation_runtime` - -Return where a locally loaded feature flag is meant to be evaluated. - -```python -get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[FeatureFlagEvaluationRuntime]` - -**Details.** Reads the `evaluation_runtime` each flag definition carries, so no extra -request is made. Returns `None` when local evaluation has not loaded a -definition for this key. A definition that carries no runtime reports -`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. - -**Correct example.** - -```python -from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime -runtime = get_feature_flag_evaluation_runtime("my-flag") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1160) - -### `posthog.get_feature_flag_keys_by_evaluation_runtime` - -Return the keys of locally loaded flags that a runtime can evaluate. - -```python -get_feature_flag_keys_by_evaluation_runtime( - evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], -) -> list[str] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required** | - -
- -**Returns** `list[str]` - -**Details.** A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so -it is returned for `CLIENT` and for `SERVER`. Use this to decide which -flags to hand to a browser when a backend serves flags to its own -frontend. - -**Correct example.** - -```python -from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime -client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1184) - -## Configs - -
-Settings (7) - -| Setting | -| --- | -| `POSTHOG_MW_CLIENT`
**Where:** Django settings
client used for automatic exception capture, or the global client. This does not redirect events explicitly captured through other clients. | -| `POSTHOG_MW_CAPTURE_EXCEPTIONS`
**Where:** Django settings
`False` enables context enrichment only; `True` enables automatic exception capture; `None` inherits the effective client's `enable_exception_autocapture`. When omitted, the legacy default is `True`. | -| `POSTHOG_MW_REQUEST_FILTER`
**Where:** Django settings
a callback receiving the request. Returning `False` disables both enrichment and automatic exception capture for that request. | -| `POSTHOG_MW_EXTRA_PROPERTIES`
**Where:** Django settings
a callback returning additional event properties. | -| `POSTHOG_MW_CAPTURE_TRACING_HEADERS`
**Where:** Django settings
read PostHog identity and session headers as request-scoped analytics context (default: `True`). Explicit capture IDs and event properties take precedence. These values are never authentication or authorization. Authenticated Django user identity remains the fallback when no usable header ID is available or header capture is disabled. | -| `POSTHOG_MW_TRUST_TRACING_HEADERS`
**Where:** Django settings
deprecated alias for `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. | -| `POSTHOG_MW_PROPERTIES_MAP`
**Where:** Django settings
an optional callback transforming request properties. | - -
- -## Types - -### `OptionalCaptureArgs` - -Optional arguments for the capture method. - -
-Fields (8) - -| Field | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to track with the event | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
Group identifiers to associate with this event (format: {group_type: group_key}) | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this event. Defaults to False. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L26) - -### `OptionalSetArgs` - -Optional arguments for the set method. - -
-Fields (5) - -| Field | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to set on the person | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this operation. Defaults to False. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L70) - -### `FeatureFlagEvaluations` +Returning does not guarantee server receipt: pending work can remain after a +timeout or span export failure, and failed events may be dropped by consumers. +Calls made directly from SDK callbacks such as `on_error` are deferred +rather than blocking the worker that invoked the callback. -A point-in-time snapshot of feature flag evaluations for a single distinct_id. +**Parameters:** -Returned by `Client.evaluate_flags` — branch on `is_enabled` / -`get_flag` and pass the same object to `Client.capture` via the -`flags` option so the captured event carries the exact flag values the code -branched on. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`timeout_seconds` | `Optional[float]` | Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | `10` -Example: +**Examples:** ```python -flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) -if flags.is_enabled("new-dashboard"): - render_new_dashboard() -posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +import posthog +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the global client open. +posthog.flush(timeout_seconds=10) ``` -To narrow the set of flags that get attached to a captured event, use the in-memory -helpers `only` and `only_accessed`. To narrow the set of flags requested -from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. - -#### `FeatureFlagEvaluations.is_enabled` - -Return whether the flag is enabled. Fires `$feature_flag_called` on the -first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. - -A flag that has a value always wins over `default_value`, including a -disabled flag, which returns `False` even when `default_value=True`. +### `posthog.join` ```python -is_enabled( - key: str, - default_value: bool = False, - send_feature_flag_events: bool = True, -) -> bool +join() -> None ``` -
-Parameters (3) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `default_value`
**Type:** `bool` · **Default:** `False`
Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | - -
- -**Returns** `bool` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L164) - -#### `FeatureFlagEvaluations.get_flag` - -Return the flag value. Fires `$feature_flag_called` on first access. +Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. -Returns the variant string for multivariate flags, `True` for enabled flags -without a variant, `False` for disabled flags, and `None` for flags that -were not returned by the evaluation. +Failed or undrainable events may be dropped and reported through logging or +`on_error`; returning does not guarantee server receipt. Lifecycle cleanup +is attempted once, and cleanup failures are logged without retry. -Pass `send_feature_flag_events=False` to skip the event for this read, as -with `is_enabled`. +**Examples:** ```python -get_flag(key: str, send_feature_flag_events: bool = True) -> Optional[FlagValue] +from posthog import join +join() ``` -
-Parameters (2) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True` | - -
- -**Returns** `Optional[FlagValue]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L191) - -#### `FeatureFlagEvaluations.get_flag_payload` - -Return the payload associated with a flag. - -Does not count as an access for `only_accessed` and does not fire any event. +### `posthog.start_span` ```python -get_flag_payload(key: str) -> Optional[Any] +start_span(name: str, *, kind: Optional[str] = None, attributes: Optional[Mapping[str, Any]] = None, parent: Union[Span, str, None] = None, tracestate: Optional[str] = None, start_time: Union[datetime.datetime, float, None] = None) -> Span ``` -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[Any]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L211) - -#### `FeatureFlagEvaluations.only_accessed` - -Return a filtered copy containing only flags accessed via `is_enabled` -or `get_flag` before this call. - -Order-dependent: if nothing has been accessed yet, the returned snapshot is -empty. The method honors its name — pre-access if you want a populated result. - -```python -only_accessed() -> FeatureFlagEvaluations -``` +Start a span for distributed tracing. Alpha. -**Returns** `FeatureFlagEvaluations` +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on the +way out); or call `end()` yourself for a span that cannot wrap a block. +Spans started inside the block nest under it automatically. Always returns +a usable handle, even when tracing is off, so calling code never branches. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L219) +**Parameters:** -#### `FeatureFlagEvaluations.only` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | *required* +`kind` | `Optional[str]` | `internal` (default), `server`, `client`, `producer` or `consumer`. | `None` +`attributes` | `Optional[Mapping[str, Any]]` | Initial attributes. | `None` +`parent` | `Union[Span, str, None]` | A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | `None` +`tracestate` | `Optional[str]` | The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | `None` +`start_time` | `Union[datetime, float, None]` | A `datetime` or epoch seconds, to backdate the span. | `None` -Return a filtered copy containing only flags with the given keys. Keys that -are not present in the evaluation are dropped and logged as a warning. +**Examples:** ```python -only(keys: List[str]) -> FeatureFlagEvaluations -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `keys`
**Type:** `List[str]` · **Required** | - -
- -**Returns** `FeatureFlagEvaluations` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L229) - -#### `FeatureFlagEvaluations.keys` - -Return the flag keys that are part of this evaluation. +import posthog +posthog.traces = {"service_name": "checkout-api"} -```python -FeatureFlagEvaluations.keys: List[str] +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L249) - -#### `FeatureFlagEvaluations.unresolved_flags` - -Return a read-only mapping of flag key to the reason local evaluation -left it without a value. - -A flag is listed when it has a loaded local definition, was in the requested -scope, was inconclusive locally, and no remote value filled the gap. Listed -flags are not part of `keys`, and reading one reports the -`local_evaluation_inconclusive` error instead of `flag_missing`. Reading -this mapping does not count as an access and does not fire any event. -Snapshots returned by `only` and `only_accessed`, and by -`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no -entries. +### `posthog.get_active_span` ```python -FeatureFlagEvaluations.unresolved_flags: Mapping[str, UnresolvedFlagReason] +get_active_span() -> Optional[Span] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L254) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L110) - -### `FeatureFlagResult` - -The result of calling a feature flag which includes the flag result, variant, and payload. - -
-Fields (5) - -| Field | -| --- | -| `key`
**Type:** `str`
The unique identifier of the feature flag. | -| `enabled`
**Type:** `bool`
Whether the feature flag is enabled for the current context. | -| `variant`
**Type:** `Optional[str]`
The variant value if the flag is enabled and has variants, None otherwise. | -| `payload`
**Type:** `Optional[Any]`
Additional data associated with the feature flag, if any. | -| `reason`
**Type:** `Optional[str]`
A description of why the flag was enabled or disabled, if available. | - -
+The span that is active in the current context, or `None`. Alpha. -#### `FeatureFlagResult.get_value` +Only entering a span (`with posthog.start_span(...) as span:`) makes it +active; a span started manually is not. Use it to propagate the trace to +the next service: `span.traceparent()` is the header value. -Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. -This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. +**Examples:** ```python -get_value() -> FlagValue +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() ``` -**Returns** `FlagValue`. Either a string variant or boolean value representing the flag's state. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L582) - -#### `FeatureFlagResult.from_value_and_payload` - -Creates a FeatureFlagResult from a flag value and payload. +### `posthog.shutdown` ```python -from_value_and_payload( - key: str, - value: Union[FlagValue, None], - payload: Any, -) -> Union[FeatureFlagResult, None] +shutdown() -> None ``` -
-Parameters (3) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The unique identifier of the feature flag. | -| `value`
**Type:** `Union[FlagValue, None]` · **Required**
The value of the flag (string variant or boolean). | -| `payload`
**Type:** `Any` · **Required**
Additional data associated with the feature flag. | +Attempt final delivery and permanently shut down the global client. -
+Call this for final process cleanup, not at the end of each request or +serverless invocation that shares the module-level client. Use `flush()` +before returning from those invocations instead. Shutdown closes capture +lanes, stops background workers and the feature flag poller, and tears down +integrations. The global client is not recreated automatically after shutdown. -**Returns** `Union[FeatureFlagResult, None]`. Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. +This normally blocks until queued events have been attempted and cleanup +finishes. Failed or undrainable events may be dropped and reported through +logging or `on_error`; returning does not guarantee server receipt. Event +draining has no timeout. Queued spans get a final flush with up to 30 seconds +waiting for an in-flight flush, then a fresh 30-second drain budget; the last +HTTP request is not cut short. Unsent queued spans and still-open spans are +discarded with a warning. +Lifecycle cleanup is attempted once, and cleanup failures are logged without +retry. Calls made directly from SDK callbacks such as `on_error` are deferred +to avoid deadlocking the worker. If blocking completion is required, signal an application-owned +thread, return from the callback, and call `shutdown()` from that thread. +Do not wait inside a callback for another thread or task calling a lifecycle +method. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L592) +**Examples:** -#### `FeatureFlagResult.from_flag_details` +```python +from posthog import shutdown +shutdown() +``` -Create a FeatureFlagResult from a FeatureFlag object. +### `posthog.setup` ```python -from_flag_details( - details: Union[FeatureFlag, None], - override_match_value: Optional[FlagValue] = None, -) -> FeatureFlagResult | None +setup() -> Client ``` -
-Parameters (2) - -| Parameter | -| --- | -| `details`
**Type:** `Union[FeatureFlag, None]` · **Required**
The FeatureFlag object to convert. | -| `override_match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | +Create or return the global PostHog client configured by module settings. -
+Most applications should either instantiate `Posthog` directly or set +`posthog.api_key`/other module settings before calling top-level helpers. +`setup()` is called automatically by global APIs such as `capture()`. -**Returns** `FeatureFlagResult | None`. FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L618) +Type | Description +---- | ----------- +`Client` | The global `Client` instance. If both `api_key` and +`Client` | `project_api_key` are missing or blank, the client is disabled and +`Client` | module-level calls become no-ops. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L563) +## Types -### `FeatureFlag` +### `OptionalCaptureArgs` -Detailed feature flag evaluation returned by the flags API. +Bases: `TypedDict` -`enabled`, `variant` and `metadata.payload` are the value rendered the way -responses before `/flags?v=4` carried it, which the legacy getters return. +Optional arguments for the capture method. -
-Fields (5) +**Parameters:** -| Field | -| --- | -| `key`
**Type:** `str`
Feature flag key. | -| `enabled`
**Type:** `bool`
Whether the flag is enabled for the evaluated user or group. | -| `variant`
**Type:** `Optional[str]`
Variant key for multivariate flags, otherwise `None`. | -| `reason`
**Type:** `Optional[FlagReason]`
Optional reason metadata explaining the result. | -| `metadata`
**Type:** `Union[FlagMetadata, LegacyFlagMetadata]`
Payload and other metadata returned by the API. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | +`properties` | | Dictionary of properties to track with the event | +`timestamp` | | When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`groups` | | Group identifiers to associate with this event (format: {group_type: group_key}) | +`flags` | | A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | +`send_feature_flags` | | Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | +`disable_geoip` | | Whether to disable GeoIP lookup for this event. Defaults to False. | -
+**Attributes:** -#### `FeatureFlag.get_value` +Name | Type | Description +---- | ---- | ----------- +`disable_geoip` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[ID_TYPES]]` | +`flags` | `NotRequired[Optional[FeatureFlagEvaluations]]` | +`groups` | `NotRequired[Optional[Dict[str, str]]]` | +`properties` | `NotRequired[Optional[Dict[str, Any]]]` | +`send_feature_flags` | `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]` | +`timestamp` | `NotRequired[Optional[Union[datetime, str]]]` | +`uuid` | `NotRequired[Optional[Union[str, UUID]]]` | -Return the variant for a multivariate flag, otherwise whether the flag is enabled. +#### `posthog.args.OptionalCaptureArgs.disable_geoip` ```python -get_value() -> FlagValue +disable_geoip: NotRequired[Optional[bool]] ``` -**Returns** `FlagValue` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L285) - -#### `FeatureFlag.from_json` - -Parse one flag record of a `/flags` response. - -A record with a `value` member is a `/flags?v=4` record. A record -without one comes from an older server: its value is `variant`, or -`enabled` when there is no variant, and its config version is `1`. +#### `posthog.args.OptionalCaptureArgs.distinct_id` ```python -from_json(resp: Any) -> FeatureFlag +distinct_id: NotRequired[Optional[ID_TYPES]] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `resp`
**Type:** `Any` · **Required** | - -
- -**Returns** `FeatureFlag` +#### `posthog.args.OptionalCaptureArgs.flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L289) - -#### `FeatureFlag.from_value_and_payload` +```python +flags: NotRequired[Optional[FeatureFlagEvaluations]] +``` -Build a flag from its value and payload. A string value is a variant, so the flag is enabled. +#### `posthog.args.OptionalCaptureArgs.groups` ```python -from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag +groups: NotRequired[Optional[Dict[str, str]]] ``` -
-Parameters (3) +#### `posthog.args.OptionalCaptureArgs.properties` -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `value`
**Type:** `FlagValue` · **Required** | -| `payload`
**Type:** `Any` · **Required** | +```python +properties: NotRequired[Optional[Dict[str, Any]]] +``` -
+#### `posthog.args.OptionalCaptureArgs.send_feature_flags` -**Returns** `FeatureFlag` +```python +send_feature_flags: NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]] +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L299) +#### `posthog.args.OptionalCaptureArgs.timestamp` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L245) +```python +timestamp: NotRequired[Optional[Union[datetime, str]]] +``` -### `FlagsAndPayloads` +#### `posthog.args.OptionalCaptureArgs.uuid` -Feature flag values and payloads keyed by feature flag key. +```python +uuid: NotRequired[Optional[Union[str, UUID]]] +``` -
-Fields (2) +### `FeatureFlagEvaluations` -| Field | -| --- | -| `featureFlags`
**Type:** `Optional[dict[str, FlagValue]]`
Each flag's value, keyed by flag key. | -| `featureFlagPayloads`
**Type:** `Optional[dict[str, Any]]`
Each flag's payload, keyed by flag key. | +```python +FeatureFlagEvaluations(host: _FeatureFlagEvaluationsHost, distinct_id: str, flags: Dict[str, _EvaluatedFlagRecord], groups: Optional[Mapping[str, Union[str, int]]] = None, disable_geoip: Optional[bool] = None, request_id: Optional[str] = None, evaluated_at: Optional[int] = None, errors_while_computing: bool = False, quota_limited: bool = False, minimal_flag_called_events: bool = False, accessed: Optional[Set[str]] = None, unresolved_flags: Optional[Mapping[str, UnresolvedFlagReason]] = None) -> None +``` -
+A point-in-time snapshot of feature flag evaluations for a single distinct_id. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L551) +Returned by `Client.evaluate_flags` — branch on `is_enabled` / +`get_flag` and pass the same object to `Client.capture` via the +`flags` option so the captured event carries the exact flag values the code +branched on. -### `FeatureFlagEvaluationRuntime` +Example:: -Where a feature flag is meant to be evaluated. + flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) + if flags.is_enabled("new-dashboard"): + render_new_dashboard() + posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) -Set per flag in PostHog and carried on every locally cached flag definition. -`ALL` means the flag suits both client-side and server-side evaluation, so -it matches either runtime. Inheriting from `str` keeps the members directly -comparable to their `"all"` / `"client"` / `"server"` values. +To narrow the set of flags that get attached to a captured event, use the in-memory +helpers `only` and `only_accessed`. To narrow the set of flags requested +from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. -
-Fields (3) +**Functions:** -| Field | -| --- | -| `ALL`
**Value:** `'all'`
The flag suits both client-side and server-side evaluation. | -| `CLIENT`
**Value:** `'client'`
The flag is meant for client-side evaluation. | -| `SERVER`
**Value:** `'server'`
The flag is meant for server-side evaluation. | +Name | Description +---- | ----------- +`get_flag` | Return the flag value. Fires `$feature_flag_called` on first access. +`get_flag_payload` | Return the payload associated with a flag. +`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the +`only` | Return a filtered copy containing only flags with the given keys. Keys that +`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` -
+**Attributes:** -#### `FeatureFlagEvaluationRuntime.from_value` +Name | Type | Description +---- | ---- | ----------- +`keys` | `List[str]` | Return the flag keys that are part of this evaluation. +`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation -Coerce a raw `evaluation_runtime` value to a member. +Internal — instances are created by the SDK via `Client.evaluate_flags()`. -A missing, null or unrecognized value becomes `ALL`, which is the -default PostHog applies to a flag that does not set a runtime. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.get_flag` ```python -from_value(value: Any) -> FeatureFlagEvaluationRuntime +get_flag(key: str, *, send_feature_flag_events: bool = True) -> Optional[FlagValue] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `value`
**Type:** `Any` · **Required** | - -
- -**Returns** `FeatureFlagEvaluationRuntime` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L98) +Return the flag value. Fires `$feature_flag_called` on first access. -#### `FeatureFlagEvaluationRuntime.matches` +Returns the variant string for multivariate flags, `True` for enabled flags +without a variant, `False` for disabled flags, and `None` for flags that +were not returned by the evaluation. -Whether a flag set to one of these runtimes suits the other runtime. +Pass `send_feature_flag_events=False` to skip the event for this read, as +with `is_enabled`. -`ALL` matches every runtime, so the check is symmetric. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.get_flag_payload` ```python -matches(other: FeatureFlagEvaluationRuntime) -> bool +get_flag_payload(key: str) -> Optional[Any] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `other`
**Type:** `FeatureFlagEvaluationRuntime` · **Required** | - -
- -**Returns** `bool` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L112) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L80) +Return the payload associated with a flag. -### `UnresolvedFlagReason` +Does not count as an access for `only_accessed` and does not fire any event. -Why local evaluation left a flag without a value. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.is_enabled` -Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from -`str` keeps the members directly comparable to their string values. When more -than one cause applies, the first reason in the order below is reported. +```python +is_enabled(key: str, default_value: bool = False, *, send_feature_flag_events: bool = True) -> bool +``` -
-Fields (4) +Return whether the flag is enabled. Fires `$feature_flag_called` on the +first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. -| Field | -| --- | -| `EXPERIENCE_CONTINUITY`
**Value:** `'experience_continuity'`
The flag has experience continuity enabled, which local evaluation never resolves. Change the flag to fix it. | -| `UNSUPPORTED_DEFINITION`
**Value:** `'unsupported_definition'`
The flag uses something the local evaluator does not support, such as a static cohort, an unknown operator, a malformed value, a dependency with no loaded definition or a circular dependency. Change the flag or upgrade the SDK to fix it. | -| `UNRESOLVED_DEPENDENCY`
**Value:** `'unresolved_dependency'`
A flag this flag depends on has a loaded definition but was unresolved. | -| `MISSING_CONTEXT`
**Value:** `'missing_context'`
The call did not pass a property, group property or device id the flag needs, or passed it in an unusable form. Pass it to fix it. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`default_value` | `bool` | Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | `False` +`send_feature_flag_events` | `bool` | Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | `True` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L120) +A flag that has a value always wins over `default_value`, including a +disabled flag, which returns `False` even when `default_value=True`. -### `FlagDefinitionCacheProvider` +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.keys` -Interface for external caching of feature flag definitions. +```python +keys: List[str] +``` -Enables multi-worker environments to share flag definitions, reducing API -calls while ensuring all workers have consistent data. +Return the flag keys that are part of this evaluation. -Methods may be implemented as either synchronous functions or async -functions. If a method returns an awaitable, the SDK runs it to completion -before continuing. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.only` -The four methods handle the complete lifecycle of flag definition caching: +```python +only(keys: List[str]) -> FeatureFlagEvaluations +``` -1. `should_fetch_flag_definitions()` - Called before each poll to determine - if this worker should fetch new definitions. Use for distributed lock - coordination to ensure only one worker fetches at a time. +Return a filtered copy containing only flags with the given keys. Keys that +are not present in the evaluation are dropped and logged as a warning. -2. `get_flag_definitions()` - Called when `should_fetch_flag_definitions()` - returns False. Returns cached definitions if available. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.only_accessed` -3. `on_flag_definitions_received()` - Called after successfully fetching - new definitions from the API. Store the data in your external cache - and release any locks. +```python +only_accessed() -> FeatureFlagEvaluations +``` -4. `shutdown()` - Called when the PostHog client shuts down. Release any - distributed locks and clean up resources. +Return a filtered copy containing only flags accessed via `is_enabled` +or `get_flag` before this call. -#### `FlagDefinitionCacheProvider.get_flag_definitions` +Order-dependent: if nothing has been accessed yet, the returned snapshot is +empty. The method honors its name — pre-access if you want a populated result. -Retrieve cached flag definitions. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.unresolved_flags` ```python -get_flag_definitions( -) -> Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]] +unresolved_flags: Mapping[str, UnresolvedFlagReason] ``` -**Returns** `Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]]`. Cached flag definitions if available and valid, None otherwise. May return an awaitable resolving to the same value. Returning None will trigger a fetch from the API if this worker has no flags loaded yet. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L93) - -#### `FlagDefinitionCacheProvider.should_fetch_flag_definitions` +Return a read-only mapping of flag key to the reason local evaluation +left it without a value. -Determine whether this instance should fetch new flag definitions. +A flag is listed when it has a loaded local definition, was in the requested +scope, was inconclusive locally, and no remote value filled the gap. Listed +flags are not part of `keys`, and reading one reports the +`local_evaluation_inconclusive` error instead of `flag_missing`. Reading +this mapping does not count as an access and does not fire any event. +Snapshots returned by `only` and `only_accessed`, and by +`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no +entries. -Use this for distributed lock coordination. Only one worker should -return True to avoid thundering herd problems. A typical implementation -uses a distributed lock (e.g., Redis SETNX) that expires after the -poll interval. +### `FeatureFlagResult` ```python -should_fetch_flag_definitions() -> Union[bool, Awaitable[bool]] +FeatureFlagResult(key: str, enabled: bool, variant: Optional[str], payload: Optional[Any], reason: Optional[str]) -> None ``` -**Returns** `Union[bool, Awaitable[bool]]`. True if this instance should fetch from the API, False otherwise. May return an awaitable resolving to the same value. When False, the client will call `get_flag_definitions()` to retrieve cached data instead. +The result of calling a feature flag which includes the flag result, variant, and payload. + +**Attributes:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L109) +Name | Type | Description +---- | ---- | ----------- +`key` | `str` | The unique identifier of the feature flag. +`enabled` | `bool` | Whether the feature flag is enabled for the current context. +`variant` | `Optional[str]` | The variant value if the flag is enabled and has variants, None otherwise. +`payload` | `Optional[Any]` | Additional data associated with the feature flag, if any. +`reason` | `Optional[str]` | A description of why the flag was enabled or disabled, if available. -#### `FlagDefinitionCacheProvider.on_flag_definitions_received` +**Functions:** -Called after successfully receiving new flag definitions from PostHog. +Name | Description +---- | ----------- +`from_flag_details` | Create a FeatureFlagResult from a FeatureFlag object. +`from_value_and_payload` | Creates a FeatureFlagResult from a flag value and payload. +`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. -Use this to store the data in your external cache and release any -distributed locks acquired in `should_fetch_flag_definitions()`. +#### `posthog.types.FeatureFlagResult.enabled` ```python -on_flag_definitions_received(data: FlagDefinitionCacheData) -> Optional[Awaitable[None]] +enabled: bool ``` -
-Parameters (1) +#### `posthog.types.FeatureFlagResult.from_flag_details` -| Parameter | -| --- | -| `data`
**Type:** `FlagDefinitionCacheData` · **Required**
The flag definitions to cache, containing flags, group_type_mapping, and cohorts. | +```python +from_flag_details(details: Union[FeatureFlag, None], override_match_value: Optional[FlagValue] = None) -> FeatureFlagResult | None +``` -
+Create a FeatureFlagResult from a FeatureFlag object. -**Returns** `Optional[Awaitable[None]]` +**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L126) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`details` | `Union[FeatureFlag, None]` | The FeatureFlag object to convert. | *required* +`override_match_value` | `Optional[FlagValue]` | If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | `None` -#### `FlagDefinitionCacheProvider.shutdown` +**Returns:** -Called when the PostHog client shuts down. +Type | Description +---- | ----------- +`FeatureFlagResult \| None` | FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. -Use this to release any distributed locks and clean up resources. -This method is called even if `should_fetch_flag_definitions()` -returned False, so implementations should handle the case where -no lock was acquired. +#### `posthog.types.FeatureFlagResult.from_value_and_payload` ```python -shutdown() -> Optional[Awaitable[None]] +from_value_and_payload(key: str, value: Union[FlagValue, None], payload: Any) -> Union[FeatureFlagResult, None] ``` -**Returns** `Optional[Awaitable[None]]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L141) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L56) +Creates a FeatureFlagResult from a flag value and payload. -### `FlagDefinitionCacheData` +**Parameters:** -Data structure for cached flag definitions. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The unique identifier of the feature flag. | *required* +`value` | `Union[FlagValue, None]` | The value of the flag (string variant or boolean). | *required* +`payload` | `Any` | Additional data associated with the feature flag. | *required* -
-Fields (5) +**Returns:** -| Field | -| --- | -| `flags`
**Type:** `Required[List[Dict[str, Any]]]`
List of feature flag definition dictionaries from the API. | -| `group_type_mapping`
**Type:** `Required[Dict[str, str]]`
Mapping of group type indices to group names. | -| `cohorts`
**Type:** `Required[Dict[str, Any]]`
Dictionary of cohort definitions for local evaluation. | -| `minimal_flag_called_events`
**Type:** `NotRequired[bool]`
Server-controlled gate for minimal `$feature_flag_called` events. Treated as False when absent. | -| `property_matching_version`
**Type:** `NotRequired[int]`
Exact/is_not matching selector. Missing means legacy; only version 2 enables explicit matching. | +Type | Description +---- | ----------- +`Union[FeatureFlagResult, None]` | Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. -
+#### `posthog.types.FeatureFlagResult.get_value` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L35) +```python +get_value() -> FlagValue +``` -### `InconclusiveMatchError` +Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. -Raised when local evaluation can't determine a flag's value. `reason` says -why, as reported by `FeatureFlagEvaluations.unresolved_flags`. +**Returns:** -
-Fields (1) +Name | Type | Description +---- | ---- | ----------- +`FlagValue` | `FlagValue` | Either a string variant or boolean value representing the flag's state. -| Field | -| --- | -| `reason`
**Type:** `UnresolvedFlagReason`
Why local evaluation couldn't resolve the flag. | +#### `posthog.types.FeatureFlagResult.key` -
+```python +key: str +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L98) +#### `posthog.types.FeatureFlagResult.payload` -### `RequiresServerEvaluation` +```python +payload: Optional[Any] +``` -Raised when feature flag evaluation requires server-side data that is not -available locally (e.g., static cohorts). +#### `posthog.types.FeatureFlagResult.reason` -This error should propagate immediately to trigger API fallback, unlike -InconclusiveMatchError which allows trying other conditions. +```python +reason: Optional[str] +``` -
-Fields (1) +#### `posthog.types.FeatureFlagResult.variant` -| Field | -| --- | -| `reason`
**Type:** `UnresolvedFlagReason`
Why the flag needs server-side evaluation. | +```python +variant: Optional[str] +``` -
+### `FeatureFlag` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L115) +```python +FeatureFlag(key: str, enabled: bool, variant: Optional[str], reason: Optional[FlagReason], metadata: Union[FlagMetadata, LegacyFlagMetadata]) -> None +``` -### `CaptureCompression` +Detailed feature flag evaluation returned by the flags API. -Selects the request-body compression for capture-v1 uploads. +`enabled`, `variant` and `metadata.payload` are the value rendered the way +responses before `/flags?v=4` carried it, which the legacy getters return. -Only honored when `capture_mode` is `V1`; the legacy `/batch/` path -keeps using its own `gzip` flag. `NONE` sends the body uncompressed. -`GZIP` and `DEFLATE` (zlib, RFC 1950) are both stdlib / zero-dependency; -`ZSTD` is faster and compresses better but needs the optional zstandard -package (`pip install posthog[zstd]`) until stdlib support lands in -Python 3.14. Each maps to the matching `Content-Encoding` token the v1 -server decodes (`br` is accepted by the server too but is intentionally -left out for now). Inheriting from `str` keeps the members comparable to -and serializable as their token values. +**Attributes:** -
-Fields (4) +Name | Type | Description +---- | ---- | ----------- +`key` | `str` | Feature flag key. +`enabled` | `bool` | Whether the flag is enabled for the evaluated user or group. +`variant` | `Optional[str]` | Variant key for multivariate flags, otherwise `None`. +`reason` | `Optional[FlagReason]` | Optional reason metadata explaining the result. +`metadata` | `Union[FlagMetadata, LegacyFlagMetadata]` | Payload and other metadata returned by the API. -| Field | -| --- | -| `NONE`
**Value:** `'none'`
Sends the body uncompressed. | -| `GZIP`
**Value:** `'gzip'`
gzip, from the standard library. | -| `DEFLATE`
**Value:** `'deflate'`
zlib (RFC 1950), from the standard library. | -| `ZSTD`
**Value:** `'zstd'`
Faster and smaller, but needs `pip install posthog[zstd]`. | +**Functions:** -
+Name | Description +---- | ----------- +`from_json` | Parse one flag record of a `/flags` response. +`from_value_and_payload` | Build a flag from its value and payload. A string value is a variant, so the flag is enabled. +`get_value` | Return the variant for a multivariate flag, otherwise whether the flag is enabled. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/capture_compression.py#L21) +#### `posthog.types.FeatureFlag.enabled` -### `Span` +```python +enabled: bool +``` -A handle to a span. +#### `posthog.types.FeatureFlag.from_json` -Every method is safe to call on any handle, including after `end()` and -on the inert handles returned when tracing is off, so calling code never -branches on whether tracing is running. Entering a handle (`with span:`) -makes it the active span for the block and ends it on exit, recording an -`Exception` raised inside it. A `BaseException` that is not an -`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) -still ends the span but is not recorded as a failure. +```python +from_json(resp: Any) -> FeatureFlag +``` -#### `Span.set_attribute` +Parse one flag record of a `/flags` response. -Set one attribute on the span; last write wins. Ignored after `end()`. +A record with a `value` member is a `/flags?v=4` record. A record +without one comes from an older server: its value is `variant`, or +`enabled` when there is no variant, and its config version is `1`. -Returns the span, so calls chain. Prefer primitive values: strings, -booleans, integers and floats keep their type. Lists and mappings are -sent as OTLP arrays and maps, but PostHog stores them as serialized -strings. `None` removes the key; anything else is stringified. +#### `posthog.types.FeatureFlag.from_value_and_payload` ```python -set_attribute(key: str, value: Any) -> Span +from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag ``` -
-Parameters (2) +Build a flag from its value and payload. A string value is a variant, so the flag is enabled. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `value`
**Type:** `Any` · **Required** | +#### `posthog.types.FeatureFlag.get_value` -
+```python +get_value() -> FlagValue +``` -**Returns** `Span` +Return the variant for a multivariate flag, otherwise whether the flag is enabled. -**Correct example.** +#### `posthog.types.FeatureFlag.key` ```python -span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +key: str ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L21) - -#### `Span.set_attributes` +#### `posthog.types.FeatureFlag.metadata` -Set several attributes at once; last write wins per key. Ignored after `end()`. +```python +metadata: Union[FlagMetadata, LegacyFlagMetadata] +``` -Returns the span, so calls chain. Same encoding as `set_attribute()`. +#### `posthog.types.FeatureFlag.reason` ```python -set_attributes(attributes: Mapping[str, Any]) -> Span +reason: Optional[FlagReason] ``` -
-Parameters (1) +#### `posthog.types.FeatureFlag.variant` -| Parameter | -| --- | -| `attributes`
**Type:** `Mapping[str, Any]` · **Required** | +```python +variant: Optional[str] +``` -
+### `FlagsAndPayloads` -**Returns** `Span` +Bases: `TypedDict` -**Correct example.** +Feature flag values and payloads keyed by feature flag key. -```python -span.set_attributes({"db.system": "postgresql", "db.rows": 12}) -``` +**Attributes:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L36) +Name | Type | Description +---- | ---- | ----------- +`featureFlags` | `Optional[dict[str, FlagValue]]` | Each flag's value, keyed by flag key. +`featureFlagPayloads` | `Optional[dict[str, Any]]` | Each flag's payload, keyed by flag key. -#### `Span.add_event` +#### `posthog.types.FlagsAndPayloads.featureFlagPayloads` -Add a timestamped event to the span. Ignored after `end()`. +```python +featureFlagPayloads: Optional[dict[str, Any]] +``` -`timestamp` defaults to now; it accepts a `datetime`, or seconds -since the epoch as a `float` or `int`. Returns the span, so calls -chain. +#### `posthog.types.FlagsAndPayloads.featureFlags` ```python -add_event( - name: str, - attributes: Optional[Mapping[str, Any]] = None, - timestamp: Union[datetime, float, None] = None, -) -> Span +featureFlags: Optional[dict[str, FlagValue]] ``` -
-Parameters (3) +### `UnresolvedFlagReason` -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | -| `timestamp`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | +Bases: `str`, `Enum` -
+Why local evaluation left a flag without a value. -**Returns** `Span` +Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from +`str` keeps the members directly comparable to their string values. When more +than one cause applies, the first reason in the order below is reported. -**Correct example.** +
+Values -```python -span.add_event("cache.miss", {"key": "user:42"}) -``` +EXPERIENCE_CONTINUITY: The flag has experience continuity enabled, which + local evaluation never resolves. Change the flag to fix it. +UNSUPPORTED_DEFINITION: The flag uses something the local evaluator does not + support, such as a static cohort, an unknown operator, a malformed value, + a dependency with no loaded definition or a circular dependency. Change + the flag or upgrade the SDK to fix it. +UNRESOLVED_DEPENDENCY: A flag this flag depends on has a loaded definition + but was unresolved. +MISSING_CONTEXT: The call did not pass a property, group property or device + id the flag needs, or passed it in an unusable form. Pass it to fix it. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L48) +
-#### `Span.set_status` +**Attributes:** -Set the span status to `"ok"` or `"error"`. Ignored after `end()`. +Name | Type | Description +---- | ---- | ----------- +`EXPERIENCE_CONTINUITY` | | +`MISSING_CONTEXT` | | +`UNRESOLVED_DEPENDENCY` | | +`UNSUPPORTED_DEFINITION` | | -Unset by default. Any other `code` is ignored. `ok` is final for the -scoped form: an `Exception` raised inside `with span:` does not override -it. Returns the span, so calls chain. +#### `posthog.types.UnresolvedFlagReason.EXPERIENCE_CONTINUITY` ```python -set_status(code: str, message: Optional[str] = None) -> Span +EXPERIENCE_CONTINUITY = 'experience_continuity' ``` -
-Parameters (2) - -| Parameter | -| --- | -| `code`
**Type:** `str` · **Required** | -| `message`
**Type:** `Optional[str]` · **Default:** `None` | - -
+#### `posthog.types.UnresolvedFlagReason.MISSING_CONTEXT` -**Returns** `Span` +```python +MISSING_CONTEXT = 'missing_context' +``` -**Correct example.** +#### `posthog.types.UnresolvedFlagReason.UNRESOLVED_DEPENDENCY` ```python -span.set_status("error", "upstream timed out") +UNRESOLVED_DEPENDENCY = 'unresolved_dependency' ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L67) +#### `posthog.types.UnresolvedFlagReason.UNSUPPORTED_DEFINITION` -#### `Span.record_exception` - -Record an exception as an `exception` event and mark the span `error`. +```python +UNSUPPORTED_DEFINITION = 'unsupported_definition' +``` -Ignored after `end()`. The event carries `exception.type`, -`exception.message` and, for a raised exception, -`exception.stacktrace` (its last `max_attribute_value_length` -characters, so a chained traceback keeps the outermost exception and -may lose its cause). Returns the span, so calls chain. Inside -`with span:` a raised `Exception` is recorded automatically, so -this is for exceptions that are caught and handled. +### `InconclusiveMatchError` ```python -record_exception(exception: BaseException) -> Span +InconclusiveMatchError(*args, reason: Optional[UnresolvedFlagReason] = None) ``` -
-Parameters (1) +Bases: `Exception` -| Parameter | -| --- | -| `exception`
**Type:** `BaseException` · **Required** | +Raised when local evaluation can't determine a flag's value. `reason` says +why, as reported by `FeatureFlagEvaluations.unresolved_flags`. -
+**Attributes:** -**Returns** `Span` +Name | Type | Description +---- | ---- | ----------- +`reason` | `UnresolvedFlagReason` | Why local evaluation couldn't resolve the flag. -**Correct example.** +#### `posthog.feature_flags.InconclusiveMatchError.reason` ```python -try: - charge(card) -except PaymentError as e: - span.record_exception(e) +reason: UnresolvedFlagReason = UnresolvedFlagReason.UNSUPPORTED_DEFINITION ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L81) - -#### `Span.update_name` - -Rename the span, for a name only known after it started. Ignored after `end()`. - -Returns the span, so calls chain. +### `RequiresServerEvaluation` ```python -update_name(name: str) -> Span +RequiresServerEvaluation(*args, reason: Optional[UnresolvedFlagReason] = None) ``` -
-Parameters (1) +Bases: `Exception` + +Raised when feature flag evaluation requires server-side data that is not +available locally (e.g., static cohorts). -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | +This error should propagate immediately to trigger API fallback, unlike +InconclusiveMatchError which allows trying other conditions. -
+**Attributes:** -**Returns** `Span` +Name | Type | Description +---- | ---- | ----------- +`reason` | `UnresolvedFlagReason` | Why the flag needs server-side evaluation. -**Correct example.** +#### `posthog.feature_flags.RequiresServerEvaluation.reason` ```python -span = posthog.start_span("http.request") -span.update_name(f"{request.method} {route.pattern}") +reason: UnresolvedFlagReason = UnresolvedFlagReason.UNSUPPORTED_DEFINITION ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L102) +### `Span` -#### `Span.traceparent` +A handle to a span. -The W3C `traceparent` header value to propagate, or `None`. +Every method is safe to call on any handle, including after `end()` and +on the inert handles returned when tracing is off, so calling code never +branches on whether tracing is running. Entering a handle (`with span:`) +makes it the active span for the block and ends it on exit, recording an +`Exception` raised inside it. A `BaseException` that is not an +`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) +still ends the span but is not recorded as a failure. + +**Functions:** + +Name | Description +---- | ----------- +`add_event` | Add a timestamped event to the span. Ignored after `end()`. +`end` | End the span and queue it for export. Idempotent. +`record_exception` | Record an exception as an `exception` event and mark the span `error`. +`set_attribute` | Set one attribute on the span; last write wins. Ignored after `end()`. +`set_attributes` | Set several attributes at once; last write wins per key. Ignored after `end()`. +`set_status` | Set the span status to `"ok"` or `"error"`. Ignored after `end()`. +`traceparent` | The W3C `traceparent` header value to propagate, or `None`. +`tracestate` | The W3C `tracestate` header value to propagate, or `None`. +`update_name` | Rename the span, for a name only known after it started. Ignored after `end()`. + +#### `posthog.tracing.span.Span.add_event` ```python -traceparent() -> Optional[str] +add_event(name: str, attributes: Optional[Mapping[str, Any]] = None, timestamp: Union[datetime, float, None] = None) -> Span ``` -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L115) +Add a timestamped event to the span. Ignored after `end()`. -#### `Span.tracestate` +`timestamp` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`. Returns the span, so calls +chain. -The W3C `tracestate` header value to propagate, or `None`. +**Examples:** ```python -tracestate() -> Optional[str] +span.add_event("cache.miss", {"key": "user:42"}) ``` -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L119) +#### `posthog.tracing.span.Span.end` -#### `Span.end` +```python +end(end_time: Union[datetime, float, None] = None) -> None +``` End the span and queue it for export. Idempotent. @@ -4853,22 +3707,7 @@ since the epoch as a `float` or `int`, and is never earlier than the start. Later calls, and later mutations, no-op. `with span:` ends the span on exit, so call this only for spans started manually. -```python -end(end_time: Union[datetime, float, None] = None) -> None -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `end_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | - -
- -**Returns** `None` - -**Correct example.** +**Examples:** ```python span = posthog.start_span("job") @@ -4878,139 +3717,124 @@ finally: span.end() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L123) +#### `posthog.tracing.span.Span.record_exception` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L9) +```python +record_exception(exception: BaseException) -> Span +``` -### `PostHogMetrics` +Record an exception as an `exception` event and mark the span `error`. -The `client.metrics` API: `count`, `gauge`, `histogram`, `flush`. +Ignored after `end()`. The event carries `exception.type`, +`exception.message` and, for a raised exception, +`exception.stacktrace` (its last `max_attribute_value_length` +characters, so a chained traceback keeps the outermost exception and +may lose its cause). Returns the span, so calls chain. Inside +`with span:` a raised `Exception` is recorded automatically, so +this is for exceptions that are caught and handled. -Thread-safe; safe to call from hot paths. Configure via the `metrics` -client option (`flush_interval` is in seconds, matching the client's own -`flush_interval` — unlike posthog-js, whose `flushIntervalMs` is milliseconds): +**Examples:** ```python -client = Client("phc_...", metrics={"service_name": "billing-worker"}) -client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) -client.metrics.gauge("queue.depth", 42) -client.metrics.histogram("job.duration", 187, unit="ms") +try: + charge(card) +except PaymentError as e: + span.record_exception(e) ``` -#### `PostHogMetrics.count` - -Record an increment for a monotonic counter (things that only go up). +#### `posthog.tracing.span.Span.set_attribute` ```python -count( - name: str, - value: float = 1, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +set_attribute(key: str, value: Any) -> Span ``` -
-Parameters (4) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Default:** `1` | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | - -
+Set one attribute on the span; last write wins. Ignored after `end()`. -**Returns** `None` +Returns the span, so calls chain. Prefer primitive values: strings, +booleans, integers and floats keep their type. Lists and mappings are +sent as OTLP arrays and maps, but PostHog stores them as serialized +strings. `None` removes the key; anything else is stringified. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L374) +**Examples:** -#### `PostHogMetrics.gauge` +```python +span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +``` -Record the current value of something that goes up and down. +#### `posthog.tracing.span.Span.set_attributes` ```python -gauge( - name: str, - value: float, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +set_attributes(attributes: Mapping[str, Any]) -> Span ``` -
-Parameters (4) +Set several attributes at once; last write wins per key. Ignored after `end()`. + +Returns the span, so calls chain. Same encoding as `set_attribute()`. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Required** | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | +**Examples:** -
+```python +span.set_attributes({"db.system": "postgresql", "db.rows": 12}) +``` + +#### `posthog.tracing.span.Span.set_status` -**Returns** `None` +```python +set_status(code: str, message: Optional[str] = None) -> Span +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L384) +Set the span status to `"ok"` or `"error"`. Ignored after `end()`. -#### `PostHogMetrics.histogram` +Unset by default. Any other `code` is ignored. `ok` is final for the +scoped form: an `Exception` raised inside `with span:` does not override +it. Returns the span, so calls chain. -Record one observation of a distribution (durations, sizes). +**Examples:** ```python -histogram( - name: str, - value: float, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +span.set_status("error", "upstream timed out") ``` -
-Parameters (4) +#### `posthog.tracing.span.Span.traceparent` -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Required** | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | +```python +traceparent() -> Optional[str] +``` -
+The W3C `traceparent` header value to propagate, or `None`. -**Returns** `None` +#### `posthog.tracing.span.Span.tracestate` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L394) +```python +tracestate() -> Optional[str] +``` -#### `PostHogMetrics.flush` +The W3C `tracestate` header value to propagate, or `None`. -Sends everything aggregated so far without waiting for the flush interval. +#### `posthog.tracing.span.Span.update_name` ```python -flush() -> None +update_name(name: str) -> Span ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L404) +Rename the span, for a name only known after it started. Ignored after `end()`. -#### `PostHogMetrics.reset` +Returns the span, so calls chain. -Clears the flush timer and drops the current window. +**Examples:** ```python -reset() -> None +span = posthog.start_span("http.request") +span.update_name(f"{request.method} {route.pattern}") ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L409) +### `Emails` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L297) +```python +Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None) -> None +``` -### `Emails` +Bases: `_EmailsBase` Sends transactional email from PostHog email templates. @@ -5024,82 +3848,66 @@ to `max_retries` times, with the same idempotency key. Set is in seconds, per request. Pass `session` to send through your own `requests.Session`, for example a test double. -#### `Emails.send` - -Queue one email from a transactional email template. - -```python -send( - to: str, - template_id: Union[str, UUID], - template_data: Optional[Mapping[str, Any]] = None, - distinct_id: Optional[str] = None, - idempotency_key: Optional[str] = None, - max_retries: Optional[int] = None, -) -> SendEmailResult -``` +**Functions:** -
-Parameters (6) +Name | Description +---- | ----------- +`close` | Close the HTTP connections this client opened. A `session` you passed in stays open. +`get` | Read what happened to an email that `send` queued. +`send` | Queue one email from a transactional email template. -| Parameter | -| --- | -| `to`
**Type:** `str` · **Required**
One recipient email address. | -| `template_id`
**Type:** `Union[str, UUID]` · **Required**
The UUID of a template made transactional in PostHog. | -| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | -| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None`
The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | -| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None`
1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | -| `max_retries`
**Type:** `Optional[int]` · **Default:** `None`
Overrides the client's maximum number of retries for this send. `0` turns retries off. | +**Attributes:** -
+Name | Type | Description +---- | ---- | ----------- +`disabled` | | +`host` | | +`max_retries` | | +`secret_key` | | +`timeout` | | -**Returns** `SendEmailResult`. The queued email. A result means PostHog queued the email, not that it was delivered. +#### `posthog.emails.Emails.close` -**Raises** `EmailError`. PostHog did not queue the email, or the client could -not tell whether it did. +```python +close() -> None +``` -**Raises** `(TypeError, ValueError)`. An argument has the wrong type or format. +Close the HTTP connections this client opened. A `session` you passed in stays open. -**Correct example.** +#### `posthog.emails.Emails.disabled` ```python -emails.send( - to="user@example.com", - template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", - template_data={"name": "Ada"}, - distinct_id="user_123", - idempotency_key="welcome:user_123", -) +disabled = disabled ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L588) - -#### `Emails.get` - -Read what happened to an email that `send` queued. +#### `posthog.emails.Emails.get` ```python get(message_id: Union[str, UUID]) -> EmailStatus ``` -
-Parameters (1) +Read what happened to an email that `send` queued. -| Parameter | -| --- | -| `message_id`
**Type:** `Union[str, UUID]` · **Required**
The `id` of the `SendEmailResult` that `send` returned. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`message_id` | `Union[str, UUID]` | The `id` of the `SendEmailResult` that `send` returned. | *required* -**Returns** `EmailStatus`. The email's latest status, for 30 days after the send. +**Returns:** -**Raises** `EmailError`. PostHog did not answer with a status. `code` is -`not_found` for an unknown ID, an email older than 30 days, -or for a few seconds after the send. +Type | Description +---- | ----------- +`EmailStatus` | The email's latest status, for 30 days after the send. -**Raises** `ValueError`. `message_id` is not a message ID. +**Raises:** -**Correct example.** +Type | Description +---- | ----------- +`EmailError` | PostHog did not answer with a status. `code` is `not_found` for an unknown ID, an email older than 30 days, or for a few seconds after the send. +`ValueError` | `message_id` is not a message ID. + +**Examples:** ```python result = emails.send(to="user@example.com", template_id="...") @@ -5108,115 +3916,82 @@ if status.status == "bounced": print(status.reason) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L659) - -#### `Emails.close` - -Close the HTTP connections this client opened. A `session` you passed in stays open. +#### `posthog.emails.Emails.host` ```python -close() -> None +host = determine_app_host(host) ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L737) +#### `posthog.emails.Emails.max_retries` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L553) +```python +max_retries = max_retries +``` -### `AsyncEmails` +#### `posthog.emails.Emails.secret_key` -The async counterpart of `Emails`. Needs `posthog[async]`. +```python +secret_key = secret_key.strip() if isinstance(secret_key, str) else None +``` -Pass `http_client` to send through your own `httpx.AsyncClient`, for -example one with an `httpx.MockTransport` in tests. +#### `posthog.emails.Emails.send` -#### `AsyncEmails.send` +```python +send(*, to: str, template_id: Union[str, UUID], template_data: Optional[Mapping[str, Any]] = None, distinct_id: Optional[str] = None, idempotency_key: Optional[str] = None, max_retries: Optional[int] = None) -> SendEmailResult +``` Queue one email from a transactional email template. -Takes the same arguments and raises the same errors as -`Emails.send`. +**Parameters:** -```python -async send( - to: str, - template_id: Union[str, UUID], - template_data: Optional[Mapping[str, Any]] = None, - distinct_id: Optional[str] = None, - idempotency_key: Optional[str] = None, - max_retries: Optional[int] = None, -) -> SendEmailResult -``` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`to` | `str` | One recipient email address. | *required* +`template_id` | `Union[str, UUID]` | The UUID of a template made transactional in PostHog. | *required* +`template_data` | `Optional[Mapping[str, Any]]` | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | `None` +`distinct_id` | `Optional[str]` | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | `None` +`idempotency_key` | `Optional[str]` | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | `None` +`max_retries` | `Optional[int]` | Overrides the client's maximum number of retries for this send. `0` turns retries off. | `None` -
-Parameters (6) +**Returns:** -| Parameter | -| --- | -| `to`
**Type:** `str` · **Required** | -| `template_id`
**Type:** `Union[str, UUID]` · **Required** | -| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | -| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None` | -| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `max_retries`
**Type:** `Optional[int]` · **Default:** `None` | +Type | Description +---- | ----------- +`SendEmailResult` | The queued email. A result means PostHog queued the email, not that +`SendEmailResult` | it was delivered. -
+**Raises:** -**Returns** `SendEmailResult` +Type | Description +---- | ----------- +`EmailError` | PostHog did not queue the email, or the client could not tell whether it did. +`(TypeError, ValueError)` | An argument has the wrong type or format. -**Correct example.** +**Examples:** ```python -await emails.send( +emails.send( to="user@example.com", template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", template_data={"name": "Ada"}, distinct_id="user_123", + idempotency_key="welcome:user_123", ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L792) - -#### `AsyncEmails.get` - -Read what happened to an email that `send` queued. - -Takes the same argument and raises the same errors as -`Emails.get`. +#### `posthog.emails.Emails.timeout` ```python -async get(message_id: Union[str, UUID]) -> EmailStatus +timeout = timeout ``` -
-Parameters (1) - -| Parameter | -| --- | -| `message_id`
**Type:** `Union[str, UUID]` · **Required** | - -
- -**Returns** `EmailStatus` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L838) - -#### `AsyncEmails.aclose` - -Close the HTTP connections this client opened. An `http_client` you passed in stays open. +### `EmailError` ```python -async aclose() -> None +EmailError(*, name: str, code: str, message: str, status_code: Optional[int] = None, why: Optional[str] = None, fix: Optional[str] = None, docs_url: Optional[str] = None, field: Optional[str] = None, retry_after: Optional[float] = None) -> None ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L899) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L765) - -### `EmailError` +Bases: `Exception` PostHog did not queue the email, or the client could not tell whether it did. @@ -5224,203 +3999,104 @@ Branch on `code`, PostHog's stable error code, or on `name`, a coarse category of the failure. The message never contains the secret key or the request body. -
-Fields (9) - -| Field | -| --- | -| `name`
A coarse category of the failure. | -| `code`
PostHog's stable error code. | -| `message`
What went wrong. It never contains the secret key or the request body. | -| `status_code`
The HTTP status of the response, or `None` when none arrived. | -| `why`
PostHog's explanation of the failure, when it gave one. | -| `fix`
What to change to fix it, when PostHog said. | -| `docs_url`
A docs page about the error, when PostHog gave one. | -| `field`
The request field the error is about, when there is one. | -| `retry_after`
Seconds to wait before retrying, when PostHog said. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L122) - -### `EmailStatus` - -What happened to an email that `send()` queued. - -`status` is one of: - -- `queued`: the email waits to go out. -- `sent`: PostHog handed the email to the email provider. -- `failed`: the email was not sent, and `reason` says why. -- `delivered`: the recipient's mail server accepted the email. -- `bounced` and `complained`: the recipient's mail provider reported - them after delivery. - -Later SDK versions can see values this list does not have yet. -`reason` says why a failed email was not sent, such as -`provider_error` or `recipient_suppressed`, or gives the bounce type of -a bounced email: `hard`, `soft` or `unknown`. It is `None` otherwise. - -
-Fields (5) - -| Field | -| --- | -| `id`
**Type:** `str`
The email's message ID. | -| `status`
**Type:** `str`
Where the email is now, one of the values above. | -| `created_at`
**Type:** `datetime`
When PostHog queued the email. | -| `status_at`
**Type:** `datetime`
When the email reached its current status. | -| `reason`
**Type:** `Optional[str]` · **Default:** `None`
Why a failed email was not sent, or a bounced email's bounce type. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L189) - -### `SendEmailResult` - -The queued email. `id` is its message ID. - -
-Fields (3) - -| Field | -| --- | -| `id`
**Type:** `str`
The email's message ID. | -| `replayed`
**Type:** `bool` · **Default:** `False`
`True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. | -| `warnings`
**Type:** `tuple[EmailWarning, ...]` · **Default:** `()`
Warnings PostHog returned about the request. | +**Attributes:** -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L173) - -### `Prompts` - -Fetch and compile LLM prompts from PostHog. +Name | Type | Description +---- | ---- | ----------- +`name` | | A coarse category of the failure. +`code` | | PostHog's stable error code. +`message` | | What went wrong. It never contains the secret key or the request body. +`status_code` | | The HTTP status of the response, or `None` when none arrived. +`why` | | PostHog's explanation of the failure, when it gave one. +`fix` | | What to change to fix it, when PostHog said. +`docs_url` | | A docs page about the error, when PostHog gave one. +`field` | | The request field the error is about, when there is one. +`retry_after` | | Seconds to wait before retrying, when PostHog said. -Can be initialized with a PostHog client or with direct options. - -#### `Prompts.get` - -Fetch a prompt by name from the PostHog API. - -When `with_metadata` is `True`, returns a `PromptResult` -with `source`, `name`, `version`, and `config` metadata. When -omitted or `False`, returns a plain string (deprecated -- will be -removed in a future major version). +#### `posthog.emails.EmailError.code` ```python -get( - name: str, - with_metadata: Optional[bool] = None, - cache_ttl_seconds: Optional[int] = None, - fallback: Optional[str] = None, - version: Optional[int] = None, - label: Optional[str] = None, -) -> Union[str, PromptResult] +code = code ``` -
-Parameters (6) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The name of the prompt to fetch | -| `with_metadata`
**Type:** `Optional[bool]` · **Default:** `None`
If True, returns a PromptResult with source info. Omitting this parameter is deprecated. | -| `cache_ttl_seconds`
**Type:** `Optional[int]` · **Default:** `None`
Cache TTL in seconds (defaults to instance default) | -| `fallback`
**Type:** `Optional[str]` · **Default:** `None`
Fallback prompt to use if fetch fails and no cache available | -| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to fetch. Mutually exclusive with label. If neither is given, fetches the latest version | -| `label`
**Type:** `Optional[str]` · **Default:** `None`
Fetch the version this label currently points to, e.g. 'production'. Mutually exclusive with version | +#### `posthog.emails.EmailError.docs_url` -
- -**Returns** `Union[str, PromptResult]`. str if with_metadata is False/omitted, PromptResult if True - -**Raises** `ValueError`. If both version and label are provided - -**Raises** `Exception`. If the prompt cannot be fetched and no fallback is available - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L359) - -#### `Prompts.get_all` +```python +docs_url = docs_url +``` -Fetch every prompt in one batch. +#### `posthog.emails.EmailError.field` -Returns a dict mapping prompt name to `PromptResult`. With a -label, each prompt is at the version the label points to, and prompts -without the label are not included. Without a label, every prompt is -included at its latest version, matching what `get(name)` returns. +```python +field = field +``` -Each fetched prompt is stored in the cache, so later -`get(name, label=...)` (or plain `get(name)`) calls are served -from cache within the TTL. An app with many prompts can call this once -per cache cycle instead of making one `get()` request per prompt. +#### `posthog.emails.EmailError.fix` ```python -get_all(label: Optional[str] = None) -> Dict[str, PromptResult] +fix = fix ``` -
-Parameters (1) +#### `posthog.emails.EmailError.message` -| Parameter | -| --- | -| `label`
**Type:** `Optional[str]` · **Default:** `None`
The label to resolve, e.g. 'production'. Omit to fetch latest versions. | +```python +message = message +``` -
+#### `posthog.emails.EmailError.name` -**Returns** `Dict[str, PromptResult]`. Dict of prompt name to PromptResult. +```python +name = name +``` -**Raises** `Exception`. If the request fails, or a label was passed and the -server does not support fetching prompts by label on the list -endpoint (PostHog releases from before September 2026). +#### `posthog.emails.EmailError.retry_after` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L433) +```python +retry_after = retry_after +``` -#### `Prompts.compile` +#### `posthog.emails.EmailError.status_code` -Replace {{variableName}} placeholders with values. +```python +status_code = status_code +``` -Unmatched variables are left unchanged. -Supports variable names with hyphens and dots (e.g., user-id, company.name). +#### `posthog.emails.EmailError.why` ```python -compile(prompt: str, variables: PromptVariables) -> str +why = why ``` -
-Parameters (2) - -| Parameter | -| --- | -| `prompt`
**Type:** `str` · **Required**
The prompt template string | -| `variables`
**Type:** `PromptVariables` · **Required**
Object containing variable values | +### `SendEmailResult` -
+```python +SendEmailResult(id: str, replayed: bool = False, warnings: tuple[EmailWarning, ...] = ()) -> None +``` -**Returns** `str`. The compiled prompt string +The queued email. `id` is its message ID. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L720) +**Attributes:** -#### `Prompts.clear_cache` +Name | Type | Description +---- | ---- | ----------- +`id` | `str` | The email's message ID. +`replayed` | `bool` | `True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. +`warnings` | `tuple[EmailWarning, ...]` | Warnings PostHog returned about the request. -Clear cached prompts. +#### `posthog.emails.SendEmailResult.id` ```python -clear_cache(name: Optional[str] = None, version: Optional[int] = None) -> None +id: str ``` -
-Parameters (2) - -| Parameter | -| --- | -| `name`
**Type:** `Optional[str]` · **Default:** `None`
Specific prompt name to clear. If None, clears all cached prompts. | -| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to clear. Requires name. | - -
+#### `posthog.emails.SendEmailResult.replayed` -**Returns** `None` +```python +replayed: bool = False +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L745) +#### `posthog.emails.SendEmailResult.warnings` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L227) +```python +warnings: tuple[EmailWarning, ...] = () +``` diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index daeb05fe0..adf86813c 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -8,15 +8,21 @@ tableOfContents: - value: "Getting started" url: getting-started depth: 0 + - value: "Setup" + url: setup + depth: 0 + - value: "Capture" + url: capture + depth: 0 + - value: "Identify" + url: identify + depth: 0 - value: "Traces" url: traces depth: 0 - value: "Alias" url: alias depth: 0 - - value: "Capture" - url: capture - depth: 0 - value: "Capture AI" url: capture-ai depth: 0 @@ -50,15 +56,9 @@ tableOfContents: - value: "Group identify" url: group-identify depth: 0 - - value: "Identify" - url: identify - depth: 0 - value: "Is feature enabled" url: is-feature-enabled depth: 0 - - value: "Setup" - url: setup - depth: 0 - value: "Shutdown" url: shutdown depth: 0 @@ -74,9 +74,6 @@ tableOfContents: - value: "Module functions" url: module-functions depth: 0 - - value: "Configs" - url: configs - depth: 0 - value: "Types" url: types depth: 0 @@ -84,6 +81,7 @@ tableOfContents: ## Getting started + The Python SDK captures events, evaluates feature flags and reports errors from Python 3.10 or later. ### Install @@ -120,200 +118,284 @@ posthog.shutdown() In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [AsyncClient](#asyncclient). -## Traces - -### `Client.start_span` - -Start a span for distributed tracing. Alpha. +## Setup -Returns a span handle. Use it as a context manager to make it the active -span for the block and end it on exit (recording a raised exception on -the way out); or call `end()` yourself for a span that cannot wrap a -block. Spans started inside the block nest under it automatically. -Always returns a usable handle, even when tracing is off, so calling -code never branches. +### `Client(...)` ```python -start_span( - name: str, - kind: Optional[str] = None, - attributes: Optional[Mapping[str, Any]] = None, - parent: Union[Span, str, None] = None, - tracestate: Optional[str] = None, - start_time: Union[datetime, float, None] = None, -) -> Span +__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) ``` -
-Parameters (6) +Initialize a new PostHog client instance. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | -| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | -| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | -| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | -| `start_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`project_api_key` | `str` | PostHog project API key/token. | *required* +`host` | | PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | `None` +`debug` | | Enable verbose SDK logging and re-raise errors from public API methods. | `False` +`max_queue_size` | | Maximum number of events buffered before upload. | `10000` +`send` | | If False, queueing succeeds but events are not sent. | `True` +`on_error` | | Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | `None` +`flush_at` | | Number of queued events that triggers a batch upload. | `100` +`flush_interval` | | Maximum seconds a background consumer waits before flushing a partial batch. | `5.0` +`gzip` | | Whether to gzip event upload payloads. | `False` +`max_retries` | | Number of upload retries. Values below 0 are treated as 0. | `3` +`sync_mode` | | If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | `False` +`timeout` | `float` | HTTP request timeout in seconds for event uploads. | `15` +`thread` | | Number of background consumer threads. | `1` +`poll_interval` | | Seconds between local feature flag definition refreshes. | `30` +`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example::
posthog.Client(project_api_key, secret_key="phx_...") | `None` +`personal_api_key` | | Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | `None` +`disabled` | | If True, disable captures and API requests. Useful in tests. | `False` +`disable_geoip` | | Whether to disable server-side GeoIP enrichment. Defaults to True. | `True` +`is_server` | | Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | `True` +`historical_migration` | | Mark events as historical migration imports. | `False` +`feature_flags_request_timeout_seconds` | `float` | Timeout in seconds for feature flag and remote config requests. | `3` +`feature_flags_request_max_retries` | | Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | `1` +`app_host` | `Optional[str]` | Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | `None` +`email_request_timeout_seconds` | `float` | Timeout in seconds for each email send request. Defaults to 15. | `15` +`email_request_max_retries` | `int` | Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | `2` +`super_properties` | | Properties merged into every captured event. | `None` +`enable_exception_autocapture` | | Automatically capture uncaught exceptions. | `False` +`log_captured_exceptions` | | Also log exceptions captured by error tracking. | `False` +`project_root` | | Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | `None` +`privacy_mode` | | For AI observability, capture usage metadata without prompt inputs or outputs. | `False` +`enable_full_ai_capture` | | Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | `False` +`before_send` | | Optional callback that can modify or drop events before upload. Return `None` to drop an event. | `None` +`flag_fallback_cache_url` | | Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | `None` +`enable_local_evaluation` | | Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | `True` +`flag_definition_cache_provider` | `Optional[FlagDefinitionCacheProvider]` | Optional external cache provider for sharing feature flag definitions across workers. | `None` +`capture_exception_code_variables` | | Capture local variable values on exception stack frames. | `False` +`capture_trace_context` | | When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | `False` +`traces` | `Optional[dict]` | Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | `None` +`code_variables_mask_patterns` | | Variable-name patterns to mask when capturing code variables. | `None` +`code_variables_ignore_patterns` | | Variable-name patterns to omit when capturing code variables. | `None` +`code_variables_mask_url_credentials` | | Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | `None` +`code_variables_detect_secrets` | | Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | `None` +`in_app_modules` | `list[str] \| None` | Module/package prefixes treated as in-app frames in captured exceptions. | `None` +`enable_exception_autocapture_rate_limiting` | | Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | `False` +`exception_autocapture_bucket_size` | | Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | `DEFAULT_BUCKET_SIZE` +`exception_autocapture_refill_rate` | | Tokens restored per refill interval for each exception type's bucket. | `DEFAULT_REFILL_RATE` +`exception_autocapture_refill_interval_seconds` | | Seconds between token refills for autocaptured exception rate limiting. | `DEFAULT_REFILL_INTERVAL_SECONDS` +`capture_mode` | `Optional[Union[CaptureMode, str]]` | Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | `None` +`capture_compression` | `Optional[Union[CaptureCompression, str]]` | Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | `None` + +**Examples:** -
+```python +from posthog import Posthog -**Returns** `Span` +posthog = Posthog('', host='') +``` -**Correct example.** +## Capture -```python -posthog = Posthog("", traces={"service_name": "checkout-api"}) +### `Client.capture` -with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: - span.set_attribute("plan", user.plan) - with posthog.start_span("db.query", kind="client"): - ... - outgoing_headers = {"traceparent": span.traceparent()} +```python +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2794) +Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) -### `Client.get_active_span` +**Parameters:** -The span that is active in the current context, or `None`. Alpha. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name to capture. | *required* +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to include with the event. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`groups` | | A dictionary of group information. | +`flags` | | A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | +`send_feature_flags` | | Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -Only entering a span (`with posthog.start_span(...) as span:`) makes -it active; a span started manually is not. Use it to propagate the -trace to the next service: `span.traceparent()` is the header value. +**Examples:** ```python -get_active_span() -> Optional[Span] +# Anonymous event +posthog.capture('some-anon-event') +``` +```python +# Context usage +from posthog import identify_context, new_context +with new_context(): + identify_context('distinct_id_of_the_user') + posthog.capture('user_signed_up') + posthog.capture('user_logged_in') + posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +``` +```python +# Set event properties +posthog.capture( + "user_signed_up", + distinct_id="distinct_id_of_the_user", + properties={ + "login_type": "email", + "is_free_trial": "true" + } +) +``` +```python +# Page view event +posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) ``` -**Returns** `Optional[Span]` +## Identify -**Correct example.** +### `Client.set` ```python -span = posthog.get_active_span() -if span is not None: - headers["traceparent"] = span.traceparent() +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2853) +Set properties on a person profile. -## Alias +**Parameters:** -### `Client.alias` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to set. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -Create an alias between two distinct IDs. +**Examples:** + +```python +# Set with distinct id +posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) +``` Note: This method will not raise exceptions. Errors are logged. +### `Client.set_once` + ```python -alias( - previous_id: ID_TYPES, - distinct_id: Optional[str], - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (5) - -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required**
The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | -| `distinct_id`
**Type:** `Optional[str]` · **Required**
The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | +Set properties on a person profile only if they haven't been set before. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of properties to set once. | +`timestamp` | | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -**Correct example.** +**Examples:** ```python -posthog.alias(previous_id='distinct_id', distinct_id='alias_id') +posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2168) - -## Capture +Note: This method will not raise exceptions. Errors are logged. -### `Client.capture` +## Traces -Captures an event manually. [Learn about capture best practices](https://posthog.com/docs/product-analytics/capture-events) +### `Client.start_span` ```python -capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +start_span(name: str, *, kind: Optional[str] = None, attributes: Optional[Mapping[str, Any]] = None, parent: Union[Span, str, None] = None, tracestate: Optional[str] = None, start_time: Union[datetime, float, None] = None) -> Span ``` -
-Parameters (9) +Start a span for distributed tracing. Alpha. -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name to capture. | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to include with the event. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
A dictionary of group information. | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on +the way out); or call `end()` yourself for a span that cannot wrap a +block. Spans started inside the block nest under it automatically. +Always returns a usable handle, even when tracing is off, so calling +code never branches. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | *required* +`kind` | `Optional[str]` | `internal` (default), `server`, `client`, `producer` or `consumer`. | `None` +`attributes` | `Optional[Mapping[str, Any]]` | Initial attributes. | `None` +`parent` | `Union[Span, str, None]` | A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. A forked child starts with no active span; pass the parent span to continue a trace across a fork. | `None` +`tracestate` | `Optional[str]` | The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | `None` +`start_time` | `Union[datetime, float, None]` | A `datetime` or epoch seconds, to backdate the span. | `None` -**Correct example.** +**Examples:** ```python -# Anonymous event -posthog.capture('some-anon-event') +posthog = Posthog("", traces={"service_name": "checkout-api"}) + +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} ``` -**Correct example.** +### `Client.get_active_span` ```python -# Context usage -from posthog import identify_context, new_context -with new_context(): - identify_context('distinct_id_of_the_user') - posthog.capture('user_signed_up') - posthog.capture('user_logged_in') - posthog.capture('some-custom-action', distinct_id='distinct_id_of_the_user') +get_active_span() -> Optional[Span] ``` -**Correct example.** +The span that is active in the current context, or `None`. Alpha. + +Only entering a span (`with posthog.start_span(...) as span:`) makes +it active; a span started manually is not. Use it to propagate the +trace to the next service: `span.traceparent()` is the header value. + +**Examples:** ```python -# Set event properties -posthog.capture( - "user_signed_up", - distinct_id="distinct_id_of_the_user", - properties={ - "login_type": "email", - "is_free_trial": "true" - } -) +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() +``` + +## Alias + +### `Client.alias` + +```python +alias(previous_id: ID_TYPES, distinct_id: Optional[str], timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -**Correct example.** +Create an alias between two distinct IDs. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`previous_id` | `ID_TYPES` | The previous distinct ID. Required - the call is dropped with a warning if it is missing or empty. | *required* +`distinct_id` | `Optional[str]` | The new distinct ID to alias to. Falls back to the context distinct ID; the call is dropped with a warning if neither is available. | *required* +`timestamp` | `Optional[Union[datetime, str]]` | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this event. | `None` + +**Examples:** ```python -# Page view event -posthog.capture('$pageview', distinct_id="distinct_id_of_the_user", properties={'$current_url': 'https://example.com'}) +posthog.alias(previous_id='distinct_id', distinct_id='alias_id') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1738) +Note: This method will not raise exceptions. Errors are logged. ## Capture AI ### `Client.capture_ai` +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + Capture an AI event on the dedicated AI capture endpoint. Beta: the signature is stable; operational limits (per-event size @@ -326,56 +408,31 @@ isolated AI lane with its own consumer pool and a higher per-event size cap, posting to the dedicated AI ingestion endpoint. The payload is sent as given — no redaction or truncation is applied here. -```python -capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1797) - ## Capture exception ### `Client.capture_exception` -Capture an exception for error tracking. - -When OpenTelemetry is installed and a valid span is active, its trace and -span IDs are added as `$trace_id` and `$span_id` event properties. - ```python -capture_exception( - exception: Optional[ExceptionArg], - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +capture_exception(exception: Optional[ExceptionArg], **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -
-Parameters (6) +Capture an exception for error tracking. -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Required**
The exception to capture. | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated. Pass `flags` from `evaluate_flags()` instead. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | +When OpenTelemetry is installed and a valid span is active, its trace and +span IDs are added as `$trace_id` and `$span_id` event properties. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`exception` | `Optional[ExceptionArg]` | The exception to capture. | *required* +`distinct_id` | | The distinct ID of the user. | +`properties` | | A dictionary of additional properties. Overriding reserved exception properties is deprecated and will stop working in the next major version. | +`flags` | | A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. Attaches those exact flag values to the captured `$exception` event. | +`send_feature_flags` | | Deprecated. Pass `flags` from `evaluate_flags()` instead. | +`disable_geoip` | | Whether to disable GeoIP for this event. | -**Correct example.** +**Examples:** ```python try: @@ -385,12 +442,14 @@ except Exception as e: posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2234) - ## Emails ### `Client.emails` +```python +emails: Emails +``` + Send transactional email from PostHog email templates, and read the status of each email sent with `get`. @@ -400,11 +459,7 @@ scope. Sends go to `app_host`, or to the PostHog Cloud app host of configure each send. A disabled or shut-down client sends nothing. See `posthog.emails` for setup. -```python -Client.emails: Emails -``` - -**Correct example.** +**Examples:** ```python client.emails.send( @@ -415,12 +470,14 @@ client.emails.send( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1256) - ## Flush ### `Client.flush` +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` + Attempt immediate delivery of queued events, ended spans and autocaptured metrics, keeping the client reusable. For a client shared across requests or serverless invocations (including @@ -434,22 +491,13 @@ a timeout or span export failure, and failed events may be dropped by the consumers. Calls made directly from SDK callbacks such as `on_error` are deferred rather than blocking the worker that invoked the callback. -```python -flush(timeout_seconds: Optional[float] = 10) -> None -``` - -
-Parameters (1) +**Parameters:** -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`timeout_seconds` | `Optional[float]` | Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently. The span exporter waits up to this many seconds for an in-flight flush, then uses a fresh drain budget once it acquires the lock. If the lock wait times out, the in-flight flush is left to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. Each span request is bounded by the client's `timeout` in seconds, and the last request is not cut short. This is therefore not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | `10` -
- -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.capture('event_name', distinct_id='user_id') @@ -457,48 +505,31 @@ posthog.capture('event_name', distinct_id='user_id') posthog.flush(timeout_seconds=10) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2872) - ## Get feature flag ### `Client.get_feature_flag` -Get multivariate feature flag value for a user. - ```python -get_feature_flag( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FlagValue] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_feature_flag(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FlagValue] +``` -
+Get multivariate feature flag value for a user. + +**Parameters:** -**Returns** `Optional[FlagValue]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python enabled_variant = posthog.get_feature_flag('flag-key', 'distinct_id_of_your_user') @@ -508,50 +539,40 @@ if enabled_variant == 'variant-key': # replace 'variant-key' with the key of you matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4324) - ## Get feature flag payload ### `Client.get_feature_flag_payload` +```python +get_feature_flag_payload(key: str, distinct_id: ID_TYPES, *, match_value: Optional[FlagValue] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[object] +``` + Get the payload for a feature flag. -```python -get_feature_flag_payload( - key: str, - distinct_id: ID_TYPES, - match_value: Optional[FlagValue] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[object] -``` - -
-Parameters (10) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
The specific flag value to get payload for. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `False`
Deprecated. Use get_feature_flag() instead if you need events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`match_value` | `Optional[FlagValue]` | The specific flag value to get payload for. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Deprecated. Use get_feature_flag() instead if you need events. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. +**Returns:** -**Correct example.** +Type | Description +---- | ----------- +`Optional[object]` | The payload associated with the matched feature flag value, or None. +`Optional[object]` | This method returns the payload only, not the FeatureFlagResult wrapper +`Optional[object]` | used internally to compute it. + +**Examples:** ```python is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') @@ -562,50 +583,19 @@ if is_my_flag_enabled: matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4424) - ## Get feature flag result ### `Client.get_feature_flag_result` +```python +get_feature_flag_result(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FeatureFlagResult] +``` + Get a FeatureFlagResult object which contains the flag result and payload for a key by evaluating locally or remotely depending on whether local evaluation is enabled and the flag can be locally evaluated. This also captures the `$feature_flag_called` event unless `send_feature_flag_events` is `False`. -```python -get_feature_flag_result( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FeatureFlagResult] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
- -**Returns** `Optional[FeatureFlagResult]`. Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. - -**Correct example.** +**Examples:** ```python flag_result = posthog.get_feature_flag_result('flag-key', 'distinct_id_of_your_user') @@ -615,178 +605,138 @@ if flag_result and flag_result.get_value() == 'variant-key': matched_flag_payload = flag_result.payload ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4269) +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Returns:** + +Type | Description +---- | ----------- +`Optional[FeatureFlagResult]` | Optional[FeatureFlagResult]: The feature flag result or None if disabled/not found. ## Get feature flags ### `Client.get_feature_variants` -Get feature flag variants for a user. - ```python -get_feature_variants( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> dict[str, Union[bool, str]] +get_feature_variants(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> dict[str, Union[bool, str]] ``` -
-Parameters (7) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
+Get feature flag variants for a user. -**Returns** `dict[str, Union[bool, str]]` +**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1499) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` ### `Client.get_all_flags` -Get all feature flags for a user. - ```python -get_all_flags( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> Optional[dict[str, Union[bool, str]]] -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_all_flags(distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> Optional[dict[str, Union[bool, str]]] +``` -
+Get all feature flags for a user. -**Returns** `Optional[dict[str, Union[bool, str]]]` +**Parameters:** -**Correct example.** +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** ```python posthog.get_all_flags('distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4744) - ## Get feature flags and payloads ### `Client.get_feature_flags_and_payloads` -Get feature flags and payloads for a user. - ```python -get_feature_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsAndPayloads +get_feature_flags_and_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsAndPayloads ``` -
-Parameters (7) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Get feature flags and payloads for a user. -
+**Parameters:** -**Returns** `FlagsAndPayloads` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python result = posthog.get_feature_flags_and_payloads('') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1580) - ### `Client.get_all_flags_and_payloads` -Get all feature flags and their payloads for a user. - ```python -get_all_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsAndPayloads -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +get_all_flags_and_payloads(distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsAndPayloads +``` -
+Get all feature flags and their payloads for a user. + +**Parameters:** -**Returns** `FlagsAndPayloads` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python posthog.get_all_flags_and_payloads('distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4790) - ## Evaluate flags ### `Client.evaluate_flags` +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys: Optional[List[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` + Evaluate all feature flags for a user in a single call and return a `FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / `.get_flag()` and pass the same snapshot to `capture` via the @@ -800,38 +750,26 @@ Local evaluation is transparent: when the poller resolves a flag, the snapshot's `$feature_flag_called` events are tagged `locally_evaluated=True` and reason `"Evaluated locally"`. -```python -evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[List[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `flag_keys`
**Type:** `Optional[List[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | If True, never fall back to remote evaluation — flags that can't be evaluated locally are omitted from the snapshot and listed with a reason in its `unresolved_flags`. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`flag_keys` | `Optional[List[str]]` | Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is True. If the server also does not know the key, it is omitted from the snapshot. | `None` +`device_id` | `Optional[str]` | Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | `None` -**Returns** `FeatureFlagEvaluations`. class:`FeatureFlagEvaluations` snapshot. +**Returns:** -**Correct example.** +Type | Description +---- | ----------- +`FeatureFlagEvaluations` | A `FeatureFlagEvaluations` snapshot. + +**Examples:** ```python flags = posthog.evaluate_flags( @@ -843,46 +781,29 @@ if flags.is_enabled("new-dashboard"): posthog.capture("page_viewed", distinct_id="user_123", flags=flags) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4875) - ## Group identify ### `Client.group_identify` -Identify a group and set its properties. - -Note: This method will not raise exceptions. Errors are logged. - ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[Union[str, UUID]] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[Union[str, UUID]] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] ``` -
-Parameters (7) - -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required**
The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | -| `group_key`
**Type:** `str` · **Required**
The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of properties to set on the group. | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this event. | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user performing the action. | +Identify a group and set its properties. -
+**Parameters:** -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`group_type` | `str` | The type of group (e.g., 'company', 'team'). Required - the call is dropped with a warning if it is missing or empty. | *required* +`group_key` | `str` | The unique identifier for the group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`properties` | `Optional[Dict[str, Any]]` | A dictionary of properties to set on the group. | `None` +`timestamp` | `Optional[Union[datetime, str]]` | The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[Union[str, UUID]]` | A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this event. | `None` +`distinct_id` | `Optional[ID_TYPES]` | The distinct ID of the user performing the action. | `None` -**Correct example.** +**Examples:** ```python posthog.group_identify('company', 'company_id_in_your_db', { @@ -891,117 +812,33 @@ posthog.group_identify('company', 'company_id_in_your_db', { }) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2093) - -## Identify - -### `Client.set` - -Set properties on a person profile. - -Note: This method will not raise exceptions. Errors are logged. - -```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] -``` - -
-Parameters (5) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | - -
- -**Returns** `Optional[str]` - -**Correct example.** - -```python -# Set with distinct id -posthog.set(distinct_id='user123', properties={'name': 'Max Hedgehog'}) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1995) - -### `Client.set_once` - -Set properties on a person profile only if they haven't been set before. - Note: This method will not raise exceptions. Errors are logged. -```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] -``` - -
-Parameters (5) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
The distinct ID of the user. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
A dictionary of properties to set once. | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
The timestamp of the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP for this event. | - -
- -**Returns** `Optional[str]` +## Is feature enabled -**Correct example.** +### `Client.feature_enabled` ```python -posthog.set_once(distinct_id='user123', properties={'initial_signup_date': '2024-01-01'}) +feature_enabled(key: str, distinct_id: ID_TYPES, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[bool] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2045) - -## Is feature enabled - -### `Client.feature_enabled` - Check if a feature flag is enabled for a user. -```python -feature_enabled( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[bool] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to only evaluate locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | - -
+**Parameters:** -**Returns** `Optional[bool]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`only_evaluate_locally` | `bool` | Whether to only evaluate locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` -**Correct example.** +**Examples:** ```python is_my_flag_enabled = posthog.feature_enabled('flag-key', 'distinct_id_of_your_user') @@ -1011,163 +848,32 @@ if is_my_flag_enabled: matched_flag_payload = posthog.get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3982) - -## Setup - -### `Client(...)` - -Initialize a new PostHog client instance. - -```python -Client( - project_api_key: str, - host = None, - debug = False, - max_queue_size = 10000, - send = True, - on_error = None, - flush_at = 100, - flush_interval = 5.0, - gzip = False, - max_retries = 3, - sync_mode = False, - timeout: float = 15, - thread = 1, - poll_interval = 30, - personal_api_key = None, - disabled = False, - disable_geoip = True, - is_server = True, - historical_migration = False, - feature_flags_request_timeout_seconds: float = 3, - feature_flags_request_max_retries = 1, - super_properties = None, - enable_exception_autocapture = False, - log_captured_exceptions = False, - project_root = None, - privacy_mode = False, - before_send = None, - flag_fallback_cache_url = None, - enable_local_evaluation = True, - flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, - capture_exception_code_variables = False, - code_variables_mask_patterns = None, - code_variables_ignore_patterns = None, - code_variables_mask_url_credentials = None, - code_variables_detect_secrets = None, - in_app_modules: list[str] | None = None, - enable_exception_autocapture_rate_limiting = False, - exception_autocapture_bucket_size = ExceptionCapture.DEFAULT_BUCKET_SIZE, - exception_autocapture_refill_rate = ExceptionCapture.DEFAULT_REFILL_RATE, - exception_autocapture_refill_interval_seconds = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, - capture_mode: Optional[Union[CaptureMode, str]] = None, - capture_compression: Optional[Union[CaptureCompression, str]] = None, - secret_key = None, - metrics: Optional[dict] = None, - enable_full_ai_capture = False, - capture_trace_context = False, - traces: Optional[dict] = None, - app_host: Optional[str] = None, - email_request_timeout_seconds: float = 15, - email_request_max_retries: int = 2, -) -``` - -
-Parameters (50) - -| Parameter | -| --- | -| `project_api_key`
**Type:** `str` · **Required**
PostHog project API key/token. | -| `host`
**Default:** `None`
PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as `https://us.posthog.com` are mapped to the corresponding ingestion host. | -| `debug`
**Default:** `False`
Enable verbose SDK logging and re-raise errors from public API methods. | -| `max_queue_size`
**Default:** `10000`
Maximum number of events buffered before upload. | -| `send`
**Default:** `True`
If False, queueing succeeds but events are not sent. | -| `on_error`
**Default:** `None`
Optional callback invoked by background consumers when an upload fails. Keep it short and non-blocking. Calling lifecycle methods directly is safe and deferred, but do not start another thread or task that calls `flush()`, `join()`, or `shutdown()` and then wait for it from the callback. | -| `flush_at`
**Default:** `100`
Number of queued events that triggers a batch upload. | -| `flush_interval`
**Default:** `5.0`
Maximum seconds a background consumer waits before flushing a partial batch. | -| `gzip`
**Default:** `False`
Whether to gzip event upload payloads. | -| `max_retries`
**Default:** `3`
Number of upload retries. Values below 0 are treated as 0. | -| `sync_mode`
**Default:** `False`
If True, send each event synchronously instead of using background worker threads. This blocks the calling thread; in asyncio applications such as FastAPI, use `AsyncPosthog` instead. | -| `timeout`
**Type:** `float` · **Default:** `15`
HTTP request timeout in seconds for event uploads. | -| `thread`
**Default:** `1`
Number of background consumer threads. | -| `poll_interval`
**Default:** `30`
Seconds between local feature flag definition refreshes. | -| `personal_api_key`
**Default:** `None`
Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | -| `disabled`
**Default:** `False`
If True, disable captures and API requests. Useful in tests. | -| `disable_geoip`
**Default:** `True`
Whether to disable server-side GeoIP enrichment. Defaults to True. | -| `is_server`
**Default:** `True`
Whether events are emitted from a server-side runtime. Defaults to True; set to False when using the SDK as a client/CLI so the device OS is attributed to the person normally. | -| `historical_migration`
**Default:** `False`
Mark events as historical migration imports. | -| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3`
Timeout in seconds for feature flag and remote config requests. | -| `feature_flags_request_max_retries`
**Default:** `1`
Number of retries for feature flag requests after network, transport, or timeout failures. Defaults to 1. Set to 0 to disable retries. | -| `super_properties`
**Default:** `None`
Properties merged into every captured event. | -| `enable_exception_autocapture`
**Default:** `False`
Automatically capture uncaught exceptions. | -| `log_captured_exceptions`
**Default:** `False`
Also log exceptions captured by error tracking. | -| `project_root`
**Default:** `None`
Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. | -| `privacy_mode`
**Default:** `False`
For AI observability, capture usage metadata without prompt inputs or outputs. | -| `before_send`
**Default:** `None`
Optional callback that can modify or drop events before upload. Return `None` to drop an event. | -| `flag_fallback_cache_url`
**Default:** `None`
Optional feature flag fallback cache URL, such as `memory://local/?ttl=300&size=10000` or a Redis URL. | -| `enable_local_evaluation`
**Default:** `True`
Whether to poll feature flag definitions for local evaluation when a personal API key is configured. | -| `flag_definition_cache_provider`
**Type:** `Optional[FlagDefinitionCacheProvider]` · **Default:** `None`
Optional external cache provider for sharing feature flag definitions across workers. | -| `capture_exception_code_variables`
**Default:** `False`
Capture local variable values on exception stack frames. | -| `code_variables_mask_patterns`
**Default:** `None`
Variable-name patterns to mask when capturing code variables. | -| `code_variables_ignore_patterns`
**Default:** `None`
Variable-name patterns to omit when capturing code variables. | -| `code_variables_mask_url_credentials`
**Default:** `None`
Scrub credentials embedded in URLs/DSNs (e.g. `user:pass@host`) from captured code variables, regardless of the surrounding variable name. Defaults to True. | -| `code_variables_detect_secrets`
**Default:** `None`
Last-resort entropy-based detection that redacts high-entropy secret-looking values (API keys, tokens, strong passwords) sitting in innocuously-named variables, after the name and URL checks. Skips structured ids (UUIDs, ObjectIds, hashes). Defaults to True. | -| `in_app_modules`
**Type:** `list[str]` \| `None` · **Default:** `None`
Module/package prefixes treated as in-app frames in captured exceptions. | -| `enable_exception_autocapture_rate_limiting`
**Default:** `False`
Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. | -| `exception_autocapture_bucket_size`
**Default:** `ExceptionCapture.DEFAULT_BUCKET_SIZE`
Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). | -| `exception_autocapture_refill_rate`
**Default:** `ExceptionCapture.DEFAULT_REFILL_RATE`
Tokens restored per refill interval for each exception type's bucket. | -| `exception_autocapture_refill_interval_seconds`
**Default:** `ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS`
Seconds between token refills for autocaptured exception rate limiting. | -| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None`
Capture wire protocol to use. Defaults to `CaptureMode.V0` (legacy `/batch/`). Set `CaptureMode.V1` (or pass the string `"v1"`) to opt into `/i/v1/analytics/events`. When omitted, the `POSTHOG_CAPTURE_MODE` env var is consulted, then `V0`. | -| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None`
Request-body compression for capture-v1 uploads (ignored in V0, which uses `gzip`). `CaptureCompression.GZIP` or `DEFLATE` (or the strings `"gzip"`/`"deflate"`). When omitted, the `POSTHOG_CAPTURE_COMPRESSION` env var is consulted, then the legacy `gzip` flag, then no compression. | -| `secret_key`
**Default:** `None`
A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:
`posthog.Client(project_api_key, secret_key="phx_...")` | -| `metrics`
**Type:** `Optional[dict]` · **Default:** `None` | -| `enable_full_ai_capture`
**Default:** `False`
Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. `privacy_mode` always wins. Defaults to False. | -| `capture_trace_context`
**Default:** `False`
When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as `$trace_id` and `$span_id` properties to events captured with `capture()` and `capture_ai()`, so they can be correlated with backend traces. Explicit `$trace_id`/`$span_id` values passed in `properties` win. Exception events (`capture_exception`) always attach these IDs regardless of this setting. Defaults to False. | -| `traces`
**Type:** `Optional[dict]` · **Default:** `None`
Config dict for distributed tracing: `service_name`, `service_version`, `environment`, `resource_attributes`, `flush_interval` (5 s), `max_queue_size` (2048), `max_export_batch_size` (512), `max_live_spans` (10000), `max_span_age` (3600 s), `max_attributes_per_span` (128), `max_events_per_span` (128), `max_attribute_value_length` (8192). `before_span_send` is a callable, or a list run in order, that receives each finished span as a dict (`trace_id`, `span_id` and `parent_span_id` are read-only) and returns it, edited, or `None` to drop it; a hook that raises drops the span. Tracing is off until this is provided. Spans export on a background timer even with `sync_mode`; serverless handlers should call `flush()` before returning. Defaults to None. | -| `app_host`
**Type:** `Optional[str]` · **Default:** `None`
Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | -| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15`
Timeout in seconds for each email send request. Defaults to 15. | -| `email_request_max_retries`
**Type:** `int` · **Default:** `2`
Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | - -
+## Shutdown -**Correct example.** +### `Client.join` ```python -from posthog import Posthog - -posthog = Posthog('', host='') +join() -> None ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L684) - -## Shutdown - -### `Client.join` - Attempt to process queued events and end the consumer threads. Do not use directly, call `shutdown()` instead. Failed or undrainable events may be dropped and reported through logging or `on_error`; returning does not guarantee server receipt. Lifecycle cleanup is attempted once, and cleanup failures are logged without retry. -```python -join() -> None -``` - -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.join() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3342) - ### `Client.shutdown` +```python +shutdown() -> None +``` + Attempt final delivery and permanently shut down the client. Call this for final process cleanup or when disposing of a client that @@ -1193,125 +899,77 @@ application-owned thread and return before that thread calls shutdown. Do not wait inside the callback for another thread or task that calls a lifecycle method. -```python -shutdown() -> None -``` - -**Returns** `None` - -**Correct example.** +**Examples:** ```python posthog.shutdown() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3364) - ## Flag definition loader ### `Client.load_feature_flags` -Load feature flags for local evaluation. - ```python load_feature_flags() ``` -**Correct example.** +Load feature flags for local evaluation. + +**Examples:** ```python posthog.load_feature_flags() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L3825) - ### `Client.feature_flag_definitions` -Return feature flag definitions loaded for local evaluation. - ```python feature_flag_definitions() ``` -**Returns** . The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5252) - -## SDK utils - -### Other - -#### `Client.queue` - -The analytics lane's queue (kept for backwards compatibility). +Return feature flag definitions loaded for local evaluation. -```python -Client.queue: Queue -``` +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1293) +Type | Description +---- | ----------- + | The currently loaded feature flag definitions, or `None` before + | local evaluation has loaded definitions. -#### `Client.consumers` +## SDK utils -Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). +### `Client.queue` ```python -Client.consumers: Optional[List[Consumer]] +queue: Queue ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1298) - -#### `Client.feature_flags` - -Get the local evaluation feature flags. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1478) - -#### `Client.metrics` - -The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. - -Samples fold into per-series aggregates in memory and flush as one OTLP -data point per series per window, so recording from hot paths is cheap. -Configure via the `metrics` client option; pending metrics flush on -`shutdown()`. - -```python -Client.metrics: PostHogMetrics -``` +The analytics lane's queue (kept for backwards compatibility). -**Correct example.** +### `Client.consumers` ```python -client = Posthog("", metrics={"service_name": "billing-worker"}) -client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) -client.metrics.gauge("queue.depth", 42) -client.metrics.histogram("job.duration", 187, unit="ms") +consumers: Optional[List[Consumer]] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L2718) - -### Contexts - -#### `Client.new_context` +Flat list of the lanes' consumers, analytics first (kept for backwards compatibility). -Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). +### `Client.new_context` ```python new_context(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (2) +Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` +`capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -**Correct example.** +**Examples:** ```python with client.new_context(): @@ -1319,252 +977,298 @@ with client.new_context(): client.capture('event_name') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1378) +
+Category -#### `Client.scoped` +Contexts -Decorator that creates a new context for the wrapped function using this client. +
+ +### `Client.scoped` ```python scoped(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (2) +Decorator that creates a new context for the wrapped function using this client. -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to create a fresh context that doesn't inherit from parent. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` +`capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1400) +
+Category -#### `Client.tag` +Contexts -Add a tag to the current context. +
+ +### `Client.tag` ```python tag(name: str, value: Any) -> None ``` -
-Parameters (2) +Add a tag to the current context. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The tag key. | -| `value`
**Type:** `Any` · **Required**
The tag value. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | The tag key. | *required* +`value` | `Any` | The tag value. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1416) +Contexts -#### `Client.get_tags` +
-Get all tags from the current context. +### `Client.get_tags` ```python get_tags() -> Dict[str, Any] ``` -**Returns** `Dict[str, Any]`. Dict of all tags in the current context. +Get all tags from the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1429) +**Returns:** -#### `Client.identify_context` +Type | Description +---- | ----------- +`Dict[str, Any]` | Dict of all tags in the current context. -Identify the current context with a distinct ID. +
+Category + +Contexts + +
+ +### `Client.identify_context` ```python identify_context(distinct_id: str) -> None ``` -
-Parameters (1) +Identify the current context with a distinct ID. -| Parameter | -| --- | -| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `str` | The distinct ID to associate with the current context and its children. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1441) +Contexts -#### `Client.set_context_session` +
-Set the session ID for the current context. +### `Client.set_context_session` ```python set_context_session(session_id: str) -> None ``` -
-Parameters (1) +Set the session ID for the current context. -| Parameter | -| --- | -| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`session_id` | `str` | The session ID to associate with the current context and its children. | *required* -**Returns** `None` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1453) +Contexts -#### `Client.set_context_device_id` +
-Set the device ID for the current context. +### `Client.set_context_device_id` ```python set_context_device_id(device_id: str) -> None ``` -
-Parameters (1) +Set the device ID for the current context. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`device_id` | `str` | The device ID to associate with the current context and its children. | *required* + +
+Category -| Parameter | -| --- | -| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children. | +Contexts
-**Returns** `None` +### `Client.feature_flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1465) +```python +feature_flags +``` + +Get the local evaluation feature flags. -### Feature flags +### `Client.get_feature_payloads` -#### `Client.get_feature_payloads` +```python +get_feature_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> dict[str, Optional[str]] +``` Get feature flag payloads for a user, preserving valid serialized JSON. +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The distinct ID of the user. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** + ```python -get_feature_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> dict[str, Optional[str]] +payloads = posthog.get_feature_payloads('') ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Feature flags
-**Returns** `dict[str, Optional[str]]` - -**Correct example.** +### `Client.get_flags_decision` ```python -payloads = posthog.get_feature_payloads('') +get_flags_decision(distinct_id: Optional[ID_TYPES] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys_to_evaluate: Optional[list[str]] = None, device_id: Optional[str] = None) -> FlagsResponse ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1535) +Get feature flags decision. -#### `Client.get_flags_decision` +**Parameters:** -Get feature flags decision. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The distinct ID of the user. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | A dictionary of group information. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | A dictionary of person properties. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | A dictionary of group properties. | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP for this request. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | `None` +`device_id` | `Optional[str]` | The device ID for this request. | `None` + +**Examples:** ```python -get_flags_decision( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FlagsResponse +decision = posthog.get_flags_decision('user123') ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The distinct ID of the user. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
A dictionary of group information. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
A dictionary of person properties. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
A dictionary of group properties. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP for this request. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
The device ID for this request. | +Feature flags
-**Returns** `FlagsResponse` - -**Correct example.** +### `Client.metrics` ```python -decision = posthog.get_flags_decision('user123') +metrics: PostHogMetrics ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L1628) +The `posthog.metrics` API: a statsd-style pre-aggregating metrics client — alpha. + +Samples fold into per-series aggregates in memory and flush as one OTLP +data point per series per window, so recording from hot paths is cheap. +Configure via the `metrics` client option; pending metrics flush on +`shutdown()`. -#### `Client.get_remote_config_payload` +**Examples:** -Get the payload for a remote config feature flag. +```python +client = Posthog("", metrics={"service_name": "billing-worker"}) +client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) +client.metrics.gauge("queue.depth", 42) +client.metrics.histogram("job.duration", 187, unit="ms") +``` + +### `Client.get_remote_config_payload` ```python get_remote_config_payload(key: str) ``` -
-Parameters (1) +Get the payload for a remote config feature flag. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The remote config feature flag key. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The remote config feature flag key. | *required* -**Returns** . The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned. +**Returns:** -**Note.** Requires `secret_key` for authentication. +Type | Description +---- | ----------- + | The payload associated with the feature flag, or `None` if the + | client is disabled, no personal API key is configured, or the request + | fails. Encrypted payloads are decrypted by PostHog before being + | returned. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L4670) +
+Note -#### `Client.get_feature_flag_evaluation_runtime` +Requires `secret_key` for authentication. -Return where a locally loaded feature flag is meant to be evaluated. +
+ +
+Category + +Feature flags + +
+ +### `Client.get_feature_flag_evaluation_runtime` ```python get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] ``` -
-Parameters (1) +Return where a locally loaded feature flag is meant to be evaluated. + +**Parameters:** -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* -
+**Returns:** -**Returns** `Optional[FeatureFlagEvaluationRuntime]`. The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. +Type | Description +---- | ----------- +`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has +`Optional[FeatureFlagEvaluationRuntime]` | not loaded a definition for this key. A definition that carries no +`Optional[FeatureFlagEvaluationRuntime]` | runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default +`Optional[FeatureFlagEvaluationRuntime]` | PostHog applies. -**Correct example.** +**Examples:** ```python from posthog import FeatureFlagEvaluationRuntime @@ -1574,9 +1278,18 @@ if runtime is FeatureFlagEvaluationRuntime.SERVER: ... ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5264) +
+Category -#### `Client.get_feature_flag_keys_by_evaluation_runtime` +Feature flags + +
+ +### `Client.get_feature_flag_keys_by_evaluation_runtime` + +```python +get_feature_flag_keys_by_evaluation_runtime(evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str]) -> list[str] +``` Return the keys of locally loaded flags that a runtime can evaluate. @@ -1585,24 +1298,20 @@ so it is returned for `CLIENT` and for `SERVER`, and asking for `ALL` returns every loaded flag. Use this to decide which flags to hand to a browser when a backend serves flags to its own frontend. -```python -get_feature_flag_keys_by_evaluation_runtime( - evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], -) -> list[str] -``` - -
-Parameters (1) +**Parameters:** -| Parameter | -| --- | -| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required**
The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`evaluation_runtime` | `Union[FeatureFlagEvaluationRuntime, str]` | The runtime to match, as a `FeatureFlagEvaluationRuntime` or its string value. | *required* -
+**Returns:** -**Returns** `list[str]`. The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. +Type | Description +---- | ----------- +`list[str]` | The matching flag keys, in the order local evaluation loaded them. +`list[str]` | Empty when no definitions are loaded. -**Correct example.** +**Examples:** ```python from posthog import FeatureFlagEvaluationRuntime @@ -1612,13 +1321,18 @@ client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/client.py#L5298) +
+Category -### Framework integrations +Feature flags + +
-#### `posthog.integrations.django.PosthogContextMiddleware` +### `posthog.integrations.django.PosthogContextMiddleware` -**Available in:** Django apps +```python +PosthogContextMiddleware(get_response) +``` Middleware to automatically track Django requests. @@ -1664,373 +1378,420 @@ This middleware is hybrid-capable: it supports both WSGI (sync) and ASGI (async) detects at initialization whether the next middleware in the chain is async or sync, and adapts its behavior accordingly. This ensures compatibility with both pure sync and pure async middleware chains, as well as mixed chains in ASGI mode. -```python -PosthogContextMiddleware(get_response) -``` +**Functions:** -
-Parameters (1) +Name | Description +---- | ----------- +`aextract_properties` | Async version of extract_properties for use in async request handling. +`aextract_request_user` | Async version of extract_request_user for use in async request handling. +`aextract_tags` | Compatibility alias for `aextract_properties`. +`extract_properties` | Extract event properties and identity from a synchronous request. +`extract_request_user` | Extract user ID and email from request in sync context. +`extract_tags` | Compatibility alias for `extract_properties`. +`process_exception` | Process exceptions from views and downstream middleware. -| Parameter | -| --- | -| `get_response`
**Required**
The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | +**Attributes:** -
+Name | Type | Description +---- | ---- | ----------- +`async_capable` | | +`capture_exceptions` | `Optional[bool]` | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`extra_tags` | | Compatibility alias for `extra_properties`. +`get_response` | | +`properties_map` | | +`request_filter` | | +`sync_capable` | | +`tag_map` | | Compatibility alias for `properties_map`. +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L31) +Initialize the middleware with Django's next handler. -#### `PosthogContextMiddleware.trust_tracing_headers` +**Parameters:** -**Available in:** Django apps +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`get_response` | | The next middleware or view handler in Django's middleware chain. May be synchronous or asynchronous. | -Deprecated alias for `capture_tracing_headers`. +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_properties` ```python -PosthogContextMiddleware.trust_tracing_headers: bool +aextract_properties(request) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L158) +Async version of extract_properties for use in async request handling. -#### `PosthogContextMiddleware.extra_tags` +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. -**Available in:** Django apps +Follows Django's naming convention for async methods (auser, asave, etc.). -Compatibility alias for `extra_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_request_user` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L167) +```python +aextract_request_user(request) +``` -#### `PosthogContextMiddleware.tag_map` +Async version of extract_request_user for use in async request handling. -**Available in:** Django apps +Uses await request.auser() instead of request.user to avoid +SynchronousOnlyOperation in async context. -Compatibility alias for `properties_map`. +Follows Django's naming convention for async methods (auser, asave, etc.). -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L176) +#### `posthog.integrations.django.PosthogContextMiddleware.aextract_tags` -#### `PosthogContextMiddleware.extract_tags` +```python +aextract_tags(request) +``` -**Available in:** Django apps +Compatibility alias for `aextract_properties`. -Compatibility alias for `extract_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.async_capable` ```python -extract_tags(request) +async_capable = True ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.capture_exceptions` -| Parameter | -| --- | -| `request`
**Required** | +```python +capture_exceptions: Optional[bool] = capture_exceptions if (capture_exceptions is None or isinstance(capture_exceptions, bool)) else True +``` -
+#### `posthog.integrations.django.PosthogContextMiddleware.capture_tracing_headers` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L184) +```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers, canonical_name='POSTHOG_MW_CAPTURE_TRACING_HEADERS', deprecated_name='POSTHOG_MW_TRUST_TRACING_HEADERS') +``` -#### `PosthogContextMiddleware.extract_properties` +#### `posthog.integrations.django.PosthogContextMiddleware.client` -**Available in:** Django apps +```python +client = cast('Optional[Client]', settings.POSTHOG_MW_CLIENT) +``` -Extract event properties and identity from a synchronous request. +#### `posthog.integrations.django.PosthogContextMiddleware.extra_properties` ```python -extract_properties(request) +extra_properties = cast('Callable[[HttpRequest], Dict[str, Any]]', extra_properties) if callable(extra_properties) else None ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.extra_tags` -| Parameter | -| --- | -| `request`
**Required** | +```python +extra_tags +``` -
+Compatibility alias for `extra_properties`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L189) +#### `posthog.integrations.django.PosthogContextMiddleware.extract_properties` -#### `PosthogContextMiddleware.extract_request_user` +```python +extract_properties(request) +``` -**Available in:** Django apps +Extract event properties and identity from a synchronous request. -Extract user ID and email from request in sync context. +#### `posthog.integrations.django.PosthogContextMiddleware.extract_request_user` ```python extract_request_user(request) ``` -
-Parameters (1) - -| Parameter | -| --- | -| `request`
**Required** | - -
+Extract user ID and email from request in sync context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L250) +#### `posthog.integrations.django.PosthogContextMiddleware.extract_tags` -#### `PosthogContextMiddleware.aextract_tags` +```python +extract_tags(request) +``` -**Available in:** Django apps +Compatibility alias for `extract_properties`. -Compatibility alias for `aextract_properties`. +#### `posthog.integrations.django.PosthogContextMiddleware.get_response` ```python -async aextract_tags(request) +get_response = get_response ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.process_exception` -| Parameter | -| --- | -| `request`
**Required** | +```python +process_exception(request, exception) +``` -
+Process exceptions from views and downstream middleware. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L256) +Django calls this WHILE still inside the context created by __call__, +so request tags have already been extracted and set. This method just +needs to capture the exception directly. -#### `PosthogContextMiddleware.aextract_properties` +Django converts view exceptions into responses before they propagate through +the middleware stack, so the context manager in __call__/__acall__ never sees them. -**Available in:** Django apps +Note: Django's process_exception is always synchronous, even for async views. -Async version of extract_properties for use in async request handling. +#### `posthog.integrations.django.PosthogContextMiddleware.properties_map` -Uses await request.auser() instead of request.user to avoid -SynchronousOnlyOperation in async context. +```python +properties_map = cast('Callable[[Dict[str, Any]], Dict[str, Any]]', properties_map) if callable(properties_map) else None +``` -Follows Django's naming convention for async methods (auser, asave, etc.). +#### `posthog.integrations.django.PosthogContextMiddleware.request_filter` ```python -async aextract_properties(request) +request_filter = cast('Optional[Callable[[HttpRequest], bool]]', settings.POSTHOG_MW_REQUEST_FILTER) ``` -
-Parameters (1) +#### `posthog.integrations.django.PosthogContextMiddleware.sync_capable` -| Parameter | -| --- | -| `request`
**Required** | +```python +sync_capable = True +``` -
+#### `posthog.integrations.django.PosthogContextMiddleware.tag_map` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L261) +```python +tag_map +``` -#### `PosthogContextMiddleware.aextract_request_user` +Compatibility alias for `properties_map`. -**Available in:** Django apps +#### `posthog.integrations.django.PosthogContextMiddleware.trust_tracing_headers` -Async version of extract_request_user for use in async request handling. +```python +trust_tracing_headers: bool +``` -Uses await request.auser() instead of request.user to avoid -SynchronousOnlyOperation in async context. +Deprecated alias for `capture_tracing_headers`. -Follows Django's naming convention for async methods (auser, asave, etc.). +### `posthog.integrations.flask.PosthogFlaskIntegration` ```python -async aextract_request_user(request) +PosthogFlaskIntegration(app: Optional[Flask] = None, *, client: Optional[Client] = None, capture_exceptions: Optional[bool] = None, request_filter: Optional[Callable[[Request], bool]] = None, extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, trust_tracing_headers: Optional[bool] = None, capture_tracing_headers: Optional[bool] = None) -> None ``` -
-Parameters (1) - -| Parameter | -| --- | -| `request`
**Required** | +Add PostHog request context and exception tracking to a Flask app. -
+**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L274) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`app` | `Optional[Flask]` | An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | `None` +`client` | `Optional[Client]` | Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | `None` +`capture_exceptions` | `Optional[bool]` | Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | `None` +`request_filter` | `Optional[Callable[[Request], bool]]` | Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | `None` +`extra_properties` | `Optional[Callable[[Request], Mapping[str, Any]]]` | Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | `None` +`capture_tracing_headers` | `Optional[bool]` | Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | `None` +`trust_tracing_headers` | `Optional[bool]` | Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | `None` -#### `PosthogContextMiddleware.process_exception` +The integration intentionally does not capture exceptions handled by an +application error handler, expected HTTP exceptions, request or response +bodies, query strings, cookies, authorization headers, or arbitrary headers. +Call `capture_exception` explicitly from a custom error handler if a +handled exception should be reported. -**Available in:** Django apps +**Functions:** -Process exceptions from views and downstream middleware. +Name | Description +---- | ----------- +`init_app` | Register the integration with a Flask application once. -Django calls this WHILE still inside the context created by __call__, -so request tags have already been extracted and set. This method just -needs to capture the exception directly. +**Attributes:** -Django converts view exceptions into responses before they propagate through -the middleware stack, so the context manager in __call__/__acall__ never sees them. +Name | Type | Description +---- | ---- | ----------- +`capture_exceptions` | | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`request_filter` | | +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -Note: Django's process_exception is always synchronous, even for async views. +#### `posthog.integrations.flask.PosthogFlaskIntegration.capture_exceptions` ```python -process_exception(request, exception) +capture_exceptions = capture_exceptions ``` -
-Parameters (2) +#### `posthog.integrations.flask.PosthogFlaskIntegration.capture_tracing_headers` -| Parameter | -| --- | -| `request`
**Required** | -| `exception`
**Required** | - -
+```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers) +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/django.py#L376) +#### `posthog.integrations.flask.PosthogFlaskIntegration.client` -#### `posthog.integrations.flask.PosthogFlaskIntegration` +```python +client = client +``` -**Available in:** Flask apps +#### `posthog.integrations.flask.PosthogFlaskIntegration.extra_properties` -Add PostHog request context and exception tracking to a Flask app. +```python +extra_properties = extra_properties +``` -The integration intentionally does not capture exceptions handled by an -application error handler, expected HTTP exceptions, request or response -bodies, query strings, cookies, authorization headers, or arbitrary headers. -Call `capture_exception` explicitly from a custom error handler if a -handled exception should be reported. +#### `posthog.integrations.flask.PosthogFlaskIntegration.init_app` ```python -PosthogFlaskIntegration( - app: Optional[Flask] = None, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - request_filter: Optional[Callable[[Request], bool]] = None, - extra_properties: Optional[Callable[[Request], Mapping[str, Any]]] = None, - trust_tracing_headers: Optional[bool] = None, - capture_tracing_headers: Optional[bool] = None, -) +init_app(app: Flask) -> None ``` -
-Parameters (7) - -| Parameter | -| --- | -| `app`
**Type:** `Optional[Flask]` · **Default:** `None`
An optional Flask application. If omitted, call `init_app` later (the Flask application-factory pattern). | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions that reach Flask's unhandled exception machinery. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | -| `request_filter`
**Type:** `Optional[Callable[[Request], bool]]` · **Default:** `None`
Optional callback receiving Flask's request object. A false return value disables both context and exception capture for that request. | -| `extra_properties`
**Type:** `Optional[Callable[[Request], Mapping[str, Any]]]` · **Default:** `None`
Optional callback returning additional event properties. This is useful for application-specific metadata such as an authenticated user's role. Values should not contain secrets or request bodies. | -| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | -| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | +Register the integration with a Flask application once. -
+#### `posthog.integrations.flask.PosthogFlaskIntegration.request_filter` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L91) +```python +request_filter = request_filter +``` -#### `PosthogFlaskIntegration.trust_tracing_headers` +#### `posthog.integrations.flask.PosthogFlaskIntegration.trust_tracing_headers` -**Available in:** Flask apps +```python +trust_tracing_headers: bool +``` Deprecated alias for `capture_tracing_headers`. +### `posthog.integrations.asgi.PosthogASGIMiddleware` + ```python -PosthogFlaskIntegration.trust_tracing_headers: bool +PosthogASGIMiddleware(app: _ASGIApp, client: Optional[Client] = None, capture_exceptions: Optional[bool] = None, request_filter: Optional[_RequestFilter] = None, extra_properties: Optional[_ExtraProperties] = None, trust_tracing_headers: Optional[bool] = None, *, capture_tracing_headers: Optional[bool] = None) -> None ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L146) - -#### `PosthogFlaskIntegration.init_app` +Add PostHog context and automatic exception capture to an ASGI app. -**Available in:** Flask apps +**Parameters:** -Register the integration with a Flask application once. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`app` | `_ASGIApp` | The downstream ASGI application. | *required* +`client` | `Optional[Client]` | Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | `None` +`capture_exceptions` | `Optional[bool]` | Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | `None` +`request_filter` | `Optional[_RequestFilter]` | Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | `None` +`extra_properties` | `Optional[_ExtraProperties]` | Optional sync or async callback receiving the ASGI scope and returning additional event properties. | `None` +`capture_tracing_headers` | `Optional[bool]` | Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | `None` +`trust_tracing_headers` | `Optional[bool]` | Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | `None` -```python -init_app(app: Flask) -> None -``` +**Attributes:** -
-Parameters (1) +Name | Type | Description +---- | ---- | ----------- +`app` | | +`capture_exceptions` | | +`capture_tracing_headers` | | +`client` | | +`extra_properties` | | +`request_filter` | | +`trust_tracing_headers` | `bool` | Deprecated alias for `capture_tracing_headers`. -| Parameter | -| --- | -| `app`
**Type:** `Flask` · **Required** | +#### `posthog.integrations.asgi.PosthogASGIMiddleware.app` -
+```python +app = app +``` -**Returns** `None` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.capture_exceptions` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/flask.py#L154) +```python +capture_exceptions = capture_exceptions +``` -#### `posthog.integrations.asgi.PosthogASGIMiddleware` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.capture_tracing_headers` -**Available in:** ASGI apps, such as FastAPI and Starlette +```python +capture_tracing_headers = _resolve_capture_tracing_headers(capture_tracing_headers, trust_tracing_headers) +``` -Add PostHog context and automatic exception capture to an ASGI app. +#### `posthog.integrations.asgi.PosthogASGIMiddleware.client` ```python -PosthogASGIMiddleware( - app: _ASGIApp, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - request_filter: Optional[_RequestFilter] = None, - extra_properties: Optional[_ExtraProperties] = None, - trust_tracing_headers: Optional[bool] = None, - capture_tracing_headers: Optional[bool] = None, -) +client = client ``` -
-Parameters (7) +#### `posthog.integrations.asgi.PosthogASGIMiddleware.extra_properties` -| Parameter | -| --- | -| `app`
**Type:** `_ASGIApp` · **Required**
The downstream ASGI application. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional destination for automatically captured exceptions. The global client is used by default. Request context still enriches events captured through any client and does not redirect capture calls. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Capture exceptions escaping the downstream app. If omitted, inherit the effective client's `enable_exception_autocapture` setting. Pass `True` or `False` to override it. | -| `request_filter`
**Type:** `Optional[_RequestFilter]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope. Returning `False` bypasses all instrumentation for that scope. | -| `extra_properties`
**Type:** `Optional[_ExtraProperties]` · **Default:** `None`
Optional sync or async callback receiving the ASGI scope and returning additional event properties. | -| `trust_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Deprecated alias for `capture_tracing_headers`. The capture-named option takes precedence when both are supplied. | -| `capture_tracing_headers`
**Type:** `Optional[bool]` · **Default:** `None`
Read PostHog distinct and session ID headers as request-scoped analytics context. Defaults to True. Explicit capture IDs and event properties take precedence. Never use these values for security. | +```python +extra_properties = extra_properties +``` -
+#### `posthog.integrations.asgi.PosthogASGIMiddleware.request_filter` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L182) +```python +request_filter = request_filter +``` -#### `PosthogASGIMiddleware.trust_tracing_headers` +#### `posthog.integrations.asgi.PosthogASGIMiddleware.trust_tracing_headers` -**Available in:** ASGI apps, such as FastAPI and Starlette +```python +trust_tracing_headers: bool +``` Deprecated alias for `capture_tracing_headers`. +### `posthog.integrations.celery.PosthogCeleryIntegration` + ```python -PosthogASGIMiddleware.trust_tracing_headers: bool +PosthogCeleryIntegration(client: Optional[Client] = None, capture_exceptions: bool = True, capture_task_lifecycle_events: bool = True, propagate_context: bool = True, task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/asgi.py#L225) +Celery integration that captures task lifecycle events and exceptions. + +**Parameters:** -#### `posthog.integrations.celery.PosthogCeleryIntegration` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`client` | `Optional[Client]` | Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | `None` +`capture_exceptions` | `bool` | Whether to capture task exceptions via `capture_exception` (default `True`). | `True` +`capture_task_lifecycle_events` | `bool` | Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | `True` +`propagate_context` | `bool` | Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | `True` +`task_filter` | `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` | Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | `None` -**Available in:** Celery workers +**Functions:** -Celery integration that captures task lifecycle events and exceptions. +Name | Description +---- | ----------- +`instrument` | Connect Celery signal handlers to capture task events and exceptions. +`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events +`uninstrument` | Disconnect Celery signal handlers and unregister exit cleanup. + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`capture_exceptions` | | +`capture_task_lifecycle_events` | | +`client` | | +`propagate_context` | | +`task_filter` | | + +#### `posthog.integrations.celery.PosthogCeleryIntegration.capture_exceptions` ```python -PosthogCeleryIntegration( - client: Optional[Client] = None, - capture_exceptions: bool = True, - capture_task_lifecycle_events: bool = True, - propagate_context: bool = True, - task_filter: Optional[Callable[[Optional[str], dict[str, Any]], bool]] = None, -) +capture_exceptions = capture_exceptions ``` -
-Parameters (5) +#### `posthog.integrations.celery.PosthogCeleryIntegration.capture_task_lifecycle_events` -| Parameter | -| --- | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional `Client` instance. When provided, all events and exceptions are captured through this client rather than the global `posthog` module. Don't skip this if using a custom flag definition cache provider, and pass the custom `Client` instance here initialized with the custom provider so fork safety for that provider is handled correctly. | -| `capture_exceptions`
**Type:** `bool` · **Default:** `True`
Whether to capture task exceptions via `capture_exception` (default `True`). | -| `capture_task_lifecycle_events`
**Type:** `bool` · **Default:** `True`
Whether to emit lifecycle events of the task such as "started", "success", "failure" etc. (default `True`). | -| `propagate_context`
**Type:** `bool` · **Default:** `True`
Whether to propagate PostHog context (distinct ID, session ID, tags) from the producer to the worker via task headers (default `True`). | -| `task_filter`
**Type:** `Optional[Callable[[Optional[str], dict[str, Any]], bool]]` · **Default:** `None`
Optional callback `(task_name, task_properties) -> bool` expected to return `False` if a given task should not be tracked. | +```python +capture_task_lifecycle_events = capture_task_lifecycle_events +``` -
+#### `posthog.integrations.celery.PosthogCeleryIntegration.client` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L89) +```python +client = client +``` -#### `PosthogCeleryIntegration.instrument` +#### `posthog.integrations.celery.PosthogCeleryIntegration.instrument` -**Available in:** Celery workers +```python +instrument() -> None +``` Connect Celery signal handlers to capture task events and exceptions. Call this after initializing the PostHog client and this integration. @@ -2042,34 +1803,18 @@ process must initialize PostHog, this integration, and call `instrument()`. Celery provides `worker_process_init` signal to help with this. +#### `posthog.integrations.celery.PosthogCeleryIntegration.propagate_context` + ```python -instrument() -> None +propagate_context = propagate_context ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L129) - -#### `PosthogCeleryIntegration.uninstrument` - -**Available in:** Celery workers - -Disconnect Celery signal handlers and unregister exit cleanup. - -Do not use directly, call `shutdown()` instead. +#### `posthog.integrations.celery.PosthogCeleryIntegration.shutdown` ```python -uninstrument() -> None +shutdown() -> None ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L182) - -#### `PosthogCeleryIntegration.shutdown` - -**Available in:** Celery workers - Disconnect all signal handlers registered by `instrument()`, flush all pending events and cleanly shutdown the integration. @@ -2077,748 +1822,505 @@ and cleanly shutdown the integration. but there is no guarantee those will always be called, so we strongly recommend calling it manually when the integration is no longer needed to avoid data loss. +#### `posthog.integrations.celery.PosthogCeleryIntegration.task_filter` + ```python -shutdown() -> None +task_filter = task_filter ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/celery.py#L190) +#### `posthog.integrations.celery.PosthogCeleryIntegration.uninstrument` -#### `posthog.integrations.drf.create_exception_handler` - -**Available in:** Django REST framework apps +```python +uninstrument() -> None +``` -Create a PostHog-instrumented DRF exception handler. +Disconnect Celery signal handlers and unregister exit cleanup. -When `POSTHOG_MW_REQUEST_FILTER` is configured, it is also applied to the -underlying Django request before capture so handled errors cannot bypass the -middleware's per-request exclusion. +Do not use directly, call `shutdown()` instead. -The delegated handler is called first. A `None` response is never -captured here because DRF will re-raise that exception, allowing Django's -middleware to capture it as unhandled. +### `posthog.request.set_socket_options` ```python -create_exception_handler( - handler: Optional[Callable[[Exception, Mapping[str, Any]], Any]] = None, - client: Optional[Client] = None, - capture_exceptions: Optional[bool] = None, - capture_4xx: bool = False, - exception_filter: Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]] = None, -) -> Callable[[Exception, Mapping[str, Any]], Any] +set_socket_options(socket_options: Optional[SocketOptions]) -> None ``` -
-Parameters (5) +Configure socket options for all SDK HTTP connections. -| Parameter | -| --- | -| `handler`
**Type:** `Optional[Callable[[Exception, Mapping[str, Any]], Any]]` · **Default:** `None`
Handler to delegate to. Defaults to DRF's standard exception handler. Its return value and raised exceptions are preserved. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional PostHog client. Client precedence is this argument, the legacy `POSTHOG_DRF_CLIENT` alias, `POSTHOG_MW_CLIENT`, then the global PostHog client. | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture handled DRF exceptions. An explicit value takes precedence over `POSTHOG_MW_CAPTURE_EXCEPTIONS`. A boolean setting is used directly; an explicit `None` setting inherits the effective client's `enable_exception_autocapture`. An omitted or malformed setting preserves the legacy `True` default. | -| `capture_4xx`
**Type:** `bool` · **Default:** `False`
Also capture handled 4xx responses. Disabled by default to avoid reporting expected API errors. | -| `exception_filter`
**Type:** `Optional[Callable[[Exception, Any, Mapping[str, Any]], bool]]` · **Default:** `None`
Optional final filter called with `(exception, response, context)`. Returning `False` suppresses capture. | +Call this during initialization, before making API requests. Pass `None` +to reset to the default socket behavior. -
+**Parameters:** -**Returns** `Callable[[Exception, Mapping[str, Any]], Any]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`socket_options` | `Optional[SocketOptions]` | A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | *required* -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/drf.py#L140) +
+Example -#### `posthog.integrations.otel.PostHogContextSpanProcessor` +from posthog import set_socket_options +set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) -**Available in:** the `otel` extra, `posthog[otel]` +
-Add PostHog request IDs to application-owned OpenTelemetry SDK spans. +### `posthog.request.enable_keep_alive` -Add this processor to the application's existing TracerProvider before -starting requests. It snapshots child span context at span start, without -changing exporters, sampling or providers. Request integrations must also -enrich an incoming span that started before request context was available. +```python +enable_keep_alive() -> None +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L20) +Enable TCP keepalive for SDK HTTP connections. -#### `PostHogContextSpanProcessor.on_start` +This helps prevent idle pooled connections from being dropped by network +infrastructure. Call during initialization, before making API requests. -**Available in:** the `otel` extra, `posthog[otel]` +### `posthog.request.disable_connection_reuse` ```python -on_start(span: Span, parent_context: Optional[Context] = None) -> None +disable_connection_reuse() -> None ``` -
-Parameters (2) - -| Parameter | -| --- | -| `span`
**Type:** `Span` · **Required** | -| `parent_context`
**Type:** `Optional[Context]` · **Default:** `None` | - -
+Disable HTTP connection reuse for SDK requests. -**Returns** `None` +Each request will create a fresh connection. This can avoid issues with +environments that terminate pooled connections, but adds per-request +overhead. Call during initialization, before making API requests. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L29) +## AsyncClient -#### `posthog.integrations.otel.enrich_current_span` +Needs the `async` extra, `posthog[async]`. -**Available in:** the `otel` extra, `posthog[otel]` +### `AsyncClient(...)` -Add request IDs to an existing recording span after request context is set. +```python +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) -> None +``` -Explicit span attributes take precedence. Missing OpenTelemetry support and -context lookup failures do not interrupt request handling. +### `AsyncClient.capture` ```python -enrich_current_span() -> None +capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/integrations/otel.py#L11) +Queue an event without blocking for network delivery. -### HTTP connection +### `AsyncClient.capture_immediate` -#### `posthog.request.set_socket_options` +```python +capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` -Configure socket options for all SDK HTTP connections. +Capture one event and wait until its delivery attempt completes. -Call this during initialization, before making API requests. Pass `None` -to reset to the default socket behavior. +### `AsyncClient.set` ```python -set_socket_options(socket_options: Optional[SocketOptions]) -> None +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `socket_options`
**Type:** `Optional[SocketOptions]` · **Required**
A list of `(level, option, value)` tuples accepted by urllib3/`socket.setsockopt()`, or `None` to reset defaults. | - -
+### `AsyncClient.set_once` -**Returns** `None` +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` -**Correct example.** +### `AsyncClient.alias` ```python -from posthog import set_socket_options -set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]) +alias(previous_id: ID_TYPES, distinct_id: Optional[str], timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L143) +### `AsyncClient.capture_exception` -#### `posthog.request.enable_keep_alive` +```python +capture_exception(exception: Optional[ExceptionArg] = None, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` -Enable TCP keepalive for SDK HTTP connections. +Capture an exception. This method never raises, including in debug mode. -This helps prevent idle pooled connections from being dropped by network -infrastructure. Call during initialization, before making API requests. +### `AsyncClient.emails` ```python -enable_keep_alive() -> None +emails: AsyncEmails ``` -**Returns** `None` +Send transactional email from PostHog email templates, and read the +status of each email sent with `get`. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L166) +Needs `secret_key`, a project secret API key with the `hog_flow:write` +scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog +Cloud app host of `host`. `email_request_timeout_seconds` and +`email_request_max_retries` configure each send. A disabled or shut-down +client sends nothing. See `posthog.emails` for setup. -#### `posthog.request.disable_connection_reuse` +**Examples:** -Disable HTTP connection reuse for SDK requests. +```python +await client.emails.send( + to="user@example.com", + template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", + distinct_id="user_123", +) +``` -Each request will create a fresh connection. This can avoid issues with -environments that terminate pooled connections, but adds per-request -overhead. Call during initialization, before making API requests. +### `AsyncClient.flush` ```python -disable_connection_reuse() -> None +flush(timeout_seconds: Optional[float] = 10) -> None ``` -**Returns** `None` +### `AsyncClient.evaluate_flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/request.py#L176) +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` -### AI wrapper clients +Evaluate flags remotely without blocking the event loop. -#### `posthog.ai.openai` - -**Available in:** apps with the `openai` package - -Exports `OpenAI`, `AsyncOpenAI`, `AsyncAzureOpenAI`, `AzureOpenAI`. - -#### `posthog.ai.anthropic` - -**Available in:** apps with the `anthropic` package - -Exports `Anthropic`, `AsyncAnthropic`, `AnthropicBedrock`, `AnthropicVertex`, `AsyncAnthropicBedrock`, `AsyncAnthropicVertex`. - -#### `posthog.ai.gemini` - -**Available in:** apps with the Google Gen AI package - -Exports `Client`, `AsyncClient`. - -#### `posthog.ai.langchain` - -**Available in:** the `langchain` extra, `posthog[langchain]` - -Exports `CallbackHandler`. - -#### `posthog.ai.openai_agents` - -**Available in:** apps with the `openai-agents` package +The returned snapshot has synchronous in-memory accessors. Pass it to +`capture(flags=...)` to attach the exact values used for branching. +This client does not evaluate flags locally, so the snapshot's +`unresolved_flags` is always empty. -Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `Trace`, `Client`, `PostHogTracingProcessor`. +### `AsyncClient.group_identify` -#### `posthog.ai.claude_agent_sdk` +```python +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime, str]] = None, uuid: Optional[Union[str, UUID]] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] +``` -**Available in:** apps with the `claude-agent-sdk` package +### `AsyncClient.shutdown` -Exports `TYPE_CHECKING`, `Any`, `Callable`, `Dict`, `Optional`, `Union`, `ClaudeAgentOptions`, `ResultMessage`, `Client`, `PostHogClaudeSDKClient`, `PostHogClaudeAgentProcessor`. +```python +shutdown() -> None +``` -## AsyncClient +### `AsyncClient.join` -### `AsyncClient.alias` +```python +join() -> None +``` -**Available in:** the `async` extra, `posthog[async]` +### `AsyncClient.get_remote_config_payload` ```python -alias( - previous_id: ID_TYPES, - distinct_id: Optional[str], - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +get_remote_config_payload(key: str) -> Optional[Any] ``` -
-Parameters (5) +Fetch and decrypt a remote-config payload without blocking the loop. -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required** | -| `distinct_id`
**Type:** `Optional[str]` · **Required** | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | +## Module functions -
+### `posthog.new_context` -**Returns** `Optional[str]` +```python +new_context(fresh: bool = False, capture_exceptions: Optional[bool] = None, client: Optional[Client] = None) +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L772) +Create a new context scope that will be active for the duration of the with block. -### `AsyncClient.capture` +**Parameters:** -**Available in:** the `async` extra, `posthog[async]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | `bool` | Whether to start with a fresh context (default: False) | `False` +`capture_exceptions` | `Optional[bool]` | Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | `None` +`client` | `Optional[Client]` | Optional Posthog client instance to use for this context (default: None) | `None` -Queue an event without blocking for network delivery. +**Examples:** ```python -capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | +Contexts
-**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L570) - -### `AsyncClient.capture_immediate` - -**Available in:** the `async` extra, `posthog[async]` - -Capture one event and wait until its delivery attempt completes. +### `posthog.scoped` ```python -async capture_immediate( - event: str, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +scoped(fresh = False, capture_exceptions: Optional[bool] = None) ``` -
-Parameters (1) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L613) +Decorator that creates a new context for the function. -### `AsyncClient.capture_exception` +**Parameters:** -**Available in:** the `async` extra, `posthog[async]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`fresh` | | Whether to start with a fresh context (default: False) | `False` +`capture_exceptions` | `Optional[bool]` | Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | `None` -Capture an exception. This method never raises, including in debug mode. +**Examples:** ```python -capture_exception( - exception: Optional[ExceptionArg] = None, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None` | +Contexts
-**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L823) - -### `AsyncClient.emails` - -**Available in:** the `async` extra, `posthog[async]` - -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. - -Needs `secret_key`, a project secret API key with the `hog_flow:write` -scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog -Cloud app host of `host`. `email_request_timeout_seconds` and -`email_request_max_retries` configure each send. A disabled or shut-down -client sends nothing. See `posthog.emails` for setup. +### `posthog.set_context_session` ```python -AsyncClient.emails: AsyncEmails +set_context_session(session_id: str) ``` -**Correct example.** - -```python -await client.emails.send( - to="user@example.com", - template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", - distinct_id="user_123", -) -``` +Set the session ID for the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L268) +**Parameters:** -### `AsyncClient.flush` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`session_id` | `str` | The session ID to associate with the current context and its children | *required* -**Available in:** the `async` extra, `posthog[async]` +**Examples:** ```python -async flush(timeout_seconds: Optional[float] = 10) -> None +from posthog import set_context_session +set_context_session("session_123") ``` -
-Parameters (1) +
+Category -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10` | +Contexts
-**Returns** `None` +### `posthog.set_context_device_id` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1204) +```python +set_context_device_id(device_id: str) +``` -### `AsyncClient.evaluate_flags` +Set the device ID for the current context, associating all feature flag requests +in this or child contexts with the given device ID. -**Available in:** the `async` extra, `posthog[async]` +**Parameters:** -Evaluate flags remotely without blocking the event loop. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`device_id` | `str` | The device ID to associate with the current context and its children | *required* -The returned snapshot has synchronous in-memory accessors. Pass it to -`capture(flags=...)` to attach the exact values used for branching. -This client does not evaluate flags locally, so the snapshot's -`unresolved_flags` is always empty. +**Examples:** ```python -async evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations +from posthog import set_context_device_id +set_context_device_id("device_123") ``` -
-Parameters (7) +
+Category -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None` | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | -| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None` | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None` | +Contexts
-**Returns** `FeatureFlagEvaluations` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L959) - -### `AsyncClient.group_identify` - -**Available in:** the `async` extra, `posthog[async]` +### `posthog.identify_context` ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime, str]] = None, - uuid: Optional[Union[str, UUID]] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +identify_context(distinct_id: str) ``` -
-Parameters (7) - -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required** | -| `group_key`
**Type:** `str` · **Required** | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None` | -| `timestamp`
**Type:** `Optional[Union[datetime, str]]` · **Default:** `None` | -| `uuid`
**Type:** `Optional[Union[str, UUID]]` · **Default:** `None` | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None` | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None` | - -
- -**Returns** `Optional[str]` +Identify the current context with a distinct ID. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L727) +**Parameters:** -### `AsyncClient.set` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `str` | The distinct ID to associate with the current context and its children | *required* -**Available in:** the `async` extra, `posthog[async]` +**Examples:** ```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +from posthog import identify_context +identify_context("user_123") ``` -**Returns** `Optional[str]` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L701) +Identification -### `AsyncClient.set_once` +
-**Available in:** the `async` extra, `posthog[async]` +### `posthog.set_capture_exception_code_variables_context` ```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +set_capture_exception_code_variables_context(enabled: bool) ``` -**Returns** `Optional[str]` +Override code-variable capture for exceptions in the current context. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L714) +**Parameters:** -### `AsyncClient(...)` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`enabled` | `bool` | Whether exceptions captured in this context should include local variable values from stack frames. | *required* -**Available in:** the `async` extra, `posthog[async]` - -```python -AsyncClient( - project_api_key: str, - host: Optional[str] = None, - debug: bool = False, - max_queue_size: int = 10000, - send: bool = True, - on_error = None, - flush_at: int = 100, - flush_interval: float = 5.0, - gzip: bool = False, - max_retries: int = 3, - timeout: float = 15, - thread: int = 1, - disabled: bool = False, - disable_geoip: bool = True, - is_server: bool = True, - historical_migration: bool = False, - super_properties: Optional[dict[str, Any]] = None, - before_send = None, - log_captured_exceptions: bool = False, - project_root: Optional[str] = None, - capture_exception_code_variables: bool = False, - code_variables_mask_patterns = None, - code_variables_ignore_patterns = None, - code_variables_mask_url_credentials = None, - code_variables_detect_secrets = None, - in_app_modules: Optional[list[str]] = None, - capture_mode: Optional[Union[CaptureMode, str]] = None, - capture_compression: Optional[Union[CaptureCompression, str]] = None, - capture_trace_context: bool = False, - secret_key: Optional[str] = None, - personal_api_key: Optional[str] = None, - feature_flags_request_timeout_seconds: float = 3, - feature_flags_request_max_retries: int = 1, - app_host: Optional[str] = None, - email_request_timeout_seconds: float = 15, - email_request_max_retries: int = 2, -) -``` +
+Category -
-Parameters (36) - -| Parameter | -| --- | -| `project_api_key`
**Type:** `str` · **Required** | -| `host`
**Type:** `Optional[str]` · **Default:** `None` | -| `debug`
**Type:** `bool` · **Default:** `False` | -| `max_queue_size`
**Type:** `int` · **Default:** `10000` | -| `send`
**Type:** `bool` · **Default:** `True` | -| `on_error`
**Default:** `None` | -| `flush_at`
**Type:** `int` · **Default:** `100` | -| `flush_interval`
**Type:** `float` · **Default:** `5.0` | -| `gzip`
**Type:** `bool` · **Default:** `False` | -| `max_retries`
**Type:** `int` · **Default:** `3` | -| `timeout`
**Type:** `float` · **Default:** `15` | -| `thread`
**Type:** `int` · **Default:** `1` | -| `disabled`
**Type:** `bool` · **Default:** `False` | -| `disable_geoip`
**Type:** `bool` · **Default:** `True` | -| `is_server`
**Type:** `bool` · **Default:** `True` | -| `historical_migration`
**Type:** `bool` · **Default:** `False` | -| `super_properties`
**Type:** `Optional[dict[str, Any]]` · **Default:** `None` | -| `before_send`
**Default:** `None` | -| `log_captured_exceptions`
**Type:** `bool` · **Default:** `False` | -| `project_root`
**Type:** `Optional[str]` · **Default:** `None` | -| `capture_exception_code_variables`
**Type:** `bool` · **Default:** `False` | -| `code_variables_mask_patterns`
**Default:** `None` | -| `code_variables_ignore_patterns`
**Default:** `None` | -| `code_variables_mask_url_credentials`
**Default:** `None` | -| `code_variables_detect_secrets`
**Default:** `None` | -| `in_app_modules`
**Type:** `Optional[list[str]]` · **Default:** `None` | -| `capture_mode`
**Type:** `Optional[Union[CaptureMode, str]]` · **Default:** `None` | -| `capture_compression`
**Type:** `Optional[Union[CaptureCompression, str]]` · **Default:** `None` | -| `capture_trace_context`
**Type:** `bool` · **Default:** `False` | -| `secret_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `personal_api_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `feature_flags_request_timeout_seconds`
**Type:** `float` · **Default:** `3` | -| `feature_flags_request_max_retries`
**Type:** `int` · **Default:** `1` | -| `app_host`
**Type:** `Optional[str]` · **Default:** `None` | -| `email_request_timeout_seconds`
**Type:** `float` · **Default:** `15` | -| `email_request_max_retries`
**Type:** `int` · **Default:** `2` | +Contexts
-[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L102) - -### `AsyncClient.shutdown` - -**Available in:** the `async` extra, `posthog[async]` +### `posthog.set_code_variables_mask_patterns_context` ```python -async shutdown() -> None +set_code_variables_mask_patterns_context(mask_patterns: list[str]) ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1235) - -### `AsyncClient.join` - -**Available in:** the `async` extra, `posthog[async]` +Override code-variable mask patterns for exceptions in the current context. -```python -async join() -> None -``` +**Parameters:** -**Returns** `None` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`mask_patterns` | `list[str]` | Variable-name patterns whose values should be replaced with `***` when code variables are captured. | *required* -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1305) +
+Category -### `AsyncClient.get_remote_config_payload` +Contexts -**Available in:** the `async` extra, `posthog[async]` +
-Fetch and decrypt a remote-config payload without blocking the loop. +### `posthog.set_code_variables_ignore_patterns_context` ```python -async get_remote_config_payload(key: str) -> Optional[Any] +set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) ``` -
-Parameters (1) +Override code-variable ignore patterns for exceptions in the current context. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`ignore_patterns` | `list[str]` | Variable-name patterns that should be omitted entirely when code variables are captured. | *required* -**Returns** `Optional[Any]` +
+Category -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/async_client.py#L1064) +Contexts -## Module functions +
-### `posthog.start_span` +### `posthog.set_code_variables_mask_url_credentials_context` -Start a span for distributed tracing. Alpha. +```python +set_code_variables_mask_url_credentials_context(enabled: bool) +``` -Returns a span handle. Use it as a context manager to make it the active -span for the block and end it on exit (recording a raised exception on the -way out); or call `end()` yourself for a span that cannot wrap a block. -Spans started inside the block nest under it automatically. Always returns -a usable handle, even when tracing is off, so calling code never branches. +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from +captured code variables for the current context. + +### `posthog.set_code_variables_detect_secrets_context` ```python -start_span( - name: str, - kind: Optional[str] = None, - attributes: Optional[Mapping[str, Any]] = None, - parent: Union[Span, str, None] = None, - tracestate: Optional[str] = None, - start_time: Union[datetime.datetime, float, None] = None, -) -> Span +set_code_variables_detect_secrets_context(enabled: bool) ``` -
-Parameters (6) +Whether to apply entropy-based secret detection as a last-resort redaction of +high-entropy values (API keys, tokens, strong passwords) in captured code +variables for the current context. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | -| `kind`
**Type:** `Optional[str]` · **Default:** `None`
`internal` (default), `server`, `client`, `producer` or `consumer`. | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Initial attributes. | -| `parent`
**Type:** `Union[Span, str, None]` · **Default:** `None`
A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | -| `tracestate`
**Type:** `Optional[str]` · **Default:** `None`
The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | -| `start_time`
**Type:** `Union[datetime.datetime, float, None]` · **Default:** `None`
A `datetime` or epoch seconds, to backdate the span. | +
+Category -
+Contexts -**Returns** `Span` +
-**Correct example.** +### `posthog.tag` ```python -import posthog -posthog.traces = {"service_name": "checkout-api"} - -with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: - span.set_attribute("plan", user.plan) - with posthog.start_span("db.query", kind="client"): - ... - outgoing_headers = {"traceparent": span.traceparent()} +tag(name: str, value: Any) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1284) +Add a tag to the current context. -### `posthog.get_active_span` +**Parameters:** -The span that is active in the current context, or `None`. Alpha. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | The tag key | *required* +`value` | `Any` | The tag value | *required* -Only entering a span (`with posthog.start_span(...) as span:`) makes it -active; a span started manually is not. Use it to propagate the trace to -the next service: `span.traceparent()` is the header value. +**Examples:** ```python -get_active_span() -> Optional[Span] +from posthog import tag +tag("user_id", "123") ``` -**Returns** `Optional[Span]` +
+Category -**Correct example.** +Contexts -```python -span = posthog.get_active_span() -if span is not None: - headers["traceparent"] = span.traceparent() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1339) - -### `posthog.alias` +
-Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. +### `posthog.get_tags` ```python -alias( - previous_id: ID_TYPES, - distinct_id: str, - timestamp: Optional[Union[datetime.datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, -) -> Optional[str] +get_tags() -> Dict[str, Any] ``` -
-Parameters (5) - -| Parameter | -| --- | -| `previous_id`
**Type:** `ID_TYPES` · **Required**
The unique ID of the user before | -| `distinct_id`
**Type:** `str` · **Required**
The current unique id | -| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | - -
+Get all tags from the current context. -**Returns** `Optional[str]` +**Returns:** -**Details.** To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action. +Type | Description +---- | ----------- +`Dict[str, Any]` | Dict of all tags in the current context -**Correct example.** +
+Category -```python -# Alias user -from posthog import alias -alias(previous_id='distinct_id', distinct_id='alias_id') -``` +Contexts -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L685) +
### `posthog.capture` -Capture anything a user does within your system. - ```python capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` -
-Parameters (2) +Capture anything a user does within your system. -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name to specify the event | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name to specify the event | *required* +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Optional arguments including: distinct_id: Unique identifier for the user properties: Dict of event properties timestamp: When the event occurred. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this event. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. groups: Dict of group types and IDs flags: A FeatureFlagEvaluations snapshot from evaluate_flags(). The exact values from the snapshot are attached with no extra /flags request. send_feature_flags: Deprecated. Prefer flags=... from evaluate_flags(). When truthy, evaluates flags during capture and attaches them to the event. disable_geoip: Whether to disable GeoIP lookup | `{}` -**Returns** `Optional[str]` +
+Details -**Details.** Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. +Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type. + +
-**Correct example.** +**Examples:** ```python # Context and capture usage @@ -2847,9 +2349,6 @@ with new_context(): capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict ``` - -**Correct example.** - ```python # Set event properties from posthog import capture @@ -2863,10 +2362,12 @@ capture( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L466) - ### `posthog.capture_ai` +```python +capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + Capture an AI event on the dedicated AI capture endpoint. Beta: the signature is stable; operational limits (per-event size cap, @@ -2879,23 +2380,14 @@ with its own consumer pool and a higher per-event size cap, posting to the dedicated AI ingestion endpoint. The payload is sent as given — no redaction or truncation is applied here. -```python -capture_ai(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `event`
**Type:** `str` · **Required**
The event name, normally one of the `$ai_*` event names. | -| `**kwargs`
Same optional arguments as `capture()`. | +**Parameters:** -
- -**Returns** `Optional[str]` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`event` | `str` | The event name, normally one of the `$ai_*` event names. | *required* +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Same optional arguments as `capture()`. | `{}` -**Correct example.** +**Examples:** ```python from posthog import capture_ai @@ -2907,126 +2399,231 @@ uuid = capture_ai( ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L539) - -### `posthog.capture_exception` - -Capture exceptions that happen in your code. +### `posthog.set` ```python -capture_exception( - exception: Optional[ExceptionArg] = None, - **kwargs: Unpack[OptionalCaptureArgs], -) -> Optional[str] +set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] ``` -
-Parameters (2) +Set properties on a user record. -| Parameter | -| --- | -| `exception`
**Type:** `Optional[ExceptionArg]` · **Default:** `None`
The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | -| `**kwargs`
Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`**kwargs` | `Unpack[OptionalSetArgs]` | Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | `{}` -**Returns** `Optional[str]` +
+Details -**Details.** Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. +This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). + +
-**Correct example.** +**Examples:** ```python -# Capture exception -from posthog import capture_exception -try: - risky_operation() -except Exception as e: - capture_exception(e) +# Set person properties +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L725) - -### `posthog.flush` +### `posthog.set_once` -Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. +```python +set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +``` -Call `flush()` before a short-lived request or serverless invocation returns -when using the shared module-level client. Use `shutdown()` only for final -process cleanup or a client that will not be reused. Flush does not stop the -background workers or feature flag poller, and does not end open spans. +Set properties on a user record, only if they do not yet exist. -Returning does not guarantee server receipt: pending work can remain after a -timeout or span export failure, and failed events may be dropped by consumers. -Calls made directly from SDK callbacks such as `on_error` are deferred -rather than blocking the worker that invoked the callback. +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`**kwargs` | `Unpack[OptionalSetArgs]` | Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | `{}` + +
+Details + +This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. + +
+ +**Examples:** ```python -flush(timeout_seconds: Optional[float] = 10) -> None +# Set property once +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) + +``` + +### `posthog.group_identify` + +```python +group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, Any]] = None, timestamp: Optional[Union[datetime.datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None, distinct_id: Optional[ID_TYPES] = None) -> Optional[str] +``` + +Set properties on a group. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`group_type` | `str` | Type of your group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`group_key` | `str` | Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | *required* +`properties` | `Optional[Dict[str, Any]]` | Properties to set on the group | `None` +`timestamp` | `Optional[Union[datetime, str]]` | Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | Optional UUID for the event | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`distinct_id` | `Optional[ID_TYPES]` | Optional distinct ID of the user performing the action | `None` + +**Examples:** + +```python +# Group identify +from posthog import group_identify +group_identify('company', 'company_id_in_your_db', { + 'name': 'Awesome Inc.', + 'employees': 11 +}) +``` + +### `posthog.alias` + +```python +alias(previous_id: ID_TYPES, distinct_id: str, timestamp: Optional[Union[datetime.datetime, str]] = None, uuid: Optional[str] = None, disable_geoip: Optional[bool] = None) -> Optional[str] ``` -
-Parameters (1) +Associate user behaviour before and after they e.g. register, login, or perform some other identifying action. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`previous_id` | `ID_TYPES` | The unique ID of the user before | *required* +`distinct_id` | `str` | The current unique id | *required* +`timestamp` | `Optional[Union[datetime, str]]` | Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | `None` +`uuid` | `Optional[str]` | Optional UUID for the event | `None` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` + +
+Details -| Parameter | -| --- | -| `timeout_seconds`
**Type:** `Optional[float]` · **Default:** `10`
Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | +To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call. This will allow you to answer questions like "Which marketing channels leads to users churning after a month?" or "What do users do on our website before signing up?". Particularly useful for associating user behaviour before and after they e.g. register, login, or perform some other identifying action.
-**Returns** `None` +**Examples:** + +```python +# Alias user +from posthog import alias +alias(previous_id='distinct_id', distinct_id='alias_id') +``` -**Correct example.** +### `posthog.capture_exception` ```python -import posthog -posthog.capture('event_name', distinct_id='user_id') -# Before a serverless invocation returns; keep the global client open. -posthog.flush(timeout_seconds=10) +capture_exception(exception: Optional[ExceptionArg] = None, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +``` + +Capture exceptions that happen in your code. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`exception` | `Optional[ExceptionArg]` | The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` | `None` +`**kwargs` | `Unpack[OptionalCaptureArgs]` | Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. Overriding reserved exception properties through `properties` is deprecated and will stop working in the next major version. | `{}` + +
+Details + +Capture exception is idempotent - if it is called twice with the same exception instance, only a occurrence will be tracked in posthog. This is because, generally, contexts will cause exceptions to be captured automatically. However, to ensure you track an exception, if you catch and do not re-raise it, capturing it manually is recommended, unless you are certain it will have crossed a context boundary (e.g. by existing a `with posthog.new_context():` block already). If the passed exception was raised and caught, the captured stack trace will consist of every frame between where the exception was raised and the point at which it is captured (the "traceback"). If the passed exception was never raised, e.g. if you call `posthog.capture_exception(ValueError("Some Error"))`, the stack trace captured will be the full stack trace at the moment the exception was captured. Note that heavy use of contexts will lead to truncated stack traces, as the exception will be captured by the context entered most recently, which may not be the point you catch the exception for the final time in your code. It's recommended to use contexts sparingly, for this reason. `capture_exception` takes the same set of optional arguments as `capture`. + +
+ +**Examples:** + +```python +# Capture exception +from posthog import capture_exception +try: + risky_operation() +except Exception as e: + capture_exception(e) +``` + +### `posthog.feature_enabled` + +```python +feature_enabled(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[bool] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1223) +Use feature flags to enable or disable features for users. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` + +
+Details + +You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. + +
+ +**Examples:** + +```python +# Boolean feature flag +from posthog import feature_enabled, get_feature_flag_payload +is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') +if is_my_flag_enabled: + matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +``` ### `posthog.get_feature_flag` +```python +get_feature_flag(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FlagValue] +``` + Get feature flag variant for users. Used with experiments. -```python -get_feature_flag( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FlagValue] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping from group type to group key | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties in format { group_type_name: { group_properties } } | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping from group type to group key | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties in format { group_type_name: { group_properties } } | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`send_feature_flag_events` | `bool` | Whether to send feature flag events | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` + +
+Details -**Returns** `Optional[FlagValue]` +`groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. -**Details.** `groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}. +
-**Correct example.** +**Examples:** ```python # Multivariate feature flag @@ -3036,54 +2633,48 @@ if enabled_variant == 'variant-key': matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L809) +### `posthog.get_all_flags` -### `posthog.get_feature_flag_payload` +```python +get_all_flags(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None, flag_keys_to_evaluate: Optional[list[str]] = None) -> Optional[dict[str, FlagValue]] +``` -Get the payload associated with a feature flag value. +Get all flags for a given user. -Deprecated for new code. Prefer `evaluate_flags()` and -`flags.get_flag_payload(key)` so flag evaluation happens once per request. +**Parameters:** -```python -get_feature_flag_payload( - key: str, - distinct_id: ID_TYPES, - match_value: Optional[FlagValue] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[object] -``` - -
-Parameters (10) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
Optional flag value to use when selecting a payload. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The user's distinct ID | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Groups mapping | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | Optional list of flag keys to evaluate (evaluates all if None) | `None` + +
+Details + +Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False.
-**Returns** `Optional[object]`. The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. +**Examples:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L965) +```python +# All flags for user +from posthog import get_all_flags +get_all_flags('distinct_id_of_your_user') +``` ### `posthog.get_feature_flag_result` +```python +get_feature_flag_result(key: str, distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[FeatureFlagResult] +``` + Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: @@ -3093,136 +2684,123 @@ This method evaluates a feature flag and returns a FeatureFlagResult object cont - key: The flag key - reason: Why the flag was enabled/disabled +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send a $feature_flag_called event. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` + Example: -``python +```python result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') if result and result.enabled: # Use the variant and payload print(f"Variant: {result.variant}") print(f"Payload: {result.payload}") -`` - -```python -get_feature_flag_result( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[FeatureFlagResult] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send a $feature_flag_called event. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | +``` -
+### `posthog.get_feature_flag_payload` + +```python +get_feature_flag_payload(key: str, distinct_id: ID_TYPES, match_value: Optional[FlagValue] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, send_feature_flag_events: bool = True, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None) -> Optional[object] +``` -**Returns** `Optional[FeatureFlagResult]` +Get the payload associated with a feature flag value. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L908) +Deprecated for new code. Prefer `evaluate_flags()` and +`flags.get_flag_payload(key)` so flag evaluation happens once per request. -### `posthog.get_all_flags` +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`match_value` | `Optional[FlagValue]` | Optional flag value to use when selecting a payload. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`send_feature_flag_events` | `bool` | Whether to send a $feature_flag_called event. | `True` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` + +**Returns:** + +Type | Description +---- | ----------- +`Optional[object]` | The payload associated with the matched feature flag value, or None. +`Optional[object]` | This function returns the payload only, not the FeatureFlagResult wrapper +`Optional[object]` | used internally to compute it. -Get all flags for a given user. +### `posthog.get_remote_config_payload` ```python -get_all_flags( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, -) -> Optional[dict[str, FlagValue]] -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate (evaluates all if None) | +get_remote_config_payload(key: str) +``` -
+Get the payload for a remote config feature flag. -**Returns** `Optional[dict[str, FlagValue]]` +**Parameters:** -**Details.** Flags are key-value pairs where the key is the flag key and the value is the flag variant, or True, or False. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The key of the feature flag | *required* -**Correct example.** +**Returns:** -```python -# All flags for user -from posthog import get_all_flags -get_all_flags('distinct_id_of_your_user') -``` +Type | Description +---- | ----------- + | The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L861) +
+Note + +Requires secret_key to be set for authentication + +
### `posthog.get_all_flags_and_payloads` +```python +get_all_flags_and_payloads(distinct_id: ID_TYPES, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, device_id: Optional[str] = None, flag_keys_to_evaluate: Optional[list[str]] = None) -> FlagsAndPayloads +``` + Get all feature flag values and payloads for a user. -```python -get_all_flags_and_payloads( - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, - flag_keys_to_evaluate: Optional[list[str]] = None, -) -> FlagsAndPayloads -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags. | -| `flag_keys_to_evaluate`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list of flag keys to evaluate. Evaluates all flags when omitted. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `ID_TYPES` | The user's distinct ID. | *required* +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | Whether to evaluate only locally. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`device_id` | `Optional[str]` | Optional device ID override for experience-continuity flags. | `None` +`flag_keys_to_evaluate` | `Optional[list[str]]` | Optional list of flag keys to evaluate. Evaluates all flags when omitted. | `None` -**Returns** `FlagsAndPayloads`. A dict with `featureFlags` and `featureFlagPayloads` entries. +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1037) +Type | Description +---- | ----------- +`FlagsAndPayloads` | A dict with `featureFlags` and `featureFlagPayloads` entries. ### `posthog.evaluate_flags` +```python +evaluate_flags(distinct_id: Optional[ID_TYPES] = None, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, only_evaluate_locally: bool = False, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +``` + Evaluate all feature flags for a user in a single call and return a `FeatureFlagEvaluations` snapshot. Branch on `.is_enabled()` / `.get_flag()` and pass the same snapshot to `capture()` via the @@ -3232,38 +2810,20 @@ Prefer this over repeated `get_feature_flag()` calls and over `capture(send_feature_flags=True)` — it consolidates flag evaluation into a single `/flags` request per incoming request. -```python -evaluate_flags( - distinct_id: Optional[ID_TYPES] = None, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - disable_geoip: Optional[bool] = None, - flag_keys: Optional[list[str]] = None, - device_id: Optional[str] = None, -) -> FeatureFlagEvaluations -``` - -
-Parameters (8) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Mapping of group type to group key. | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties to use for evaluation. | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties keyed by group type. | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup. | -| `flag_keys`
**Type:** `Optional[list[str]]` · **Default:** `None`
Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | - -
+**Parameters:** -**Returns** `FeatureFlagEvaluations` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | `Optional[ID_TYPES]` | The user's distinct ID. If `None`, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. | `None` +`groups` | `Optional[Mapping[str, Union[str, int]]]` | Mapping of group type to group key. | `None` +`person_properties` | `Optional[Dict[str, Any]]` | Person properties to use for evaluation. | `None` +`group_properties` | `Optional[Dict[str, Dict[str, Any]]]` | Group properties keyed by group type. | `None` +`only_evaluate_locally` | `bool` | If `True`, never fall back to remote evaluation and omit flags that cannot be evaluated locally. The snapshot's `unresolved_flags` lists them with a reason. | `False` +`disable_geoip` | `Optional[bool]` | Whether to disable GeoIP lookup. | `None` +`flag_keys` | `Optional[list[str]]` | Optional list that scopes local evaluation, the underlying `/flags` request, and the returned snapshot. When omitted or `None`, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per `evaluate_flags` call unless `only_evaluate_locally` is `True`. If the server also does not know the key, it is omitted from the snapshot. | `None` +`device_id` | `Optional[str]` | Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. | `None` -**Correct example.** +**Examples:** ```python from posthog import evaluate_flags, capture @@ -3273,1578 +2833,872 @@ if flags.is_enabled("new-dashboard"): capture("page_viewed", distinct_id="user_123", flags=flags) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1079) - -### `posthog.group_identify` - -Set properties on a group. +### `posthog.feature_flag_definitions` ```python -group_identify( - group_type: str, - group_key: str, - properties: Optional[Dict[str, Any]] = None, - timestamp: Optional[Union[datetime.datetime, str]] = None, - uuid: Optional[str] = None, - disable_geoip: Optional[bool] = None, - distinct_id: Optional[ID_TYPES] = None, -) -> Optional[str] +feature_flag_definitions() ``` -
-Parameters (7) +Returns loaded feature flags. -| Parameter | -| --- | -| `group_type`
**Type:** `str` · **Required**
Type of your group. Required - the call is dropped with a warning if it is missing or empty. | -| `group_key`
**Type:** `str` · **Required**
Unique identifier of the group. Required - the call is dropped with a warning if it is missing or empty. | -| `properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Properties to set on the group | -| `timestamp`
**Type:** `Optional[Union[datetime.datetime, str]]` · **Default:** `None`
Optional timestamp for the event. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `Optional[str]` · **Default:** `None`
Optional UUID for the event | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `distinct_id`
**Type:** `Optional[ID_TYPES]` · **Default:** `None`
Optional distinct ID of the user performing the action | +
+Details -
+Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. -**Returns** `Optional[str]` +
-**Correct example.** +**Examples:** ```python -# Group identify -from posthog import group_identify -group_identify('company', 'company_id_in_your_db', { - 'name': 'Awesome Inc.', - 'employees': 11 -}) +from posthog import feature_flag_definitions +definitions = feature_flag_definitions() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L637) - -### `posthog.set` - -Set properties on a user record. +### `posthog.get_feature_flag_evaluation_runtime` ```python -set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | +Return where a locally loaded feature flag is meant to be evaluated. -
+
+Details -**Returns** `Optional[str]` +Reads the `evaluation_runtime` each flag definition carries, so no extra +request is made. Returns `None` when local evaluation has not loaded a +definition for this key. A definition that carries no runtime reports +`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. -**Details.** This will overwrite previous people property values. Generally operates similar to `capture`, with distinct_id being an optional argument, defaulting to the current context's distinct ID. If there is no context-level distinct ID, and no override distinct_id is passed, this function will do nothing. Context tags are folded into $set properties, so tagging the current context and then calling `set` will cause those tags to be set on the user (unlike capture, which causes them to just be set on the event). +
-**Correct example.** +**Examples:** ```python -# Set person properties -from posthog import set -set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime +runtime = get_feature_flag_evaluation_runtime("my-flag") ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L573) +
+Category -### `posthog.set_once` +Feature flags -Set properties on a user record, only if they do not yet exist. +
+ +### `posthog.get_feature_flag_keys_by_evaluation_runtime` ```python -set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str] +get_feature_flag_keys_by_evaluation_runtime(evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str]) -> list[str] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `**kwargs`
Optional arguments including: distinct_id: Unique identifier for the user. Falls back to the context distinct ID; if none exists, this call does nothing. properties: Dict of person properties to set only once. timestamp: When the properties were set. UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. uuid: Unique identifier for this operation. If omitted, one is generated and returned. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. disable_geoip: Whether to disable GeoIP lookup. | +Return the keys of locally loaded flags that a runtime can evaluate. -
+
+Details -**Returns** `Optional[str]` +A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so +it is returned for `CLIENT` and for `SERVER`. Use this to decide which +flags to hand to a browser when a backend serves flags to its own +frontend. -**Details.** This will not overwrite previous people property values, unlike `set`. Otherwise, operates in an identical manner to `set`. +
-**Correct example.** +**Examples:** ```python -# Set property once -from posthog import set_once -set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) +from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime +client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L605) - -### `posthog.feature_enabled` - -Use feature flags to enable or disable features for users. +
+Category -```python -feature_enabled( - key: str, - distinct_id: ID_TYPES, - groups: Optional[Mapping[str, Union[str, int]]] = None, - person_properties: Optional[Dict[str, Any]] = None, - group_properties: Optional[Dict[str, Dict[str, Any]]] = None, - only_evaluate_locally: bool = False, - send_feature_flag_events: bool = True, - disable_geoip: Optional[bool] = None, - device_id: Optional[str] = None, -) -> Optional[bool] -``` - -
-Parameters (9) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key | -| `distinct_id`
**Type:** `ID_TYPES` · **Required**
The user's distinct ID | -| `groups`
**Type:** `Optional[Mapping[str, Union[str, int]]]` · **Default:** `None`
Groups mapping | -| `person_properties`
**Type:** `Optional[Dict[str, Any]]` · **Default:** `None`
Person properties | -| `group_properties`
**Type:** `Optional[Dict[str, Dict[str, Any]]]` · **Default:** `None`
Group properties | -| `only_evaluate_locally`
**Type:** `bool` · **Default:** `False`
Whether to evaluate only locally | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether to send feature flag events | -| `disable_geoip`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to disable GeoIP lookup | -| `device_id`
**Type:** `Optional[str]` · **Default:** `None`
Optional device ID override for experience-continuity flags | +Feature flags
-**Returns** `Optional[bool]` - -**Details.** You can call `posthog.load_feature_flags()` before to make sure you're not doing unexpected requests. - -**Correct example.** +### `posthog.load_feature_flags` ```python -# Boolean feature flag -from posthog import feature_enabled, get_feature_flag_payload -is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user') -if is_my_flag_enabled: - matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user') +load_feature_flags() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L757) - -### `posthog.setup` - -Create or return the global PostHog client configured by module settings. +Load feature flag definitions from PostHog. -Most applications should either instantiate `Posthog` directly or set -`posthog.api_key`/other module settings before calling top-level helpers. -`setup()` is called automatically by global APIs such as `capture()`. +**Examples:** ```python -setup() -> Client +from posthog import load_feature_flags +load_feature_flags() ``` -**Returns** `Client`. The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. +### `posthog.flush` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1394) +```python +flush(timeout_seconds: Optional[float] = 10) -> None +``` -### `posthog.join` +Attempt immediate delivery of queued events and ended spans, keeping the global client reusable. -Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. +Call `flush()` before a short-lived request or serverless invocation returns +when using the shared module-level client. Use `shutdown()` only for final +process cleanup or a client that will not be reused. Flush does not stop the +background workers or feature flag poller, and does not end open spans. -Failed or undrainable events may be dropped and reported through logging or -`on_error`; returning does not guarantee server receipt. Lifecycle cleanup -is attempted once, and cleanup failures are logged without retry. - -```python -join() -> None -``` - -**Returns** `None` - -**Correct example.** - -```python -from posthog import join -join() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1265) - -### `posthog.shutdown` - -Attempt final delivery and permanently shut down the global client. - -Call this for final process cleanup, not at the end of each request or -serverless invocation that shares the module-level client. Use `flush()` -before returning from those invocations instead. Shutdown closes capture -lanes, stops background workers and the feature flag poller, and tears down -integrations. The global client is not recreated automatically after shutdown. - -This normally blocks until queued events have been attempted and cleanup -finishes. Failed or undrainable events may be dropped and reported through -logging or `on_error`; returning does not guarantee server receipt. Event -draining has no timeout. Queued spans get a final flush with up to 30 seconds -waiting for an in-flight flush, then a fresh 30-second drain budget; the last -HTTP request is not cut short. Unsent queued spans and still-open spans are -discarded with a warning. -Lifecycle cleanup is attempted once, and cleanup failures are logged without -retry. Calls made directly from SDK callbacks such as `on_error` are deferred -to avoid deadlocking the worker. If blocking completion is required, signal an application-owned -thread, return from the callback, and call `shutdown()` from that thread. -Do not wait inside a callback for another thread or task calling a lifecycle -method. - -```python -shutdown() -> None -``` - -**Returns** `None` - -**Correct example.** - -```python -from posthog import shutdown -shutdown() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1359) - -### `posthog.feature_flag_definitions` - -Returns loaded feature flags. - -```python -feature_flag_definitions() -``` - -**Details.** Returns loaded feature flags, if any. Helpful for debugging what flag information you have loaded. - -**Correct example.** - -```python -from posthog import feature_flag_definitions -definitions = feature_flag_definitions() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1142) - -### `posthog.load_feature_flags` - -Load feature flag definitions from PostHog. - -```python -load_feature_flags() -``` - -**Correct example.** - -```python -from posthog import load_feature_flags -load_feature_flags() -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1208) - -### `posthog.new_context` - -Create a new context scope that will be active for the duration of the with block. - -```python -new_context( - fresh: bool = False, - capture_exceptions: Optional[bool] = None, - client: Optional[Client] = None, -) -``` - -
-Parameters (3) - -| Parameter | -| --- | -| `fresh`
**Type:** `bool` · **Default:** `False`
Whether to start with a fresh context (default: False) | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture exceptions raised within the context. If omitted, defaults to the relevant client's exception autocapture setting. | -| `client`
**Type:** `Optional[Client]` · **Default:** `None`
Optional Posthog client instance to use for this context (default: None) | - -
- -**Correct example.** - -```python -from posthog import new_context, tag, capture -with new_context(): - tag("request_id", "123") - capture("event_name", properties={"property": "value"}) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L98) - -### `posthog.scoped` - -Decorator that creates a new context for the function. - -```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `fresh`
**Default:** `False`
Whether to start with a fresh context (default: False) | -| `capture_exceptions`
**Type:** `Optional[bool]` · **Default:** `None`
Whether to capture and track exceptions with posthog error tracking. If omitted, defaults to the global exception autocapture setting. | - -
- -**Correct example.** - -```python -from posthog import scoped, tag, capture -@scoped() -def process_payment(payment_id): - tag("payment_id", payment_id) - capture("payment_started") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L127) - -### `posthog.set_context_session` - -Set the session ID for the current context. - -```python -set_context_session(session_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `session_id`
**Type:** `str` · **Required**
The session ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import set_context_session -set_context_session("session_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L150) - -### `posthog.set_context_device_id` - -Set the device ID for the current context, associating all feature flag requests -in this or child contexts with the given device ID. - -```python -set_context_device_id(device_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `device_id`
**Type:** `str` · **Required**
The device ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import set_context_device_id -set_context_device_id("device_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L169) - -### `posthog.identify_context` - -Identify the current context with a distinct ID. - -```python -identify_context(distinct_id: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `distinct_id`
**Type:** `str` · **Required**
The distinct ID to associate with the current context and its children | - -
- -**Correct example.** - -```python -from posthog import identify_context -identify_context("user_123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L189) - -### `posthog.set_capture_exception_code_variables_context` - -Override code-variable capture for exceptions in the current context. - -```python -set_capture_exception_code_variables_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required**
Whether exceptions captured in this context should include local variable values from stack frames. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L208) - -### `posthog.set_code_variables_mask_patterns_context` - -Override code-variable mask patterns for exceptions in the current context. - -```python -set_code_variables_mask_patterns_context(mask_patterns: list[str]) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `mask_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns whose values should be replaced with `***` when code variables are captured. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L222) - -### `posthog.set_code_variables_ignore_patterns_context` - -Override code-variable ignore patterns for exceptions in the current context. - -```python -set_code_variables_ignore_patterns_context(ignore_patterns: list[str]) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `ignore_patterns`
**Type:** `list[str]` · **Required**
Variable-name patterns that should be omitted entirely when code variables are captured. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L236) - -### `posthog.set_code_variables_mask_url_credentials_context` - -Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from -captured code variables for the current context. - -```python -set_code_variables_mask_url_credentials_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required** | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L250) - -### `posthog.set_code_variables_detect_secrets_context` - -Whether to apply entropy-based secret detection as a last-resort redaction of -high-entropy values (API keys, tokens, strong passwords) in captured code -variables for the current context. - -```python -set_code_variables_detect_secrets_context(enabled: bool) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `enabled`
**Type:** `bool` · **Required** | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L258) - -### `posthog.tag` - -Add a tag to the current context. - -```python -tag(name: str, value: Any) -``` - -
-Parameters (2) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The tag key | -| `value`
**Type:** `Any` · **Required**
The tag value | - -
- -**Correct example.** - -```python -from posthog import tag -tag("user_id", "123") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L270) - -### `posthog.get_tags` - -Get all tags from the current context. - -```python -get_tags() -> Dict[str, Any] -``` - -**Returns** `Dict[str, Any]`. Dict of all tags in the current context - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L290) - -### `posthog.get_remote_config_payload` - -Get the payload for a remote config feature flag. - -```python -get_remote_config_payload(key: str) -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The key of the feature flag | - -
- -**Returns** . The payload associated with the feature flag. If payload is encrypted, the return value will be decrypted - -**Note.** Requires secret_key to be set for authentication - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1017) - -### `posthog.get_feature_flag_evaluation_runtime` - -Return where a locally loaded feature flag is meant to be evaluated. - -```python -get_feature_flag_evaluation_runtime(key: str) -> Optional[FeatureFlagEvaluationRuntime] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[FeatureFlagEvaluationRuntime]` - -**Details.** Reads the `evaluation_runtime` each flag definition carries, so no extra -request is made. Returns `None` when local evaluation has not loaded a -definition for this key. A definition that carries no runtime reports -`FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. - -**Correct example.** - -```python -from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_runtime -runtime = get_feature_flag_evaluation_runtime("my-flag") -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1160) - -### `posthog.get_feature_flag_keys_by_evaluation_runtime` - -Return the keys of locally loaded flags that a runtime can evaluate. - -```python -get_feature_flag_keys_by_evaluation_runtime( - evaluation_runtime: Union[FeatureFlagEvaluationRuntime, str], -) -> list[str] -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `evaluation_runtime`
**Type:** `Union[FeatureFlagEvaluationRuntime, str]` · **Required** | - -
- -**Returns** `list[str]` - -**Details.** A flag set to `FeatureFlagEvaluationRuntime.ALL` suits either runtime, so -it is returned for `CLIENT` and for `SERVER`. Use this to decide which -flags to hand to a browser when a backend serves flags to its own -frontend. - -**Correct example.** - -```python -from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evaluation_runtime -client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) -``` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/__init__.py#L1184) - -## Configs - -
-Settings (7) - -| Setting | -| --- | -| `POSTHOG_MW_CLIENT`
**Where:** Django settings
client used for automatic exception capture, or the global client. This does not redirect events explicitly captured through other clients. | -| `POSTHOG_MW_CAPTURE_EXCEPTIONS`
**Where:** Django settings
`False` enables context enrichment only; `True` enables automatic exception capture; `None` inherits the effective client's `enable_exception_autocapture`. When omitted, the legacy default is `True`. | -| `POSTHOG_MW_REQUEST_FILTER`
**Where:** Django settings
a callback receiving the request. Returning `False` disables both enrichment and automatic exception capture for that request. | -| `POSTHOG_MW_EXTRA_PROPERTIES`
**Where:** Django settings
a callback returning additional event properties. | -| `POSTHOG_MW_CAPTURE_TRACING_HEADERS`
**Where:** Django settings
read PostHog identity and session headers as request-scoped analytics context (default: `True`). Explicit capture IDs and event properties take precedence. These values are never authentication or authorization. Authenticated Django user identity remains the fallback when no usable header ID is available or header capture is disabled. | -| `POSTHOG_MW_TRUST_TRACING_HEADERS`
**Where:** Django settings
deprecated alias for `POSTHOG_MW_CAPTURE_TRACING_HEADERS`; the capture-named setting takes precedence. | -| `POSTHOG_MW_PROPERTIES_MAP`
**Where:** Django settings
an optional callback transforming request properties. | - -
- -## Types - -### `OptionalCaptureArgs` - -Optional arguments for the capture method. - -
-Fields (8) - -| Field | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to track with the event | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `groups`
**Type:** `NotRequired[Optional[Dict[str, str]]]`
Group identifiers to associate with this event (format: {group_type: group_key}) | -| `flags`
**Type:** `NotRequired[Optional[FeatureFlagEvaluations]]`
A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | -| `send_feature_flags`
**Type:** `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]`
Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this event. Defaults to False. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L26) - -### `OptionalSetArgs` - -Optional arguments for the set method. - -
-Fields (5) - -| Field | -| --- | -| `distinct_id`
**Type:** `NotRequired[Optional[ID_TYPES]]`
Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | -| `properties`
**Type:** `NotRequired[Optional[Dict[str, Any]]]`
Dictionary of properties to set on the person | -| `timestamp`
**Type:** `NotRequired[Optional[Union[datetime, str]]]`
When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | -| `uuid`
**Type:** `NotRequired[Optional[Union[str, UUID]]]`
Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | -| `disable_geoip`
**Type:** `NotRequired[Optional[bool]]`
Whether to disable GeoIP lookup for this operation. Defaults to False. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/args.py#L70) - -### `FeatureFlagEvaluations` +Returning does not guarantee server receipt: pending work can remain after a +timeout or span export failure, and failed events may be dropped by consumers. +Calls made directly from SDK callbacks such as `on_error` are deferred +rather than blocking the worker that invoked the callback. -A point-in-time snapshot of feature flag evaluations for a single distinct_id. +**Parameters:** -Returned by `Client.evaluate_flags` — branch on `is_enabled` / -`get_flag` and pass the same object to `Client.capture` via the -`flags` option so the captured event carries the exact flag values the code -branched on. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`timeout_seconds` | `Optional[float]` | Seconds to wait for event queues to drain, shared across event lanes. Defaults to 10 seconds. Pass `None` to wait without a time limit; this does not guarantee successful delivery. Queued spans flush concurrently, waiting up to this many seconds for an in-flight flush before starting a fresh drain budget. A lock wait timeout leaves the in-flight flush to finish. At least one span request is attempted after acquiring the lock, even with no budget left; retriable failures are retried after backoff while budget remains, with one last attempt at the deadline. The last span request is not cut short and is bounded by the client's `timeout` in seconds, so this is not a strict wall-clock limit for the whole call. With `None`, a retriable span failure is left for a later flush rather than retried within this call. | `10` -Example: +**Examples:** ```python -flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) -if flags.is_enabled("new-dashboard"): - render_new_dashboard() -posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +import posthog +posthog.capture('event_name', distinct_id='user_id') +# Before a serverless invocation returns; keep the global client open. +posthog.flush(timeout_seconds=10) ``` -To narrow the set of flags that get attached to a captured event, use the in-memory -helpers `only` and `only_accessed`. To narrow the set of flags requested -from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. - -#### `FeatureFlagEvaluations.is_enabled` - -Return whether the flag is enabled. Fires `$feature_flag_called` on the -first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. - -A flag that has a value always wins over `default_value`, including a -disabled flag, which returns `False` even when `default_value=True`. +### `posthog.join` ```python -is_enabled( - key: str, - default_value: bool = False, - send_feature_flag_events: bool = True, -) -> bool +join() -> None ``` -
-Parameters (3) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The feature flag key. | -| `default_value`
**Type:** `bool` · **Default:** `False`
Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True`
Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | - -
- -**Returns** `bool` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L164) - -#### `FeatureFlagEvaluations.get_flag` - -Return the flag value. Fires `$feature_flag_called` on first access. +Attempt to process queued events and stop the client's background workers. Use `shutdown()` directly in most cases. -Returns the variant string for multivariate flags, `True` for enabled flags -without a variant, `False` for disabled flags, and `None` for flags that -were not returned by the evaluation. +Failed or undrainable events may be dropped and reported through logging or +`on_error`; returning does not guarantee server receipt. Lifecycle cleanup +is attempted once, and cleanup failures are logged without retry. -Pass `send_feature_flag_events=False` to skip the event for this read, as -with `is_enabled`. +**Examples:** ```python -get_flag(key: str, send_feature_flag_events: bool = True) -> Optional[FlagValue] +from posthog import join +join() ``` -
-Parameters (2) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `send_feature_flag_events`
**Type:** `bool` · **Default:** `True` | - -
- -**Returns** `Optional[FlagValue]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L191) - -#### `FeatureFlagEvaluations.get_flag_payload` - -Return the payload associated with a flag. - -Does not count as an access for `only_accessed` and does not fire any event. +### `posthog.start_span` ```python -get_flag_payload(key: str) -> Optional[Any] +start_span(name: str, *, kind: Optional[str] = None, attributes: Optional[Mapping[str, Any]] = None, parent: Union[Span, str, None] = None, tracestate: Optional[str] = None, start_time: Union[datetime.datetime, float, None] = None) -> Span ``` -
-Parameters (1) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | - -
- -**Returns** `Optional[Any]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L211) - -#### `FeatureFlagEvaluations.only_accessed` - -Return a filtered copy containing only flags accessed via `is_enabled` -or `get_flag` before this call. - -Order-dependent: if nothing has been accessed yet, the returned snapshot is -empty. The method honors its name — pre-access if you want a populated result. - -```python -only_accessed() -> FeatureFlagEvaluations -``` +Start a span for distributed tracing. Alpha. -**Returns** `FeatureFlagEvaluations` +Returns a span handle. Use it as a context manager to make it the active +span for the block and end it on exit (recording a raised exception on the +way out); or call `end()` yourself for a span that cannot wrap a block. +Spans started inside the block nest under it automatically. Always returns +a usable handle, even when tracing is off, so calling code never branches. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L219) +**Parameters:** -#### `FeatureFlagEvaluations.only` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`name` | `str` | A low-cardinality operation name, e.g. `GET /users/:id`. Variable values belong in attributes, not the name. | *required* +`kind` | `Optional[str]` | `internal` (default), `server`, `client`, `producer` or `consumer`. | `None` +`attributes` | `Optional[Mapping[str, Any]]` | Initial attributes. | `None` +`parent` | `Union[Span, str, None]` | A span handle, or an inbound W3C `traceparent` header value to continue a remote trace. Defaults to the active span. | `None` +`tracestate` | `Optional[str]` | The inbound `tracestate` header accompanying a `traceparent` string `parent`; preserved and propagated. | `None` +`start_time` | `Union[datetime, float, None]` | A `datetime` or epoch seconds, to backdate the span. | `None` -Return a filtered copy containing only flags with the given keys. Keys that -are not present in the evaluation are dropped and logged as a warning. +**Examples:** ```python -only(keys: List[str]) -> FeatureFlagEvaluations -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `keys`
**Type:** `List[str]` · **Required** | - -
- -**Returns** `FeatureFlagEvaluations` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L229) - -#### `FeatureFlagEvaluations.keys` - -Return the flag keys that are part of this evaluation. +import posthog +posthog.traces = {"service_name": "checkout-api"} -```python -FeatureFlagEvaluations.keys: List[str] +with posthog.start_span("POST /checkout", parent=request.headers.get("traceparent")) as span: + span.set_attribute("plan", user.plan) + with posthog.start_span("db.query", kind="client"): + ... + outgoing_headers = {"traceparent": span.traceparent()} ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L249) - -#### `FeatureFlagEvaluations.unresolved_flags` - -Return a read-only mapping of flag key to the reason local evaluation -left it without a value. - -A flag is listed when it has a loaded local definition, was in the requested -scope, was inconclusive locally, and no remote value filled the gap. Listed -flags are not part of `keys`, and reading one reports the -`local_evaluation_inconclusive` error instead of `flag_missing`. Reading -this mapping does not count as an access and does not fire any event. -Snapshots returned by `only` and `only_accessed`, and by -`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no -entries. +### `posthog.get_active_span` ```python -FeatureFlagEvaluations.unresolved_flags: Mapping[str, UnresolvedFlagReason] +get_active_span() -> Optional[Span] ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L254) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flag_evaluations.py#L110) - -### `FeatureFlagResult` - -The result of calling a feature flag which includes the flag result, variant, and payload. - -
-Fields (5) - -| Field | -| --- | -| `key`
**Type:** `str`
The unique identifier of the feature flag. | -| `enabled`
**Type:** `bool`
Whether the feature flag is enabled for the current context. | -| `variant`
**Type:** `Optional[str]`
The variant value if the flag is enabled and has variants, None otherwise. | -| `payload`
**Type:** `Optional[Any]`
Additional data associated with the feature flag, if any. | -| `reason`
**Type:** `Optional[str]`
A description of why the flag was enabled or disabled, if available. | - -
+The span that is active in the current context, or `None`. Alpha. -#### `FeatureFlagResult.get_value` +Only entering a span (`with posthog.start_span(...) as span:`) makes it +active; a span started manually is not. Use it to propagate the trace to +the next service: `span.traceparent()` is the header value. -Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. -This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. +**Examples:** ```python -get_value() -> FlagValue +span = posthog.get_active_span() +if span is not None: + headers["traceparent"] = span.traceparent() ``` -**Returns** `FlagValue`. Either a string variant or boolean value representing the flag's state. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L582) - -#### `FeatureFlagResult.from_value_and_payload` - -Creates a FeatureFlagResult from a flag value and payload. +### `posthog.shutdown` ```python -from_value_and_payload( - key: str, - value: Union[FlagValue, None], - payload: Any, -) -> Union[FeatureFlagResult, None] +shutdown() -> None ``` -
-Parameters (3) - -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required**
The unique identifier of the feature flag. | -| `value`
**Type:** `Union[FlagValue, None]` · **Required**
The value of the flag (string variant or boolean). | -| `payload`
**Type:** `Any` · **Required**
Additional data associated with the feature flag. | +Attempt final delivery and permanently shut down the global client. -
+Call this for final process cleanup, not at the end of each request or +serverless invocation that shares the module-level client. Use `flush()` +before returning from those invocations instead. Shutdown closes capture +lanes, stops background workers and the feature flag poller, and tears down +integrations. The global client is not recreated automatically after shutdown. -**Returns** `Union[FeatureFlagResult, None]`. Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. +This normally blocks until queued events have been attempted and cleanup +finishes. Failed or undrainable events may be dropped and reported through +logging or `on_error`; returning does not guarantee server receipt. Event +draining has no timeout. Queued spans get a final flush with up to 30 seconds +waiting for an in-flight flush, then a fresh 30-second drain budget; the last +HTTP request is not cut short. Unsent queued spans and still-open spans are +discarded with a warning. +Lifecycle cleanup is attempted once, and cleanup failures are logged without +retry. Calls made directly from SDK callbacks such as `on_error` are deferred +to avoid deadlocking the worker. If blocking completion is required, signal an application-owned +thread, return from the callback, and call `shutdown()` from that thread. +Do not wait inside a callback for another thread or task calling a lifecycle +method. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L592) +**Examples:** -#### `FeatureFlagResult.from_flag_details` +```python +from posthog import shutdown +shutdown() +``` -Create a FeatureFlagResult from a FeatureFlag object. +### `posthog.setup` ```python -from_flag_details( - details: Union[FeatureFlag, None], - override_match_value: Optional[FlagValue] = None, -) -> FeatureFlagResult | None +setup() -> Client ``` -
-Parameters (2) - -| Parameter | -| --- | -| `details`
**Type:** `Union[FeatureFlag, None]` · **Required**
The FeatureFlag object to convert. | -| `override_match_value`
**Type:** `Optional[FlagValue]` · **Default:** `None`
If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | +Create or return the global PostHog client configured by module settings. -
+Most applications should either instantiate `Posthog` directly or set +`posthog.api_key`/other module settings before calling top-level helpers. +`setup()` is called automatically by global APIs such as `capture()`. -**Returns** `FeatureFlagResult | None`. FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. +**Returns:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L618) +Type | Description +---- | ----------- +`Client` | The global `Client` instance. If both `api_key` and +`Client` | `project_api_key` are missing or blank, the client is disabled and +`Client` | module-level calls become no-ops. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L563) +## Types -### `FeatureFlag` +### `OptionalCaptureArgs` -Detailed feature flag evaluation returned by the flags API. +Bases: `TypedDict` -`enabled`, `variant` and `metadata.payload` are the value rendered the way -responses before `/flags?v=4` carried it, which the legacy getters return. +Optional arguments for the capture method. -
-Fields (5) +**Parameters:** -| Field | -| --- | -| `key`
**Type:** `str`
Feature flag key. | -| `enabled`
**Type:** `bool`
Whether the flag is enabled for the evaluated user or group. | -| `variant`
**Type:** `Optional[str]`
Variant key for multivariate flags, otherwise `None`. | -| `reason`
**Type:** `Optional[FlagReason]`
Optional reason metadata explaining the result. | -| `metadata`
**Type:** `Union[FlagMetadata, LegacyFlagMetadata]`
Payload and other metadata returned by the API. | +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | Unique identifier for the person associated with this event. If not set, the context distinct_id is used, if available, otherwise a UUID is generated, and the event is marked as personless. Setting context-level distinct_id's is recommended. | +`properties` | | Dictionary of properties to track with the event | +`timestamp` | | When the event occurred (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | Unique identifier for this specific event. If not provided, one is generated. The event UUID is returned, so you can correlate it with actions in your app (like showing users an error ID if you capture an exception). If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`groups` | | Group identifiers to associate with this event (format: {group_type: group_key}) | +`flags` | | A `FeatureFlagEvaluations` snapshot from `evaluate_flags()`. The exact flag values from the snapshot are attached to the event with no additional network call — prefer this over `send_feature_flags`. | +`send_feature_flags` | | Deprecated — prefer `flags` with a `FeatureFlagEvaluations` snapshot. Whether to include currently active feature flags in the event properties. Can be a boolean or a SendFeatureFlagsOptions object. Defaults to False. Fires a hidden `/flags` request on capture and may return different values than the ones the code branched on. | +`disable_geoip` | | Whether to disable GeoIP lookup for this event. Defaults to False. | -
+**Attributes:** -#### `FeatureFlag.get_value` +Name | Type | Description +---- | ---- | ----------- +`disable_geoip` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[ID_TYPES]]` | +`flags` | `NotRequired[Optional[FeatureFlagEvaluations]]` | +`groups` | `NotRequired[Optional[Dict[str, str]]]` | +`properties` | `NotRequired[Optional[Dict[str, Any]]]` | +`send_feature_flags` | `NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]]` | +`timestamp` | `NotRequired[Optional[Union[datetime, str]]]` | +`uuid` | `NotRequired[Optional[Union[str, UUID]]]` | -Return the variant for a multivariate flag, otherwise whether the flag is enabled. +#### `posthog.args.OptionalCaptureArgs.disable_geoip` ```python -get_value() -> FlagValue +disable_geoip: NotRequired[Optional[bool]] ``` -**Returns** `FlagValue` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L285) - -#### `FeatureFlag.from_json` - -Parse one flag record of a `/flags` response. - -A record with a `value` member is a `/flags?v=4` record. A record -without one comes from an older server: its value is `variant`, or -`enabled` when there is no variant, and its config version is `1`. +#### `posthog.args.OptionalCaptureArgs.distinct_id` ```python -from_json(resp: Any) -> FeatureFlag +distinct_id: NotRequired[Optional[ID_TYPES]] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `resp`
**Type:** `Any` · **Required** | - -
- -**Returns** `FeatureFlag` +#### `posthog.args.OptionalCaptureArgs.flags` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L289) - -#### `FeatureFlag.from_value_and_payload` +```python +flags: NotRequired[Optional[FeatureFlagEvaluations]] +``` -Build a flag from its value and payload. A string value is a variant, so the flag is enabled. +#### `posthog.args.OptionalCaptureArgs.groups` ```python -from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag +groups: NotRequired[Optional[Dict[str, str]]] ``` -
-Parameters (3) +#### `posthog.args.OptionalCaptureArgs.properties` -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `value`
**Type:** `FlagValue` · **Required** | -| `payload`
**Type:** `Any` · **Required** | +```python +properties: NotRequired[Optional[Dict[str, Any]]] +``` -
+#### `posthog.args.OptionalCaptureArgs.send_feature_flags` -**Returns** `FeatureFlag` +```python +send_feature_flags: NotRequired[Optional[Union[bool, SendFeatureFlagsOptions]]] +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L299) +#### `posthog.args.OptionalCaptureArgs.timestamp` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L245) +```python +timestamp: NotRequired[Optional[Union[datetime, str]]] +``` -### `FlagsAndPayloads` +#### `posthog.args.OptionalCaptureArgs.uuid` -Feature flag values and payloads keyed by feature flag key. +```python +uuid: NotRequired[Optional[Union[str, UUID]]] +``` -
-Fields (2) +### `FeatureFlagEvaluations` -| Field | -| --- | -| `featureFlags`
**Type:** `Optional[dict[str, FlagValue]]`
Each flag's value, keyed by flag key. | -| `featureFlagPayloads`
**Type:** `Optional[dict[str, Any]]`
Each flag's payload, keyed by flag key. | +```python +FeatureFlagEvaluations(host: _FeatureFlagEvaluationsHost, distinct_id: str, flags: Dict[str, _EvaluatedFlagRecord], groups: Optional[Mapping[str, Union[str, int]]] = None, disable_geoip: Optional[bool] = None, request_id: Optional[str] = None, evaluated_at: Optional[int] = None, errors_while_computing: bool = False, quota_limited: bool = False, minimal_flag_called_events: bool = False, accessed: Optional[Set[str]] = None, unresolved_flags: Optional[Mapping[str, UnresolvedFlagReason]] = None) -> None +``` -
+A point-in-time snapshot of feature flag evaluations for a single distinct_id. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L551) +Returned by `Client.evaluate_flags` — branch on `is_enabled` / +`get_flag` and pass the same object to `Client.capture` via the +`flags` option so the captured event carries the exact flag values the code +branched on. -### `FeatureFlagEvaluationRuntime` +Example:: -Where a feature flag is meant to be evaluated. + flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) + if flags.is_enabled("new-dashboard"): + render_new_dashboard() + posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) -Set per flag in PostHog and carried on every locally cached flag definition. -`ALL` means the flag suits both client-side and server-side evaluation, so -it matches either runtime. Inheriting from `str` keeps the members directly -comparable to their `"all"` / `"client"` / `"server"` values. +To narrow the set of flags that get attached to a captured event, use the in-memory +helpers `only` and `only_accessed`. To narrow the set of flags requested +from the server in the first place, pass `flag_keys` to `Client.evaluate_flags`. -
-Fields (3) +**Functions:** -| Field | -| --- | -| `ALL`
**Value:** `'all'`
The flag suits both client-side and server-side evaluation. | -| `CLIENT`
**Value:** `'client'`
The flag is meant for client-side evaluation. | -| `SERVER`
**Value:** `'server'`
The flag is meant for server-side evaluation. | +Name | Description +---- | ----------- +`get_flag` | Return the flag value. Fires `$feature_flag_called` on first access. +`get_flag_payload` | Return the payload associated with a flag. +`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the +`only` | Return a filtered copy containing only flags with the given keys. Keys that +`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` -
+**Attributes:** -#### `FeatureFlagEvaluationRuntime.from_value` +Name | Type | Description +---- | ---- | ----------- +`keys` | `List[str]` | Return the flag keys that are part of this evaluation. +`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation -Coerce a raw `evaluation_runtime` value to a member. +Internal — instances are created by the SDK via `Client.evaluate_flags()`. -A missing, null or unrecognized value becomes `ALL`, which is the -default PostHog applies to a flag that does not set a runtime. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.get_flag` ```python -from_value(value: Any) -> FeatureFlagEvaluationRuntime +get_flag(key: str, *, send_feature_flag_events: bool = True) -> Optional[FlagValue] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `value`
**Type:** `Any` · **Required** | - -
- -**Returns** `FeatureFlagEvaluationRuntime` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L98) +Return the flag value. Fires `$feature_flag_called` on first access. -#### `FeatureFlagEvaluationRuntime.matches` +Returns the variant string for multivariate flags, `True` for enabled flags +without a variant, `False` for disabled flags, and `None` for flags that +were not returned by the evaluation. -Whether a flag set to one of these runtimes suits the other runtime. +Pass `send_feature_flag_events=False` to skip the event for this read, as +with `is_enabled`. -`ALL` matches every runtime, so the check is symmetric. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.get_flag_payload` ```python -matches(other: FeatureFlagEvaluationRuntime) -> bool +get_flag_payload(key: str) -> Optional[Any] ``` -
-Parameters (1) - -| Parameter | -| --- | -| `other`
**Type:** `FeatureFlagEvaluationRuntime` · **Required** | - -
- -**Returns** `bool` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L112) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L80) +Return the payload associated with a flag. -### `UnresolvedFlagReason` +Does not count as an access for `only_accessed` and does not fire any event. -Why local evaluation left a flag without a value. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.is_enabled` -Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from -`str` keeps the members directly comparable to their string values. When more -than one cause applies, the first reason in the order below is reported. +```python +is_enabled(key: str, default_value: bool = False, *, send_feature_flag_events: bool = True) -> bool +``` -
-Fields (4) +Return whether the flag is enabled. Fires `$feature_flag_called` on the +first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. -| Field | -| --- | -| `EXPERIENCE_CONTINUITY`
**Value:** `'experience_continuity'`
The flag has experience continuity enabled, which local evaluation never resolves. Change the flag to fix it. | -| `UNSUPPORTED_DEFINITION`
**Value:** `'unsupported_definition'`
The flag uses something the local evaluator does not support, such as a static cohort, an unknown operator, a malformed value, a dependency with no loaded definition or a circular dependency. Change the flag or upgrade the SDK to fix it. | -| `UNRESOLVED_DEPENDENCY`
**Value:** `'unresolved_dependency'`
A flag this flag depends on has a loaded definition but was unresolved. | -| `MISSING_CONTEXT`
**Value:** `'missing_context'`
The call did not pass a property, group property or device id the flag needs, or passed it in an unusable form. Pass it to fix it. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The feature flag key. | *required* +`default_value` | `bool` | Returned when the flag has no value in this evaluation — the key was not part of the evaluated set, or the evaluation itself came back empty (failed `/flags` request, quota limit, or no resolvable `distinct_id`). Defaults to `False`. | `False` +`send_feature_flag_events` | `bool` | Whether this read sends `$feature_flag_called`. When `False`, no event is sent and the dedupe cache is left alone, but the key still counts as accessed for `only_accessed`. | `True` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/types.py#L120) +A flag that has a value always wins over `default_value`, including a +disabled flag, which returns `False` even when `default_value=True`. -### `FlagDefinitionCacheProvider` +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.keys` -Interface for external caching of feature flag definitions. +```python +keys: List[str] +``` -Enables multi-worker environments to share flag definitions, reducing API -calls while ensuring all workers have consistent data. +Return the flag keys that are part of this evaluation. -Methods may be implemented as either synchronous functions or async -functions. If a method returns an awaitable, the SDK runs it to completion -before continuing. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.only` -The four methods handle the complete lifecycle of flag definition caching: +```python +only(keys: List[str]) -> FeatureFlagEvaluations +``` -1. `should_fetch_flag_definitions()` - Called before each poll to determine - if this worker should fetch new definitions. Use for distributed lock - coordination to ensure only one worker fetches at a time. +Return a filtered copy containing only flags with the given keys. Keys that +are not present in the evaluation are dropped and logged as a warning. -2. `get_flag_definitions()` - Called when `should_fetch_flag_definitions()` - returns False. Returns cached definitions if available. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.only_accessed` -3. `on_flag_definitions_received()` - Called after successfully fetching - new definitions from the API. Store the data in your external cache - and release any locks. +```python +only_accessed() -> FeatureFlagEvaluations +``` -4. `shutdown()` - Called when the PostHog client shuts down. Release any - distributed locks and clean up resources. +Return a filtered copy containing only flags accessed via `is_enabled` +or `get_flag` before this call. -#### `FlagDefinitionCacheProvider.get_flag_definitions` +Order-dependent: if nothing has been accessed yet, the returned snapshot is +empty. The method honors its name — pre-access if you want a populated result. -Retrieve cached flag definitions. +#### `posthog.feature_flag_evaluations.FeatureFlagEvaluations.unresolved_flags` ```python -get_flag_definitions( -) -> Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]] +unresolved_flags: Mapping[str, UnresolvedFlagReason] ``` -**Returns** `Union[Optional[FlagDefinitionCacheData], Awaitable[Optional[FlagDefinitionCacheData]]]`. Cached flag definitions if available and valid, None otherwise. May return an awaitable resolving to the same value. Returning None will trigger a fetch from the API if this worker has no flags loaded yet. - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L93) - -#### `FlagDefinitionCacheProvider.should_fetch_flag_definitions` +Return a read-only mapping of flag key to the reason local evaluation +left it without a value. -Determine whether this instance should fetch new flag definitions. +A flag is listed when it has a loaded local definition, was in the requested +scope, was inconclusive locally, and no remote value filled the gap. Listed +flags are not part of `keys`, and reading one reports the +`local_evaluation_inconclusive` error instead of `flag_missing`. Reading +this mapping does not count as an access and does not fire any event. +Snapshots returned by `only` and `only_accessed`, and by +`AsyncClient.evaluate_flags()`, which evaluates only remotely, carry no +entries. -Use this for distributed lock coordination. Only one worker should -return True to avoid thundering herd problems. A typical implementation -uses a distributed lock (e.g., Redis SETNX) that expires after the -poll interval. +### `FeatureFlagResult` ```python -should_fetch_flag_definitions() -> Union[bool, Awaitable[bool]] +FeatureFlagResult(key: str, enabled: bool, variant: Optional[str], payload: Optional[Any], reason: Optional[str]) -> None ``` -**Returns** `Union[bool, Awaitable[bool]]`. True if this instance should fetch from the API, False otherwise. May return an awaitable resolving to the same value. When False, the client will call `get_flag_definitions()` to retrieve cached data instead. +The result of calling a feature flag which includes the flag result, variant, and payload. + +**Attributes:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L109) +Name | Type | Description +---- | ---- | ----------- +`key` | `str` | The unique identifier of the feature flag. +`enabled` | `bool` | Whether the feature flag is enabled for the current context. +`variant` | `Optional[str]` | The variant value if the flag is enabled and has variants, None otherwise. +`payload` | `Optional[Any]` | Additional data associated with the feature flag, if any. +`reason` | `Optional[str]` | A description of why the flag was enabled or disabled, if available. -#### `FlagDefinitionCacheProvider.on_flag_definitions_received` +**Functions:** -Called after successfully receiving new flag definitions from PostHog. +Name | Description +---- | ----------- +`from_flag_details` | Create a FeatureFlagResult from a FeatureFlag object. +`from_value_and_payload` | Creates a FeatureFlagResult from a flag value and payload. +`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. -Use this to store the data in your external cache and release any -distributed locks acquired in `should_fetch_flag_definitions()`. +#### `posthog.types.FeatureFlagResult.enabled` ```python -on_flag_definitions_received(data: FlagDefinitionCacheData) -> Optional[Awaitable[None]] +enabled: bool ``` -
-Parameters (1) +#### `posthog.types.FeatureFlagResult.from_flag_details` -| Parameter | -| --- | -| `data`
**Type:** `FlagDefinitionCacheData` · **Required**
The flag definitions to cache, containing flags, group_type_mapping, and cohorts. | +```python +from_flag_details(details: Union[FeatureFlag, None], override_match_value: Optional[FlagValue] = None) -> FeatureFlagResult | None +``` -
+Create a FeatureFlagResult from a FeatureFlag object. -**Returns** `Optional[Awaitable[None]]` +**Parameters:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L126) +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`details` | `Union[FeatureFlag, None]` | The FeatureFlag object to convert. | *required* +`override_match_value` | `Optional[FlagValue]` | If provided, this value will be used to populate the enabled and variant fields instead of the values from the FeatureFlag. | `None` -#### `FlagDefinitionCacheProvider.shutdown` +**Returns:** -Called when the PostHog client shuts down. +Type | Description +---- | ----------- +`FeatureFlagResult \| None` | FeatureFlagResult | None: A new FeatureFlagResult instance, or None if details is None. -Use this to release any distributed locks and clean up resources. -This method is called even if `should_fetch_flag_definitions()` -returned False, so implementations should handle the case where -no lock was acquired. +#### `posthog.types.FeatureFlagResult.from_value_and_payload` ```python -shutdown() -> Optional[Awaitable[None]] +from_value_and_payload(key: str, value: Union[FlagValue, None], payload: Any) -> Union[FeatureFlagResult, None] ``` -**Returns** `Optional[Awaitable[None]]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L141) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L56) +Creates a FeatureFlagResult from a flag value and payload. -### `FlagDefinitionCacheData` +**Parameters:** -Data structure for cached flag definitions. +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`key` | `str` | The unique identifier of the feature flag. | *required* +`value` | `Union[FlagValue, None]` | The value of the flag (string variant or boolean). | *required* +`payload` | `Any` | Additional data associated with the feature flag. | *required* -
-Fields (5) +**Returns:** -| Field | -| --- | -| `flags`
**Type:** `Required[List[Dict[str, Any]]]`
List of feature flag definition dictionaries from the API. | -| `group_type_mapping`
**Type:** `Required[Dict[str, str]]`
Mapping of group type indices to group names. | -| `cohorts`
**Type:** `Required[Dict[str, Any]]`
Dictionary of cohort definitions for local evaluation. | -| `minimal_flag_called_events`
**Type:** `NotRequired[bool]`
Server-controlled gate for minimal `$feature_flag_called` events. Treated as False when absent. | -| `property_matching_version`
**Type:** `NotRequired[int]`
Exact/is_not matching selector. Missing means legacy; only version 2 enables explicit matching. | +Type | Description +---- | ----------- +`Union[FeatureFlagResult, None]` | Union[FeatureFlagResult, None]: A new FeatureFlagResult instance, or None if value is None. -
+#### `posthog.types.FeatureFlagResult.get_value` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/flag_definition_cache.py#L35) +```python +get_value() -> FlagValue +``` -### `InconclusiveMatchError` +Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. -Raised when local evaluation can't determine a flag's value. `reason` says -why, as reported by `FeatureFlagEvaluations.unresolved_flags`. +**Returns:** -
-Fields (1) +Name | Type | Description +---- | ---- | ----------- +`FlagValue` | `FlagValue` | Either a string variant or boolean value representing the flag's state. -| Field | -| --- | -| `reason`
**Type:** `UnresolvedFlagReason`
Why local evaluation couldn't resolve the flag. | +#### `posthog.types.FeatureFlagResult.key` -
+```python +key: str +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L98) +#### `posthog.types.FeatureFlagResult.payload` -### `RequiresServerEvaluation` +```python +payload: Optional[Any] +``` -Raised when feature flag evaluation requires server-side data that is not -available locally (e.g., static cohorts). +#### `posthog.types.FeatureFlagResult.reason` -This error should propagate immediately to trigger API fallback, unlike -InconclusiveMatchError which allows trying other conditions. +```python +reason: Optional[str] +``` -
-Fields (1) +#### `posthog.types.FeatureFlagResult.variant` -| Field | -| --- | -| `reason`
**Type:** `UnresolvedFlagReason`
Why the flag needs server-side evaluation. | +```python +variant: Optional[str] +``` -
+### `FeatureFlag` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/feature_flags.py#L115) +```python +FeatureFlag(key: str, enabled: bool, variant: Optional[str], reason: Optional[FlagReason], metadata: Union[FlagMetadata, LegacyFlagMetadata]) -> None +``` -### `CaptureCompression` +Detailed feature flag evaluation returned by the flags API. -Selects the request-body compression for capture-v1 uploads. +`enabled`, `variant` and `metadata.payload` are the value rendered the way +responses before `/flags?v=4` carried it, which the legacy getters return. -Only honored when `capture_mode` is `V1`; the legacy `/batch/` path -keeps using its own `gzip` flag. `NONE` sends the body uncompressed. -`GZIP` and `DEFLATE` (zlib, RFC 1950) are both stdlib / zero-dependency; -`ZSTD` is faster and compresses better but needs the optional zstandard -package (`pip install posthog[zstd]`) until stdlib support lands in -Python 3.14. Each maps to the matching `Content-Encoding` token the v1 -server decodes (`br` is accepted by the server too but is intentionally -left out for now). Inheriting from `str` keeps the members comparable to -and serializable as their token values. +**Attributes:** -
-Fields (4) +Name | Type | Description +---- | ---- | ----------- +`key` | `str` | Feature flag key. +`enabled` | `bool` | Whether the flag is enabled for the evaluated user or group. +`variant` | `Optional[str]` | Variant key for multivariate flags, otherwise `None`. +`reason` | `Optional[FlagReason]` | Optional reason metadata explaining the result. +`metadata` | `Union[FlagMetadata, LegacyFlagMetadata]` | Payload and other metadata returned by the API. -| Field | -| --- | -| `NONE`
**Value:** `'none'`
Sends the body uncompressed. | -| `GZIP`
**Value:** `'gzip'`
gzip, from the standard library. | -| `DEFLATE`
**Value:** `'deflate'`
zlib (RFC 1950), from the standard library. | -| `ZSTD`
**Value:** `'zstd'`
Faster and smaller, but needs `pip install posthog[zstd]`. | +**Functions:** -
+Name | Description +---- | ----------- +`from_json` | Parse one flag record of a `/flags` response. +`from_value_and_payload` | Build a flag from its value and payload. A string value is a variant, so the flag is enabled. +`get_value` | Return the variant for a multivariate flag, otherwise whether the flag is enabled. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/capture_compression.py#L21) +#### `posthog.types.FeatureFlag.enabled` -### `Span` +```python +enabled: bool +``` -A handle to a span. +#### `posthog.types.FeatureFlag.from_json` -Every method is safe to call on any handle, including after `end()` and -on the inert handles returned when tracing is off, so calling code never -branches on whether tracing is running. Entering a handle (`with span:`) -makes it the active span for the block and ends it on exit, recording an -`Exception` raised inside it. A `BaseException` that is not an -`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) -still ends the span but is not recorded as a failure. +```python +from_json(resp: Any) -> FeatureFlag +``` -#### `Span.set_attribute` +Parse one flag record of a `/flags` response. -Set one attribute on the span; last write wins. Ignored after `end()`. +A record with a `value` member is a `/flags?v=4` record. A record +without one comes from an older server: its value is `variant`, or +`enabled` when there is no variant, and its config version is `1`. -Returns the span, so calls chain. Prefer primitive values: strings, -booleans, integers and floats keep their type. Lists and mappings are -sent as OTLP arrays and maps, but PostHog stores them as serialized -strings. `None` removes the key; anything else is stringified. +#### `posthog.types.FeatureFlag.from_value_and_payload` ```python -set_attribute(key: str, value: Any) -> Span +from_value_and_payload(key: str, value: FlagValue, payload: Any) -> FeatureFlag ``` -
-Parameters (2) +Build a flag from its value and payload. A string value is a variant, so the flag is enabled. -| Parameter | -| --- | -| `key`
**Type:** `str` · **Required** | -| `value`
**Type:** `Any` · **Required** | +#### `posthog.types.FeatureFlag.get_value` -
+```python +get_value() -> FlagValue +``` -**Returns** `Span` +Return the variant for a multivariate flag, otherwise whether the flag is enabled. -**Correct example.** +#### `posthog.types.FeatureFlag.key` ```python -span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +key: str ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L21) - -#### `Span.set_attributes` +#### `posthog.types.FeatureFlag.metadata` -Set several attributes at once; last write wins per key. Ignored after `end()`. +```python +metadata: Union[FlagMetadata, LegacyFlagMetadata] +``` -Returns the span, so calls chain. Same encoding as `set_attribute()`. +#### `posthog.types.FeatureFlag.reason` ```python -set_attributes(attributes: Mapping[str, Any]) -> Span +reason: Optional[FlagReason] ``` -
-Parameters (1) +#### `posthog.types.FeatureFlag.variant` -| Parameter | -| --- | -| `attributes`
**Type:** `Mapping[str, Any]` · **Required** | +```python +variant: Optional[str] +``` -
+### `FlagsAndPayloads` -**Returns** `Span` +Bases: `TypedDict` -**Correct example.** +Feature flag values and payloads keyed by feature flag key. -```python -span.set_attributes({"db.system": "postgresql", "db.rows": 12}) -``` +**Attributes:** -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L36) +Name | Type | Description +---- | ---- | ----------- +`featureFlags` | `Optional[dict[str, FlagValue]]` | Each flag's value, keyed by flag key. +`featureFlagPayloads` | `Optional[dict[str, Any]]` | Each flag's payload, keyed by flag key. -#### `Span.add_event` +#### `posthog.types.FlagsAndPayloads.featureFlagPayloads` -Add a timestamped event to the span. Ignored after `end()`. +```python +featureFlagPayloads: Optional[dict[str, Any]] +``` -`timestamp` defaults to now; it accepts a `datetime`, or seconds -since the epoch as a `float` or `int`. Returns the span, so calls -chain. +#### `posthog.types.FlagsAndPayloads.featureFlags` ```python -add_event( - name: str, - attributes: Optional[Mapping[str, Any]] = None, - timestamp: Union[datetime, float, None] = None, -) -> Span +featureFlags: Optional[dict[str, FlagValue]] ``` -
-Parameters (3) +### `UnresolvedFlagReason` -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `attributes`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | -| `timestamp`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | +Bases: `str`, `Enum` -
+Why local evaluation left a flag without a value. -**Returns** `Span` +Reported by `FeatureFlagEvaluations.unresolved_flags`. Inheriting from +`str` keeps the members directly comparable to their string values. When more +than one cause applies, the first reason in the order below is reported. -**Correct example.** +
+Values -```python -span.add_event("cache.miss", {"key": "user:42"}) -``` +EXPERIENCE_CONTINUITY: The flag has experience continuity enabled, which + local evaluation never resolves. Change the flag to fix it. +UNSUPPORTED_DEFINITION: The flag uses something the local evaluator does not + support, such as a static cohort, an unknown operator, a malformed value, + a dependency with no loaded definition or a circular dependency. Change + the flag or upgrade the SDK to fix it. +UNRESOLVED_DEPENDENCY: A flag this flag depends on has a loaded definition + but was unresolved. +MISSING_CONTEXT: The call did not pass a property, group property or device + id the flag needs, or passed it in an unusable form. Pass it to fix it. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L48) +
-#### `Span.set_status` +**Attributes:** -Set the span status to `"ok"` or `"error"`. Ignored after `end()`. +Name | Type | Description +---- | ---- | ----------- +`EXPERIENCE_CONTINUITY` | | +`MISSING_CONTEXT` | | +`UNRESOLVED_DEPENDENCY` | | +`UNSUPPORTED_DEFINITION` | | -Unset by default. Any other `code` is ignored. `ok` is final for the -scoped form: an `Exception` raised inside `with span:` does not override -it. Returns the span, so calls chain. +#### `posthog.types.UnresolvedFlagReason.EXPERIENCE_CONTINUITY` ```python -set_status(code: str, message: Optional[str] = None) -> Span +EXPERIENCE_CONTINUITY = 'experience_continuity' ``` -
-Parameters (2) - -| Parameter | -| --- | -| `code`
**Type:** `str` · **Required** | -| `message`
**Type:** `Optional[str]` · **Default:** `None` | - -
+#### `posthog.types.UnresolvedFlagReason.MISSING_CONTEXT` -**Returns** `Span` +```python +MISSING_CONTEXT = 'missing_context' +``` -**Correct example.** +#### `posthog.types.UnresolvedFlagReason.UNRESOLVED_DEPENDENCY` ```python -span.set_status("error", "upstream timed out") +UNRESOLVED_DEPENDENCY = 'unresolved_dependency' ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L67) +#### `posthog.types.UnresolvedFlagReason.UNSUPPORTED_DEFINITION` -#### `Span.record_exception` - -Record an exception as an `exception` event and mark the span `error`. +```python +UNSUPPORTED_DEFINITION = 'unsupported_definition' +``` -Ignored after `end()`. The event carries `exception.type`, -`exception.message` and, for a raised exception, -`exception.stacktrace` (its last `max_attribute_value_length` -characters, so a chained traceback keeps the outermost exception and -may lose its cause). Returns the span, so calls chain. Inside -`with span:` a raised `Exception` is recorded automatically, so -this is for exceptions that are caught and handled. +### `InconclusiveMatchError` ```python -record_exception(exception: BaseException) -> Span +InconclusiveMatchError(*args, reason: Optional[UnresolvedFlagReason] = None) ``` -
-Parameters (1) +Bases: `Exception` -| Parameter | -| --- | -| `exception`
**Type:** `BaseException` · **Required** | +Raised when local evaluation can't determine a flag's value. `reason` says +why, as reported by `FeatureFlagEvaluations.unresolved_flags`. -
+**Attributes:** -**Returns** `Span` +Name | Type | Description +---- | ---- | ----------- +`reason` | `UnresolvedFlagReason` | Why local evaluation couldn't resolve the flag. -**Correct example.** +#### `posthog.feature_flags.InconclusiveMatchError.reason` ```python -try: - charge(card) -except PaymentError as e: - span.record_exception(e) +reason: UnresolvedFlagReason = UnresolvedFlagReason.UNSUPPORTED_DEFINITION ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L81) - -#### `Span.update_name` - -Rename the span, for a name only known after it started. Ignored after `end()`. - -Returns the span, so calls chain. +### `RequiresServerEvaluation` ```python -update_name(name: str) -> Span +RequiresServerEvaluation(*args, reason: Optional[UnresolvedFlagReason] = None) ``` -
-Parameters (1) +Bases: `Exception` + +Raised when feature flag evaluation requires server-side data that is not +available locally (e.g., static cohorts). -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | +This error should propagate immediately to trigger API fallback, unlike +InconclusiveMatchError which allows trying other conditions. -
+**Attributes:** -**Returns** `Span` +Name | Type | Description +---- | ---- | ----------- +`reason` | `UnresolvedFlagReason` | Why the flag needs server-side evaluation. -**Correct example.** +#### `posthog.feature_flags.RequiresServerEvaluation.reason` ```python -span = posthog.start_span("http.request") -span.update_name(f"{request.method} {route.pattern}") +reason: UnresolvedFlagReason = UnresolvedFlagReason.UNSUPPORTED_DEFINITION ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L102) +### `Span` -#### `Span.traceparent` +A handle to a span. -The W3C `traceparent` header value to propagate, or `None`. +Every method is safe to call on any handle, including after `end()` and +on the inert handles returned when tracing is off, so calling code never +branches on whether tracing is running. Entering a handle (`with span:`) +makes it the active span for the block and ends it on exit, recording an +`Exception` raised inside it. A `BaseException` that is not an +`Exception` (`GeneratorExit`, `CancelledError`, `KeyboardInterrupt`) +still ends the span but is not recorded as a failure. + +**Functions:** + +Name | Description +---- | ----------- +`add_event` | Add a timestamped event to the span. Ignored after `end()`. +`end` | End the span and queue it for export. Idempotent. +`record_exception` | Record an exception as an `exception` event and mark the span `error`. +`set_attribute` | Set one attribute on the span; last write wins. Ignored after `end()`. +`set_attributes` | Set several attributes at once; last write wins per key. Ignored after `end()`. +`set_status` | Set the span status to `"ok"` or `"error"`. Ignored after `end()`. +`traceparent` | The W3C `traceparent` header value to propagate, or `None`. +`tracestate` | The W3C `tracestate` header value to propagate, or `None`. +`update_name` | Rename the span, for a name only known after it started. Ignored after `end()`. + +#### `posthog.tracing.span.Span.add_event` ```python -traceparent() -> Optional[str] +add_event(name: str, attributes: Optional[Mapping[str, Any]] = None, timestamp: Union[datetime, float, None] = None) -> Span ``` -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L115) +Add a timestamped event to the span. Ignored after `end()`. -#### `Span.tracestate` +`timestamp` defaults to now; it accepts a `datetime`, or seconds +since the epoch as a `float` or `int`. Returns the span, so calls +chain. -The W3C `tracestate` header value to propagate, or `None`. +**Examples:** ```python -tracestate() -> Optional[str] +span.add_event("cache.miss", {"key": "user:42"}) ``` -**Returns** `Optional[str]` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L119) +#### `posthog.tracing.span.Span.end` -#### `Span.end` +```python +end(end_time: Union[datetime, float, None] = None) -> None +``` End the span and queue it for export. Idempotent. @@ -4853,22 +3707,7 @@ since the epoch as a `float` or `int`, and is never earlier than the start. Later calls, and later mutations, no-op. `with span:` ends the span on exit, so call this only for spans started manually. -```python -end(end_time: Union[datetime, float, None] = None) -> None -``` - -
-Parameters (1) - -| Parameter | -| --- | -| `end_time`
**Type:** `Union[datetime, float, None]` · **Default:** `None` | - -
- -**Returns** `None` - -**Correct example.** +**Examples:** ```python span = posthog.start_span("job") @@ -4878,139 +3717,124 @@ finally: span.end() ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L123) +#### `posthog.tracing.span.Span.record_exception` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/tracing/span.py#L9) +```python +record_exception(exception: BaseException) -> Span +``` -### `PostHogMetrics` +Record an exception as an `exception` event and mark the span `error`. -The `client.metrics` API: `count`, `gauge`, `histogram`, `flush`. +Ignored after `end()`. The event carries `exception.type`, +`exception.message` and, for a raised exception, +`exception.stacktrace` (its last `max_attribute_value_length` +characters, so a chained traceback keeps the outermost exception and +may lose its cause). Returns the span, so calls chain. Inside +`with span:` a raised `Exception` is recorded automatically, so +this is for exceptions that are caught and handled. -Thread-safe; safe to call from hot paths. Configure via the `metrics` -client option (`flush_interval` is in seconds, matching the client's own -`flush_interval` — unlike posthog-js, whose `flushIntervalMs` is milliseconds): +**Examples:** ```python -client = Client("phc_...", metrics={"service_name": "billing-worker"}) -client.metrics.count("invoices.processed", 1, attributes={"plan": "pro"}) -client.metrics.gauge("queue.depth", 42) -client.metrics.histogram("job.duration", 187, unit="ms") +try: + charge(card) +except PaymentError as e: + span.record_exception(e) ``` -#### `PostHogMetrics.count` - -Record an increment for a monotonic counter (things that only go up). +#### `posthog.tracing.span.Span.set_attribute` ```python -count( - name: str, - value: float = 1, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +set_attribute(key: str, value: Any) -> Span ``` -
-Parameters (4) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Default:** `1` | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | - -
+Set one attribute on the span; last write wins. Ignored after `end()`. -**Returns** `None` +Returns the span, so calls chain. Prefer primitive values: strings, +booleans, integers and floats keep their type. Lists and mappings are +sent as OTLP arrays and maps, but PostHog stores them as serialized +strings. `None` removes the key; anything else is stringified. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L374) +**Examples:** -#### `PostHogMetrics.gauge` +```python +span.set_attribute("http.status_code", 200).set_attribute("cache.hit", True) +``` -Record the current value of something that goes up and down. +#### `posthog.tracing.span.Span.set_attributes` ```python -gauge( - name: str, - value: float, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +set_attributes(attributes: Mapping[str, Any]) -> Span ``` -
-Parameters (4) +Set several attributes at once; last write wins per key. Ignored after `end()`. + +Returns the span, so calls chain. Same encoding as `set_attribute()`. -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Required** | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | +**Examples:** -
+```python +span.set_attributes({"db.system": "postgresql", "db.rows": 12}) +``` + +#### `posthog.tracing.span.Span.set_status` -**Returns** `None` +```python +set_status(code: str, message: Optional[str] = None) -> Span +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L384) +Set the span status to `"ok"` or `"error"`. Ignored after `end()`. -#### `PostHogMetrics.histogram` +Unset by default. Any other `code` is ignored. `ok` is final for the +scoped form: an `Exception` raised inside `with span:` does not override +it. Returns the span, so calls chain. -Record one observation of a distribution (durations, sizes). +**Examples:** ```python -histogram( - name: str, - value: float, - unit: Optional[str] = None, - attributes: Optional[dict] = None, -) -> None +span.set_status("error", "upstream timed out") ``` -
-Parameters (4) +#### `posthog.tracing.span.Span.traceparent` -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required** | -| `value`
**Type:** `float` · **Required** | -| `unit`
**Type:** `Optional[str]` · **Default:** `None` | -| `attributes`
**Type:** `Optional[dict]` · **Default:** `None` | +```python +traceparent() -> Optional[str] +``` -
+The W3C `traceparent` header value to propagate, or `None`. -**Returns** `None` +#### `posthog.tracing.span.Span.tracestate` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L394) +```python +tracestate() -> Optional[str] +``` -#### `PostHogMetrics.flush` +The W3C `tracestate` header value to propagate, or `None`. -Sends everything aggregated so far without waiting for the flush interval. +#### `posthog.tracing.span.Span.update_name` ```python -flush() -> None +update_name(name: str) -> Span ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L404) +Rename the span, for a name only known after it started. Ignored after `end()`. -#### `PostHogMetrics.reset` +Returns the span, so calls chain. -Clears the flush timer and drops the current window. +**Examples:** ```python -reset() -> None +span = posthog.start_span("http.request") +span.update_name(f"{request.method} {route.pattern}") ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L409) +### `Emails` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/metrics_capture.py#L297) +```python +Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None) -> None +``` -### `Emails` +Bases: `_EmailsBase` Sends transactional email from PostHog email templates. @@ -5024,82 +3848,66 @@ to `max_retries` times, with the same idempotency key. Set is in seconds, per request. Pass `session` to send through your own `requests.Session`, for example a test double. -#### `Emails.send` - -Queue one email from a transactional email template. - -```python -send( - to: str, - template_id: Union[str, UUID], - template_data: Optional[Mapping[str, Any]] = None, - distinct_id: Optional[str] = None, - idempotency_key: Optional[str] = None, - max_retries: Optional[int] = None, -) -> SendEmailResult -``` +**Functions:** -
-Parameters (6) +Name | Description +---- | ----------- +`close` | Close the HTTP connections this client opened. A `session` you passed in stays open. +`get` | Read what happened to an email that `send` queued. +`send` | Queue one email from a transactional email template. -| Parameter | -| --- | -| `to`
**Type:** `str` · **Required**
One recipient email address. | -| `template_id`
**Type:** `Union[str, UUID]` · **Required**
The UUID of a template made transactional in PostHog. | -| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None`
Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | -| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None`
The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | -| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None`
1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | -| `max_retries`
**Type:** `Optional[int]` · **Default:** `None`
Overrides the client's maximum number of retries for this send. `0` turns retries off. | +**Attributes:** -
+Name | Type | Description +---- | ---- | ----------- +`disabled` | | +`host` | | +`max_retries` | | +`secret_key` | | +`timeout` | | -**Returns** `SendEmailResult`. The queued email. A result means PostHog queued the email, not that it was delivered. +#### `posthog.emails.Emails.close` -**Raises** `EmailError`. PostHog did not queue the email, or the client could -not tell whether it did. +```python +close() -> None +``` -**Raises** `(TypeError, ValueError)`. An argument has the wrong type or format. +Close the HTTP connections this client opened. A `session` you passed in stays open. -**Correct example.** +#### `posthog.emails.Emails.disabled` ```python -emails.send( - to="user@example.com", - template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", - template_data={"name": "Ada"}, - distinct_id="user_123", - idempotency_key="welcome:user_123", -) +disabled = disabled ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L588) - -#### `Emails.get` - -Read what happened to an email that `send` queued. +#### `posthog.emails.Emails.get` ```python get(message_id: Union[str, UUID]) -> EmailStatus ``` -
-Parameters (1) +Read what happened to an email that `send` queued. -| Parameter | -| --- | -| `message_id`
**Type:** `Union[str, UUID]` · **Required**
The `id` of the `SendEmailResult` that `send` returned. | +**Parameters:** -
+Name | Type | Description | Default +---- | ---- | ----------- | ------- +`message_id` | `Union[str, UUID]` | The `id` of the `SendEmailResult` that `send` returned. | *required* -**Returns** `EmailStatus`. The email's latest status, for 30 days after the send. +**Returns:** -**Raises** `EmailError`. PostHog did not answer with a status. `code` is -`not_found` for an unknown ID, an email older than 30 days, -or for a few seconds after the send. +Type | Description +---- | ----------- +`EmailStatus` | The email's latest status, for 30 days after the send. -**Raises** `ValueError`. `message_id` is not a message ID. +**Raises:** -**Correct example.** +Type | Description +---- | ----------- +`EmailError` | PostHog did not answer with a status. `code` is `not_found` for an unknown ID, an email older than 30 days, or for a few seconds after the send. +`ValueError` | `message_id` is not a message ID. + +**Examples:** ```python result = emails.send(to="user@example.com", template_id="...") @@ -5108,115 +3916,82 @@ if status.status == "bounced": print(status.reason) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L659) - -#### `Emails.close` - -Close the HTTP connections this client opened. A `session` you passed in stays open. +#### `posthog.emails.Emails.host` ```python -close() -> None +host = determine_app_host(host) ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L737) +#### `posthog.emails.Emails.max_retries` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L553) +```python +max_retries = max_retries +``` -### `AsyncEmails` +#### `posthog.emails.Emails.secret_key` -The async counterpart of `Emails`. Needs `posthog[async]`. +```python +secret_key = secret_key.strip() if isinstance(secret_key, str) else None +``` -Pass `http_client` to send through your own `httpx.AsyncClient`, for -example one with an `httpx.MockTransport` in tests. +#### `posthog.emails.Emails.send` -#### `AsyncEmails.send` +```python +send(*, to: str, template_id: Union[str, UUID], template_data: Optional[Mapping[str, Any]] = None, distinct_id: Optional[str] = None, idempotency_key: Optional[str] = None, max_retries: Optional[int] = None) -> SendEmailResult +``` Queue one email from a transactional email template. -Takes the same arguments and raises the same errors as -`Emails.send`. +**Parameters:** -```python -async send( - to: str, - template_id: Union[str, UUID], - template_data: Optional[Mapping[str, Any]] = None, - distinct_id: Optional[str] = None, - idempotency_key: Optional[str] = None, - max_retries: Optional[int] = None, -) -> SendEmailResult -``` +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`to` | `str` | One recipient email address. | *required* +`template_id` | `Union[str, UUID]` | The UUID of a template made transactional in PostHog. | *required* +`template_data` | `Optional[Mapping[str, Any]]` | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | `None` +`distinct_id` | `Optional[str]` | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | `None` +`idempotency_key` | `Optional[str]` | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | `None` +`max_retries` | `Optional[int]` | Overrides the client's maximum number of retries for this send. `0` turns retries off. | `None` -
-Parameters (6) +**Returns:** -| Parameter | -| --- | -| `to`
**Type:** `str` · **Required** | -| `template_id`
**Type:** `Union[str, UUID]` · **Required** | -| `template_data`
**Type:** `Optional[Mapping[str, Any]]` · **Default:** `None` | -| `distinct_id`
**Type:** `Optional[str]` · **Default:** `None` | -| `idempotency_key`
**Type:** `Optional[str]` · **Default:** `None` | -| `max_retries`
**Type:** `Optional[int]` · **Default:** `None` | +Type | Description +---- | ----------- +`SendEmailResult` | The queued email. A result means PostHog queued the email, not that +`SendEmailResult` | it was delivered. -
+**Raises:** -**Returns** `SendEmailResult` +Type | Description +---- | ----------- +`EmailError` | PostHog did not queue the email, or the client could not tell whether it did. +`(TypeError, ValueError)` | An argument has the wrong type or format. -**Correct example.** +**Examples:** ```python -await emails.send( +emails.send( to="user@example.com", template_id="0190f6d2-7c1e-7b3a-9f5e-1c2d3e4f5a6b", template_data={"name": "Ada"}, distinct_id="user_123", + idempotency_key="welcome:user_123", ) ``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L792) - -#### `AsyncEmails.get` - -Read what happened to an email that `send` queued. - -Takes the same argument and raises the same errors as -`Emails.get`. +#### `posthog.emails.Emails.timeout` ```python -async get(message_id: Union[str, UUID]) -> EmailStatus +timeout = timeout ``` -
-Parameters (1) - -| Parameter | -| --- | -| `message_id`
**Type:** `Union[str, UUID]` · **Required** | - -
- -**Returns** `EmailStatus` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L838) - -#### `AsyncEmails.aclose` - -Close the HTTP connections this client opened. An `http_client` you passed in stays open. +### `EmailError` ```python -async aclose() -> None +EmailError(*, name: str, code: str, message: str, status_code: Optional[int] = None, why: Optional[str] = None, fix: Optional[str] = None, docs_url: Optional[str] = None, field: Optional[str] = None, retry_after: Optional[float] = None) -> None ``` -**Returns** `None` - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L899) - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L765) - -### `EmailError` +Bases: `Exception` PostHog did not queue the email, or the client could not tell whether it did. @@ -5224,203 +3999,104 @@ Branch on `code`, PostHog's stable error code, or on `name`, a coarse category of the failure. The message never contains the secret key or the request body. -
-Fields (9) - -| Field | -| --- | -| `name`
A coarse category of the failure. | -| `code`
PostHog's stable error code. | -| `message`
What went wrong. It never contains the secret key or the request body. | -| `status_code`
The HTTP status of the response, or `None` when none arrived. | -| `why`
PostHog's explanation of the failure, when it gave one. | -| `fix`
What to change to fix it, when PostHog said. | -| `docs_url`
A docs page about the error, when PostHog gave one. | -| `field`
The request field the error is about, when there is one. | -| `retry_after`
Seconds to wait before retrying, when PostHog said. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L122) - -### `EmailStatus` - -What happened to an email that `send()` queued. - -`status` is one of: - -- `queued`: the email waits to go out. -- `sent`: PostHog handed the email to the email provider. -- `failed`: the email was not sent, and `reason` says why. -- `delivered`: the recipient's mail server accepted the email. -- `bounced` and `complained`: the recipient's mail provider reported - them after delivery. - -Later SDK versions can see values this list does not have yet. -`reason` says why a failed email was not sent, such as -`provider_error` or `recipient_suppressed`, or gives the bounce type of -a bounced email: `hard`, `soft` or `unknown`. It is `None` otherwise. - -
-Fields (5) - -| Field | -| --- | -| `id`
**Type:** `str`
The email's message ID. | -| `status`
**Type:** `str`
Where the email is now, one of the values above. | -| `created_at`
**Type:** `datetime`
When PostHog queued the email. | -| `status_at`
**Type:** `datetime`
When the email reached its current status. | -| `reason`
**Type:** `Optional[str]` · **Default:** `None`
Why a failed email was not sent, or a bounced email's bounce type. | - -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L189) - -### `SendEmailResult` - -The queued email. `id` is its message ID. - -
-Fields (3) - -| Field | -| --- | -| `id`
**Type:** `str`
The email's message ID. | -| `replayed`
**Type:** `bool` · **Default:** `False`
`True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. | -| `warnings`
**Type:** `tuple[EmailWarning, ...]` · **Default:** `()`
Warnings PostHog returned about the request. | +**Attributes:** -
- -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/emails.py#L173) - -### `Prompts` - -Fetch and compile LLM prompts from PostHog. +Name | Type | Description +---- | ---- | ----------- +`name` | | A coarse category of the failure. +`code` | | PostHog's stable error code. +`message` | | What went wrong. It never contains the secret key or the request body. +`status_code` | | The HTTP status of the response, or `None` when none arrived. +`why` | | PostHog's explanation of the failure, when it gave one. +`fix` | | What to change to fix it, when PostHog said. +`docs_url` | | A docs page about the error, when PostHog gave one. +`field` | | The request field the error is about, when there is one. +`retry_after` | | Seconds to wait before retrying, when PostHog said. -Can be initialized with a PostHog client or with direct options. - -#### `Prompts.get` - -Fetch a prompt by name from the PostHog API. - -When `with_metadata` is `True`, returns a `PromptResult` -with `source`, `name`, `version`, and `config` metadata. When -omitted or `False`, returns a plain string (deprecated -- will be -removed in a future major version). +#### `posthog.emails.EmailError.code` ```python -get( - name: str, - with_metadata: Optional[bool] = None, - cache_ttl_seconds: Optional[int] = None, - fallback: Optional[str] = None, - version: Optional[int] = None, - label: Optional[str] = None, -) -> Union[str, PromptResult] +code = code ``` -
-Parameters (6) - -| Parameter | -| --- | -| `name`
**Type:** `str` · **Required**
The name of the prompt to fetch | -| `with_metadata`
**Type:** `Optional[bool]` · **Default:** `None`
If True, returns a PromptResult with source info. Omitting this parameter is deprecated. | -| `cache_ttl_seconds`
**Type:** `Optional[int]` · **Default:** `None`
Cache TTL in seconds (defaults to instance default) | -| `fallback`
**Type:** `Optional[str]` · **Default:** `None`
Fallback prompt to use if fetch fails and no cache available | -| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to fetch. Mutually exclusive with label. If neither is given, fetches the latest version | -| `label`
**Type:** `Optional[str]` · **Default:** `None`
Fetch the version this label currently points to, e.g. 'production'. Mutually exclusive with version | +#### `posthog.emails.EmailError.docs_url` -
- -**Returns** `Union[str, PromptResult]`. str if with_metadata is False/omitted, PromptResult if True - -**Raises** `ValueError`. If both version and label are provided - -**Raises** `Exception`. If the prompt cannot be fetched and no fallback is available - -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L359) - -#### `Prompts.get_all` +```python +docs_url = docs_url +``` -Fetch every prompt in one batch. +#### `posthog.emails.EmailError.field` -Returns a dict mapping prompt name to `PromptResult`. With a -label, each prompt is at the version the label points to, and prompts -without the label are not included. Without a label, every prompt is -included at its latest version, matching what `get(name)` returns. +```python +field = field +``` -Each fetched prompt is stored in the cache, so later -`get(name, label=...)` (or plain `get(name)`) calls are served -from cache within the TTL. An app with many prompts can call this once -per cache cycle instead of making one `get()` request per prompt. +#### `posthog.emails.EmailError.fix` ```python -get_all(label: Optional[str] = None) -> Dict[str, PromptResult] +fix = fix ``` -
-Parameters (1) +#### `posthog.emails.EmailError.message` -| Parameter | -| --- | -| `label`
**Type:** `Optional[str]` · **Default:** `None`
The label to resolve, e.g. 'production'. Omit to fetch latest versions. | +```python +message = message +``` -
+#### `posthog.emails.EmailError.name` -**Returns** `Dict[str, PromptResult]`. Dict of prompt name to PromptResult. +```python +name = name +``` -**Raises** `Exception`. If the request fails, or a label was passed and the -server does not support fetching prompts by label on the list -endpoint (PostHog releases from before September 2026). +#### `posthog.emails.EmailError.retry_after` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L433) +```python +retry_after = retry_after +``` -#### `Prompts.compile` +#### `posthog.emails.EmailError.status_code` -Replace {{variableName}} placeholders with values. +```python +status_code = status_code +``` -Unmatched variables are left unchanged. -Supports variable names with hyphens and dots (e.g., user-id, company.name). +#### `posthog.emails.EmailError.why` ```python -compile(prompt: str, variables: PromptVariables) -> str +why = why ``` -
-Parameters (2) - -| Parameter | -| --- | -| `prompt`
**Type:** `str` · **Required**
The prompt template string | -| `variables`
**Type:** `PromptVariables` · **Required**
Object containing variable values | +### `SendEmailResult` -
+```python +SendEmailResult(id: str, replayed: bool = False, warnings: tuple[EmailWarning, ...] = ()) -> None +``` -**Returns** `str`. The compiled prompt string +The queued email. `id` is its message ID. -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L720) +**Attributes:** -#### `Prompts.clear_cache` +Name | Type | Description +---- | ---- | ----------- +`id` | `str` | The email's message ID. +`replayed` | `bool` | `True` when the response says PostHog replayed an earlier send for the same `idempotency_key` instead of sending again. +`warnings` | `tuple[EmailWarning, ...]` | Warnings PostHog returned about the request. -Clear cached prompts. +#### `posthog.emails.SendEmailResult.id` ```python -clear_cache(name: Optional[str] = None, version: Optional[int] = None) -> None +id: str ``` -
-Parameters (2) - -| Parameter | -| --- | -| `name`
**Type:** `Optional[str]` · **Default:** `None`
Specific prompt name to clear. If None, clears all cached prompts. | -| `version`
**Type:** `Optional[int]` · **Default:** `None`
Specific prompt version to clear. Requires name. | - -
+#### `posthog.emails.SendEmailResult.replayed` -**Returns** `None` +```python +replayed: bool = False +``` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L745) +#### `posthog.emails.SendEmailResult.warnings` -[Source](https://github.com/PostHog/posthog-python/blob/v7.83.1/posthog/ai/prompts.py#L227) +```python +warnings: tuple[EmailWarning, ...] = () +``` From f93ae0f0304775b549beb5a75b5d8aa59998e78a Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 5 Nov 2026 10:38:37 -0500 Subject: [PATCH 5/9] docs: regenerate the 7.x reference from current main Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 61 +++++++++++++++++--------- references/posthog-python-reference.md | 61 +++++++++++++++++--------- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index fbe09b77a..6d9a78319 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) +__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -157,6 +157,7 @@ Name | Type | Description | Default `app_host` | `Optional[str]` | Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | `None` `email_request_timeout_seconds` | `float` | Timeout in seconds for each email send request. Defaults to 15. | `15` `email_request_max_retries` | `int` | Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | `2` +`migrated_from` | `Optional[str]` | The email provider you moved from, such as `"resend"`. `emails` sends it with every request. | `None` `super_properties` | | Properties merged into every captured event. | `None` `enable_exception_autocapture` | | Automatically capture uncaught exceptions. | `False` `log_captured_exceptions` | | Also log exceptions captured by error tracking. | `False` @@ -450,10 +451,10 @@ except Exception as e: emails: Emails ``` -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. +Send transactional email from PostHog email templates or from content +in your code, and read the status of each email sent with `get`. -Needs `secret_key`, a project secret API key with the `hog_flow:write` +Needs `secret_key`, a project secret API key with the `transactional_email:write` scope. Sends go to `app_host`, or to the PostHog Cloud app host of `host`. `email_request_timeout_seconds` and `email_request_max_retries` configure each send. A disabled or shut-down client sends nothing. See @@ -1893,7 +1894,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) -> None +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -1944,10 +1945,10 @@ Capture an exception. This method never raises, including in debug mode. emails: AsyncEmails ``` -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. +Send transactional email from PostHog email templates or from content +in your code, and read the status of each email sent with `get`. -Needs `secret_key`, a project secret API key with the `hog_flow:write` +Needs `secret_key`, a project secret API key with the `transactional_email:write` scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog Cloud app host of `host`. `email_request_timeout_seconds` and `email_request_max_retries` configure each send. A disabled or shut-down @@ -3831,12 +3832,12 @@ span.update_name(f"{request.method} {route.pattern}") ### `Emails` ```python -Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None) -> None +Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None, migrated_from: Optional[str] = None) -> None ``` Bases: `_EmailsBase` -Sends transactional email from PostHog email templates. +Sends transactional email from PostHog email templates or from content in your code. `host` is your PostHog app host. PostHog Cloud ingestion hosts map to the app host, so `us.i.posthog.com` sends to `us.posthog.com`. Any other @@ -3846,7 +3847,8 @@ Each send retries network errors, rate limits and an unavailable service up to `max_retries` times, with the same idempotency key. Set `max_retries=0` when a job runner already retries the send. `timeout` is in seconds, per request. Pass `session` to send through your own -`requests.Session`, for example a test double. +`requests.Session`, for example a test double. `migrated_from`, such +as `"resend"`, tells PostHog which provider your sends came from. **Functions:** @@ -3854,7 +3856,7 @@ Name | Description ---- | ----------- `close` | Close the HTTP connections this client opened. A `session` you passed in stays open. `get` | Read what happened to an email that `send` queued. -`send` | Queue one email from a transactional email template. +`send` | Queue one email, from a template in PostHog or from content in your code. **Attributes:** @@ -3863,6 +3865,7 @@ Name | Type | Description `disabled` | | `host` | | `max_retries` | | +`migrated_from` | | `secret_key` | | `timeout` | | @@ -3928,6 +3931,12 @@ host = determine_app_host(host) max_retries = max_retries ``` +#### `posthog.emails.Emails.migrated_from` + +```python +migrated_from = migrated_from +``` + #### `posthog.emails.Emails.secret_key` ```python @@ -3937,21 +3946,26 @@ secret_key = secret_key.strip() if isinstance(secret_key, str) else None #### `posthog.emails.Emails.send` ```python -send(*, to: str, template_id: Union[str, UUID], template_data: Optional[Mapping[str, Any]] = None, distinct_id: Optional[str] = None, idempotency_key: Optional[str] = None, max_retries: Optional[int] = None) -> SendEmailResult +send(**kwargs: Any) -> SendEmailResult ``` -Queue one email from a transactional email template. +Queue one email, from a template in PostHog or from content in your code. + +Pass exactly one form. The template form names a template made in +PostHog with `template_id`. The code form names the email with +`template_key` and passes `subject` and `html`, `text` or both: +see `CodeEmailArgs`. **Parameters:** Name | Type | Description | Default ---- | ---- | ----------- | ------- -`to` | `str` | One recipient email address. | *required* -`template_id` | `Union[str, UUID]` | The UUID of a template made transactional in PostHog. | *required* -`template_data` | `Optional[Mapping[str, Any]]` | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | `None` -`distinct_id` | `Optional[str]` | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | `None` -`idempotency_key` | `Optional[str]` | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | `None` -`max_retries` | `Optional[int]` | Overrides the client's maximum number of retries for this send. `0` turns retries off. | `None` +`to` | | One recipient email address. | +`template_id` | | The UUID of a template made transactional in PostHog. | +`template_data` | | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | +`distinct_id` | | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | +`idempotency_key` | | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | +`max_retries` | | Overrides the client's maximum number of retries for this send. `0` turns retries off. | **Returns:** @@ -3977,6 +3991,13 @@ emails.send( distinct_id="user_123", idempotency_key="welcome:user_123", ) +emails.send( + to="user@example.com", + template_key="password-reset", + subject="Reset your password", + html=rendered_html, + distinct_id="user_123", +) ``` #### `posthog.emails.Emails.timeout` diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index adf86813c..72e490700 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) +__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -157,6 +157,7 @@ Name | Type | Description | Default `app_host` | `Optional[str]` | Your PostHog app host, such as `https://posthog.example.com`. `emails` sends there. Needed only when `host` is not PostHog Cloud, for example a reverse proxy, which must not receive the secret key. | `None` `email_request_timeout_seconds` | `float` | Timeout in seconds for each email send request. Defaults to 15. | `15` `email_request_max_retries` | `int` | Number of retries for an email send after a network error, a rate limit, or an unavailable service. Defaults to 2. Set to 0 when a job runner already retries the send. | `2` +`migrated_from` | `Optional[str]` | The email provider you moved from, such as `"resend"`. `emails` sends it with every request. | `None` `super_properties` | | Properties merged into every captured event. | `None` `enable_exception_autocapture` | | Automatically capture uncaught exceptions. | `False` `log_captured_exceptions` | | Also log exceptions captured by error tracking. | `False` @@ -450,10 +451,10 @@ except Exception as e: emails: Emails ``` -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. +Send transactional email from PostHog email templates or from content +in your code, and read the status of each email sent with `get`. -Needs `secret_key`, a project secret API key with the `hog_flow:write` +Needs `secret_key`, a project secret API key with the `transactional_email:write` scope. Sends go to `app_host`, or to the PostHog Cloud app host of `host`. `email_request_timeout_seconds` and `email_request_max_retries` configure each send. A disabled or shut-down client sends nothing. See @@ -1893,7 +1894,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2) -> None +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -1944,10 +1945,10 @@ Capture an exception. This method never raises, including in debug mode. emails: AsyncEmails ``` -Send transactional email from PostHog email templates, and read the -status of each email sent with `get`. +Send transactional email from PostHog email templates or from content +in your code, and read the status of each email sent with `get`. -Needs `secret_key`, a project secret API key with the `hog_flow:write` +Needs `secret_key`, a project secret API key with the `transactional_email:write` scope, and `posthog[async]`. Sends go to `app_host`, or to the PostHog Cloud app host of `host`. `email_request_timeout_seconds` and `email_request_max_retries` configure each send. A disabled or shut-down @@ -3831,12 +3832,12 @@ span.update_name(f"{request.method} {route.pattern}") ### `Emails` ```python -Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None) -> None +Emails(secret_key: Optional[str], *, host: Optional[str] = None, timeout: float = 15, max_retries: int = 2, disabled: bool = False, session: Optional[requests.Session] = None, migrated_from: Optional[str] = None) -> None ``` Bases: `_EmailsBase` -Sends transactional email from PostHog email templates. +Sends transactional email from PostHog email templates or from content in your code. `host` is your PostHog app host. PostHog Cloud ingestion hosts map to the app host, so `us.i.posthog.com` sends to `us.posthog.com`. Any other @@ -3846,7 +3847,8 @@ Each send retries network errors, rate limits and an unavailable service up to `max_retries` times, with the same idempotency key. Set `max_retries=0` when a job runner already retries the send. `timeout` is in seconds, per request. Pass `session` to send through your own -`requests.Session`, for example a test double. +`requests.Session`, for example a test double. `migrated_from`, such +as `"resend"`, tells PostHog which provider your sends came from. **Functions:** @@ -3854,7 +3856,7 @@ Name | Description ---- | ----------- `close` | Close the HTTP connections this client opened. A `session` you passed in stays open. `get` | Read what happened to an email that `send` queued. -`send` | Queue one email from a transactional email template. +`send` | Queue one email, from a template in PostHog or from content in your code. **Attributes:** @@ -3863,6 +3865,7 @@ Name | Type | Description `disabled` | | `host` | | `max_retries` | | +`migrated_from` | | `secret_key` | | `timeout` | | @@ -3928,6 +3931,12 @@ host = determine_app_host(host) max_retries = max_retries ``` +#### `posthog.emails.Emails.migrated_from` + +```python +migrated_from = migrated_from +``` + #### `posthog.emails.Emails.secret_key` ```python @@ -3937,21 +3946,26 @@ secret_key = secret_key.strip() if isinstance(secret_key, str) else None #### `posthog.emails.Emails.send` ```python -send(*, to: str, template_id: Union[str, UUID], template_data: Optional[Mapping[str, Any]] = None, distinct_id: Optional[str] = None, idempotency_key: Optional[str] = None, max_retries: Optional[int] = None) -> SendEmailResult +send(**kwargs: Any) -> SendEmailResult ``` -Queue one email from a transactional email template. +Queue one email, from a template in PostHog or from content in your code. + +Pass exactly one form. The template form names a template made in +PostHog with `template_id`. The code form names the email with +`template_key` and passes `subject` and `html`, `text` or both: +see `CodeEmailArgs`. **Parameters:** Name | Type | Description | Default ---- | ---- | ----------- | ------- -`to` | `str` | One recipient email address. | *required* -`template_id` | `Union[str, UUID]` | The UUID of a template made transactional in PostHog. | *required* -`template_data` | `Optional[Mapping[str, Any]]` | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | `None` -`distinct_id` | `Optional[str]` | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | `None` -`idempotency_key` | `Optional[str]` | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | `None` -`max_retries` | `Optional[int]` | Overrides the client's maximum number of retries for this send. `0` turns retries off. | `None` +`to` | | One recipient email address. | +`template_id` | | The UUID of a template made transactional in PostHog. | +`template_data` | | Values for the template's `{{ variables.* }}` placeholders. Values are encoded the way capture encodes properties. | +`distinct_id` | | The recipient's distinct ID in your product. The email's events go to this person. Without it, they go to a person whose distinct ID is the email address. | +`idempotency_key` | | 1 to 255 visible ASCII characters. A send with a key that PostHog has already accepted queues nothing and returns the first send's result. Without it, the client makes a key that covers its own retries. Pass a key derived from what the email is for, such as `welcome:user_123`, to cover retries outside this call, too. | +`max_retries` | | Overrides the client's maximum number of retries for this send. `0` turns retries off. | **Returns:** @@ -3977,6 +3991,13 @@ emails.send( distinct_id="user_123", idempotency_key="welcome:user_123", ) +emails.send( + to="user@example.com", + template_key="password-reset", + subject="Reset your password", + html=rendered_html, + distinct_id="user_123", +) ``` #### `posthog.emails.Emails.timeout` From 800bded07752379b25dda6c24d39caba0f79dba9 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 5 Nov 2026 14:27:01 -0500 Subject: [PATCH 6/9] docs: regenerate the 7 and reference pages Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 193 +++++++++++++++++++++++-- references/posthog-python-reference.md | 193 +++++++++++++++++++++++-- 2 files changed, 358 insertions(+), 28 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index 6d9a78319..da50b2031 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, _use_ai_lane=False, _enable_multimodal_capture=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -958,7 +958,7 @@ Flat list of the lanes' consumers, analytics first (kept for backwards compatibi ### `Client.new_context` ```python -new_context(fresh = False, capture_exceptions: Optional[bool] = None) +new_context(fresh=False, capture_exceptions: Optional[bool] = None) ``` Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). @@ -988,7 +988,7 @@ Contexts ### `Client.scoped` ```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) +scoped(fresh=False, capture_exceptions: Optional[bool] = None) ``` Decorator that creates a new context for the wrapped function using this client. @@ -1419,7 +1419,7 @@ Name | Type | Description | Default #### `posthog.integrations.django.PosthogContextMiddleware.aextract_properties` ```python -aextract_properties(request) +async aextract_properties(request) ``` Async version of extract_properties for use in async request handling. @@ -1432,7 +1432,7 @@ Follows Django's naming convention for async methods (auser, asave, etc.). #### `posthog.integrations.django.PosthogContextMiddleware.aextract_request_user` ```python -aextract_request_user(request) +async aextract_request_user(request) ``` Async version of extract_request_user for use in async request handling. @@ -1445,7 +1445,7 @@ Follows Django's naming convention for async methods (auser, asave, etc.). #### `posthog.integrations.django.PosthogContextMiddleware.aextract_tags` ```python -aextract_tags(request) +async aextract_tags(request) ``` Compatibility alias for `aextract_properties`. @@ -1894,7 +1894,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -1908,7 +1908,7 @@ Queue an event without blocking for network delivery. ### `AsyncClient.capture_immediate` ```python -capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +async capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` Capture one event and wait until its delivery attempt completes. @@ -1967,13 +1967,13 @@ await client.emails.send( ### `AsyncClient.flush` ```python -flush(timeout_seconds: Optional[float] = 10) -> None +async flush(timeout_seconds: Optional[float] = 10) -> None ``` ### `AsyncClient.evaluate_flags` ```python -evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +async evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations ``` Evaluate flags remotely without blocking the event loop. @@ -1992,19 +1992,19 @@ group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, A ### `AsyncClient.shutdown` ```python -shutdown() -> None +async shutdown() -> None ``` ### `AsyncClient.join` ```python -join() -> None +async join() -> None ``` ### `AsyncClient.get_remote_config_payload` ```python -get_remote_config_payload(key: str) -> Optional[Any] +async get_remote_config_payload(key: str) -> Optional[Any] ``` Fetch and decrypt a remote-config payload without blocking the loop. @@ -2046,7 +2046,7 @@ Contexts ### `posthog.scoped` ```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) +scoped(fresh=False, capture_exceptions: Optional[bool] = None) ``` Decorator that creates a new context for the function. @@ -4121,3 +4121,168 @@ replayed: bool = False ```python warnings: tuple[EmailWarning, ...] = () ``` + +### `OptionalSetArgs` + +Bases: `TypedDict` + +Optional arguments for the set method. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | +`properties` | | Dictionary of properties to set on the person | +`timestamp` | | When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP lookup for this operation. Defaults to False. | + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`disable_geoip` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[ID_TYPES]]` | +`properties` | `NotRequired[Optional[Dict[str, Any]]]` | +`timestamp` | `NotRequired[Optional[Union[datetime, str]]]` | +`uuid` | `NotRequired[Optional[Union[str, UUID]]]` | + +#### `posthog.args.OptionalSetArgs.disable_geoip` + +```python +disable_geoip: NotRequired[Optional[bool]] +``` + +#### `posthog.args.OptionalSetArgs.distinct_id` + +```python +distinct_id: NotRequired[Optional[ID_TYPES]] +``` + +#### `posthog.args.OptionalSetArgs.properties` + +```python +properties: NotRequired[Optional[Dict[str, Any]]] +``` + +#### `posthog.args.OptionalSetArgs.timestamp` + +```python +timestamp: NotRequired[Optional[Union[datetime, str]]] +``` + +#### `posthog.args.OptionalSetArgs.uuid` + +```python +uuid: NotRequired[Optional[Union[str, UUID]]] +``` + +### `CodeEmailArgs` + +Bases: `_RecipientArgs` + +A send of email content that your code rendered for one recipient, named by a key. + +The content goes out as is. To send a React email, render it to HTML in +your app first. + +An optional field passed as `None` counts as left out. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`to` | | One recipient email address. | +`template_key` | | Names the email, so its metrics, logs and status group under it. Letters, digits, `-` and `_`, at most 400. | +`subject` | | The subject line. | +`html` | | The HTML body. Give `html`, `text` or both. | +`text` | | The plain-text body. Without it, PostHog derives it from `html`. HTML with no text in it, such as a single image, goes out without a plain-text part. | +`from_` | | A verified sender, such as `"Acme "`. | +`reply_to` | | One address or a list of addresses. An empty list sends no reply-to. | +`capture_engagement` | | Capture the email's opens and clicks as events of the recipient. Defaults to `True`. A project whose admin turned engagement capture off captures nothing, whatever the send asks. A template made in PostHog follows the project's setting, so the template form doesn't take it. | +`distinct_id` | | The recipient's distinct ID in your product. | +`idempotency_key` | | 1 to 255 visible ASCII characters. Template sends and code sends share one set of keys: a key already used for another email, or for a `template_id` send, raises `idempotency_key_reused`. A retry with the same key returns the first send's result, also when its workflow was paused since. | +`max_retries` | | Overrides the client's maximum number of retries for this send. `0` turns retries off. | + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`capture_engagement` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[str]]` | +`from_` | `NotRequired[Optional[str]]` | +`html` | `NotRequired[Optional[str]]` | +`idempotency_key` | `NotRequired[Optional[str]]` | +`max_retries` | `NotRequired[Optional[int]]` | +`reply_to` | `NotRequired[Optional[Union[str, Sequence[str]]]]` | +`subject` | `str` | +`template_key` | `str` | +`text` | `NotRequired[Optional[str]]` | +`to` | `str` | + +#### `posthog.emails.CodeEmailArgs.capture_engagement` + +```python +capture_engagement: NotRequired[Optional[bool]] +``` + +#### `posthog.emails.CodeEmailArgs.distinct_id` + +```python +distinct_id: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.from_` + +```python +from_: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.html` + +```python +html: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.idempotency_key` + +```python +idempotency_key: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.max_retries` + +```python +max_retries: NotRequired[Optional[int]] +``` + +#### `posthog.emails.CodeEmailArgs.reply_to` + +```python +reply_to: NotRequired[Optional[Union[str, Sequence[str]]]] +``` + +#### `posthog.emails.CodeEmailArgs.subject` + +```python +subject: str +``` + +#### `posthog.emails.CodeEmailArgs.template_key` + +```python +template_key: str +``` + +#### `posthog.emails.CodeEmailArgs.text` + +```python +text: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.to` + +```python +to: str +``` diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index 72e490700..d44721f51 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host: str = None, debug: str = False, max_queue_size: str = 10000, send: str = True, on_error: str = None, flush_at: str = 100, flush_interval: str = 5.0, gzip: str = False, max_retries: str = 3, sync_mode: str = False, timeout: float = 15, thread: float = 1, poll_interval: float = 30, personal_api_key: float = None, disabled: float = False, disable_geoip: float = True, is_server: float = True, historical_migration: float = False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: float = 1, super_properties: float = None, enable_exception_autocapture: float = False, log_captured_exceptions: float = False, project_root: float = None, privacy_mode: float = False, before_send: float = None, flag_fallback_cache_url: float = None, enable_local_evaluation: float = True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables: Optional[FlagDefinitionCacheProvider] = False, code_variables_mask_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_ignore_patterns: Optional[FlagDefinitionCacheProvider] = None, code_variables_mask_url_credentials: Optional[FlagDefinitionCacheProvider] = None, code_variables_detect_secrets: Optional[FlagDefinitionCacheProvider] = None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting: list[str] | None = False, exception_autocapture_bucket_size: list[str] | None = ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate: list[str] | None = ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds: list[str] | None = ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key: Optional[Union[CaptureCompression, str]] = None, metrics: Optional[dict] = None, enable_full_ai_capture: Optional[dict] = False, capture_trace_context: Optional[dict] = False, _use_ai_lane: Optional[dict] = False, _enable_multimodal_capture: Optional[dict] = False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, _use_ai_lane=False, _enable_multimodal_capture=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -958,7 +958,7 @@ Flat list of the lanes' consumers, analytics first (kept for backwards compatibi ### `Client.new_context` ```python -new_context(fresh = False, capture_exceptions: Optional[bool] = None) +new_context(fresh=False, capture_exceptions: Optional[bool] = None) ``` Create a new context for managing shared state. Learn more about [contexts](/docs/libraries/python#contexts). @@ -988,7 +988,7 @@ Contexts ### `Client.scoped` ```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) +scoped(fresh=False, capture_exceptions: Optional[bool] = None) ``` Decorator that creates a new context for the wrapped function using this client. @@ -1419,7 +1419,7 @@ Name | Type | Description | Default #### `posthog.integrations.django.PosthogContextMiddleware.aextract_properties` ```python -aextract_properties(request) +async aextract_properties(request) ``` Async version of extract_properties for use in async request handling. @@ -1432,7 +1432,7 @@ Follows Django's naming convention for async methods (auser, asave, etc.). #### `posthog.integrations.django.PosthogContextMiddleware.aextract_request_user` ```python -aextract_request_user(request) +async aextract_request_user(request) ``` Async version of extract_request_user for use in async request handling. @@ -1445,7 +1445,7 @@ Follows Django's naming convention for async methods (auser, asave, etc.). #### `posthog.integrations.django.PosthogContextMiddleware.aextract_tags` ```python -aextract_tags(request) +async aextract_tags(request) ``` Compatibility alias for `aextract_properties`. @@ -1894,7 +1894,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error: bool = None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send: Optional[dict[str, Any]] = None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns: bool = None, code_variables_ignore_patterns: bool = None, code_variables_mask_url_credentials: bool = None, code_variables_detect_secrets: bool = None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None +__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -1908,7 +1908,7 @@ Queue an event without blocking for network delivery. ### `AsyncClient.capture_immediate` ```python -capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] +async capture_immediate(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str] ``` Capture one event and wait until its delivery attempt completes. @@ -1967,13 +1967,13 @@ await client.emails.send( ### `AsyncClient.flush` ```python -flush(timeout_seconds: Optional[float] = 10) -> None +async flush(timeout_seconds: Optional[float] = 10) -> None ``` ### `AsyncClient.evaluate_flags` ```python -evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations +async evaluate_flags(distinct_id: Optional[ID_TYPES] = None, *, groups: Optional[Mapping[str, Union[str, int]]] = None, person_properties: Optional[Dict[str, Any]] = None, group_properties: Optional[Dict[str, Dict[str, Any]]] = None, disable_geoip: Optional[bool] = None, flag_keys: Optional[list[str]] = None, device_id: Optional[str] = None) -> FeatureFlagEvaluations ``` Evaluate flags remotely without blocking the event loop. @@ -1992,19 +1992,19 @@ group_identify(group_type: str, group_key: str, properties: Optional[Dict[str, A ### `AsyncClient.shutdown` ```python -shutdown() -> None +async shutdown() -> None ``` ### `AsyncClient.join` ```python -join() -> None +async join() -> None ``` ### `AsyncClient.get_remote_config_payload` ```python -get_remote_config_payload(key: str) -> Optional[Any] +async get_remote_config_payload(key: str) -> Optional[Any] ``` Fetch and decrypt a remote-config payload without blocking the loop. @@ -2046,7 +2046,7 @@ Contexts ### `posthog.scoped` ```python -scoped(fresh = False, capture_exceptions: Optional[bool] = None) +scoped(fresh=False, capture_exceptions: Optional[bool] = None) ``` Decorator that creates a new context for the function. @@ -4121,3 +4121,168 @@ replayed: bool = False ```python warnings: tuple[EmailWarning, ...] = () ``` + +### `OptionalSetArgs` + +Bases: `TypedDict` + +Optional arguments for the set method. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`distinct_id` | | Unique identifier for the user to set properties on. If not set, the context distinct_id is used, if available, otherwise this function does nothing. Setting context-level distinct_id's is recommended. | +`properties` | | Dictionary of properties to set on the person | +`timestamp` | | When the properties were set (defaults to current time). UTC is preferred; non-UTC datetimes and parseable ISO timestamp strings are converted to UTC. | +`uuid` | | Unique identifier for this operation. If not provided, one is generated. This UUID is returned, so you can correlate it with actions in your app. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. | +`disable_geoip` | | Whether to disable GeoIP lookup for this operation. Defaults to False. | + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`disable_geoip` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[ID_TYPES]]` | +`properties` | `NotRequired[Optional[Dict[str, Any]]]` | +`timestamp` | `NotRequired[Optional[Union[datetime, str]]]` | +`uuid` | `NotRequired[Optional[Union[str, UUID]]]` | + +#### `posthog.args.OptionalSetArgs.disable_geoip` + +```python +disable_geoip: NotRequired[Optional[bool]] +``` + +#### `posthog.args.OptionalSetArgs.distinct_id` + +```python +distinct_id: NotRequired[Optional[ID_TYPES]] +``` + +#### `posthog.args.OptionalSetArgs.properties` + +```python +properties: NotRequired[Optional[Dict[str, Any]]] +``` + +#### `posthog.args.OptionalSetArgs.timestamp` + +```python +timestamp: NotRequired[Optional[Union[datetime, str]]] +``` + +#### `posthog.args.OptionalSetArgs.uuid` + +```python +uuid: NotRequired[Optional[Union[str, UUID]]] +``` + +### `CodeEmailArgs` + +Bases: `_RecipientArgs` + +A send of email content that your code rendered for one recipient, named by a key. + +The content goes out as is. To send a React email, render it to HTML in +your app first. + +An optional field passed as `None` counts as left out. + +**Parameters:** + +Name | Type | Description | Default +---- | ---- | ----------- | ------- +`to` | | One recipient email address. | +`template_key` | | Names the email, so its metrics, logs and status group under it. Letters, digits, `-` and `_`, at most 400. | +`subject` | | The subject line. | +`html` | | The HTML body. Give `html`, `text` or both. | +`text` | | The plain-text body. Without it, PostHog derives it from `html`. HTML with no text in it, such as a single image, goes out without a plain-text part. | +`from_` | | A verified sender, such as `"Acme "`. | +`reply_to` | | One address or a list of addresses. An empty list sends no reply-to. | +`capture_engagement` | | Capture the email's opens and clicks as events of the recipient. Defaults to `True`. A project whose admin turned engagement capture off captures nothing, whatever the send asks. A template made in PostHog follows the project's setting, so the template form doesn't take it. | +`distinct_id` | | The recipient's distinct ID in your product. | +`idempotency_key` | | 1 to 255 visible ASCII characters. Template sends and code sends share one set of keys: a key already used for another email, or for a `template_id` send, raises `idempotency_key_reused`. A retry with the same key returns the first send's result, also when its workflow was paused since. | +`max_retries` | | Overrides the client's maximum number of retries for this send. `0` turns retries off. | + +**Attributes:** + +Name | Type | Description +---- | ---- | ----------- +`capture_engagement` | `NotRequired[Optional[bool]]` | +`distinct_id` | `NotRequired[Optional[str]]` | +`from_` | `NotRequired[Optional[str]]` | +`html` | `NotRequired[Optional[str]]` | +`idempotency_key` | `NotRequired[Optional[str]]` | +`max_retries` | `NotRequired[Optional[int]]` | +`reply_to` | `NotRequired[Optional[Union[str, Sequence[str]]]]` | +`subject` | `str` | +`template_key` | `str` | +`text` | `NotRequired[Optional[str]]` | +`to` | `str` | + +#### `posthog.emails.CodeEmailArgs.capture_engagement` + +```python +capture_engagement: NotRequired[Optional[bool]] +``` + +#### `posthog.emails.CodeEmailArgs.distinct_id` + +```python +distinct_id: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.from_` + +```python +from_: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.html` + +```python +html: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.idempotency_key` + +```python +idempotency_key: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.max_retries` + +```python +max_retries: NotRequired[Optional[int]] +``` + +#### `posthog.emails.CodeEmailArgs.reply_to` + +```python +reply_to: NotRequired[Optional[Union[str, Sequence[str]]]] +``` + +#### `posthog.emails.CodeEmailArgs.subject` + +```python +subject: str +``` + +#### `posthog.emails.CodeEmailArgs.template_key` + +```python +template_key: str +``` + +#### `posthog.emails.CodeEmailArgs.text` + +```python +text: NotRequired[Optional[str]] +``` + +#### `posthog.emails.CodeEmailArgs.to` + +```python +to: str +``` From e0324bc0a99290647687b86e9999da15ee9549ec Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 5 Nov 2026 14:36:12 -0500 Subject: [PATCH 7/9] docs: regenerate the 7 and reference pages from the capability map The Category boxes are gone; nothing else changed. Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 175 ------------------------- references/posthog-python-reference.md | 175 ------------------------- 2 files changed, 350 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index da50b2031..a6cf51db6 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -978,13 +978,6 @@ with client.new_context(): client.capture('event_name') ``` -
-Category - -Contexts - -
- ### `Client.scoped` ```python @@ -1000,13 +993,6 @@ Name | Type | Description | Default `fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` `capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -
-Category - -Contexts - -
- ### `Client.tag` ```python @@ -1022,13 +1008,6 @@ Name | Type | Description | Default `name` | `str` | The tag key. | *required* `value` | `Any` | The tag value. | *required* -
-Category - -Contexts - -
- ### `Client.get_tags` ```python @@ -1043,13 +1022,6 @@ Type | Description ---- | ----------- `Dict[str, Any]` | Dict of all tags in the current context. -
-Category - -Contexts - -
- ### `Client.identify_context` ```python @@ -1064,13 +1036,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `distinct_id` | `str` | The distinct ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.set_context_session` ```python @@ -1085,13 +1050,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `session_id` | `str` | The session ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.set_context_device_id` ```python @@ -1106,13 +1064,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `device_id` | `str` | The device ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.feature_flags` ```python @@ -1147,13 +1098,6 @@ Name | Type | Description | Default payloads = posthog.get_feature_payloads('') ``` -
-Category - -Feature flags - -
- ### `Client.get_flags_decision` ```python @@ -1180,13 +1124,6 @@ Name | Type | Description | Default decision = posthog.get_flags_decision('user123') ``` -
-Category - -Feature flags - -
- ### `Client.metrics` ```python @@ -1239,13 +1176,6 @@ Requires `secret_key` for authentication.
-
-Category - -Feature flags - -
- ### `Client.get_feature_flag_evaluation_runtime` ```python @@ -1279,13 +1209,6 @@ if runtime is FeatureFlagEvaluationRuntime.SERVER: ... ``` -
-Category - -Feature flags - -
- ### `Client.get_feature_flag_keys_by_evaluation_runtime` ```python @@ -1322,13 +1245,6 @@ client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( ) ``` -
-Category - -Feature flags - -
- ### `posthog.integrations.django.PosthogContextMiddleware` ```python @@ -2036,13 +1952,6 @@ with new_context(): capture("event_name", properties={"property": "value"}) ``` -
-Category - -Contexts - -
- ### `posthog.scoped` ```python @@ -2068,13 +1977,6 @@ def process_payment(payment_id): capture("payment_started") ``` -
-Category - -Contexts - -
- ### `posthog.set_context_session` ```python @@ -2096,13 +1998,6 @@ from posthog import set_context_session set_context_session("session_123") ``` -
-Category - -Contexts - -
- ### `posthog.set_context_device_id` ```python @@ -2125,13 +2020,6 @@ from posthog import set_context_device_id set_context_device_id("device_123") ``` -
-Category - -Contexts - -
- ### `posthog.identify_context` ```python @@ -2153,13 +2041,6 @@ from posthog import identify_context identify_context("user_123") ``` -
-Category - -Identification - -
- ### `posthog.set_capture_exception_code_variables_context` ```python @@ -2174,13 +2055,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `enabled` | `bool` | Whether exceptions captured in this context should include local variable values from stack frames. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_mask_patterns_context` ```python @@ -2195,13 +2069,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `mask_patterns` | `list[str]` | Variable-name patterns whose values should be replaced with `***` when code variables are captured. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_ignore_patterns_context` ```python @@ -2216,13 +2083,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `ignore_patterns` | `list[str]` | Variable-name patterns that should be omitted entirely when code variables are captured. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_mask_url_credentials_context` ```python @@ -2242,13 +2102,6 @@ Whether to apply entropy-based secret detection as a last-resort redaction of high-entropy values (API keys, tokens, strong passwords) in captured code variables for the current context. -
-Category - -Contexts - -
- ### `posthog.tag` ```python @@ -2271,13 +2124,6 @@ from posthog import tag tag("user_id", "123") ``` -
-Category - -Contexts - -
- ### `posthog.get_tags` ```python @@ -2292,13 +2138,6 @@ Type | Description ---- | ----------- `Dict[str, Any]` | Dict of all tags in the current context -
-Category - -Contexts - -
- ### `posthog.capture` ```python @@ -2881,13 +2720,6 @@ from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_ru runtime = get_feature_flag_evaluation_runtime("my-flag") ``` -
-Category - -Feature flags - -
- ### `posthog.get_feature_flag_keys_by_evaluation_runtime` ```python @@ -2913,13 +2745,6 @@ from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evalu client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) ``` -
-Category - -Feature flags - -
- ### `posthog.load_feature_flags` ```python diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index d44721f51..3022051f2 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -978,13 +978,6 @@ with client.new_context(): client.capture('event_name') ``` -
-Category - -Contexts - -
- ### `Client.scoped` ```python @@ -1000,13 +993,6 @@ Name | Type | Description | Default `fresh` | | Whether to create a fresh context that doesn't inherit from parent. | `False` `capture_exceptions` | `Optional[bool]` | Whether to automatically capture exceptions in this context. If omitted, defaults to this client's exception autocapture setting. | `None` -
-Category - -Contexts - -
- ### `Client.tag` ```python @@ -1022,13 +1008,6 @@ Name | Type | Description | Default `name` | `str` | The tag key. | *required* `value` | `Any` | The tag value. | *required* -
-Category - -Contexts - -
- ### `Client.get_tags` ```python @@ -1043,13 +1022,6 @@ Type | Description ---- | ----------- `Dict[str, Any]` | Dict of all tags in the current context. -
-Category - -Contexts - -
- ### `Client.identify_context` ```python @@ -1064,13 +1036,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `distinct_id` | `str` | The distinct ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.set_context_session` ```python @@ -1085,13 +1050,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `session_id` | `str` | The session ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.set_context_device_id` ```python @@ -1106,13 +1064,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `device_id` | `str` | The device ID to associate with the current context and its children. | *required* -
-Category - -Contexts - -
- ### `Client.feature_flags` ```python @@ -1147,13 +1098,6 @@ Name | Type | Description | Default payloads = posthog.get_feature_payloads('') ``` -
-Category - -Feature flags - -
- ### `Client.get_flags_decision` ```python @@ -1180,13 +1124,6 @@ Name | Type | Description | Default decision = posthog.get_flags_decision('user123') ``` -
-Category - -Feature flags - -
- ### `Client.metrics` ```python @@ -1239,13 +1176,6 @@ Requires `secret_key` for authentication.
-
-Category - -Feature flags - -
- ### `Client.get_feature_flag_evaluation_runtime` ```python @@ -1279,13 +1209,6 @@ if runtime is FeatureFlagEvaluationRuntime.SERVER: ... ``` -
-Category - -Feature flags - -
- ### `Client.get_feature_flag_keys_by_evaluation_runtime` ```python @@ -1322,13 +1245,6 @@ client_keys = posthog.get_feature_flag_keys_by_evaluation_runtime( ) ``` -
-Category - -Feature flags - -
- ### `posthog.integrations.django.PosthogContextMiddleware` ```python @@ -2036,13 +1952,6 @@ with new_context(): capture("event_name", properties={"property": "value"}) ``` -
-Category - -Contexts - -
- ### `posthog.scoped` ```python @@ -2068,13 +1977,6 @@ def process_payment(payment_id): capture("payment_started") ``` -
-Category - -Contexts - -
- ### `posthog.set_context_session` ```python @@ -2096,13 +1998,6 @@ from posthog import set_context_session set_context_session("session_123") ``` -
-Category - -Contexts - -
- ### `posthog.set_context_device_id` ```python @@ -2125,13 +2020,6 @@ from posthog import set_context_device_id set_context_device_id("device_123") ``` -
-Category - -Contexts - -
- ### `posthog.identify_context` ```python @@ -2153,13 +2041,6 @@ from posthog import identify_context identify_context("user_123") ``` -
-Category - -Identification - -
- ### `posthog.set_capture_exception_code_variables_context` ```python @@ -2174,13 +2055,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `enabled` | `bool` | Whether exceptions captured in this context should include local variable values from stack frames. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_mask_patterns_context` ```python @@ -2195,13 +2069,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `mask_patterns` | `list[str]` | Variable-name patterns whose values should be replaced with `***` when code variables are captured. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_ignore_patterns_context` ```python @@ -2216,13 +2083,6 @@ Name | Type | Description | Default ---- | ---- | ----------- | ------- `ignore_patterns` | `list[str]` | Variable-name patterns that should be omitted entirely when code variables are captured. | *required* -
-Category - -Contexts - -
- ### `posthog.set_code_variables_mask_url_credentials_context` ```python @@ -2242,13 +2102,6 @@ Whether to apply entropy-based secret detection as a last-resort redaction of high-entropy values (API keys, tokens, strong passwords) in captured code variables for the current context. -
-Category - -Contexts - -
- ### `posthog.tag` ```python @@ -2271,13 +2124,6 @@ from posthog import tag tag("user_id", "123") ``` -
-Category - -Contexts - -
- ### `posthog.get_tags` ```python @@ -2292,13 +2138,6 @@ Type | Description ---- | ----------- `Dict[str, Any]` | Dict of all tags in the current context -
-Category - -Contexts - -
- ### `posthog.capture` ```python @@ -2881,13 +2720,6 @@ from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_evaluation_ru runtime = get_feature_flag_evaluation_runtime("my-flag") ``` -
-Category - -Feature flags - -
- ### `posthog.get_feature_flag_keys_by_evaluation_runtime` ```python @@ -2913,13 +2745,6 @@ from posthog import FeatureFlagEvaluationRuntime, get_feature_flag_keys_by_evalu client_keys = get_feature_flag_keys_by_evaluation_runtime(FeatureFlagEvaluationRuntime.CLIENT) ``` -
-Category - -Feature flags - -
- ### `posthog.load_feature_flags` ```python From 3cd122ab723ae1594f47ec8ccb50091bd0faa6cd Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 5 Nov 2026 16:12:10 -0500 Subject: [PATCH 8/9] docs: regenerate the 7.x reference without private parameters Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 2 +- references/posthog-python-reference.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index a6cf51db6..cb917fce5 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, _use_ai_lane=False, _enable_multimodal_capture=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index 3022051f2..8d6f9cfba 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, _use_ai_lane=False, _enable_multimodal_capture=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. From 34d0850a3090aef6b82d2c500814ad69c1fe0979 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 5 Nov 2026 19:28:21 -0500 Subject: [PATCH 9/9] docs: regenerate the 7.x reference with whole summaries and Returns Co-Authored-By: Claude Opus 5.5 --- references/posthog-python-7.md | 69 ++++++++++---------------- references/posthog-python-reference.md | 69 ++++++++++---------------- 2 files changed, 54 insertions(+), 84 deletions(-) diff --git a/references/posthog-python-7.md b/references/posthog-python-7.md index cb917fce5..52f2fcdb8 100644 --- a/references/posthog-python-7.md +++ b/references/posthog-python-7.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +Client(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -146,7 +146,7 @@ Name | Type | Description | Default `timeout` | `float` | HTTP request timeout in seconds for event uploads. | `15` `thread` | | Number of background consumer threads. | `1` `poll_interval` | | Seconds between local feature flag definition refreshes. | `30` -`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example::
posthog.Client(project_api_key, secret_key="phx_...") | `None` +`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. For example, `posthog.Client(project_api_key, secret_key="phx_...")`. | `None` `personal_api_key` | | Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | `None` `disabled` | | If True, disable captures and API requests. Useful in tests. | `False` `disable_geoip` | | Whether to disable server-side GeoIP enrichment. Defaults to True. | `True` @@ -440,7 +440,7 @@ try: # Some code that might fail pass except Exception as e: - posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) + posthog.capture_exception(e, distinct_id='user_distinct_id', properties=additional_properties) ``` ## Emails @@ -569,9 +569,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[object]` | The payload associated with the matched feature flag value, or None. -`Optional[object]` | This method returns the payload only, not the FeatureFlagResult wrapper -`Optional[object]` | used internally to compute it. +`Optional[object]` | The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. **Examples:** @@ -934,8 +932,7 @@ Return feature flag definitions loaded for local evaluation. Type | Description ---- | ----------- - | The currently loaded feature flag definitions, or `None` before - | local evaluation has loaded definitions. + | The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. ## SDK utils @@ -1164,10 +1161,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- - | The payload associated with the feature flag, or `None` if the - | client is disabled, no personal API key is configured, or the request - | fails. Encrypted payloads are decrypted by PostHog before being - | returned. + | The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned.
Note @@ -1194,10 +1188,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has -`Optional[FeatureFlagEvaluationRuntime]` | not loaded a definition for this key. A definition that carries no -`Optional[FeatureFlagEvaluationRuntime]` | runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default -`Optional[FeatureFlagEvaluationRuntime]` | PostHog applies. +`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. **Examples:** @@ -1232,8 +1223,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`list[str]` | The matching flag keys, in the order local evaluation loaded them. -`list[str]` | Empty when no definitions are loaded. +`list[str]` | The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. **Examples:** @@ -1672,8 +1662,8 @@ Name | Type | Description | Default Name | Description ---- | ----------- -`instrument` | Connect Celery signal handlers to capture task events and exceptions. -`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events +`instrument` | Connect Celery signal handlers to capture task events and exceptions. Call this after initializing the PostHog client and this integration. +`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events and cleanly shutdown the integration. `uninstrument` | Disconnect Celery signal handlers and unregister exit cleanup. **Attributes:** @@ -1810,7 +1800,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None +AsyncClient(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -2164,7 +2154,7 @@ Capture allows you to capture anything a user does within your system, which you ```python # Context and capture usage -from posthog import new_context, identify_context, tag_context, capture +from posthog import new_context, identify_context, tag, capture # Enter a new context (e.g. a request/response cycle, an instance of a background job, etc) with new_context(): # Associate this context with some user, by distinct_id @@ -2185,7 +2175,7 @@ with new_context(): capture('purchase', groups={'company': 'id:5'}) # Adding a tag to the current context will cause it to appear on all subsequent events - tag_context('some-tag', 'some-value') + tag('some-tag', 'some-value') capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict ``` @@ -2577,9 +2567,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[object]` | The payload associated with the matched feature flag value, or None. -`Optional[object]` | This function returns the payload only, not the FeatureFlagResult wrapper -`Optional[object]` | used internally to compute it. +`Optional[object]` | The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. ### `posthog.get_remote_config_payload` @@ -2921,9 +2909,7 @@ Most applications should either instantiate `Posthog` directly or set Type | Description ---- | ----------- -`Client` | The global `Client` instance. If both `api_key` and -`Client` | `project_api_key` are missing or blank, the client is disabled and -`Client` | module-level calls become no-ops. +`Client` | The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. ## Types @@ -3020,12 +3006,12 @@ Returned by `Client.evaluate_flags` — branch on `is_enabled` / `flags` option so the captured event carries the exact flag values the code branched on. -Example:: - - flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) - if flags.is_enabled("new-dashboard"): - render_new_dashboard() - posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +```python +flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +``` To narrow the set of flags that get attached to a captured event, use the in-memory helpers `only` and `only_accessed`. To narrow the set of flags requested @@ -3037,16 +3023,16 @@ Name | Description ---- | ----------- `get_flag` | Return the flag value. Fires `$feature_flag_called` on first access. `get_flag_payload` | Return the payload associated with a flag. -`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the -`only` | Return a filtered copy containing only flags with the given keys. Keys that -`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` +`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. +`only` | Return a filtered copy containing only flags with the given keys. Keys that are not present in the evaluation are dropped and logged as a warning. +`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` or `get_flag` before this call. **Attributes:** Name | Type | Description ---- | ---- | ----------- `keys` | `List[str]` | Return the flag keys that are part of this evaluation. -`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation +`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation left it without a value. Internal — instances are created by the SDK via `Client.evaluate_flags()`. @@ -3166,7 +3152,7 @@ Name | Description ---- | ----------- `from_flag_details` | Create a FeatureFlagResult from a FeatureFlag object. `from_value_and_payload` | Creates a FeatureFlagResult from a flag value and payload. -`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. #### `posthog.types.FeatureFlagResult.enabled` @@ -3796,8 +3782,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`SendEmailResult` | The queued email. A result means PostHog queued the email, not that -`SendEmailResult` | it was delivered. +`SendEmailResult` | The queued email. A result means PostHog queued the email, not that it was delivered. **Raises:** diff --git a/references/posthog-python-reference.md b/references/posthog-python-reference.md index 8d6f9cfba..c1ecf21c7 100644 --- a/references/posthog-python-reference.md +++ b/references/posthog-python-reference.md @@ -123,7 +123,7 @@ In an asyncio app, use `AsyncPosthog` as an async context manager instead. See [ ### `Client(...)` ```python -__init__(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) +Client(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout: float = 15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries=1, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, secret_key=None, metrics: Optional[dict] = None, enable_full_ai_capture=False, capture_trace_context=False, traces: Optional[dict] = None, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) ``` Initialize a new PostHog client instance. @@ -146,7 +146,7 @@ Name | Type | Description | Default `timeout` | `float` | HTTP request timeout in seconds for event uploads. | `15` `thread` | | Number of background consumer threads. | `1` `poll_interval` | | Seconds between local feature flag definition refreshes. | `30` -`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example::
posthog.Client(project_api_key, secret_key="phx_...") | `None` +`secret_key` | | A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. For example, `posthog.Client(project_api_key, secret_key="phx_...")`. | `None` `personal_api_key` | | Deprecated alias for `secret_key`. Still honored for backwards compatibility; prefer `secret_key`, which also accepts a Project Secret API Key. | `None` `disabled` | | If True, disable captures and API requests. Useful in tests. | `False` `disable_geoip` | | Whether to disable server-side GeoIP enrichment. Defaults to True. | `True` @@ -440,7 +440,7 @@ try: # Some code that might fail pass except Exception as e: - posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) + posthog.capture_exception(e, distinct_id='user_distinct_id', properties=additional_properties) ``` ## Emails @@ -569,9 +569,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[object]` | The payload associated with the matched feature flag value, or None. -`Optional[object]` | This method returns the payload only, not the FeatureFlagResult wrapper -`Optional[object]` | used internally to compute it. +`Optional[object]` | The payload associated with the matched feature flag value, or None. This method returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. **Examples:** @@ -934,8 +932,7 @@ Return feature flag definitions loaded for local evaluation. Type | Description ---- | ----------- - | The currently loaded feature flag definitions, or `None` before - | local evaluation has loaded definitions. + | The currently loaded feature flag definitions, or `None` before local evaluation has loaded definitions. ## SDK utils @@ -1164,10 +1161,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- - | The payload associated with the feature flag, or `None` if the - | client is disabled, no personal API key is configured, or the request - | fails. Encrypted payloads are decrypted by PostHog before being - | returned. + | The payload associated with the feature flag, or `None` if the client is disabled, no personal API key is configured, or the request fails. Encrypted payloads are decrypted by PostHog before being returned.
Note @@ -1194,10 +1188,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has -`Optional[FeatureFlagEvaluationRuntime]` | not loaded a definition for this key. A definition that carries no -`Optional[FeatureFlagEvaluationRuntime]` | runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default -`Optional[FeatureFlagEvaluationRuntime]` | PostHog applies. +`Optional[FeatureFlagEvaluationRuntime]` | The flag's evaluation runtime, or `None` when local evaluation has not loaded a definition for this key. A definition that carries no runtime reports `FeatureFlagEvaluationRuntime.ALL`, the default PostHog applies. **Examples:** @@ -1232,8 +1223,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`list[str]` | The matching flag keys, in the order local evaluation loaded them. -`list[str]` | Empty when no definitions are loaded. +`list[str]` | The matching flag keys, in the order local evaluation loaded them. Empty when no definitions are loaded. **Examples:** @@ -1672,8 +1662,8 @@ Name | Type | Description | Default Name | Description ---- | ----------- -`instrument` | Connect Celery signal handlers to capture task events and exceptions. -`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events +`instrument` | Connect Celery signal handlers to capture task events and exceptions. Call this after initializing the PostHog client and this integration. +`shutdown` | Disconnect all signal handlers registered by `instrument()`, flush all pending events and cleanly shutdown the integration. `uninstrument` | Disconnect Celery signal handlers and unregister exit cleanup. **Attributes:** @@ -1810,7 +1800,7 @@ Needs the `async` extra, `posthog[async]`. ### `AsyncClient(...)` ```python -__init__(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None +AsyncClient(project_api_key: str, host: Optional[str] = None, debug: bool = False, max_queue_size: int = 10000, send: bool = True, on_error=None, flush_at: int = 100, flush_interval: float = 5.0, gzip: bool = False, max_retries: int = 3, timeout: float = 15, thread: int = 1, disabled: bool = False, disable_geoip: bool = True, is_server: bool = True, historical_migration: bool = False, super_properties: Optional[dict[str, Any]] = None, before_send=None, log_captured_exceptions: bool = False, project_root: Optional[str] = None, capture_exception_code_variables: bool = False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, code_variables_mask_url_credentials=None, code_variables_detect_secrets=None, in_app_modules: Optional[list[str]] = None, capture_mode: Optional[Union[CaptureMode, str]] = None, capture_compression: Optional[Union[CaptureCompression, str]] = None, capture_trace_context: bool = False, secret_key: Optional[str] = None, personal_api_key: Optional[str] = None, feature_flags_request_timeout_seconds: float = 3, feature_flags_request_max_retries: int = 1, app_host: Optional[str] = None, email_request_timeout_seconds: float = 15, email_request_max_retries: int = 2, migrated_from: Optional[str] = None) -> None ``` ### `AsyncClient.capture` @@ -2164,7 +2154,7 @@ Capture allows you to capture anything a user does within your system, which you ```python # Context and capture usage -from posthog import new_context, identify_context, tag_context, capture +from posthog import new_context, identify_context, tag, capture # Enter a new context (e.g. a request/response cycle, an instance of a background job, etc) with new_context(): # Associate this context with some user, by distinct_id @@ -2185,7 +2175,7 @@ with new_context(): capture('purchase', groups={'company': 'id:5'}) # Adding a tag to the current context will cause it to appear on all subsequent events - tag_context('some-tag', 'some-value') + tag('some-tag', 'some-value') capture('another-event') # Will be captured with `'some-tag': 'some-value'` in the properties dict ``` @@ -2577,9 +2567,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`Optional[object]` | The payload associated with the matched feature flag value, or None. -`Optional[object]` | This function returns the payload only, not the FeatureFlagResult wrapper -`Optional[object]` | used internally to compute it. +`Optional[object]` | The payload associated with the matched feature flag value, or None. This function returns the payload only, not the FeatureFlagResult wrapper used internally to compute it. ### `posthog.get_remote_config_payload` @@ -2921,9 +2909,7 @@ Most applications should either instantiate `Posthog` directly or set Type | Description ---- | ----------- -`Client` | The global `Client` instance. If both `api_key` and -`Client` | `project_api_key` are missing or blank, the client is disabled and -`Client` | module-level calls become no-ops. +`Client` | The global `Client` instance. If both `api_key` and `project_api_key` are missing or blank, the client is disabled and module-level calls become no-ops. ## Types @@ -3020,12 +3006,12 @@ Returned by `Client.evaluate_flags` — branch on `is_enabled` / `flags` option so the captured event carries the exact flag values the code branched on. -Example:: - - flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) - if flags.is_enabled("new-dashboard"): - render_new_dashboard() - posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +```python +flags = posthog.evaluate_flags(distinct_id, person_properties={"plan": "enterprise"}) +if flags.is_enabled("new-dashboard"): + render_new_dashboard() +posthog.capture("page_viewed", distinct_id=distinct_id, flags=flags) +``` To narrow the set of flags that get attached to a captured event, use the in-memory helpers `only` and `only_accessed`. To narrow the set of flags requested @@ -3037,16 +3023,16 @@ Name | Description ---- | ----------- `get_flag` | Return the flag value. Fires `$feature_flag_called` on first access. `get_flag_payload` | Return the payload associated with a flag. -`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the -`only` | Return a filtered copy containing only flags with the given keys. Keys that -`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` +`is_enabled` | Return whether the flag is enabled. Fires `$feature_flag_called` on the first access per (distinct_id, flag, value) tuple, deduped via the SDK's cache. +`only` | Return a filtered copy containing only flags with the given keys. Keys that are not present in the evaluation are dropped and logged as a warning. +`only_accessed` | Return a filtered copy containing only flags accessed via `is_enabled` or `get_flag` before this call. **Attributes:** Name | Type | Description ---- | ---- | ----------- `keys` | `List[str]` | Return the flag keys that are part of this evaluation. -`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation +`unresolved_flags` | `Mapping[str, UnresolvedFlagReason]` | Return a read-only mapping of flag key to the reason local evaluation left it without a value. Internal — instances are created by the SDK via `Client.evaluate_flags()`. @@ -3166,7 +3152,7 @@ Name | Description ---- | ----------- `from_flag_details` | Create a FeatureFlagResult from a FeatureFlag object. `from_value_and_payload` | Creates a FeatureFlagResult from a flag value and payload. -`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. +`get_value` | Returns the value of the flag. This is the variant if it exists, otherwise the enabled value. This is the value we report as `$feature_flag_response` in the `$feature_flag_called` event. #### `posthog.types.FeatureFlagResult.enabled` @@ -3796,8 +3782,7 @@ Name | Type | Description | Default Type | Description ---- | ----------- -`SendEmailResult` | The queued email. A result means PostHog queued the email, not that -`SendEmailResult` | it was delivered. +`SendEmailResult` | The queued email. A result means PostHog queued the email, not that it was delivered. **Raises:**