Feature Flags

A Feature Flag is a toggle for controlling the availability of content or functionality in your app or website. A flag’s Configurations determine the audience, schedule, and property values to apply when the flag is enabled. Flag properties enable making immediate code updates, bypassing the need for traditional code changes and release processes. iOS SDK 17.1+Android SDK 17.1+

Accessing flags

The Airship SDK will refresh feature flags when the app is brought to the foreground. If a feature flag is accessed before the foreground refresh completes, or after the foreground refresh has failed, feature flags will be refreshed during flag access. Feature flags will only be updated once per session and will persist for the duration of each session.

Once defined in the dashboard, a feature flag can be accessed by its name in the SDK after takeOff.

Accessing a feature flag

The SDK provides asynchronous access to feature flags using Kotlin suspend functions, which is intended to be called from a coroutine. For more info, see Coroutines Overview guide.

// Get the FeatureFlag result
val result: Result<FeatureFlag> = FeatureFlagManager.shared().flag("YOUR_FLAG_NAME")

// Check if the app is eligible or not
if (result.getOrNull()?.isEligible == true) {
    // Do something with the flag
} else {
    // Disable feature or use default behavior
}
// Get the FeatureFlag 
FeatureFlag featureFlag = FeatureFlagManager.shared().flagAsPendingResult("YOUR_FLAG_NAME").getResult();

// Check if the app is eligible or not
if (featureFlag != null && featureFlag.isEligible()) {
    // Do something with the flag
} else {
    // Disable feature or use default behavior
}

The SDK provides asynchronous access to feature flags using an async method, which are intended to be called from a Task or a function that supports concurrency. For more info, see Concurrency guide.

// Get the FeatureFlag
let flag: FeatureFlag = try? await FeatureFlagManager.shared.flag(name: "YOUR_FLAG_NAME")

// Check if the app is eligible or not
if (flag?.isEligible == true) {
    // Do something with the flag
} else {
    // Disable feature or use default behavior
}
// Not supported
const flag = await Airship.featureFlagManager.flag("YOUR_FLAG_NAME");
if (flag.isEligible) {
    // Do something with the flag
} else { 
    // Disable feature or use default behavior
}
var flag = await Airship.featureFlagManager.flag("my-flag");
if (flag.isEligible) {
    // Do something with the flag
} else {
    // Disable feature or use default behavior
}
Airship.featureFlagManager.flag("YOUR_FLAG_NAME", (flag) => {
    if (flag.isEligible) {
        // Do something with the flag
    } else {
        // Disable feature or use default behavior
    }
});
const flag = await Airship.featureFlagManager.flag("YOUR_FLAG_NAME")
if (flag.isEligible) {
    // Do something with the flag
} else {
    // Disable feature or use default behavior
}
// Not supported
// Not supported
// Not supported
// Not supported

Tracking interaction

To generate the Feature Flag Interaction Event, you must manually call trackInteraction with the feature flag. Analytics must be enabled. See: Data Collection: Privacy Manager.

Tracking an interaction

FeatureFlagManager.shared().trackInteraction(featureFlag)
FeatureFlagManager.shared().trackInteraction(featureFlag)
FeatureFlagManager.shared.trackInteraction(flag: featureFlag)
// Not supported
await Airship.featureFlagManager.trackInteraction(flag);
Airship.featureFlagManager.trackInteraction(flag)
Airship.featureFlagManager.trackInteraction(flag);
await Airship.featureFlagManager.trackInteraction(flag)
// Not supported
// Not supported
// Not supported
// Not supported

Error handling

If a feature flag allows evaluation with stale data, the SDK will evaluate the flag if a definition for the flag is found. Otherwise, feature flag evaluation will depend on updated local state. If the SDK is unable to evaluate a flag due to data not being able to fetched, an error will be returned or raised. The app can either treat the error as the flag being ineligible or retry again at a later time.

Handling errors

FeatureFlagManager.shared().flag("YOUR_FLAG_NAME").fold(
        onSuccess = { flag -> 
            // do something with the flag
        },
        onFailure = {error ->
            // do something with the error
        }
)
FeatureFlag featureFlag = FeatureFlagManager.shared().flagAsPendingResult("YOUR_FLAG_NAME").getResult();
if (featureFlag == null) {
    // error
} else if (featureFlag.isEligible()) {
    // Do something with the flag
}
do {
    let flag = try await FeatureFlagManager.shared.flag(name: "YOUR_FLAG_NAME")
    if (flag.isEligible == true) {
        // Do something with the flag
    }
} catch {
    // Do something with the error
}
// Not supported
try {
    await Airship.featureFlagManager.flag("YOUR_FLAG_NAME");
} catch(error) {
    // Do something with the error
}
Airship.featureFlagManager.flag("another_rad_flag").then((flag) => {
    if (flag.isEligible) {
        // Do something with the flag
    }
}).catchError((error) => {
    debugPrint("flag error: $error")
});
Airship.featureFlagManager.flag(
  "another_rad_flag",
  (flag) => { 
    // do something with the flag
  },
  (error) => {
    console.log("error: " + error)
  }
);
try {
    const flag = await Airship.featureFlagManager.flag("another_rad_flag")
} catch (error) {
    console.log("error: " + error)
}
// Not supported
// Not supported
// Not supported
// Not supported