Official Python SDK for ToggleAI — Feature Flags, Remote Configs, and Logging.
Project description
toggleai-sdk (Python)
Official Python SDK for ToggleAI — Feature Flags, Remote Configs, Error Monitoring, and A/B Testing.
Features
- 🌍 Async-native — built on
httpxwith fullasynciosupport. - ⚡ Zero-latency evaluation — evaluates flags locally in-memory after the initial fetch.
- 🔄 Real-time polling — automatic background refresh keeps configs fresh.
- 🎯 Advanced targeting — full support for targeting rules, user attributes, and percentage rollouts.
- 🐞 Structured logging — batched, async-safe log & error ingestion.
- 🧪 A/B Testing — track conversions and record exposures for running experiments.
- 🖥️ Server-side evaluation — call the backend for absolute real-time accuracy.
- 🔧 Sync-friendly —
init_sync()andclose_sync()for Django/Flask projects. - 🛡️ Typed — full type hints throughout, compatible with
mypy --strict.
Installation
pip install toggleai-sdk
# or with uv / poetry
uv add toggleai-sdk
poetry add toggleai-sdk
Requires Python 3.10+ (for match expressions in the evaluator).
Quick Start
Async (FastAPI, etc.)
from toggleai import ToggleAIClient, EvaluationContext
client = ToggleAIClient(
client_id="pk_live_xxxxxxxxxxxxxxxx",
secret="sk_live_xxxxxxxxxxxxxxxx",
)
await client.init()
# Boolean flag — evaluated locally (sub-ms)
if client.get_flag("new-checkout"):
show_new_checkout()
# Typed flag value
color = client.get_flag_value("button-color", default="#000")
# Remote config
timeout = client.get_config("api_timeout_ms", default=5000)
# With user context (for targeting + rollout)
ctx = EvaluationContext(user_id="user_123", attributes={"plan": "premium", "country": "US"})
if client.get_flag("premium-feature", ctx):
...
await client.close()
Sync (Django / Flask)
from toggleai import ToggleAIClient
client = ToggleAIClient(client_id="pk_live_xxx", secret="sk_live_xxx")
client.init_sync() # blocks until ready
enabled = client.get_flag("dark-mode")
timeout = client.get_config("api_timeout_ms", default=5000)
client.close_sync() # flush logs + teardown
Feature Flags
Local evaluation (instant, cached)
# Boolean
enabled = client.get_flag("my-flag")
# Typed value (multivariate flag)
color = client.get_flag_value("button-color", default="blue")
max_qty = client.get_flag_value("max-quantity", default=10)
# Full evaluation result with reason
result = client.evaluate_flag("my-flag", ctx)
print(result.reason) # "TARGETING_MATCH", "ROLLOUT", "DEFAULT", …
print(result.variation_key) # None or "variation-a"
# Evaluate all flags at once
all_results = client.evaluate_all_flags(ctx)
Server-side evaluation (real-time)
# Single flag
result = await client.evaluate_flag_remote("my-flag", ctx)
# All flags
results = await client.evaluate_all_flags_remote(ctx)
Remote Configs
# Single value (typed by caller)
timeout: int = client.get_config("api_timeout_ms", default=5000)
theme: dict = client.get_config("theme_colors", default={"primary": "#fff"})
# All configs
all_configs = client.get_all_configs() # Dict[str, Any]
# Existence check
if client.has_config("feature_rollout_message"):
...
Logging & Error Monitoring
logger = client.get_logger()
logger.info("User signed in", context={"userId": "u_123"})
logger.warn("Slow query detected", duration_ms=450.0)
logger.error("Payment failed", context={"orderId": "o_99"})
logger.fatal("Out of memory")
# Capture an exception with stack trace
try:
await risky_operation()
except Exception as exc:
logger.capture_error(exc, context={"endpoint": "/checkout"})
# Set a default context applied to all subsequent logs
logger.set_context({"service": "payments", "version": "2.1.0"})
# Manual flush (call before shutdown)
await logger.flush()
A/B Experiment Tracking
Track a conversion event
from toggleai import TrackConversionOptions
await client.track_conversion(TrackConversionOptions(
experiment_id="exp_xyz",
variation_id="var_abc", # DB UUID from evaluate_flag().variation_key
metric_key="signup",
value=1.0,
user_id="user_42",
))
Auto-experiment event tracking
from toggleai import TrackEventOptions
await client.track(TrackEventOptions(
metric_key="purchase_completed",
user_identifier="user_42",
value=29.99,
))
Record an exposure
from toggleai import ExposureOptions
await client.record_exposure(ExposureOptions(
experiment_id="exp_xyz",
variation_id="var_abc",
user_identifier="user_42",
))
Event Listeners
client = ToggleAIClient(
client_id="pk_live_xxx",
secret="sk_live_xxx",
on_ready=lambda: print("ToggleAI ready!"),
on_config_update=lambda p: print(f"Config refreshed at {p.generated_at}"),
on_error=lambda e: print(f"SDK error: {e.code} — {e}"),
)
Default Context
client = ToggleAIClient(
client_id="...",
secret="...",
default_context=EvaluationContext(
attributes={"server_region": "us-east-1", "app_version": "3.0.0"}
),
)
The default context is merged with every per-call context (per-call takes precedence).
Error Handling
from toggleai import ToggleAIError
try:
await client.init()
except ToggleAIError as exc:
match exc.code:
case "INVALID_KEY": print("Check your API credentials.")
case "RATE_LIMITED": print("Slow down.")
case "FORBIDDEN": print("Insufficient API key scope.")
case "NETWORK_ERROR": print("Cannot reach the ToggleAI API.")
case _: print(f"Unexpected error: {exc}")
Inspection
payload = client.get_payload() # ConfigPayload | None
flag_def = client.get_flag_definition("my-flag")
flag_keys = client.get_flag_keys() # List[str]
config_keys = client.get_config_keys() # List[str]
env = client.get_environment() # {"id": ..., "slug": ...}
API Reference
Client
| Method | Returns | Description |
|---|---|---|
init() |
Awaitable[None] |
Fetch config, start polling |
init_sync() |
None |
Sync wrapper for init() |
close() |
Awaitable[None] |
Stop polling, flush, teardown |
close_sync() |
None |
Sync wrapper for close() |
refresh() |
Awaitable[None] |
Manually refresh config |
is_ready() |
bool |
Is client initialised? |
get_state() |
ClientState |
Current lifecycle state |
Feature Flags
| Method | Returns | Description |
|---|---|---|
get_flag(key, ctx?, default?) |
bool |
Boolean flag value |
get_flag_value(key, ctx?, default?) |
Any |
Typed flag value |
evaluate_flag(key, ctx?) |
FlagEvaluationResult |
Full local evaluation |
evaluate_all_flags(ctx?) |
Dict[str, ...] |
All flags, local |
evaluate_flag_remote(key, ctx?) |
Awaitable[FlagEvaluationResult] |
Server-side single |
evaluate_all_flags_remote(ctx?) |
Awaitable[Dict[str, ...]] |
Server-side all |
Remote Configs
| Method | Returns | Description |
|---|---|---|
get_config(key, default?) |
Any |
Config value |
get_all_configs() |
Dict[str, Any] |
All config values |
has_config(key) |
bool |
Key existence check |
get_config_keys() |
List[str] |
All config keys |
Logging
| Method | Description |
|---|---|
get_logger() |
Get the attached ToggleAILogger |
logger.info(msg, **kw) |
Log an info message |
logger.error(msg_or_exc, **kw) |
Log error or exception |
logger.capture_error(exc, **kw) |
Capture exception + stack trace |
logger.set_context(ctx) |
Set default log context |
await logger.flush() |
Flush queued events |
Backend Endpoints
| Endpoint | Method | Description |
|---|---|---|
/sdk/config |
GET | Fetch full config payload |
/sdk/evaluate |
POST | Server-side evaluate all flags |
/sdk/evaluate/:flagKey |
POST | Server-side evaluate single flag |
/sdk/connect |
POST | Register SDK connection |
/sdk/logs/ingest |
POST | Ingest a single log event |
/sdk/logs/ingest/batch |
POST | Ingest a batch of log events |
/sdk/experiments/:id/track |
POST | Track experiment conversion |
/sdk/track |
POST | Auto-experiment event tracking |
/sdk/expose |
POST | Record experiment exposures |
Development
# Install dev deps
pip install -e ".[dev]"
# Run tests
pytest
# Type check
mypy toggleai
# Lint
ruff check toggleai tests
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toggleai-0.1.1.tar.gz.
File metadata
- Download URL: toggleai-0.1.1.tar.gz
- Upload date:
- Size: 21.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67a22fba4cd18c59d09ae6ee5b2935c796c2479167fd92b863b77b810791382c
|
|
| MD5 |
d4caaa069b0f132275814fc3f05620c4
|
|
| BLAKE2b-256 |
f12e388fe0afe26aead888f4c031ead7378fbd26b4b5a033316ad0ae5c3276a4
|
File details
Details for the file toggleai-0.1.1-py3-none-any.whl.
File metadata
- Download URL: toggleai-0.1.1-py3-none-any.whl
- Upload date:
- Size: 20.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc17fe3590f7f7385787c1783dc09420550230ba1976cf1f38d995cea3de26aa
|
|
| MD5 |
c8a126ca951d16cd1179e3308c9c4181
|
|
| BLAKE2b-256 |
708029141f4ff325a651078dd7da2c4d98a9e103edba7e4d041c4bd069b0d3fc
|