Decide methods for the Python SDK
An overview of the decide methods for the Python SDK, which can be used to return a flag decision for a user in Optimizely Feature Experimentation.
Use the decide methods to return feature flag decisions for a user. Each decision includes whether the flag is enabled and which variation the user receives.
Decide
Returns a decision for a specific feature flag and user.
Minimum SDK version – v3.7+
Description
The decide method handles the variation decision for an individual experiment. It returns a decision result for a flag key for a user in an OptimizelyDecision object and contains the data required to deliver the flag rule.
This method ensures that Feature Experimentation properly buckets the user in experiment analytics, and you should use it if there is no need for pre-rendering decisions.
NoteDecide is a method of the
UserContextobject. See OptimizelyUserContext for details.
See the OptimizelyDecision for details of the returned decision object.
Parameters
The following table describes parameters for the decide method:
| Parameter | Type | Description |
|---|---|---|
flag_key | String | The key of the feature flag |
options (optional) | Array | Array of OptimizelyDecideOption enums. |
CMAB support
For CMAB experiments, decisions are automatically cached to reduce latency. The cache is invalidated when CMAB attributes change or TTL expires. Use CMAB-specific decide options (IGNORE_CMAB_CACHE, INVALIDATE_USER_CMAB_CACHE, RESET_CMAB_CACHE) to override default caching behavior.
Returns
The decide method returns an OptimizelyDecision object. For more information, see OptimizelyDecision.
If the method encounters a critical error (SDK not ready, invalid flag key, and so on), then it returns a decision with a null variation_key field and populates the reasons field with error messages (regardless of the OptimizelyDecideOption.INCLUDE_REASONS option).
Example decide
decidefrom optimizely import optimizely
optimizely_client = optimizely.Optimizely(sdk_key = "YOUR_SDK_KEY") #Replace with your SDK key
# Create the user and decide which flag rule and variation they bucket into
user = optimizely_client.create_user_context("user123", {"logged_in":True})
decision = user.decide("product_sort")
# The flag enabled state
enabled = decision.enabled
# The variable value:
value1 = decision.variables["sort_method"]
# All variable values
all_var_values = decision.variables
# The variation key. If null, decision fail with a critical error
variation_key = decision.variation_key
# Flag decision reasons
reasons = decision.reasons
# User for which the decision was made
user_context = decision.user_contextSide Effects
Invokes the decision notification listener if this listener is enabled.
Minimum SDK version – v3.7+
Description
Use the decide all method to retrieve decisions for all active flags before rendering content. This is particularly useful when you need to serve the correct cached version of your page or component based on the user's variation. For example when using an edge worker or cloud function.
Key features
- Pre-rendering decision – Lets you know all variation assignments ahead of time.
- Cache control – Lets you serve the correct cached content based on the user's pre-determined variations.
- Delay experiment tracking – Use
DISABLE_DECISION_EVENTto prevent the SDK from recording a decision before the user sees the feature. This ensures that participation is only tracked when the experience is delivered.
Parameters
The following table describes parameters for the decide all method:
| Parameter | Type | Description |
|---|---|---|
options (optional) | Array | Array of OptimizelyDecideOption enums. |
Returns
The decide all method returns a map of OptimizelyDecisions. For more information, see OptimizelyDecision.
If the method fails for all flags (for example, the SDK is not ready or the user context is invalid), then it returns an empty map. If the method detects an error for a specific flag, it returns error messages in the reasons field of the decision for that flag.
Example decide_all
decide_allfrom optimizely.decision.optimizely_decide_option import OptimizelyDecideOption
# Make decisions for all active (unarchived) flags in the project for a user
decisions = user.decide_all()
# Or only for enabled flags
decisions = user.decide_all([OptimizelyDecideOption.ENABLED_FLAGS_ONLY])
flag_keys = decisions.keys
flag_decisions = decisions.values
decision_for_flag_1 = decisions["flag_1"]Side effect
Invokes the decision notification listener for each decision if this listener is enabled.
Minimum SDK version – v3.7+
Parameters
The following table describes parameters for the decide for keys method:
| Parameter | Type | Description |
|---|---|---|
keys | Array | Array of string flag keys. |
options (optional) | Array | Array of OptimizelyDecideOption enums. |
Returns
Returns a map of OptimizelyDecisions. For more information, see OptimizelyDecision.
If the method fails for all flags (for example, the SDK is not ready or the user context is invalid), then it returns an empty map. If the method detects an error for a specific flag, it returns error messages in the reasons field of the decision for that flag.
Example decide_for_keys
decide_for_keysfrom optimizely.decision.optimizely_decide_option import OptimizelyDecideOption
# make a decisions for specific flags if enabled
decisions = user.decide_for_keys(["flag_1", "flag_2"], [OptimizelyDecideOption.ENABLED_FLAGS_ONLY])
decision_for_flag_1 = decisions["flag_1"]
decision_for_flag_2 = decisions["flag_2"]Side effect
Invokes the decision notification listener for each decision if this listener is enabled.
OptimizelyDecideOption
OptimizelyDecideOptionThe following table lists the OptimizelyDecideOption enum with an explanation what happens if you set them. In addition to setting these options individually for a decide method, you can also set them as global defaults when you instantiate the Optimizely client. See instantiate the Python SDK.
enum | If set |
|---|---|
| Prevents the SDK from dispatching an impression event when serving a variation. This disables decision tracking on the Optimizely Experiment Results page and the decision notification listener. |
| Returns decisions only for flags that are currently enabled. Used with the decide all method and decide for keys method. When this option is not set, the Android SDK returns all decisions regardless of whether the flag is enabled. |
| Bypasses the user profile service (both lookup and save) for the decision. When this option is not set, user profile service overrides audience targeting, traffic allocation, and experiment mutual exclusion groups. |
| Adds log messages to the reasons field of the decision. Critical errors are always returned, even if this option is not set. |
| Excludes flag variable values from the decision result. Use this option to minimize the returned decision by skipping large JSON variables. |
| Bypasses the CMAB cache and fetches a fresh decision from the CMAB service. Use when you need real-time decisions that reflect the latest context. |
| Removes the cached CMAB decision for this user and experiment before making the decision. Use when user context has changed significantly and you want to ensure a fresh decision. |
| Clears all entries from the CMAB cache before making the decision. Use sparingly for testing or cache corruption scenarios. |
The following code sample shows how to implement the OptimizelyDecideOption as a global default and locally in a decide method call.
from optimizely import optimizely
from optimizely.decision.optimizely_decide_option import OptimizelyDecideOption
#Set global default decide options when initializing the client.
optimizely_client = optimizely.Optimizely(
sdk_key = "YOUR_SDK_KEY", # Replace with your SDK key.
options = [OptimizelyDecideOption.DISABLE_DECISION_EVENT])
# Set additional options in a decide call.
user = optimizely.create_user_context("user123")
decision = user.decide_all(
options = [OptimizelyDecideOption.ENABLED_FLAGS_ONLY,
OptimizelyDecideOption.IGNORE_USER_PROFILE_SERVICE])Best practices
- Early and late invocation
- Use the decide all method early in your application's rendering process to load the correct cached content. For example, on the CDN with an Edge SDK.
- Use the decide method at the point of user interaction or when you must ensure Feature Experimentation records the decision in your experiment analytics.
- Combining methods – When using the decide and decide all methods, always pair the decide all method with the decide method for each experiment the user encounters. This prevents discrepancies between served content and analytics data.
- Parameter management – Ensure you use the
DISABLE_DECISION_EVENToption with the decide all method to avoid premature bucketing, then use the decide method to handle the decision event when the user experiences the content.
CMAB cache control
BetaCMAB for Feature Experimentation is in beta. Contact your Customer Success Manager for more information.
Minimum Python SDK version – v5.3.0+
For Contextual Multi-Armed Bandit (CMAB) experiments, the Python SDK automatically caches variation assignments to reduce latency and API calls. The cache stores decisions based on user ID, experiment ID, and CMAB attribute values.
Automatic cache invalidation
The cache is automatically invalidated when
- The cached entry's TTL expires (default: 30 minutes).
- CMAB attribute values change for a user (detected through attribute hash comparison).
Manual cache control
Use CMAB-specific decide options to control cache behavior on a per-decision basis, like in the following example:
from optimizely import optimizely
from optimizely.optimizely_factory import OptimizelyFactory
from optimizely.decision.optimizely_decide_option import OptimizelyDecideOption
# Initialize the Optimizely client.
optimizely_client = OptimizelyFactory.custom_instance(
sdk_key='YOUR_SDK_KEY', #Replace with your SDK key.
logger=optimizely.SimpleLogger()
)
# Example 1: Bypass cache for real-time decision
user = optimizely_client.create_user_context('user123', {
'age': 25,
'location': 'US'
})
decision = user.decide('my-cmab-flag', [
OptimizelyDecideOption.IGNORE_CMAB_CACHE # Always fetch fresh from CMAB service
])
# Example 2: Invalidate cache when user context changes significantly
user = optimizely_client.create_user_context('user123', {
'age': 26,
'location': 'UK' # Context changed
})
decision = user.decide('my-cmab-flag', [
OptimizelyDecideOption.INVALIDATE_USER_CMAB_CACHE # Clear cached decision for this user.
])
# Example 3: Reset entire CMAB cache (use sparingly)
decision = user.decide('my-cmab-flag', [
OptimizelyDecideOption.RESET_CMAB_CACHE # Clear all CMAB cache entries.
])CMAB decision reasons
When using INCLUDE_REASONS, CMAB-related information displays in the decision's reasons field.
decision = user.decide('my-cmab-flag', [
OptimizelyDecideOption.INCLUDE_REASONS
])
# Print CMAB-related decision reasons
for reason in decision.reasons:
print(reason)
# Examples:
# "CMAB cache hit for user 'user123' and rule 'exp_001'."
# "CMAB cache miss for user 'user123' and rule 'exp_001'."
# "CMAB cache attributes mismatch for user 'user123' and rule 'exp_001', fetching new decision."
# "Ignoring CMAB cache for user 'user123' and rule 'exp_001'."
# "Resetting CMAB cache for user 'user123' and rule 'exp_001'."
# "Invalidating CMAB cache for user 'user123' and rule 'exp_001'."
# "CMAB decision is {'variation_id': 'var_1', 'cmab_uuid': 'uuid-123'}."Note
Configure CMAB cache settings (size and TTL) at client initialization time using OptimizelyFactory.
from optimizely.optimizely_factory import OptimizelyFactory
# Set CMAB cache size (default: 10000).
OptimizelyFactory.set_cmab_cache_size(5000)
# Set CMAB cache TTL in seconds (default: 1800 = 30 minutes).
OptimizelyFactory.set_cmab_cache_ttl(3600) # 1 hour
# Or provide a custom cache implementation.
from optimizely.odp.lru_cache import LRUCache
custom_cache = LRUCache(capacity=5000, timeout=3600)
OptimizelyFactory.set_cmab_custom_cache(custom_cache)
# Then create the client.
optimizely_client = OptimizelyFactory.default_instance('SDK_KEY_HERE')Configure CMAB cache settings (size and TTL) at client initialization time. See Initialize the Python SDK or Configure the CMAB cache for the Python SDK for details.
Source files
The language and platform source files containing the implementation for Python are available on GitHub.
Updated 3 days ago