Python SDK
Server-side capture for Python — events, identity, super properties and feature flags with zero dependencies.
azfive-capture is the Python server SDK — events, identity, super properties, and feature flags / experiments, implemented on the stdlib only (zero dependencies). It follows the same behavioral spec as every other AZ-Five SDK.
Install
pip install azfive-capture
The import name is azfive_capture. Use a secret API key with the events:write scope (Settings → API Keys) — server SDKs post to /api/v1/events, where public tokens are rejected. Secret keys are also valid on /v1/decide, so server-side flag evaluation needs no extra setup.
Initialize
from azfive_capture import Client
azfive = Client("azfive_…", host="https://app.az-five.com", project="backend")
host is required (keyword-only); a missing api_key or host raises at construction — the only place this SDK raises. Delivery and flag failures are always silent.
Capture events
Server processes handle many users at once, so pass distinct_id per call:
azfive.capture("invoice_paid", {"amount": 99}, distinct_id="user-42")
# Super properties — merged into every subsequent event
azfive.register({"deployment": "eu-1"})
azfive.register_once({"first_seen_version": "2.3"})
azfive.unregister("deployment")
Events without a distinct_id are attributed to the client’s own anonymous id.
Identify & person properties
azfive.identify("user-42", set={"plan": "pro"})
azfive.alias("legacy-77")
azfive.people.set({"plan": "enterprise"}, distinct_id="user-42")
azfive.people.set_once({"signup_date": "2026-08-01"}, distinct_id="user-42")
identify with a new id emits az.identify (carrying the previous id as $anonymous_id) and reloads flags; repeating it with the same id only emits an az.set update. reset() mints a fresh anonymous id and clears super properties — reset(reset_device_id=True) also re-mints the device id. Opt-out (opt_out_capturing() / opt_in_capturing() / has_opted_out_capturing()) drops events at capture time and survives reset().
Feature flags
Flag methods take the distinct_id first; each decide response is cached per id for 60 seconds:
variant = azfive.get_flag("user-42", "exp-checkout") # 'control' | 'test' | True | False | None
if azfive.is_flag_enabled("user-42", "new-onboarding"):
payload = azfive.get_flag_payload("user-42", "new-onboarding") # no exposure event
azfive.reload_flags("user-42") # bust one id's cache
get_flag and is_flag_enabled capture an az.flag_called exposure automatically, deduped per (distinct_id, flag, value). get_flag_payload never fires an exposure. Optional person_properties on each call are sent to /v1/decide for property-based targeting.
Flush & shutdown
Events queue in memory and are delivered by a daemon thread (batch 10 / 5 s / max 1,000, oldest dropped). Failed batches — 429 included — retry on the next tick.
azfive.flush() # force delivery now
azfive.close() # drain the queue and stop the worker
close() is also registered via atexit, so short-lived scripts don’t lose their tail of events.
Reference
Client constructor
| Parameter | Default | Notes |
|---|---|---|
api_key | required | Secret key (azfive_…) with events:write |
host | required | AZ-Five deployment base URL (keyword-only) |
project | "default" | Target project slug |
batch_size | 10 | Queue length that triggers a flush |
flush_interval_s | 5.0 | Background flush period (seconds) |
max_queue_size | 1000 | Queue bound; oldest events dropped on overflow |
gzip | False | Content-Encoding: gzip on event POSTs |
opt_out | False | Start opted out of capturing |
disable_decide | False | Disable the /v1/decide flag client |
extra_static_props | None | Extra static properties merged into every event |
start_flush_thread | True | Disable the background thread (tests) |
API
capture · identify · alias · reset · get_distinct_id · get_session_id · register / register_once / unregister · people.set / people.set_once · opt_in_capturing / opt_out_capturing / has_opted_out_capturing · get_flag / is_flag_enabled / get_flag_payload / reload_flags · flush · close.
Behavior notes
- Server runtime: identity is in-memory only, there are no sessions (
get_session_id()returns""), and events are stamped with$device_type: "Server". - Custom event names: anything except the reserved
az.prefix, ≤ 200 characters; properties ≤ 64 KiB serialized. - The decide cache is a bounded LRU (per-
distinct_id, 60 s TTL); exposure dedup uses a bounded LRU as well, so long-running processes don’t grow without bound.