Flag evaluation reasons
Read time: 8 minutes
Last edited: Jan 12, 2023
Overview
This topic explains how to use the flag evaluation reason feature to get more information about the flag variations LaunchDarkly serves to contexts or users.
To learn more about how LaunchDarkly determines why a context or user receives a given flag variation, read Evaluation reasons.
A context is a generalized way of referring to the people, services, machines, or other resources that encounter feature flags in your product. To learn more, read Contexts.
Creating contexts and evaluating flags based on them is supported in the latest major versions of some of our SDKs. For these SDKs, the code samples on this page include the two most recent versions.
You can upgrade your SDKs at any time, but the ability to target by context, or review context instances that have encountered flags in your application, is only available for customers in the contexts Early Access Program (EAP). If you want access to this feature, join the EAP.
If you are using the latest version of an SDK and are not part of the EAP, your application can send contexts to LaunchDarkly and they will appear on the Users list.
Understanding the flag evaluation reason feature
Details about each SDK's configuration are available in the SDK-specific sections below.
Client-side SDKs
In client-side SDKs, you must enable an evaluation reason configuration option for this feature to work. The code samples below include this option. To learn more about configuration options, read Configuration.
This feature is available in the following client-side SDKs:
- .NET (client-side)
- Android
- C/C++ (client-side)
- Flutter
- iOS
- JavaScript
- Node.js (client-side)
- React Native
- Roku
.NET (client-side)
Expand .NET (client-side) code sample
The VariationDetail
methods, such as BoolVariationDetail
, work the same as Variation
, but also provide additional "reason" information about how a flag value was calculated. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
Configuration config = Configuration.Builder("mobile-key-123abc").EvaluationReasons(true).Build();LdClient client = LdClient.Init(config, context);EvaluationDetail<bool> detail =client.BoolVariationDetail("bool-flag-key-123abc", false);// or StringVariationDetail for a string-valued flag, and so on.bool value = detail.Value;int? index = detail.VariationIndex;EvaluationReason reason = detail.Reason;
To learn more about the VariationDetail
methods, read EvaluationDetail
and BoolVariationDetail
. To learn more about the configuration option, read EvaluationReasons
.
Android
Expand Android code sample
The variationDetail
methods, such as boolVariationDetail
, work the same as variation
. They also provide additional "reason" information about how a flag value was calculated, such as if the context matched a specific rule. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
LDConfig ldConfig = new LDConfig.Builder().mobileKey("mobile-key-123abc").evaluationReasons(true).build();LDClient client = LDClient.init(this.getApplication(), ldConfig, context, secondsToBlock);EvaluationDetail<Boolean> detail =client.boolVariationDetail("flag-key", false);// or stringVariationDetail for a string-valued flag, etc.boolean value = detail.getValue();Integer index = detail.getVariationIndex();EvaluationReason reason = detail.getReason();
To learn more about the variationDetail
methods, read EvaluationDetail
and getVariationIndex
. To learn more about the configuration option, read evaluationReasons
.
Here is an example of how to access the details of a reason object:
void printReason(EvaluationReason reason) {switch (reason.getKind()) {case OFF:Timber.d("it's off");break;case FALLTHROUGH:Timber.d("fell through");break;case TARGET_MATCH:Timber.d("targeted");break;case RULE_MATCH:EvaluationReason.RuleMatch rm =(EvaluationReason.RuleMatch)reason;Timber.d("matched rule %d/%s",rm.getRuleIndex(),rm.getRuleId());break;case PREREQUISITE_FAILED:EvaluationReason.PrerequisiteFailed pf =(EvaluationReason.PrerequisiteFailed)reason;Timber.d("prereq failed: %s", pf.getPrerequisiteKey());break;case ERROR:EvaluationReason.Error e = (EvaluationReason.Error)reason;Timber.d("error: %s", e.getErrorKind());}// or, if all you want is a simple descriptive string:Timber.d(reason.toString());}
To learn more, read EvaluationReason
.
C/C++ (client-side)
Expand C/C++ (client-side) code sample
By passing an LDVariationDetails
struct to a variation call you can programmatically inspect the reason for a particular evaluation.
The details.reason
member is the reason
object described in Evaluation reasons.
Here is an example:
struct LDConfig *config = LDConfigNew("mobile-key-123abc");LDConfigSetUseEvaluationReasons(config, LDBooleanTrue);struct LDClient *client = LDClientInit(config, user, maxwaitmilliseconds);LDVariationDetails details;LDBoolean value;value = LDBoolVariationDetail(client, "your.feature.key", LDBooleanFalse, &details);/* inspect details.reason, which is a JSON object */if (strcmp(LDGetText(LDObjectLookup(details->reason, "errorKind")), "FLAG_NOT_FOUND") == 0) {/* ... */}LDFreeDetailContents(&details);
To learn more about the LDVariationDetails
structure, inspect client.h
. To learn more about the configuration option, inspect config.h
.
Flutter
Expand Flutter code sample
The variationDetail
methods, such as boolVariationDetail
, work the same as variation
. They also provide additional "reason" information about how a flag value was calculated, such as if the user matched a specific rule. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
final LDConfig config = LDConfigBuilder("mobile-key-123abc").evaluationReasons(true).build();await LDClient.start(config, user);LDEvaluationDetail<bool> detail =await LDClient.boolVariationDetail("flag-key", false);// or stringVariationDetail for a string-valued flag, and so on.bool value = detail.value;int index = detail.variationIndex;LDEvaluationReason reason = detail.reason;
To learn more about the variationDetail
methods, read LDEvaluationDetail
and boolVariationDetail
. To learn more about the configuration option, read evaluationReasons
.
Here is an example of how to access the details of a reason object:
void printReason(LDEvaluationReason reason) {switch (reason.kind) {case LDKind.OFF:print("it's off");break;case LDKind.FALLTHROUGH:print('fell through');break;case LDKind.TARGET_MATCH:print('targeted');break;case LDKind.RULE_MATCH:print('matched rule: ${reason.ruleIndex} ${reason.ruleId}');break;case LDKind.PREREQUISITE_FAILED:print('prereq failed: ${reason.prerequisiteKey}');break;case LDKind.ERROR:print('error: ${reason.errorKind}');break;default: // LDKind.UNKNOWNprint('unknown service kind');}}
To learn more, read LDEvaluationReason
.
iOS
Expand iOS code sample
The variationDetail
methods, such as boolVariationDetail
, work the same as the variation methods. They also provide additional "reason" information about how a flag value was calculated, such as if the user matched a specific rule. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
ldConfig.evaluationReasons = trueLDClient.start(config: ldConfig, context: context)let detail = client.boolVariationDetail(forKey: "flag-key", defaultValue: false);let value: Bool = detail.valuelet variationIndex: Int? = detail.variationIndexlet reason: [String: LDValue]? = detail.reason
To learn more about the variationDetail
methods, read LDEvaluationDetail
and boolVariationDetail
. To learn more about the configuration option, read LDConfig
.
JavaScript
Expand JavaScript code sample
The variationDetail
method lets you evaluate a feature flag with the same parameters you would for variation
. With variationDetail
, you receive more information about how the value was calculated.
The variation detail returns in an object containing both the result value and a "reason" object which tells you more information about the flag evaluation. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. It also indicates if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
const options = { evaluationReasons: true };const client = LDClient.initialize('client-side-id-123abc', context, options);const detail = client.variationDetail('flag-key-123abc', false);const value = detail.value;const index = detail.variationIndex;const reason = detail.reason;
To learn more about the variationDetail
methods, read LDEvaluationDetail
and variationDetail
. To learn more about the configuration option, read evaluationReasons
.
Node.js (client-side)
Expand Node.js (client-side) code sample
The variationDetail
method lets you evaluate a feature flag with the same parameters you would for variation
. With variationDetail
, you receive more information about how the value was calculated.
The variation detail returns in an object that contains both the result value and a "reason" object which tells you more information about the flag evaluation. For example, you can find out if the user was individually targeted for the flag or was matched by one of the flag's rules. It also indicates if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
const options = { evaluationReasons: true };const client = LDClient.initialize('client-side-id-123abc', user, options);const detail = client.variationDetail('flag-key', false);const value = detail.value;const index = detail.variationIndex;const reason = detail.reason;
To learn more about the variationDetail
method, read LDEvaluationDetail
and variationDetail
. To learn more about the configuration option, read evaluationReasons
.
React Native
Expand React Native code sample
The variationDetail
methods work the same as variation
, but also provide additional reason
information about how a flag value was calculated. For example, you can find out if the user was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
let config = {mobileKey: 'mobile-key-123abc',evaluationReasons: true};await client.configure(config, user);const detail =client.boolVariationDetail('flag-key-123abc', false);const value = detail.value;const index = detail.variationIndex;const reason = detail.reason;
To learn more about the variationDetail
methods, read LDEvaluationDetail
and boolVariationDetail
. To learn more about the configuration option, read LDConfig
.
Roku
Expand Roku code sample
For each variation type there is also an associated version that returns the reason a particular value was returned.
Here is an example:
config.setUseEvaluationReasons(true)details = launchDarkly.intVariationDetail("flag-key-123abc", 123)
These variation methods return an object containing the keys value
, reason
, and variationIndex
. The value
field is the result of the evaluation. The reason
field is an object that explains why the result happened, for example details about a rule match. The reason object will always contain a kind
field. Lastly the variationIndex
field contains the ID of the particular value returned. This field may be null.
Server-side SDKs
Unlike client-side SDKs, you do not need to enable an evaluation reason configuration option in server-side SDKs for this feature to work.
This feature is available in the following server-side SDKs:
- .NET (server-side)
- Apex
- C/C++ (server-side)
- Erlang
- Go
- Haskell
- Java
- Lua
- Node.js (server-side)
- Node.js (Cloudflare)
- PHP
- Python
- Ruby
- Rust
.NET (server-side)
Expand .NET (server-side) code sample
The VariationDetail
methods, such as BoolVariationDetail
, work the same as the Variation
methods, but also provide additional "reason" information about how a flag value was calculated. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
EvaluationDetail<bool> detail =client.BoolVariationDetail("flag-key", myContext, false);// or StringVariationDetail for a string-valued flag, etc.bool value = detail.Value;int? index = detail.VariationIndex;EvaluationReason reason = detail.Reason;
To learn more, read EvaluationDetail
, BoolVariationDetail
.
Here is an example of how to access the details of a reason object:
void PrintReason(EvaluationReason reason){switch (reason.Kind){case EvaluationReasonKind.OFF:Console.WriteLine("it's off");break;case EvaluationReasonKind.FALLTHROUGH:Console.WriteLine("fell through");break;case EvaluationReasonKind.TARGET_MATCH:Console.WriteLine("targeted");break;case EvaluationReasonKind.RULE_MATCH:var rm = reason as EvaluationReason.RuleMatch;Console.WriteLine("matched rule " + rm.RuleIndex + "/" + rm.RuleID);break;case EvaluationReasonKind.PREREQUISITE_FAILED:var pf = reason as EvaluationReason.PrerequisiteFailed;Console.WriteLine("prereq failed: " + pf.PrerequisiteKey);break;case EvaluationReasonKind.ERROR:var e = reason as EvaluationReason.Error;Console.WriteLine("error: " + e.ErrorKind);break;}// or, if all you want is a simple descriptive string:System.out.println(reason.ToString());}
To learn more, read EvaluationReason
.
Apex
Expand Apex code sample
By passing an LDClient.EvaluationDetail
object to a variation call you can programmatically inspect the reason for a particular evaluation.
Here is an example:
LDClient.EvaluationDetail details = new LDClient.EvaluationDetail();Boolean value = client.boolVariation(user, 'your.feature.key', false, details);/* inspect details here */if (details.getReason().getKind() == EvaluationReason.Kind.OFF) {/* ... */}
C/C++ (server-side)
Expand C/C++ (server-side) code sample
By passing an LDDetails
struct to a variation call you can programmatically inspect the reason for a particular evaluation.
Here is an example:
struct LDDetails details;LDBoolean value;value = LDBoolVariation(client, user, "your.feature.key", LDBooleanFalse, &details);/* inspect details here */if (details.reason == LD_RULE_MATCH) {/* ... */}LDDetailsClear(&details);
To learn more about the LDDetails
structure, inspect variations.h
.
Erlang
Expand Erlang code sample
The variation_detail
function is similar to the variation function, but also returns an explanation of the evaluation that you can inspect programmatically.
Here is an example:
Flag = ldclient:variation_detail(<<"flag-key-123abc">>, #{key => <<"user-key-123abc">>}, false)
Go
Expand Go code sample
The VariationDetail
methods, such as BoolVariationDetail
, work the same as Variation
, but also provide additional "reason" information about how a flag value was calculated. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
value, detail, err := client.BoolVariationDetail("flag-key", context, false)// or StringVariationDetail for a string-valued flag, etc.index := detail.VariationIndexreason := detail.Reason
To learn more, read EvaluationDetail
and BoolVariationDetail
.
Here is an example of how to access the details of a reason object:
import ("github.com/launchdarkly/go-sdk-common/v3/ldreason")func PrintReason(reason ldreason.EvaluationReason) {switch reason.GetKind() {case ldreason.EvalReasonOff:fmt.Println("it's off")case ldreason.EvalReasonFallthrough:fmt.Println("fell through")case ldreason.EvalReasonTargetMatch:fmt.Println("targeted")case ldreason.EvalReasonRuleMatch:fmt.Printf("matched rule %d/%s\n", r.GetRuleIndex(), r.GetRuleID())case ldreason.EvalReasonPrerequisiteFailed:fmt.Printf("prereq failed: %s\n", r.GetPrerequisiteKey())case ldreason.EvalReasonError:fmt.Printf("error: %s\n", r.GetErrorKind())}// or, if all you want is a simple descriptive string:fmt.Println(reason)}
To learn more, read EvaluationReason
.
Haskell
Expand Haskell code sample
The variationDetail
functions are similar to the variation
functions, but they also return an explanation of the evaluation that is programmatically inspectable.
Here is an example:
details :: IO (EvaluationDetail Bool)details = boolVariationDetail client user "flag-key-123abc" False
For specific information on the EvaluationDetail
structure, inspect the LaunchDarkly.Server.Details
module.
Java
Expand Java code sample
The variationDetail
methods, such as boolVariationDetail
, work the same as variation
, but also provide additional "reason" information about how a flag value was calculated. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
import com.launchdarkly.sdk.*;EvaluationDetail<Boolean> detail =client.boolVariationDetail("flag-key-123abc", context, false);// or stringVariationDetail for a string-valued flag, and so on.boolean value = detail.getValue();int index = detail.getVariationIndex(); // will be < 0 if evaluation failedEvaluationReason reason = detail.getReason();
To learn more, read EvaluationDetail
and boolVariationDetail
.
Here is an example of how to access the details of a reason object:
void printReason(EvaluationReason reason) {switch (reason.getKind()) {case OFF:System.out.println("it's off");break;case FALLTHROUGH:System.out.println("fell through");break;case TARGET_MATCH:System.out.println("targeted");break;case RULE_MATCH:EvaluationReason.RuleMatch rm = (EvaluationReason.RuleMatch)reason;System.out.println("matched rule " + rm.getRuleIndex()+ "/" + rm.getRuleId());break;case PREREQUISITE_FAILED:EvaluationReason.PrerequisiteFailed pf =(EvaluationReason.PrerequisiteFailed)reason;System.out.println("prereq failed: " + pf.getPrerequisiteKey());break;case ERROR:EvaluationReason.Error e = (EvaluationReason.Error)reason;System.out.println("error: " + e.getErrorKind());}// or, if all you want is a simple descriptive string:System.out.println(reason.toString());}
To learn more, read EvaluationReason
.
Lua
Expand Lua code sample
By using the *Detail
family of variation calls you can programmatically inspect the reason for a particular evaluation:
local details = client:boolVariationDetail(client, user, "your.feature.key", false);/* inspect details here */if details.reason == "FLAG_NOT_FOUND" thenend
To learn more about configuration options, read the API docs.
Node.js (server-side)
Expand Node.js (server-side) code sample
The variationDetail
method lets you evaluate a feature flag (using the same parameters as you would for variation
) and receive more information about how the value was calculated.
The variation detail is returned in an object that contains both the result value and a "reason" object which will tell you, for instance, if the context was individually targeted for the flag or was matched by one of the flag's rules. It will also indicate if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
var detail = client.variationDetail('flag-key-123abc', context, false);var value = detail.value;var index = detail.variationIndex;var reason = detail.reason;
To learn more, read LDEvaluationDetail
and variationDetail
.
Here is an example of how to access the details of a reason object:
function printReason(reason) {switch(reason.kind) {case "OFF":console.log("it's off");break;case "FALLTHROUGH":console.log("fell through");break;case "TARGET_MATCH":console.log("targeted");break;case "RULE_MATCH":console.log("matched rule " + reason.ruleIndex + ", " + reason.ruleId);break;case "PREREQUISITE_FAILED":console.log("prereq failed: " + reason.prerequisiteKey);break;case "ERROR":console.log("error: " + reason.errorKind);break;}}
To learn more, read LDEvaluationReason
.
Node.js (Cloudflare)
This SDK uses the same code as the Node.js server-side SDK.
To learn more, read variationDetail
.
PHP
Expand PHP code sample
The variationDetail
method lets you evaluate a feature flag (using the same parameters as you would for variation
) and receive more information about how the value was calculated.
The variation detail is returned in an object that contains both the result value and a "reason" object which will tell you, for example, if the context was individually targeted for the flag or was matched by one of the flag's rules. It will also indicate if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
$detail = $client->variationDetail("flag-key-123abc", $myContext, false);$value = $detail->getValue();$index = $detail->getVariationIndex();$reason = $detail->getReason();
To learn more, read EvaluationDetail
and variationDetail
.
Here is an example of how to access the details of a reason object:
function printReason($reason) {switch ($reason->getKind()) {case EvaluationReason::OFF:echo("it's off");break;case EvaluationReason::FALLTHROUGH:echo("fell through");break;case EvaluationReason::TARGET_MATCH:echo("targeted");break;case EvaluationReason::RULE_MATCH:echo("matched rule " . $reason->getRuleIndex() ."/" . $reason->getRuleId());break;case EvaluationReason::PREREQUISITE_FAILED:echo("prereq failed: " . $reason->getPrerequisiteKey());break;case EvaluationReason::ERROR:echo("error: " . $reason->getErrorKind());break;}// or, if all you want is a simple descriptive string:echo $reason;}
To learn more, read EvaluationReason
.
Python
Expand Python code sample
The variation_detail
method lets you evaluate a feature flag with the same parameters as you would for variation
. You can use this method to receive more information about how the value was calculated.
The variation detail is returned in an object that contains both the result value and a "reason" object which will tell you, for instance, if the context was individually targeted for the flag or was matched by one of the flag's rules. It will also indicate if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
detail = client.variation_detail("flag-key-123abc", my_context, False)value = detail.valueindex = detail.variation_indexreason = detail.reason
To learn more, read EvaluationDetail
and variation_detail
.
Here is an example of how to access the details of a reason object:
def print_reason(reason):kind = reason["kind"]if kind == "OFF":print "it's off"elif kind == "FALLTHROUGH":print "fell through"elif kind == "TARGET_MATCH":print "targeted"elif kind == "RULE_MATCH":print "matched rule %d/%s" % (reason["ruleIndex"], reason["ruleId"])elif kind == "PREREQUISITE_FAILED":print "prereq failed: %s" % reason["prerequisiteKey"]elif kind == "ERROR":print "error: %s" % reason["errorKind"]
To learn more, read EvaluationDetail.reason
.
Ruby
Expand Ruby code sample
The variation_detail
method lets you evaluate a feature flag (using the same parameters as you would for variation
) and receive more information about how the value was calculated.
The variation detail is returned in an object that contains both the result value and a "reason" object which will tell you, for instance, if the context was individually targeted for the flag or was matched by one of the flag's rules. It will also indicate if the flag returned the default value due to an error. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
detail = client.variation_detail("flag-key", my_context, false)value = detail.valueindex = detail.variation_indexreason = detail.reason
To learn more, read EvaluationDetail
and variation_detail
.
Here is an example of how to access the details of a reason object:
def print_reason(reason)case reason[:kind]when "OFF"puts "it's off"when "FALLTHROUGH"puts "fell through"when "TARGET_MATCH"puts "targeted"when "RULE_MATCH"puts "matched rule #{reason[:ruleIndex]}/#{reason[:ruleId]}"when "PREREQUISITE_FAILED"puts "prereq failed: #{reason[:prerequisiteKey]}"when "ERROR"puts "error: #{reason[:errorKind]}"endend
To learn more, read EvaluationDetail.reason
.
Rust
Expand Rust code sample
The variation_detail
methods (for example, bool_variation_detail
) let you evaluate a feature flag, using the same parameters as you would for variation
, and receive more information about how the flag value was calculated. For example, you can find out if the context was individually targeted for the flag or was matched by one of the flag's rules. You can examine the "reason" data programmatically, or, if you capture detailed analytics events for flags, view it with Data Export.
Here is an example:
let detail = client.bool_variation_detail(&context, "flag-key", false);let value = detail.value;let index = detail.variation_index;let reason = detail.reason;
To learn more, read variation_detail
and bool_variation_detail
.
Here is an example of how to access the details of a reason object:
fn print_reason(reason: Reason) {match reason {Reason::Off => println!("it's off"),Reason::Fallthrough { .. } => println!("fell through"),Reason::TargetMatch => println!("targeted"),Reason::RuleMatch {rule_index,rule_id,..} => println!("matched rule {}/{}", rule_index, rule_id),Reason::PrerequisiteFailed { prerequisite_key } => {println!("prereq failed: {}", prerequisite_key)}Reason::Error { error } => println!("error: {:?}", error),};}
To learn more, read Reason
.