# Python SDK

> switchbox-flags — constructor, methods, and configuration.

The Python SDK is published to PyPI as **`switchbox-flags`** and imported as
`switchbox`. It has **zero runtime dependencies** (Python stdlib only) and is
thread-safe.

```bash
pip install switchbox-flags
```

The same reference ships in the package [README on
PyPI](https://pypi.org/project/switchbox-flags/).

## Switchbox(...)

```python
from switchbox import Switchbox

client = Switchbox(
    sdk_key="your-sdk-key",   # required
    poll_interval=10,          # seconds between background refreshes
    on_error=None,             # callback(exc) on fetch/parse failure
    timeout=10,                # per-fetch HTTP timeout, seconds
    block_on_init=True,        # fetch the first config synchronously
    telemetry=True,            # anonymous usage telemetry (see below)
    on_evaluation=None,        # callback(flag_key, value, user) per evaluation
    cdn_base_url=None,         # override the CDN host (advanced)
)
```

Creates a client. By default (`block_on_init=True`) it performs an initial
**synchronous** fetch on construction — `client.ready` is `True` on return — then
starts a background daemon thread that refreshes the config every `poll_interval`
seconds. Set `block_on_init=False` to return immediately and fetch in the
background instead (checks fall back to your defaults until `ready`). Create one
client at startup and reuse it.

Background refreshes are **conditional requests**: the SDK sends back the `ETag`
the edge gave it, so a poll that finds nothing changed returns an empty `304` with
no config body. Steady-state polling transfers almost nothing, whatever the size
of your config. This is automatic, with nothing to configure.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `sdk_key` | `str` | — | The environment's SDK key from the dashboard. |
| `poll_interval` | `int` | `10` | Seconds between background config refreshes. |
| `on_error` | `Callable[[Exception], None] \| None` | `None` | Invoked when a fetch or parse fails (the client keeps serving the last good config), or when your `on_evaluation` hook raises. |
| `timeout` | `int` | `10` | HTTP timeout for each fetch, in seconds. |
| `block_on_init` | `bool` | `True` | Fetch the first config synchronously (client `ready` on return). `False` fetches in the background. |
| `telemetry` | `bool` | `True` | Anonymous usage telemetry (see below). `False` disables it. |
| `on_evaluation` | `Callable[[str, Any, dict \| None], None] \| None` | `None` | Called after every evaluation with `(flag_key, value, user)`. See [Measure in your own analytics](/docs/recipes/measure-in-your-analytics). |
| `cdn_base_url` | `str \| None` | `None` | Override the CDN base URL. Defaults to the Switchbox edge; you rarely need this. |

## client.ready

```python
if client.ready:
    ...
```

A property — `True` once a config has been loaded at least once. Useful to gate
startup logic on the first successful fetch.

## client.enabled(flag_key, user=None)

```python
client.enabled("new_checkout", user={"user_id": "42"})  # -> bool
```

Returns whether a boolean flag is enabled for the user. Returns `False` if the
flag doesn't exist or no config has loaded — a safe default.

| Parameter | Type | Description |
|---|---|---|
| `flag_key` | `str` | The flag key to evaluate. |
| `user` | `dict \| None` | User context for targeting and rollouts. |

## client.get_value(flag_key, user=None, default=None)

```python
client.get_value("search_algorithm", user={"user_id": "42"}, default="v1")
```

Returns the resolved value of a string, number, or JSON flag (a `json` flag comes
back as a parsed object/array). Returns `default` if the flag doesn't exist or no
config is available.

| Parameter | Type | Description |
|---|---|---|
| `flag_key` | `str` | The flag key to evaluate. |
| `user` | `dict \| None` | User context for targeting and rollouts. |
| `default` | `Any` | Returned when the flag is absent or unresolved. |

## client.get_all_flags(user=None)

```python
client.get_all_flags(user={"user_id": "42"})
# {"dark_mode": True, "search_algorithm": "v2", "max_results": 50}
```

Returns every flag resolved for the user, as a dict. Empty dict if no config is
available.

## client.close()

```python
client.close()
```

Stops the background polling thread. Call it on application shutdown.

## Context manager

`Switchbox` supports `with`, which calls `close()` automatically:

```python
with Switchbox(sdk_key="your-sdk-key") as client:
    if client.enabled("new_checkout", user={"user_id": "42"}):
        show_new_checkout()
```

## The on_evaluation hook

```python
def on_evaluation(flag_key, value, user):
    ...  # forward the exposure to your analytics

client = Switchbox(sdk_key="your-sdk-key", on_evaluation=on_evaluation)
```

Called after every `enabled()` and `get_value()` call with the flag key, the
resolved value, and the user context you passed in. It is fire-and-forget: an
exception inside your handler never breaks the flag check (it is reported
through `on_error`), and the hook carries no evaluation logic. Ready-made
handlers for common analytics tools are in
[Measure in your own analytics](/docs/recipes/measure-in-your-analytics).

## Anonymous usage telemetry

The SDK reports anonymous aggregate usage from a background thread — per-flag
evaluation counts and value distribution, with **no identity, no user context,
and no cookies** — which powers the dashboard's flag usage panel. On by
default; pass `telemetry=False` to disable it. Exactly what is sent and shown
is documented in [Connection & usage](/docs/dashboard/monitoring).

## Offline behaviour

If the CDN is unreachable, the SDK keeps serving the **last successfully fetched**
config — your flags keep working. If it has never fetched a config (e.g. the
network was down at startup), `enabled()` returns `False` and `get_value()`
returns your `default`. No exceptions are raised into your call path; failures go
to `on_error` if you supplied it.

## Next

- [Evaluation order](/docs/reference/evaluation-order) — how a value is resolved.
- [JavaScript SDK](/docs/sdk/javascript) · [React SDK](/docs/sdk/react).
- [Use with OpenFeature](/docs/sdk/openfeature): the vendor-neutral API, with Switchbox as one line.
