> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.getunleash.io/sdks/python/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getunleash.io/_mcp/server. # Python > Set up the Unleash Python SDK to evaluate feature flags with context, variants, fallbacks, bootstrap, events, and custom cache. The Unleash Python SDK lets you evaluate feature flags in Python applications. It connects to Unleash or [Unleash Edge](/unleash-edge) to fetch flag configurations and evaluates them locally against an [Unleash context](/concepts/unleash-context). You can use this SDK with [Unleash Enterprise](https://www.getunleash.io/pricing) or [Unleash Open Source](https://github.com/Unleash/unleash). For an overview of how Unleash SDKs work, including offline behavior, feature compatibility across SDKs, and default refresh and metrics intervals, refer to the [SDK overview](/sdks). ## Installation ```bash pip install UnleashClient ``` ## Initialization You must initialize the SDK before you use it. Note that until the SDK has synchronized with the API, all features will evaluate to `false` unless you have a [bootstrapped configuration](#bootstrap) or you use [fallbacks](#fallback-function). ```python from UnleashClient import UnleashClient client = UnleashClient( url="https://", app_name="my-python-app", custom_headers={'Authorization': ''}) client.initialize_client() ``` ## Check flags Once the SDK is initialized, you can evaluate toggles using the `is_enabled` or `get_variant` methods. ```python enabled = client.is_enabled("my_toggle") print(enabled) > True variant = client.get_variant("variant_toggle") print(variant) > { > "name": "variant1", > "payload": { > "type": "string", > "value": "val1" > }, > "enabled": True > } ``` ## Stop the client If your program no longer needs the SDK, you can call `destroy()`, which shuts down the SDK and flushes any pending metrics to Unleash. ```python client.destroy() ``` ## Unleash context Both the `is_enabled` and `get_variant` functions support [Unleash contexts](/concepts/unleash-context) as the second parameter. ```python app_context = { "userId": "test@email.com", "sessionId": "55845", "properties": { "custom-property": "some-value" } } client.is_enabled("user_id_toggle", app_context) client.get_variant("variant_toggle", app_context) ``` The context values can be any type that has a `__str__` implementation. Types that are explicitly supported are: * Numerics * Strings * Dates * UUIDs > **Note** > > Gradual rollout strategies require you to pass either a `userId` or a `sessionId` for [stickiness](/concepts/stickiness) to work correctly. ## Fallback function You can specify a fallback function for cases where the client doesn't recognize the toggle by using the `fallback_function` keyword argument: ```python def custom_fallback(feature_name: str, context: dict) -> bool: return True client.is_enabled("my_toggle", fallback_function=custom_fallback) ``` The fallback function **must** accept the feature name and context as positional arguments in that order. The client will evaluate the fallback function if the feature flag is not found or an exception occurs when calling the `is_enabled()` method. ## Configuration options The UnleashClient constructor supports the following configuration options: | Parameter | Description | Default | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------- | | url | URL of your Unleash server. E.g. `https://app.unleash-hosted.com/demo/api/` Required. | None | | app\_name | Name of the application using the client. Required. | None | | environment | Logical environment name (deprecated). | "default" | | instance\_id | Unique identifier for this client instance. | "unleash-client-python" | | refresh\_interval | How often to fetch feature flags (seconds). | 15 | | refresh\_jitter | Jitter to add to refresh interval (seconds). | None | | metrics\_interval | How often to send metrics to Unleash (seconds). | 60 | | metrics\_jitter | Jitter to add to metrics interval (seconds). | None | | disable\_metrics | Disable sending usage metrics. | False | | disable\_registration | Disable client registration. | False | | custom\_headers | Additional HTTP headers (e.g. Authorization). | None | | custom\_options | Extra options for [HTTP requests](https://requests.readthedocs.io/en/latest/api/#main-interface). | None | | request\_timeout | HTTP request timeout (seconds). | 30 | | request\_retries | HTTP request retry count. | 3 | | custom\_strategies | Dict of `{name: strategy}` for custom activation strategies. See [custom strategies](#custom-strategies) for more information. | None | | cache\_directory | Location for the on-disk cache. Auto-determined. | None | | cache | Custom cache implementation (must extend BaseCache). See [custom cache](#custom-cache) for more information | BaseCache | | scheduler | Custom APScheduler instance. Auto-created. | BaseScheduler | | verbose\_log\_level | Python logging level for debugging feature flag failures. See [https://docs.python.org/3/library/logging.html#logging-levels](https://docs.python.org/3/library/logging.html#logging-levels) for more information. | 30 | | scheduler\_executor | APScheduler executor name to use. | None | | multiple\_instance\_mode | How to handle multiple client instances (BLOCK, WARN, SILENTLY\_ALLOW). | WARN | | event\_callback | Function to handle impression events. See [impression data](#impression-data) for more information. | None | ## Bootstrap By default, the Python SDK fetches your feature flags from the Unleash API at startup. If you want to make your SDK more resilient (e.g., during network outages), you can bootstrap the client with a local or remote toggle config. How it works: * Use a FileCache (or your own BaseCache implementation). * Pre-seed it with feature flags using bootstrap\_from\_dict, bootstrap\_from\_file, or bootstrap\_from\_url. * Pass your cache to the UnleashClient on startup. The default FileCache has built-in methods for bootstrapping from a dictionary, file, or URL. #### Dictionary ```python from UnleashClient.cache import FileCache from UnleashClient import UnleashClient cache = FileCache("MY_CACHE") cache.bootstrap_from_dict({ "version": 2, "features": [ { "name": "my_toggle", "enabled": True, "strategies": [{"name": "default"}], } ] }) client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", cache=cache ) ``` #### File ```python from pathlib import Path from UnleashClient.cache import FileCache cache = FileCache("MY_CACHE") cache.bootstrap_from_file(Path("/path/to/your_bootstrap.json")) client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", cache=cache ) ``` #### URL ```python from UnleashClient.cache import FileCache cache = FileCache("MY_CACHE") cache.bootstrap_from_url("https://your-server/bootstrap.json") client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", cache=cache ) ``` ## Custom strategies The Python SDK lets you define [custom activation strategies](/concepts/custom-activation-strategies) if the built-in ones don't cover your needs. This gives you more fine grained control over how your features evaluate. A custom strategy is just a class that implements an apply method. ```python class ActiveForEmailStrategy: def apply(self, parameters: dict, context: dict = None) -> bool: # Decide if the feature is active for this context return context.get("email") in parameters ``` Once you've defined your strategy, register it when you initialize the client. The key must match the strategy name in Unleash exactly. ```python ## You should have a custom strategy defined in Unleash called 'EmailStrategy' my_custom_strategies = { "EmailStrategy": ActiveForEmailStrategy() } client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", custom_headers={'Authorization': ''}, custom_strategies = my_custom_strategies ) ``` ## Events The Python SDK lets you tap into its behavior through [impression data](/concepts/impression-data) and lifecycle events. Provide an `event_callback` function when you initialize the client. > **Note** > > The SDK does not include a built-in event bus — you'll need to provide your own. The examples below use [Blinker](https://pypi.org/project/blinker/) to send signals. The callback receives a single `UnleashEvent`. The SDK emits the following event types: * **Impression events**: emitted when `is_enabled()` or `get_variant()` is called for a flag with [impression data](/concepts/impression-data) enabled. * **READY**: triggered once when the SDK first loads feature flags from the Unleash server or a local backup. * **FETCHED**: triggered when a new version of feature flags is pulled from the server (not on 304 Not Modified). Includes a `features` property with all flags returned by that fetch. Impression callbacks run in-process — keep them fast to avoid blocking your app. ```python from blinker import signal from UnleashClient import UnleashClient from UnleashClient.events import UnleashEvent, UnleashEventType send_data = signal('send-data') @send_data.connect def receive_data(sender, **kw): if kw["data"].event_type == UnleashEventType.READY: print("SDK is ready: toggles loaded from Unleash or backup") elif kw["data"].event_type == UnleashEventType.FETCHED: print("Fetched new feature flags:", kw["data"].features) def example_callback(event: UnleashEvent): send_data.send('anonymous', data=event) client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", custom_headers={'Authorization': ''}, event_callback=example_callback ) client.initialize_client() client.is_enabled("testFlag") ``` ## Custom cache By default, the Python SDK stores feature flags in an on-disk cache using fcache. If you need a different storage backend, for example, Redis, memory-only, or a custom database, you can provide your own cache implementation. Below is an example custom CustomCache using fcache under the hood. ```python from typing import Optional, Any from UnleashClient.cache import BaseCache from fcache.cache import FileCache as _FileCache class CustomCache(BaseCache): # This is specific for FileCache. Depending on the cache you're using, this may look different! def __init__(self, name: str, directory: Optional[str] = None): self._cache = _FileCache(name, app_cache_dir=directory) def set(self, key: str, value: Any): self._cache[key] = value self._cache.sync() def mset(self, data: dict): self._cache.update(data) self._cache.sync() def get(self, key: str, default: Optional[Any] = None): return self._cache.get(key, default) def exists(self, key: str): return key in self._cache def destroy(self): return self._cache.delete() ``` Pass your cache instance to the client with the cache argument: ```python client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", cache=CustomCache("my-cache") ) ``` ## Running in multi-process setups The Python SDK runs a background thread to keep feature flags in sync with the Unleash server. Some runtime environments, like WSGI servers and Celery workers, need extra setup to make sure the SDK works correctly. ### WSGI When using WSGI servers (e.g., for Flask or Django apps), be aware that: * Many WSGI setups disable threading by default. The SDK needs threads to poll for updates in the background. * Make sure to set `enable-threads` in your WSGI config. When running under uWSGI with multiple processes (using the `--processes` option), you may need to enable the `lazy-apps` option. This ensures each process gets a fresh SDK instance. See [The Art of Graceful Reloading](https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy) for more details. ### Celery When using the SDK in Celery tasks, make sure you initialize it inside the worker\_process\_init event. Otherwise, the worker may run but won't poll for feature flag updates. ```python from UnleashClient import UnleashClient from celery.signals import worker_process_init client = UnleashClient( url="https://YOUR-API-URL", app_name="my-python-app", custom_headers={'Authorization': ''} ) @worker_process_init.connect def configure_workers(sender=None, conf=None, **kwargs): client.initialize_client() ``` ## Migrating to v6 If you use custom strategies or access the `features` property on the Unleash Client, read the complete [v6 migration guide](https://github.com/Unleash/unleash-python-sdk/blob/main/./v6_MIGRATION_GUIDE.md) before upgrading. > Set up the Unleash Python SDK to evaluate feature flags with context, variants, fallbacks, bootstrap, events, and custom cache.