Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
"Langfuse",
"langfuse",
"Leanplum",
"Logcat",
"logit",
"logotable",
"Lookback",
Expand Down Expand Up @@ -271,6 +272,7 @@
"onesignal",
"OADA",
"openapi",
"openfeature",
"openviewpartners",
"operationalize",
"operationalized",
Expand Down
22 changes: 22 additions & 0 deletions pages/docs/featureflags.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,28 @@ See our developer guides on implementing feature flags on these platforms below:
<Cards.Card icon title="Go" href="/docs/tracking-methods/sdks/go/go-flags" />
</Cards>

### OpenFeature Providers

Mixpanel also offers [OpenFeature](https://openfeature.dev/) providers, which let you use Mixpanel's feature flags through OpenFeature's standardized, vendor-agnostic API.

#### Client Side

<Cards>
<Cards.Card icon title="Web" href="/docs/tracking-methods/sdks/javascript/javascript-openfeature" />
<Cards.Card icon title="iOS" href="/docs/tracking-methods/sdks/swift/swift-openfeature" />
<Cards.Card icon title="Android" href="/docs/tracking-methods/sdks/android/android-openfeature" />
</Cards>

#### Server Side

<Cards>
<Cards.Card icon title="Python" href="/docs/tracking-methods/sdks/python/python-openfeature" />
<Cards.Card icon title="Ruby" href="/docs/tracking-methods/sdks/ruby/ruby-openfeature" />
<Cards.Card icon title="Node.js" href="/docs/tracking-methods/sdks/nodejs/nodejs-openfeature" />
<Cards.Card icon title="Java" href="/docs/tracking-methods/sdks/java/java-openfeature" />
<Cards.Card icon title="Go" href="/docs/tracking-methods/sdks/go/go-openfeature" />
</Cards>

<Callout type="info">
If you'd like to see Feature Flags availability in other SDKs, please [reach out to the Support team](https://mixpanel.com/get-support).
</Callout>
Expand Down
3 changes: 2 additions & 1 deletion pages/docs/tracking-methods/sdks/android/_meta.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
"android-replay": "Session Replay (Android)",
"android-flags": "Feature Flags (Android)"
"android-flags": "Feature Flags (Android)",
"android-openfeature": "OpenFeature Provider (Android)",
}
189 changes: 189 additions & 0 deletions pages/docs/tracking-methods/sdks/android/android-openfeature.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { Callout } from 'nextra/components'

# OpenFeature Provider (Android)

## Overview

This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Android OpenFeature provider. OpenFeature provides a vendor-agnostic API for feature flag evaluation, allowing you to switch between providers without changing your application code.

For the native Mixpanel SDK approach, see the [Feature Flags (Android)](/docs/tracking-methods/sdks/android/android-flags) guide.

## Prerequisites

- Enterprise subscription plan with Feature Flags enabled
- Android SDK 21+
- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens)

## Installation

Add to your `build.gradle.kts`:

```kotlin
dependencies {
implementation("com.mixpanel.android:mixpanel-android-openfeature:<version>")
implementation("dev.openfeature:kotlin-sdk-android:0.7.2")
}
```

## Quick Start

```kotlin
import com.mixpanel.android.openfeature.MixpanelProvider
import com.mixpanel.android.mpmetrics.MixpanelOptions
import dev.openfeature.kotlin.sdk.OpenFeatureAPI

// 1. Create the provider
val options = MixpanelOptions.Builder()
.featureFlags()
.build()
val provider = MixpanelProvider(context, "YOUR_PROJECT_TOKEN", options)

// 2. Register the provider with OpenFeature
OpenFeatureAPI.setProviderAndWait(provider)

// 3. Get a client and evaluate flags
val client = OpenFeatureAPI.getClient()
val showNewFeature = client.getBooleanValue("new-feature-flag", false)

if (showNewFeature) {
// New feature is enabled!
}
```

### Using an Existing MixpanelAPI Instance

```kotlin
import com.mixpanel.android.mpmetrics.MixpanelAPI

val mixpanel = MixpanelAPI.getInstance(context, "YOUR_PROJECT_TOKEN", false, options)
val provider = MixpanelProvider(mixpanel.getFlags())

OpenFeatureAPI.setProviderAndWait(provider)
```

