atrixANALYTICS
SDKs

Python

atrix-analytics for Python 3.9+: thread-safe, dependency-free, never raises.

Server-side Atrix Analytics for Python 3.9 and newer, with no runtime dependencies. Events are batched, gzipped, retried with backoff and deduplicated by a client-generated UUIDv7. The client is thread-safe and never raises; with an invalid key every call does nothing.

pip install atrix-analytics

Quickstart

from atrix_analytics import Atrix

atrix = Atrix("atx_pk_eu_production_XXXXXXXXXXXXXXXXXXXXXX")  # one per process

atrix.capture("user_42", "order_completed", {"amount": 1999, "currency": "AED"})

# Person properties. Pass the visitor's anonymous id (from the web or mobile SDK) to link their history.
atrix.identify("user_42", set={"plan": "pro"}, set_once={"signup_source": "ads"}, anon_id="0190f2a4-5b6c-7d8e-9f01-23456789abcd")

# Groups: per event, plus group profiles.
atrix.capture("user_42", "report_exported", groups={"company": "acme"})
atrix.group_identify("company", "acme", {"name": "Acme", "seats": 40})

# Link a billing customer to the user so revenue webhooks are attributed to them.
atrix.set_revenue_customer("user_42", "cus_Nffrfeu", provider="stripe")

atrix.shutdown()  # optional: also runs automatically at interpreter exit

The host comes from the key: atx_pk_eu_… sends to https://eu.i.analytics.atrix.dev. To use a first-party proxy, pass host="https://analytics.example.com".

Feature flags

import os
from atrix_analytics import Atrix

atrix = Atrix(os.environ["ATRIX_KEY"], flags_secret_key=os.environ.get("ATRIX_FLAGS_SECRET"))

if atrix.is_feature_enabled("new-checkout", "user_42", person_properties={"plan": "pro"}):
    ...
variant = atrix.get_feature_flag("pricing", "user_42")  # "test" | "control" | False | None

With flags_secret_key, flags are evaluated locally (definitions polled with an ETag on a daemon thread) and only inconclusive flags call /flags. Reads emit $feature_flag_called once per user, flag and value.

Options

ArgumentDefault
hostfrom the keyCapture origin override.
flush_at / flush_interval20 / 30.0 sBatching.
max_batch_size100Events per request.
max_queue_size / max_queue_bytes1000 / 5 000 000The oldest events are dropped past this and reported as $dropped_events.
request_timeout10.0 s
consent"granted""pending" holds events in memory; "denied" makes no network calls. Also set_consent().
before_sendfn(event) -> event or None. A hook that raises drops the event.
property_denylistKeys removed after the hook.
super_propertiesStamped on every event. register() / unregister() at runtime.
flush_at_exitTrueFlush through atexit, waiting at most 5 s.
flags_secret_key, flags_poll_intervalLocal flag evaluation.
debugFalseLog problems.

Behaviour

  • capture() never blocks on the network: HTTP runs on a daemon thread, one request in flight at a time.
  • Network errors, timeouts, 408, 429 and 5xx are retried, waiting for Retry-After or min(10 min, 1 s·2^n) with ±50% jitter. A 413 splits the batch; any other 4xx drops it.
  • flush(block=True, timeout=None) waits until the queue is empty or a retry is scheduled. shutdown(timeout=None) flushes and turns the client off. Worker threads are daemons.

On this page