diff --git a/cspell.json b/cspell.json index 583e0e554d..315171ca8a 100644 --- a/cspell.json +++ b/cspell.json @@ -223,6 +223,7 @@ "Langfuse", "langfuse", "Leanplum", + "Logcat", "logit", "logotable", "Lookback", @@ -271,6 +272,7 @@ "onesignal", "OADA", "openapi", + "openfeature", "openviewpartners", "operationalize", "operationalized", diff --git a/pages/docs/featureflags.mdx b/pages/docs/featureflags.mdx index 1d52a01f2f..1660fabc31 100644 --- a/pages/docs/featureflags.mdx +++ b/pages/docs/featureflags.mdx @@ -253,6 +253,28 @@ See our developer guides on implementing feature flags on these platforms below: +### 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 + + + + + + + +#### Server Side + + + + + + + + + If you'd like to see Feature Flags availability in other SDKs, please [reach out to the Support team](https://mixpanel.com/get-support). diff --git a/pages/docs/tracking-methods/sdks/android/_meta.ts b/pages/docs/tracking-methods/sdks/android/_meta.ts index 5ee586c759..4c5d58100f 100644 --- a/pages/docs/tracking-methods/sdks/android/_meta.ts +++ b/pages/docs/tracking-methods/sdks/android/_meta.ts @@ -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)", } diff --git a/pages/docs/tracking-methods/sdks/android/android-openfeature.mdx b/pages/docs/tracking-methods/sdks/android/android-openfeature.mdx new file mode 100644 index 0000000000..02e54d77eb --- /dev/null +++ b/pages/docs/tracking-methods/sdks/android/android-openfeature.mdx @@ -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:") + 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) +``` + + +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. + + +```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") + ) +)) +``` + + +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. + + +### 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), + )) + ) +)) +``` + + +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. + + +### 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")) +)) +``` diff --git a/pages/docs/tracking-methods/sdks/go/_meta.ts b/pages/docs/tracking-methods/sdks/go/_meta.ts index 2d7221cfd8..07d9df4915 100644 --- a/pages/docs/tracking-methods/sdks/go/_meta.ts +++ b/pages/docs/tracking-methods/sdks/go/_meta.ts @@ -1,3 +1,4 @@ export default { "go-flags": "Feature Flags (Go)", + "go-openfeature": "OpenFeature Provider (Go)", } diff --git a/pages/docs/tracking-methods/sdks/go/go-openfeature.mdx b/pages/docs/tracking-methods/sdks/go/go-openfeature.mdx new file mode 100644 index 0000000000..ba7da0ca38 --- /dev/null +++ b/pages/docs/tracking-methods/sdks/go/go-openfeature.mdx @@ -0,0 +1,178 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Go) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Go 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 (Go)](/docs/tracking-methods/sdks/go/go-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +```bash +go get github.com/mixpanel/mixpanel-go/openfeature +go get github.com/open-feature/go-sdk +``` + +## Quick Start + +```go +package main + +import ( + "context" + "fmt" + + mixpanelopenfeature "github.com/mixpanel/mixpanel-go/openfeature" + "github.com/mixpanel/mixpanel-go/v2/flags" + of "github.com/open-feature/go-sdk/openfeature" +) + +func main() { + // 1. Create the Mixpanel OpenFeature provider with local evaluation + provider, err := mixpanelopenfeature.NewProviderWithLocalConfig("YOUR_PROJECT_TOKEN", flags.LocalFlagsConfig{}) + if err != nil { + panic(err) + } + + // 2. Register the provider with OpenFeature + of.SetProvider(provider) + client := of.NewClient("my-app") + + // 3. Evaluate flags + showNewFeature, _ := client.BooleanValue(context.Background(), "new-feature-flag", false, of.EvaluationContext{}) + + if showNewFeature { + fmt.Println("New feature is enabled!") + } +} +``` + +## Initialization + +### Local Evaluation (Recommended) + +Flag definitions are fetched from Mixpanel and evaluated locally. This is faster and works offline after the initial fetch. + + +Targeting by Mixpanel cohorts and sticky variants are not supported in Local Evaluation mode. + + +```go +provider, err := mixpanelopenfeature.NewProviderWithLocalConfig("YOUR_PROJECT_TOKEN", flags.LocalFlagsConfig{}) +``` + +### Remote Evaluation + +Each flag evaluation makes a request to Mixpanel's servers. + +```go +provider, err := mixpanelopenfeature.NewProviderWithRemoteConfig("YOUR_PROJECT_TOKEN", flags.RemoteFlagsConfig{}) +``` + +### Using an Existing Mixpanel Instance + +```go +mp := mixpanel.NewApiClient("YOUR_TOKEN", mixpanel.WithLocalFlags(flags.LocalFlagsConfig{})) +mp.LocalFlags.StartPollingForDefinitions(context.Background()) + +provider, err := mixpanelopenfeature.NewProvider(mp.LocalFlags) +``` + +## Usage + +### Flag Types and Evaluation Methods + +| Mixpanel Flag Type | Variant Values | OpenFeature Method | +|---|---|---| +| Feature Gate | `true` / `false` | `BooleanValue()` | +| Experiment | boolean, string, number, or JSON object | `BooleanValue()`, `StringValue()`, `FloatValue()`, `IntValue()`, or `ObjectValue()` | +| Dynamic Config | JSON object | `ObjectValue()` | + +```go +ctx := context.Background() +evalCtx := of.EvaluationContext{} + +// Feature Gate +enabled, _ := client.BooleanValue(ctx, "new-checkout", false, evalCtx) + +// Experiment with string variants +buttonColor, _ := client.StringValue(ctx, "button-color-test", "blue", evalCtx) + +// Numeric flags +threshold, _ := client.FloatValue(ctx, "score-threshold", 0.5, evalCtx) +maxItems, _ := client.IntValue(ctx, "max-items", 10, evalCtx) + +// Dynamic Config +config, _ := client.ObjectValue(ctx, "homepage-layout", map[string]any{ + "layout": "grid", +}, evalCtx) +``` + +### Evaluation Context + +```go +evalCtx := of.NewEvaluationContext("user-123", map[string]any{ + "email": "user@example.com", + "plan": "premium", +}) + +enabled, _ := client.BooleanValue(ctx, "premium-feature", false, evalCtx) +``` + + +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. + + +### Full Resolution Details + +```go +details, _ := client.BooleanValueDetails(ctx, "my-feature", false, of.EvaluationContext{}) + +fmt.Println(details.Value) +fmt.Println(details.Variant) +fmt.Println(details.Reason) +fmt.Println(details.ErrorCode) +``` + +### Accessing the Underlying Mixpanel Client + +```go +provider, _ := mixpanelopenfeature.NewProviderWithLocalConfig("YOUR_TOKEN", flags.LocalFlagsConfig{}) + +provider.Mixpanel.Track(ctx, []*mixpanel.Event{ + {Name: "button_clicked", Properties: map[string]any{"color": "blue"}}, +}) +``` + +### Shutdown + +```go +provider.Shutdown() +``` + +## Error Handling + +| Error Code | When | +|---|---| +| `PROVIDER_NOT_READY` | Flags evaluated before the local provider has finished fetching definitions | +| `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. **Provider not ready:** Ensure polling has started and definitions have been received. +2. **Flag not configured:** Verify the flag exists and is enabled in your Mixpanel project. +3. **Network issues:** For remote evaluation, check that your application can reach Mixpanel's API. + +### Type Mismatch Errors + +The flag's value type must match the evaluation method. `IntValue()` accepts whole-number `float64` values. `FloatValue()` accepts any numeric type. diff --git a/pages/docs/tracking-methods/sdks/java/_meta.ts b/pages/docs/tracking-methods/sdks/java/_meta.ts index 534176a476..de3f9c9547 100644 --- a/pages/docs/tracking-methods/sdks/java/_meta.ts +++ b/pages/docs/tracking-methods/sdks/java/_meta.ts @@ -1,4 +1,5 @@ export default { "index": "Java", "java-flags": "Feature Flags (Java)", + "java-openfeature": "OpenFeature Provider (Java)", } \ No newline at end of file diff --git a/pages/docs/tracking-methods/sdks/java/java-openfeature.mdx b/pages/docs/tracking-methods/sdks/java/java-openfeature.mdx new file mode 100644 index 0000000000..3e3918a355 --- /dev/null +++ b/pages/docs/tracking-methods/sdks/java/java-openfeature.mdx @@ -0,0 +1,186 @@ +import { Callout } from "nextra/components"; + +# OpenFeature Provider (Java) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Java 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 (Java)](/docs/tracking-methods/sdks/java/java-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Java 8 or higher +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +### Maven + +```xml + + com.mixpanel + mixpanel-java-openfeature + 0.1.0 + + + dev.openfeature + sdk + 1.20.1 + +``` + +### Gradle + +```groovy +implementation 'com.mixpanel:mixpanel-java-openfeature:0.1.0' +implementation 'dev.openfeature:sdk:1.20.1' +``` + +## Quick Start + +```java +import com.mixpanel.openfeature.MixpanelProvider; +import com.mixpanel.mixpanelapi.featureflags.config.LocalFlagsConfig; +import dev.openfeature.sdk.OpenFeatureAPI; +import dev.openfeature.sdk.Client; + +// 1. Create and register the provider with local evaluation +MixpanelProvider provider = new MixpanelProvider( + "YOUR_PROJECT_TOKEN", + new LocalFlagsConfig("YOUR_PROJECT_TOKEN") +); +OpenFeatureAPI api = OpenFeatureAPI.getInstance(); +api.setProvider(provider); + +// 2. Get a client and evaluate flags +Client client = api.getClient(); +boolean showNewFeature = client.getBooleanValue("new-feature-flag", false); + +if (showNewFeature) { + System.out.println("New feature is enabled!"); +} +``` + +## Initialization + +### Local Evaluation (Recommended) + + +Targeting by Mixpanel cohorts and sticky variants are not supported in Local Evaluation mode. + + +```java +MixpanelProvider provider = new MixpanelProvider( + "YOUR_PROJECT_TOKEN", + new LocalFlagsConfig("YOUR_PROJECT_TOKEN") +); +``` + +### Remote Evaluation + +```java +MixpanelProvider provider = new MixpanelProvider( + "YOUR_PROJECT_TOKEN", + new RemoteFlagsConfig("YOUR_PROJECT_TOKEN") +); +``` + +### Using an Existing MixpanelAPI Instance + +```java +MixpanelAPI mixpanel = new MixpanelAPI(new LocalFlagsConfig("YOUR_PROJECT_TOKEN")); +LocalFlagsProvider localFlags = mixpanel.getLocalFlags(); +localFlags.startPollingForDefinitions(); + +MixpanelProvider provider = new MixpanelProvider(localFlags); +``` + +## 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()` | + +```java +Client client = api.getClient(); + +// Feature Gate +boolean isFeatureOn = client.getBooleanValue("new-checkout", false); + +// Experiment with string variants +String buttonColor = client.getStringValue("button-color-test", "blue"); + +// Experiment with numeric variants +int maxItems = client.getIntegerValue("max-items", 10); +double threshold = client.getDoubleValue("score-threshold", 0.5); + +// Dynamic Config +Value featureConfig = client.getObjectValue("homepage-layout", new Value("default")); +``` + +### Evaluation Context + +```java +MutableContext context = new MutableContext(); +context.setTargetingKey("user-123"); +context.add("email", "user@example.com"); +context.add("plan", "premium"); +context.add("beta_tester", true); + +boolean value = client.getBooleanValue("premium-feature", false, context); +``` + + +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. + + +### Full Resolution Details + +```java +FlagEvaluationDetails details = client.getBooleanDetails("my-feature", false); + +System.out.println(details.getValue()); +System.out.println(details.getVariant()); +System.out.println(details.getReason()); +System.out.println(details.getErrorCode()); +``` + +### Accessing the Underlying MixpanelAPI + +```java +MixpanelAPI mixpanel = provider.getMixpanel(); +``` + +### Shutdown + +```java +provider.shutdown(); +``` + +## Error Handling + +| Error Code | When | +|---|---| +| `PROVIDER_NOT_READY` | Flags evaluated before the local provider has finished loading definitions | +| `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. **Provider not ready:** Flag definitions are polled asynchronously. Allow time for the initial fetch. +2. **Invalid project token:** Verify the token matches your Mixpanel project. +3. **Flag not configured:** Verify the flag exists and is enabled. + +### Type Mismatch Errors + +1. Verify the flag's value type matches your evaluation method. +2. Use `getObjectValue()` for JSON objects. +3. Integer evaluation accepts `Long` and whole-number `Double` values within `Integer` bounds. Double evaluation accepts any numeric type. diff --git a/pages/docs/tracking-methods/sdks/javascript/_meta.ts b/pages/docs/tracking-methods/sdks/javascript/_meta.ts index e0a438591d..c79fefa139 100644 --- a/pages/docs/tracking-methods/sdks/javascript/_meta.ts +++ b/pages/docs/tracking-methods/sdks/javascript/_meta.ts @@ -1,4 +1,5 @@ export default { "javascript-replay": "Session Replay (Javascript)", "javascript-flags": "Feature Flags (Javascript)", + "javascript-openfeature": "OpenFeature Provider (Web)", } diff --git a/pages/docs/tracking-methods/sdks/javascript/javascript-openfeature.mdx b/pages/docs/tracking-methods/sdks/javascript/javascript-openfeature.mdx new file mode 100644 index 0000000000..1ace7c1db7 --- /dev/null +++ b/pages/docs/tracking-methods/sdks/javascript/javascript-openfeature.mdx @@ -0,0 +1,198 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Web) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Web 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 (Web)](/docs/tracking-methods/sdks/javascript/javascript-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +```bash +npm install @mixpanel/openfeature-web-provider @openfeature/web-sdk mixpanel-browser +``` + +## Quick Start + +```typescript +import mixpanel from 'mixpanel-browser'; +import { OpenFeature } from '@openfeature/web-sdk'; +import { MixpanelProvider } from '@mixpanel/openfeature-web-provider'; + +// 1. Initialize Mixpanel with feature flags +mixpanel.init('YOUR_PROJECT_TOKEN', { + flags: { + context: { plan: 'premium' } + } +}); + +// 2. Create and register the Mixpanel provider +const provider = new MixpanelProvider(mixpanel.flags); +await OpenFeature.setProviderAndWait(provider); + +// 3. Get a client and evaluate flags +const client = OpenFeature.getClient(); +const showNewFeature = client.getBooleanValue('new-feature-flag', false); + +if (showNewFeature) { + console.log('New feature is enabled!'); +} +``` + +## 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()`, `getNumberValue()`, or `getObjectValue()` | +| Dynamic Config | JSON object | `getObjectValue()` | + +```typescript +const client = OpenFeature.getClient(); + +// Feature Gate +const isFeatureOn = client.getBooleanValue('new-checkout', false); + +// Experiment with string variants +const buttonColor = client.getStringValue('button-color-test', 'blue'); + +// Experiment with number variants +const maxItems = client.getNumberValue('max-items', 10); + +// Dynamic Config +const featureConfig = client.getObjectValue('homepage-layout', { + layout: 'grid', + itemsPerRow: 3 +}); +``` + +### Evaluation Context + +Context must be set globally via `OpenFeature.setContext()`: + +```typescript +await OpenFeature.setContext({ + email: 'user@example.com', + plan: 'premium' +}); +``` + + +Per-evaluation context (the optional third argument to evaluation methods) is **not supported** by this provider. Context must be set globally via `OpenFeature.setContext()`, which triggers a re-fetch of flag values from Mixpanel. + + +### Runtime Properties + +Pass `custom_properties` in the evaluation context for runtime targeting: + +```typescript +await OpenFeature.setContext({ + custom_properties: { + tier: 'enterprise', + seats: 50, + industry: 'technology' + } +}); +``` + + +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. + + +### Full Resolution Details + +```typescript +const details = client.getBooleanDetails('my-feature', false); + +console.log(details.value); +console.log(details.variant); +console.log(details.reason); +console.log(details.errorCode); +``` + +### React Integration + +```tsx +import { OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk'; +import { OpenFeature } from '@openfeature/web-sdk'; +import mixpanel from 'mixpanel-browser'; +import { MixpanelProvider } from '@mixpanel/openfeature-web-provider'; + +// Initialize outside of component +mixpanel.init('YOUR_PROJECT_TOKEN', { + flags: { + context: { plan: 'premium' } + } +}); +const provider = new MixpanelProvider(mixpanel.flags); +OpenFeature.setProvider(provider); + +function App() { + return ( + + + + ); +} + +function MyComponent() { + const showBanner = useBooleanFlagValue('show-banner', false); + + return ( +
+ {showBanner && } +
+ ); +} +``` + +### User Identity + +This provider does **not** call `mixpanel.identify()`. Manage identity through Mixpanel directly: + +```typescript +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 | + +To avoid `PROVIDER_NOT_READY`, use `setProviderAndWait`: + +```typescript +await OpenFeature.setProviderAndWait(provider); +``` + +## Troubleshooting + +### Flags Always Return Default Values + +1. **Feature flags not enabled:** Ensure Mixpanel was initialized with `flags` enabled: + ```typescript + mixpanel.init('YOUR_TOKEN', { flags: { context: { plan: 'premium' } } }); + ``` +2. **Provider not ready:** Use `setProviderAndWait` to ensure initialization. +3. **Network issues:** Check the browser console 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: + +```typescript +await OpenFeature.setContext({ plan: 'premium' }); +``` diff --git a/pages/docs/tracking-methods/sdks/nodejs/_meta.ts b/pages/docs/tracking-methods/sdks/nodejs/_meta.ts index 01a0e4d9dd..1327af91c4 100644 --- a/pages/docs/tracking-methods/sdks/nodejs/_meta.ts +++ b/pages/docs/tracking-methods/sdks/nodejs/_meta.ts @@ -1,3 +1,4 @@ export default { "nodejs-flags": "Feature Flags (Node.js)", + "nodejs-openfeature": "OpenFeature Provider (Node.js)", } diff --git a/pages/docs/tracking-methods/sdks/nodejs/nodejs-openfeature.mdx b/pages/docs/tracking-methods/sdks/nodejs/nodejs-openfeature.mdx new file mode 100644 index 0000000000..ccf6b0e58c --- /dev/null +++ b/pages/docs/tracking-methods/sdks/nodejs/nodejs-openfeature.mdx @@ -0,0 +1,167 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Node.js) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Node.js 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 (Node.js)](/docs/tracking-methods/sdks/nodejs/nodejs-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Node.js 10 or higher +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +```bash +npm install @mixpanel/openfeature-server-provider @openfeature/server-sdk mixpanel +``` + +## Quick Start + +```typescript +import { OpenFeature } from "@openfeature/server-sdk"; +import { MixpanelProvider } from "@mixpanel/openfeature-server-provider"; + +// 1. Create and register the provider with local evaluation +const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN"); +await OpenFeature.setProviderAndWait(provider); + +// 2. Get a client and evaluate flags +const client = OpenFeature.getClient(); +const showNewFeature = await client.getBooleanValue("new-feature-flag", false, { + distinct_id: "user-123", +}); + +if (showNewFeature) { + console.log("New feature is enabled!"); +} +``` + +## Initialization + +### Local Evaluation (Recommended) + + +Targeting by Mixpanel cohorts and sticky variants are not supported in Local Evaluation mode. + + +```typescript +const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN"); +``` + +### Remote Evaluation + +```typescript +const provider = MixpanelProvider.createRemote("YOUR_PROJECT_TOKEN"); +``` + +### Using an Existing Mixpanel Instance + +```typescript +import Mixpanel from "mixpanel"; + +const mixpanel = Mixpanel.init("YOUR_PROJECT_TOKEN", { + local_flags_config: {}, +}); +const localFlags = mixpanel.local_flags!; +localFlags.startPollingForDefinitions(); + +const provider = new MixpanelProvider(localFlags); +``` + +## 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()`, `getNumberValue()`, or `getObjectValue()` | +| Dynamic Config | JSON object | `getObjectValue()` | + +```typescript +const client = OpenFeature.getClient(); +const context = { distinct_id: "user-123" }; + +// Feature Gate +const isFeatureOn = await client.getBooleanValue("new-checkout", false, context); + +// Experiment with string variants +const buttonColor = await client.getStringValue("button-color-test", "blue", context); + +// Experiment with number variants +const maxItems = await client.getNumberValue("max-items", 10, context); + +// Dynamic Config +const featureConfig = await client.getObjectValue("homepage-layout", {}, context); +``` + +### Evaluation Context + +```typescript +// Global context +OpenFeature.setContext({ environment: "production" }); + +// Per-evaluation context (merged with and overrides global context) +const value = await client.getBooleanValue("premium-feature", false, { + distinct_id: "user-123", + email: "user@example.com", + plan: "premium", +}); +``` + + +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. + + +### Full Resolution Details + +```typescript +const details = await client.getBooleanDetails("my-feature", false, { + distinct_id: "user-123", +}); + +console.log(details.value); +console.log(details.variant); +console.log(details.reason); +console.log(details.errorCode); +``` + +### Accessing the Underlying Mixpanel Instance + +```typescript +const mixpanel = provider.mixpanel; +if (mixpanel) { + mixpanel.track("button_clicked", { distinct_id: "user-123" }); +} +``` + +### Shutdown + +```typescript +await OpenFeature.close(); +``` + +## Error Handling + +| Error Code | When | +|---|---| +| `PROVIDER_NOT_READY` | Flags evaluated before the local provider has finished loading definitions | +| `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. **Provider not ready:** Use `setProviderAndWait()` to ensure flags are ready before evaluation. +2. **Invalid project token:** Verify the token matches your Mixpanel project. +3. **Flag not configured:** Verify the flag exists and is enabled. + +### Type Mismatch Errors + +Verify the flag's value type matches your evaluation method. Use `getObjectValue()` for JSON objects. diff --git a/pages/docs/tracking-methods/sdks/python/_meta.ts b/pages/docs/tracking-methods/sdks/python/_meta.ts index 2f8a88bad9..26d9e67855 100644 --- a/pages/docs/tracking-methods/sdks/python/_meta.ts +++ b/pages/docs/tracking-methods/sdks/python/_meta.ts @@ -1,3 +1,4 @@ export default { "python-flags": "Feature Flags (Python)", + "python-openfeature": "OpenFeature Provider (Python)", } diff --git a/pages/docs/tracking-methods/sdks/python/python-openfeature.mdx b/pages/docs/tracking-methods/sdks/python/python-openfeature.mdx new file mode 100644 index 0000000000..ffd33bd04d --- /dev/null +++ b/pages/docs/tracking-methods/sdks/python/python-openfeature.mdx @@ -0,0 +1,193 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Python) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Python 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 (Python)](/docs/tracking-methods/sdks/python/python-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Python 3.9 or higher +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +```bash +pip install mixpanel-openfeature openfeature-sdk +``` + +## Quick Start + +```python +from mixpanel_openfeature import MixpanelProvider +from mixpanel.flags.types import LocalFlagsConfig +from openfeature import api + +# 1. Create and register the provider with local evaluation +provider = MixpanelProvider.from_local_config( + "YOUR_PROJECT_TOKEN", + LocalFlagsConfig(token="YOUR_PROJECT_TOKEN"), +) +api.set_provider(provider) + +# 2. Get a client and evaluate flags +client = api.get_client() +show_new_feature = client.get_boolean_value("new-feature-flag", False) + +if show_new_feature: + print("New feature is enabled!") +``` + +## Initialization + +The provider supports three initialization methods depending on your evaluation strategy. + +### Local Evaluation (Recommended) + +Evaluates flags locally using cached flag definitions polled from Mixpanel. This minimizes latency since there is no network call at evaluation time. + + +Targeting by Mixpanel cohorts and sticky variants are not supported in Local Evaluation mode. + + +```python +from mixpanel_openfeature import MixpanelProvider +from mixpanel.flags.types import LocalFlagsConfig + +provider = MixpanelProvider.from_local_config( + "YOUR_PROJECT_TOKEN", + LocalFlagsConfig(token="YOUR_PROJECT_TOKEN"), +) +``` + +### Remote Evaluation + +Evaluates flags by making a request to Mixpanel's servers for each evaluation. Use this when you need real-time flag values or cohort-based targeting. + +```python +from mixpanel_openfeature import MixpanelProvider +from mixpanel.flags.types import RemoteFlagsConfig + +provider = MixpanelProvider.from_remote_config( + "YOUR_PROJECT_TOKEN", + RemoteFlagsConfig(token="YOUR_PROJECT_TOKEN"), +) +``` + +### Using an Existing Mixpanel Instance + +If your application already has a `Mixpanel` instance configured for tracking, you can wrap its flags provider: + +```python +from mixpanel import Mixpanel +from mixpanel.flags.types import LocalFlagsConfig +from mixpanel_openfeature import MixpanelProvider + +mp = Mixpanel("YOUR_PROJECT_TOKEN", local_flags_config=LocalFlagsConfig(token="YOUR_PROJECT_TOKEN")) +mp.local_flags.start_polling_for_definitions() + +provider = MixpanelProvider(mp.local_flags) +``` + +## Usage + +### Flag Types and Evaluation Methods + +| Mixpanel Flag Type | Variant Values | OpenFeature Method | +|---|---|---| +| Feature Gate | `True` / `False` | `get_boolean_value()` | +| Experiment | boolean, string, number, or JSON object | `get_boolean_value()`, `get_string_value()`, `get_integer_value()`, `get_float_value()`, or `get_object_value()` | +| Dynamic Config | JSON object | `get_object_value()` | + +```python +client = api.get_client() + +# Feature Gate +is_feature_on = client.get_boolean_value("new-checkout", False) + +# Experiment with string variants +button_color = client.get_string_value("button-color-test", "blue") + +# Experiment with numeric variants +max_items = client.get_integer_value("max-items", 10) +threshold = client.get_float_value("score-threshold", 0.5) + +# Dynamic Config +feature_config = client.get_object_value("homepage-layout", {"layout": "default"}) +``` + +### Evaluation Context + +Pass context to provide user attributes for targeting: + +```python +from openfeature.evaluation_context import EvaluationContext + +context = EvaluationContext( + targeting_key="user-123", + attributes={ + "email": "user@example.com", + "plan": "premium", + "beta_tester": True, + }, +) + +value = client.get_boolean_value("premium-feature", False, context) +``` + + +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. + + +### Full Resolution Details + +```python +details = client.get_boolean_details("my-feature", False) + +print(details.value) # The resolved value +print(details.variant) # The variant key from Mixpanel +print(details.reason) # Why this value was returned +print(details.error_code) # Error code if evaluation failed +``` + +### Accessing the Underlying Mixpanel Instance + +When using `from_local_config` or `from_remote_config`, you can access the Mixpanel instance for tracking: + +```python +mp = provider.mixpanel +``` + +### Shutdown + +```python +provider.shutdown() +``` + +## Error Handling + +The provider uses OpenFeature's standard error codes: + +| Error Code | When | +|---|---| +| `PROVIDER_NOT_READY` | Flags evaluated before local provider has finished loading definitions | +| `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. **Provider not ready (local evaluation):** Flag definitions are polled asynchronously. Allow time for the initial fetch to complete. +2. **Invalid project token:** Verify the token matches your Mixpanel project. +3. **Flag not configured:** Verify the flag exists and is enabled in your Mixpanel project. + +### Type Mismatch Errors + +1. Verify the flag's value type in Mixpanel matches your evaluation method (e.g., string `"true"` requires `get_string_value()`, not `get_boolean_value()`). +2. Use `get_object_value()` for JSON objects. +3. Integer evaluation accepts whole-number `float` values. Float evaluation accepts any numeric type. diff --git a/pages/docs/tracking-methods/sdks/ruby/_meta.ts b/pages/docs/tracking-methods/sdks/ruby/_meta.ts index f7acbe4f14..1e4e2354db 100644 --- a/pages/docs/tracking-methods/sdks/ruby/_meta.ts +++ b/pages/docs/tracking-methods/sdks/ruby/_meta.ts @@ -1,3 +1,4 @@ export default { "ruby-flags": "Feature Flags (Ruby)", + "ruby-openfeature": "OpenFeature Provider (Ruby)", } diff --git a/pages/docs/tracking-methods/sdks/ruby/ruby-openfeature.mdx b/pages/docs/tracking-methods/sdks/ruby/ruby-openfeature.mdx new file mode 100644 index 0000000000..2022b7da0c --- /dev/null +++ b/pages/docs/tracking-methods/sdks/ruby/ruby-openfeature.mdx @@ -0,0 +1,203 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Ruby) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Ruby 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 (Ruby)](/docs/tracking-methods/sdks/ruby/ruby-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- Ruby 3.1.0 or higher +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +Add to your `Gemfile`: + +```ruby +gem 'mixpanel-ruby-openfeature' +gem 'openfeature-sdk' +gem 'mixpanel-ruby' +``` + +Then run: + +```bash +bundle install +``` + +## Quick Start + +```ruby +require 'mixpanel-ruby' +require 'mixpanel/openfeature' + +# 1. Create the provider with local evaluation +provider = Mixpanel::OpenFeature::Provider.from_local( + 'YOUR_PROJECT_TOKEN', + { poll_interval: 300 } +) + +# 2. Register the provider with OpenFeature +OpenFeature::SDK.configure do |config| + config.set_provider(provider) +end + +# 3. Get a client and evaluate flags +client = OpenFeature::SDK.build_client + +show_new_feature = client.fetch_boolean_value(flag_key: 'new-feature-flag', default_value: false) + +if show_new_feature + puts 'New feature is enabled!' +end +``` + +## Initialization + +### Local Evaluation (Recommended) + +Downloads flag definitions and evaluates them locally with no per-evaluation network requests. + + +Targeting by Mixpanel cohorts and sticky variants are not supported in Local Evaluation mode. + + +```ruby +provider = Mixpanel::OpenFeature::Provider.from_local( + 'YOUR_PROJECT_TOKEN', + { poll_interval: 300 } +) +``` + +### Remote Evaluation + +Sends each flag check to Mixpanel's servers. + +```ruby +provider = Mixpanel::OpenFeature::Provider.from_remote( + 'YOUR_PROJECT_TOKEN', + {} +) +``` + +### Using an Existing Tracker + +```ruby +tracker = Mixpanel::Tracker.new('YOUR_PROJECT_TOKEN', nil, local_flags_config: { poll_interval: 300 }) +tracker.local_flags.start_polling_for_definitions! + +provider = Mixpanel::OpenFeature::Provider.new(tracker.local_flags) +``` + +## Usage + +### Flag Types and Evaluation Methods + +| Mixpanel Flag Type | Variant Values | OpenFeature Method | +|---|---|---| +| Feature Gate | `true` / `false` | `fetch_boolean_value` | +| Experiment | boolean, string, number, or JSON object | `fetch_boolean_value`, `fetch_string_value`, `fetch_number_value`, or `fetch_object_value` | +| Dynamic Config | JSON object | `fetch_object_value` | + +```ruby +client = OpenFeature::SDK.build_client + +# Feature Gate +is_feature_on = client.fetch_boolean_value(flag_key: 'new-checkout', default_value: false) + +# Experiment with string variants +button_color = client.fetch_string_value(flag_key: 'button-color-test', default_value: 'blue') + +# Experiment with number variants +max_items = client.fetch_number_value(flag_key: 'max-items', default_value: 10) + +# Dynamic Config +feature_config = client.fetch_object_value( + flag_key: 'homepage-layout', + default_value: { 'layout' => 'grid', 'items_per_row' => 3 } +) +``` + +### Evaluation Context + +```ruby +context = OpenFeature::SDK::EvaluationContext.new( + targeting_key: 'user-123', + email: 'user@example.com', + plan: 'premium' +) + +value = client.fetch_boolean_value( + flag_key: 'premium-feature', + default_value: false, + evaluation_context: context +) +``` + + +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. + + +### Full Resolution Details + +```ruby +details = client.fetch_boolean_details(flag_key: 'my-feature', default_value: false) + +puts details.value +puts details.variant +puts details.reason +puts details.error_code +``` + +### Accessing the Mixpanel Tracker + +```ruby +provider.mixpanel.track('user-123', 'Page View', { 'page' => '/home' }) +``` + +### Rails Integration + +```ruby +# config/initializers/openfeature.rb +provider = Mixpanel::OpenFeature::Provider.from_local( + ENV['MIXPANEL_TOKEN'], + { poll_interval: 300 } +) + +OpenFeature::SDK.configure do |config| + config.set_provider(provider) +end + +at_exit { provider.shutdown } +``` + +### Shutdown + +```ruby +provider.shutdown +``` + +## 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. **Provider not ready:** Flag definitions are fetched asynchronously. Allow time for the initial fetch. +2. **Invalid project token:** Verify the token matches your Mixpanel project. +3. **Flag not configured:** Verify the flag exists and is enabled. + +### Type Mismatch Errors + +Verify the flag's value type matches your evaluation method. Use `fetch_object_value` for JSON objects. diff --git a/pages/docs/tracking-methods/sdks/swift/_meta.ts b/pages/docs/tracking-methods/sdks/swift/_meta.ts index cae800483b..62775e5fcf 100644 --- a/pages/docs/tracking-methods/sdks/swift/_meta.ts +++ b/pages/docs/tracking-methods/sdks/swift/_meta.ts @@ -1,4 +1,5 @@ export default { "swift-replay": "Session Replay (Swift)", - "swift-flags": "Feature Flags (Swift)" + "swift-flags": "Feature Flags (Swift)", + "swift-openfeature": "OpenFeature Provider (Swift)", } diff --git a/pages/docs/tracking-methods/sdks/swift/swift-openfeature.mdx b/pages/docs/tracking-methods/sdks/swift/swift-openfeature.mdx new file mode 100644 index 0000000000..372bd44b80 --- /dev/null +++ b/pages/docs/tracking-methods/sdks/swift/swift-openfeature.mdx @@ -0,0 +1,192 @@ +import { Callout } from 'nextra/components' + +# OpenFeature Provider (Swift) + +## Overview + +This guide covers using Mixpanel's [Feature Flags](/docs/featureflags) through the [OpenFeature](https://openfeature.dev/) standard with the Mixpanel Swift 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 (Swift)](/docs/tracking-methods/sdks/swift/swift-flags) guide. + +## Prerequisites + +- Enterprise subscription plan with Feature Flags enabled +- iOS 14.0+ / tvOS 14.0+ / macOS 11.0+ / watchOS 7.0+ +- Swift 5.5+ +- Project Token from your [Mixpanel Project Settings](/docs/orgs-and-projects/managing-projects#find-your-project-tokens) + +## Installation + +Add the following to your `Package.swift`: + +```swift +dependencies: [ + .package(url: "https://github.com/mixpanel/mixpanel-swift-openfeature", from: "0.1.0"), +] +``` + +Then add `MixpanelOpenFeature` as a dependency of your target: + +```swift +.target( + name: "YourTarget", + dependencies: [ + .product(name: "MixpanelOpenFeature", package: "mixpanel-swift-openfeature"), + ] +), +``` + +## Quick Start + +```swift +import Mixpanel +import MixpanelOpenFeature +import OpenFeature + +// 1. Create and register the provider +let options = MixpanelOptions(token: "YOUR_PROJECT_TOKEN") +let provider = MixpanelOpenFeatureProvider(options: options) +await OpenFeatureAPI.shared.setProviderAndWait(provider: provider) + +// 2. Get a client and evaluate flags +let client = OpenFeatureAPI.shared.getClient() +let showNewFeature = client.getBooleanValue(key: "new-feature-flag", defaultValue: false) + +if showNewFeature { + print("New feature is enabled!") +} +``` + +### Using an Existing Mixpanel Instance + +```swift +let flags = Mixpanel.mainInstance().flags +let provider = MixpanelOpenFeatureProvider(flags: flags) +await OpenFeatureAPI.shared.setProviderAndWait(provider: provider) +``` + + +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 Mixpanel instance** that was passed to the provider. + + +```swift +// When using init(options:), access via provider.mixpanel +provider.mixpanel?.identify(distinctId: "user-123") +provider.mixpanel?.track(event: "Purchase", properties: ["amount": 49.99]) + +// When using init(flags:), use the original instance +let mixpanelInstance = Mixpanel.mainInstance() +let provider = MixpanelOpenFeatureProvider(flags: mixpanelInstance.flags) +mixpanelInstance.identify(distinctId: "user-123") +``` + +## 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()` | + +```swift +let client = OpenFeatureAPI.shared.getClient() + +// Feature Gate +let isFeatureOn = client.getBooleanValue(key: "new-checkout", defaultValue: false) + +// Experiment with string variants +let buttonColor = client.getStringValue(key: "button-color-test", defaultValue: "blue") + +// Experiment with numeric variants +let maxItems = client.getIntegerValue(key: "max-items", defaultValue: 10) +let threshold = client.getDoubleValue(key: "score-threshold", defaultValue: 0.5) + +// Dynamic Config +let featureConfig = client.getObjectValue( + key: "homepage-layout", + defaultValue: Value.structure(["layout": .string("grid"), "itemsPerRow": .integer(3)]) +) +``` + +### Evaluation Context + +Context must be set globally via `OpenFeatureAPI.shared.setEvaluationContext()`: + +```swift +let ctx = MutableContext( + targetingKey: "user-123", + structure: MutableStructure(attributes: [ + "email": .string("user@example.com"), + "plan": .string("premium"), + ]) +) +await OpenFeatureAPI.shared.setEvaluationContext(evaluationContext: ctx) +``` + +### Runtime Properties + +Pass `custom_properties` in the evaluation context for [Runtime Properties](/docs/featureflags) targeting: + +```swift +let ctx = MutableContext( + structure: MutableStructure(attributes: [ + "custom_properties": .structure([ + "tier": .string("enterprise"), + "seats": .integer(50), + ]), + ]) +) +await OpenFeatureAPI.shared.setEvaluationContext(evaluationContext: ctx) +``` + + +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. + + +### Full Resolution Details + +```swift +let details = client.getBooleanDetails(key: "my-feature", defaultValue: false) + +print(details.value) +print(details.variant) +print(details.reason) +print(details.errorCode) +``` + +## 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 | + +To avoid `PROVIDER_NOT_READY`, use `setProviderAndWait`: + +```swift +await OpenFeatureAPI.shared.setProviderAndWait(provider: provider) +``` + +## Troubleshooting + +### Flags Always Return Default Values + +1. **Provider not ready:** Use `setProviderAndWait` to ensure initialization completes. +2. **Network issues:** Check for failed requests to Mixpanel's flags API. +3. **Flag not configured:** Verify the flag exists and is enabled in your Mixpanel project. + +### Flags Not Updating After Context Change + +When you update the OpenFeature context, the provider fetches new flag values: + +```swift +let newCtx = MutableContext( + structure: MutableStructure(attributes: ["plan": .string("premium")]) +) +await OpenFeatureAPI.shared.setEvaluationContext(evaluationContext: newCtx) +``` + +If flags still aren't updating, verify your targeting rules in Mixpanel use the context properties you're setting.