<Callout type="warning">
This provider does **not** call `mixpanel.identify()` or `mixpanel.track()`. If you need to update the logged-in user or use [Runtime Events](/docs/featureflags/runtime-events) for targeting, call these methods on the **same `MixpanelAPI` instance** whose `Flags` object was passed to the provider.
</Callout>

```kotlin
val provider = MixpanelProvider(context, "YOUR_PROJECT_TOKEN", options)

// Use the same instance for identity and tracking
provider.mixpanel?.identify("user-123")
provider.mixpanel?.track("Purchase Completed")
```

## Usage

### Flag Types and Evaluation Methods

| Mixpanel Flag Type | Variant Values | OpenFeature Method |
|---|---|---|
| Feature Gate | `true` / `false` | `getBooleanValue()` |
| Experiment | boolean, string, number, or JSON object | `getBooleanValue()`, `getStringValue()`, `getIntegerValue()`, `getDoubleValue()`, or `getObjectValue()` |
| Dynamic Config | JSON object | `getObjectValue()` |

```kotlin
val client = OpenFeatureAPI.getClient()

// Feature Gate
val isFeatureOn = client.getBooleanValue("new-checkout", false)

// Experiment with string variants
val buttonColor = client.getStringValue("button-color-test", "blue")

// Experiment with numeric variants
val maxItems = client.getIntegerValue("max-items", 10)
val threshold = client.getDoubleValue("score-threshold", 0.5)

// Dynamic Config
val featureConfig = client.getObjectValue("homepage-layout", Value.Structure(mapOf(
"layout" to Value.String("grid"),
"itemsPerRow" to Value.Integer(3)
)))
```

### Evaluation Context

Context must be set globally via `OpenFeatureAPI.setContext()`:

```kotlin
import dev.openfeature.kotlin.sdk.ImmutableContext
import dev.openfeature.kotlin.sdk.Value

OpenFeatureAPI.setContext(ImmutableContext(
attributes = mutableMapOf(
"email" to Value.String("user@example.com"),
"plan" to Value.String("premium")
)
))
```

<Callout type="warning">
Per-evaluation context (the optional `context` parameter on evaluation methods) is **not supported** by this provider. Context must be set globally via `OpenFeatureAPI.setContext()`, which triggers a re-fetch of flag values from Mixpanel.
</Callout>

### Runtime Properties

Pass `custom_properties` in the evaluation context for runtime targeting:

```kotlin
OpenFeatureAPI.setContext(ImmutableContext(
attributes = mutableMapOf(
"custom_properties" to Value.Structure(mapOf(
"tier" to Value.String("enterprise"),
"seats" to Value.Integer(50),
))
)
))
```

<Callout type="info">
Unlike some providers, `targetingKey` is not used as a special bucketing key. It is passed as another context property. Mixpanel's server-side configuration determines which properties are used for targeting and bucketing.
</Callout>

### Full Resolution Details

```kotlin
val details = client.getBooleanDetails("my-feature", false)

println(details.value)
println(details.variant)
println(details.reason)
println(details.errorCode)
```

### User Identity

This provider does **not** call `mixpanel.identify()`. Manage identity through the same Mixpanel instance:

```kotlin
provider.mixpanel?.identify("user-123")
```

## Error Handling

| Error Code | When |
|---|---|
| `PROVIDER_NOT_READY` | Flags evaluated before the provider has finished initializing |
| `FLAG_NOT_FOUND` | The requested flag does not exist in Mixpanel |
| `TYPE_MISMATCH` | The flag value type does not match the requested type |

## Troubleshooting

### Flags Always Return Default Values

1. **Feature flags not enabled:** Ensure MixpanelOptions includes `.featureFlags()`.
2. **Provider not ready:** Use `setProviderAndWait` to ensure initialization.
3. **Network issues:** Check Logcat for failed requests.
4. **Flag not configured:** Verify the flag exists and is enabled.

### Flags Not Updating After Context Change

Update context and the provider will re-fetch flags:

```kotlin
OpenFeatureAPI.setContext(ImmutableContext(
attributes = mutableMapOf("plan" to Value.String("premium"))
))
```
1 change: 1 addition & 0 deletions pages/docs/tracking-methods/sdks/go/_meta.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default {
"go-flags": "Feature Flags (Go)",
"go-openfeature": "OpenFeature Provider (Go)",
}
Loading
Loading