Python SDK
The Unleash Python SDK lets you evaluate feature flags in Python applications. It connects to Unleash or Unleash Edge to fetch flag configurations and evaluates them locally against an Unleash context.
You can use this SDK with Unleash Enterprise or Unleash Open Source.
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.
The SDK includes two clients: UnleashClient for synchronous applications and AsyncUnleashClient, an asyncio-native client for applications built on frameworks such as FastAPI, Starlette, or aiohttp. Both expose the same API for evaluating flags; they differ in how you initialize and stop them.
Requirements
- Python 3.8 or later
Installation
Install the SDK from PyPI:
Sync
Async
Initialization
Create a single Unleash client instance and share it across your application. Running multiple instances can lead to significantly increased request volume and may count as additional SDK connections toward your usage limits.
Set url to the /api endpoint of your Unleash instance or your Unleash Edge instance. Set the API token to a backend API token.
Flag checks are regular synchronous methods on both clients, because evaluation happens locally against the SDK’s cached configuration and performs no I/O. Only the async client’s lifecycle methods are coroutines.
Sync
Async
You can also use the client as a context manager, which initializes the client on entry and shuts it down on exit:
Check if the SDK is ready
Once initialized but not yet synchronized with Unleash, all flags evaluate to false and variants resolve to the disabled variant, unless you have a bootstrapped configuration or use a fallback function.
Initialize the client before calling is_enabled or get_variant. Flag evaluation is only supported after initialization.
To know when flag configuration is available, subscribe to the READY event. The SDK emits it when it first loads flags from the Unleash server or the local cache. The is_initialized property only tells you that initialize_client() has completed, which can happen before any flags are loaded.
The event callback runs on a background thread:
Sync
Async
UnleashClient makes its first fetch during initialize_client(), before the call returns. If that fetch fails, the client keeps polling and emits READY once a fetch succeeds.
Configuration options
Both client constructors support the following parameters. Parameters marked “Sync client only” apply only to UnleashClient.
URL of your Unleash or Unleash Edge API, for example https://<your-unleash-instance>/api.
Name of the application using the client. Included in registration, metrics, and request headers.
Logical environment name. Deprecated; the environment is determined by your API token.
Unique identifier for this client instance.
How often, in seconds, the SDK polls for updated flag configuration.
Maximum jitter, in seconds, added to the refresh interval.
How often, in seconds, the SDK sends usage metrics to Unleash.
Maximum jitter, in seconds, added to the metrics interval.
Disables sending usage metrics to Unleash.
Disables client registration with Unleash.
Additional headers for all API requests. Use this to add Authorization.
Extra options passed to the underlying HTTP requests, for example to skip SSL verification. Sync client only.
Timeout, in seconds, for requests to the Unleash server.
Number of retries for requests to the Unleash server.
Dictionary of strategy names to strategy objects. See custom strategies.
Location of the on-disk cache. When unset, the cache library determines the location.
Restricts flag fetches to a single project. Deprecated; use a project-scoped API token instead.
Numerical log level used when checking a feature flag fails.
Custom cache implementation that extends UnleashClient.cache.BaseCache. See custom cache. When unset, the SDK uses an on-disk cache.
Custom APScheduler instance. Use this to customize job stores or executors. When unset, the SDK creates its own scheduler. Sync client only.
Name of the APScheduler executor to use with a custom scheduler. Sync client only.
How the SDK handles multiple client instances: BLOCK fails construction, WARN logs a warning, and SILENTLY_ALLOW does nothing.
Function that receives SDK events, including impression events. Called on a dedicated background thread. If you run under a WSGI server or in multiple processes, see framework integration.
Identifier of an integration built on top of this SDK, such as an OpenFeature provider. Leave unset for plain SDK usage.
Version of the integration named by sdk_flavor.
Check flags
Use is_enabled to evaluate a flag. Evaluation happens locally against the SDK’s cached configuration.
Check variants
Use get_variant to evaluate a flag with variants. The method returns a dictionary:
The SDK can return two forms of the disabled variant. In both cases, name is disabled and enabled is False:
Flag disabled or not found
Flag enabled, no variant resolved
Use feature_enabled when you need the flag’s state alongside the variant result, without a separate is_enabled call.
The enabled: False field marks the result as the SDK’s default disabled variant. This distinguishes it from a real variant that happens to be named disabled, which the SDK returns with enabled: True.
Fallback function
You can specify a fallback function for cases where the client doesn’t recognize the flag by using the fallback_function keyword argument:
The fallback function must accept the feature name and context as positional arguments, in that order.
The client evaluates the fallback function if the feature flag is not found or if an exception occurs during evaluation. If the fallback function itself raises an exception, is_enabled returns False and logs a warning.
The fallback function runs as part of flag evaluation, so keep it fast: its runtime adds directly to every is_enabled call that invokes it.
Unleash context
The Unleash context holds properties such as user ID, session ID, and custom fields that drive flag evaluation, including strategy targeting, constraints, and stickiness.
Both is_enabled and get_variant accept a context dictionary as the second parameter:
The SDK enriches the context automatically before evaluation:
appNameandenvironmentare set from the client configuration.currentTimeis set to the current UTC time when you don’t provide it, so date-based constraints work without extra setup.- Any top-level key that isn’t a standard context field is moved into
properties. Passing{"custom-property": "some-value"}at the top level is equivalent to nesting it underproperties.
Context values can be any type that has a __str__ implementation. Explicitly supported types are:
- Numerics
- Strings
- Dates
- UUIDs
Gradual rollout strategies require you to pass either a userId or a sessionId for stickiness to work correctly.
Stop the client
Call destroy() to shut down the SDK and flush any pending metrics to Unleash. If you use the client as a context manager, this happens automatically on exit.
Sync
Async
A destroyed client cannot be reinitialized. Create a new instance if you need to reconnect.
Custom strategies
The SDK supports all built-in activation strategies. You can also define custom activation strategies if the built-in ones don’t cover your needs.
A custom strategy is a class that implements an apply method:
Once you’ve defined your strategy, register it when you initialize the client. The key must exactly match the strategy name in Unleash:
Sync
Async
Events
To subscribe to SDK events, provide an event_callback function when you initialize the client. The callback receives a single event object.
The SDK invokes your callback on a dedicated background thread. Flag evaluation does not wait for the callback, so a slow callback cannot block your application. Two consequences of this design:
- The callback cannot read thread-local state from the calling thread, such as Flask’s
gobject, the current Django request, orcontextvars. - If the callback cannot keep up, the SDK drops events and logs a warning instead of blocking.
Set event_callback when you construct the client; reassigning it afterwards has no effect.
Both clients deliver events this way. With AsyncUnleashClient, the callback is still a regular function, not a coroutine, and it runs on the background thread, outside the event loop.
The SDK does not include a built-in event bus. The example below uses Blinker to send signals.
Sync
Async
Impression data
When impression data is enabled for a flag, the SDK emits an impression event each time that flag is evaluated. Use impression events to track feature exposures in analytics tools.
Impression events arrive through the same event_callback with the event types FEATURE_FLAG and VARIANT. Each event includes the feature_name, the enabled result, and, for variant checks, the variant name:
Impact metrics
Impact metrics are lightweight, application-level time-series metrics stored and visualized directly inside Unleash. Use them to connect application data, such as request counts, error rates, or latency, to your feature flags and release plans.
The SDK automatically attaches appName and environment labels to all impact metrics.
Define and record metrics through the client’s impact_metrics property:
Sync
Async
Metric types
Counter
Gauge
Histogram
Use counters for cumulative values that only increase, such as the total number of requests or errors.
Impact metrics are batched and sent on the same interval as standard SDK metrics, controlled by metrics_interval.
Bootstrap
By default, the SDK fetches your feature flags from the Unleash API at startup. To make your application more resilient, for example during network outages, you can bootstrap the client with a local or remote flag configuration:
- Create a
FileCache, or your ownBaseCacheimplementation. - Pre-seed it with feature flags using
bootstrap_from_dict,bootstrap_from_file, orbootstrap_from_url. - Pass the cache to the client constructor.
A bootstrapped client can evaluate flags before its first fetch from Unleash completes. The two clients load the bootstrapped configuration at different points:
UnleashClientloads it when you construct the client.AsyncUnleashClientloads it when you callinitialize_client().
The examples below use the sync client. Pass the cache to AsyncUnleashClient the same way.
Dictionary
File
URL
Local caching and offline behavior
The SDK persists the latest flag configuration to an on-disk cache between restarts, using fcache. Set cache_directory to control where the cache is stored.
On startup, the SDK loads cached state first, then fetches fresh configuration from Unleash. If Unleash is temporarily unreachable, the SDK continues serving cached or bootstrapped values and keeps polling on refresh_interval.
Custom cache
If you need a different storage backend, for example Redis, memory-only, or a custom database, provide your own cache implementation that extends BaseCache.
Below is an example custom cache using fcache under the hood:
Pass your cache instance to either client with the cache argument:
Framework integration
UnleashClient runs background threads to poll for feature flags and send metrics, and both clients deliver events on a background thread. Some runtime environments, like WSGI servers and Celery workers, restrict threads or spawn new processes, and need extra setup to make sure the SDK works correctly.
WSGI
When using WSGI servers, for example with Flask or Django apps, be aware that:
- Many WSGI setups disable threading by default, so set
enable-threadsin your WSGI config. Without it,UnleashClientcannot poll for updates in the background, and neither client can deliver events to your callback. - When running under uWSGI with multiple processes using the
--processesoption, you may need to enable thelazy-appsoption. This ensures each process gets a fresh SDK instance.
See The Art of Graceful Reloading for more details.
Celery
When using the SDK in Celery tasks, initialize it inside the worker_process_init event. Otherwise, the worker may run but won’t poll for feature flag updates or receive event updates.
Multi-process setups
When each new process creates its own client, every process runs an independent poll cycle. With many short-lived processes, this wastes system resources and counts against your Unleash usage.
To avoid this, set up a leader and follower pattern: one process keeps the on-disk cache fresh, and the other processes call initialize_client(fetch_toggles=False). These clients then read flag configuration from the cache instead of polling the Unleash API.
This mode is available with UnleashClient. AsyncUnleashClient accepts the fetch_toggles argument for compatibility and always polls.
Unit testing
To test code that depends on feature flags without a running Unleash instance, bootstrap a cache with the flag state you want and turn off all network activity:
With fetch_toggles=False, the client loads flags from the cache only, so tests are deterministic and make no network requests. This approach uses UnleashClient, because fetch_toggles=False is specific to the sync client.
Migrating to v6
If you use custom strategies or access the features property on the Unleash client, read the complete v6 migration guide before upgrading.
Troubleshooting
All flags evaluate to false
If is_enabled always returns False:
- Confirm the flag exists and is enabled in the target environment.
- Verify
urlpoints to your Unleash API base URL, for examplehttps://<your-unleash-instance>/api. - Verify
custom_headersincludes a valid backend API token inAuthorization. - Verify the SDK completed its initial sync by checking that the
READYevent fired.is_initializedbeingTrueonly means thatinitialize_client()has completed. - Verify your Unleash context fields match your rollout strategy and constraints.
Flags never update in uWSGI or Celery workers
If the SDK initializes but flag changes never arrive:
- Under uWSGI, enable the
enable-threadsoption; the SDK needs threads to poll in the background. With multiple processes, also considerlazy-apps. - In Celery workers, initialize the client inside the
worker_process_initsignal.
See Framework integration for details.