{"id":19541296,"url":"https://github.com/wingify/vwo-fme-android-sdk","last_synced_at":"2026-02-24T08:27:35.066Z","repository":{"id":251808800,"uuid":"837177752","full_name":"wingify/vwo-fme-android-sdk","owner":"wingify","description":"VWO Feature Management and Experimentation SDK for Android","archived":false,"fork":false,"pushed_at":"2025-12-18T04:39:09.000Z","size":639,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-12-21T13:57:28.227Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://developers.vwo.com/v2/docs/fme-android","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wingify.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-02T11:31:50.000Z","updated_at":"2025-12-18T04:38:58.000Z","dependencies_parsed_at":"2025-01-07T12:02:18.005Z","dependency_job_id":"bcbf15a4-981c-4843-8f41-a5856333f4f3","html_url":"https://github.com/wingify/vwo-fme-android-sdk","commit_stats":null,"previous_names":["wingify/vwo-fme-android-sdk"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/wingify/vwo-fme-android-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wingify%2Fvwo-fme-android-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wingify%2Fvwo-fme-android-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wingify%2Fvwo-fme-android-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wingify%2Fvwo-fme-android-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wingify","download_url":"https://codeload.github.com/wingify/vwo-fme-android-sdk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wingify%2Fvwo-fme-android-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29776633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T04:54:30.205Z","status":"ssl_error","status_checked_at":"2026-02-24T04:53:58.628Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T03:09:34.417Z","updated_at":"2026-02-24T08:27:35.038Z","avatar_url":"https://github.com/wingify.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VWO FME Android SDK\n\n[![License](https://img.shields.io/github/license/wingify/vwo-fme-android-sdk?style=for-the-badge\u0026color=blue)](http://www.apache.org/licenses/LICENSE-2.0)\n[![CI](https://img.shields.io/github/actions/workflow/status/wingify/vwo-fme-android-sdk/android-unit-tests.yml?style=for-the-badge\u0026logo=github)](https://github.com/wingify/vwo-fme-node-sdk/actions?query=workflow%3ACI)\n\n## Overview\n\nThe **VWO Feature Management and Experimentation SDK** (VWO FME Android SDK) enables Android developers to integrate feature flagging and experimentation into their applications across mobile, tablet and Android tv. This SDK provides full control over feature rollout, A/B testing, and event tracking, allowing teams to manage features dynamically and gain insights into user behavior.\n\n## Requirements\n\nThe Android SDK supports: `Android API level 21 onwards`\n\n## Device Support\n\nThis SDK supports the following devices:\n\n- Mobile\n- Tablet\n- Android TV\n\n## SDK Installation\n\nAdd below Maven dependency in your project's `build.gradle` file.\n\n```groovy\nimplementation 'com.vwo.sdk:vwo-fme-android-sdk:\u003clatestVersion\u003e'\n```\n\nLatest version of SDK can be found in [Maven repository](https://mvnrepository.com/artifact/com.vwo.sdk/vwo-fme-android-sdk)\n\n## Basic Usage\nThe following example demonstrates initializing the SDK with a VWO account ID and SDK key, setting a user context, checking if a feature flag is enabled, and tracking a custom event.\n\nKotlin usage\n```kotlin\nimport com.vwo.VWO\nimport com.vwo.VWO.init\nimport com.vwo.interfaces.IVwoInitCallback\nimport com.vwo.models.user.GetFlag\nimport com.vwo.models.user.VWOUserContext\nimport com.vwo.models.user.VWOInitOptions\n\n// Initialize VWO SDK\nval vwoInitOptions = VWOInitOptions()\n// Set SDK Key and Account ID\nvwoInitOptions.sdkKey = SDK_KEY\nvwoInitOptions.accountId = ACCOUNT_ID\n\n// Create VWO instance with the vwoInitOptions\ninit(vwoInitOptions, object : IVwoInitCallback {\n    override fun vwoInitSuccess(vwoClient: VWO, message: String) {\n        this@MyActivity.vwoClient = vwoClient\n    }\n\n    override fun vwoInitFailed(message: String) {\n        //Initialization failed\n    }\n})\n\n// Create VWOUserContext object\nvar context = VWOUserContext()\n// Set User ID\ncontext.id = \"unique_user_id\"\ncontext.customVariables = mutableMapOf(\"key1\" to 21, \"key2\" to 0)\n\n// Get the GetFlag object for the feature key and context\nvwoClient.getFlag(\"feature_key\", context, object : IVwoListener {\n    override fun onSuccess(data: Any) {\n        featureFlag = data as? GetFlag\n        // Get the flag value\n        val isFeatureFlagEnabled = featureFlag?.isEnabled()\n\n        // Get the variable value for the given variable key and default value\n        val variable: String = featureFlag.getVariable(\"feature_flag_variable\", \"default-value\") as String\n    }\n\n    override fun onFailure(message: String) {\n        //Feature flag is disabled\n    }\n})\n\n// Track the event for the given event name and context\nval properties = mutableMapOf\u003cString, Any\u003e(\"cartvalue\" to 10)\nvwoClient?.trackEvent(\"vwoevent\", context, properties)\n\n// send attributes data\nval attributes = mapOf(\n    \"attributeName\" to \"attributeValue\"\n)\nvwoClient?.setAttribute(attributes, context)\n```\n\nJava usage\n```java\nimport com.vwo.VWO;\nimport com.vwo.VWO.init;\nimport com.vwo.interfaces.IVwoInitCallback;\nimport com.vwo.interfaces.IVwoListener;\nimport com.vwo.models.user.GetFlag;\nimport com.vwo.models.user.VWOUserContext;\nimport com.vwo.models.user.VWOInitOptions;\n\n// Initialize VWO SDK\nVWOInitOptions vwoInitOptions = new VWOInitOptions();\n// Set SDK Key and Account ID\nvwoInitOptions.setSdkKey(SDK_KEY);\nvwoInitOptions.setAccountId(ACCOUNT_ID);\n\n// Create VWO instance with the vwoInitOptions\ninit(vwoInitOptions, new IVwoInitCallback() {\n    @Override\n    public void vwoInitSuccess(@NonNull VWO vwoClient, @NonNull String message) {\n        MyActivity.this.vwoClient = vwoClient;\n    }\n\n    @Override\n    public void vwoInitFailed(@NonNull String message) {\n        //Initialization failed\n    }\n});\n\n// Create VWOUserContext object\nVWOUserContext context = new VWOUserContext();\ncontext.setId(\"unique_user_id\");\n\nMap\u003cString, Object\u003e customVariables = new HashMap\u003c\u003e();\ncustomVariables.put(\"variable\", \"variable-value\");\ncontext.setCustomVariables(customVariables);\n\n// Get the GetFlag object for the feature key and context\nvwoClient.getFlag(\"feature-key\", context, new IVwoListener() {\n    public void onSuccess(Object data) {\n\n        GetFlag featureFlag = (GetFlag) data;\n        // Get the flag value\n        boolean isFeatureFlagEnabled = false;\n        if (featureFlag != null) {\n            isFeatureFlagEnabled = featureFlag.isEnabled();\n        }\n        if (isFeatureFlagEnabled) {\n            // Get the variable value for the given variable key and default value\n            String variable = (String) featureFlag.getVariable(\"variable_key\", \"default-value\");\n            List\u003cMap\u003cString, Object\u003e\u003e getAllVariables = featureFlag.getVariables();\n        } else {\n            //Feature flag is disabled\n        }\n    }\n\n    public void onFailure(@NonNull String message) {\n        //Error in getFlag\n    }\n});\n\n// Track the event for the given event name, user context and properties\nMap\u003cString, Object\u003e properties = new HashMap\u003c\u003e();\nproperties.put(\"cartvalue\", 120);\nvwoClient.trackEvent(\"eventName\", context, properties);\n\n// Send attributes data\nHashMap\u003cString, Object\u003e attributes = new HashMap\u003c\u003e();\nattributes.put(\"attribute_key\", \"attribute_value\");\nvwoClient.setAttribute(attributes, context);\n```\n\n## Advanced Configuration Options\n\nTo customize the SDK further, additional parameters can be passed to the `init()` API. Here’s a table describing each option:\n\n| **Parameter**              | **Description**                                                                                                                                             | **Required** | **Type** | **Example**                     |\n|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ |----------|---------------------------------|\n| `accountId`                | VWO Account ID for authentication.                                                                                                                          | Yes          | Integer  | `123456`                        |\n| `sdkKey`                   | SDK key corresponding to the specific environment to initialize the VWO SDK Client. You can get this key from VWO Application.                              | Yes          | String   | `'32-alpha-numeric-sdk-key'`    |\n| `pollInterval`             | Time interval for fetching updates from VWO servers (in milliseconds).                                                                                      | No           | Integer   | `60000`                         |\n| `storage`                  | Custom storage connector for persisting user decisions and campaign data.                                                                                   | No           | Object   | See [Storage](#storage) section |\n| `logger`                   | Toggle log levels for more insights or for debugging purposes. You can also customize your own transport in order to have better control over log messages. | No           | Object   | See [Logger](#logger) section   |\n| `cachedSettingsExpiryTime` | Controls the duration (in milliseconds) the SDK uses cached settings before fetching new ones.                                                              | No           | Integer  | `60000`                         |\n| `batchMinSize`             | Uploads are triggered when the batch reaches this minimum size.                                                                                             | No           | Integer  | `10`                            |\n| `batchUploadTimeInterval`  | Specifies the time interval (in milliseconds) for periodic batch uploads.                                                                                   | No           | Integer  | `60000`                         |\n\nRefer to the [official VWO documentation](https://developers.vwo.com/v2/docs/fme-android-install) for additional parameter details.\n\n### User Context\n\nThe `context` object uniquely identifies users and is crucial for consistent feature rollouts. A typical `context` includes an `id` for identifying the user. It can also include other attributes that can be used for targeting and segmentation, such as `customVariables`.\n\n#### Parameters Table\n\nThe following table explains all the parameters in the `context` object:\n\n| **Parameter**     | **Description**                                                            | **Required** | **Type** | **Example**                      |\n| ----------------- | -------------------------------------------------------------------------- | ------------ | -------- | -------------------------------- |\n| `id`              | Unique identifier for the user.                                            | Yes          | String   | `'unique_user_id'`               |\n| `customVariables` | Custom attributes for targeting.                                           | No           | Object   | `mutableMapOf(\"age\" to 25))`     |\n\n#### Example\n\n```kotlin\nval context = VWOUserContext()\ncontext.id = USER_ID\ncontext.customVariables = mutableMapOf(\n    \"age\" to 25,\n    \"location\" to \"US\"\n)\n```\n\n### Basic Feature Flagging\n\nFeature Flags serve as the foundation for all testing, personalization, and rollout rules within FME.\nTo implement a feature flag, first use the `getFlag` API to retrieve the flag configuration.\nThe `getFlag` API provides a simple way to check if a feature is enabled for a specific user and access its variables. It returns a feature flag object that contains methods for checking the feature's status and retrieving any associated variables.\n\n| Parameter    | Description                                                      | Required | Type   | Example                                                                               |\n| ------------ |------------------------------------------------------------------| -------- | ------ |---------------------------------------------------------------------------------------|\n| `featureKey` | Unique identifier of the feature flag                            | Yes      | String | `'new_checkout'`                                                                      |\n| `context`    | Object containing user identification and contextual information | Yes      | Object | `VWOUserContext()`                                                                    |\n| `listener`   | Callback object to receive status update about the operation.    | Yes      | Object | see [Feature Flags \u0026 Variables](https://developers.vwo.com/v2/docs/fme-android-flags) |\n\nExample usage:\n\n```kotlin\nvwoClient.getFlag(\"featureKey\", context, object : IVwoListener {\n    override fun onSuccess(data: Any) {\n        featureFlag = data as? GetFlag\n        // Get the flag value\n        val isFeatureFlagEnabled = featureFlag?.isEnabled()\n\n        // Get the variable value for the given variable key and default value\n        val variable: String = featureFlag.getVariable(\"feature_flag_variable\", \"default-value\") as String\n    }\n\n    override fun onFailure(message: String) {\n        //Feature flag is disabled\n    }\n})\n```\n\n### Custom Event Tracking\n\nFeature flags can be enhanced with connected metrics to track key performance indicators (KPIs) for your features. These metrics help measure the effectiveness of your testing rules by comparing control versus variation performance, and evaluate the impact of personalization and rollout campaigns. Use the `trackEvent` API to track custom events like conversions, user interactions, and other important metrics:\n\n| Parameter         | Description                                                            | Required | Type   | Example                                     |\n| ----------------- | ---------------------------------------------------------------------- | -------- | ------ |---------------------------------------------|\n| `eventName`       | Name of the event you want to track                                    | Yes      | String | `'purchase_completed'`                      |\n| `context`         | Object containing user identification and other contextual information | Yes      | Object | `VWOUserContext()`                          |\n| `eventProperties` | Additional properties/metadata associated with the event               | No       | Object | `mutableMapOf\u003cString, Any\u003e(\"amount\" to 10)` |\n\nExample usage:\n\n```kotlin\nval context = VWOUserContext()\ncontext.id = USER_ID\nval properties = mutableMapOf\u003cString, Any\u003e(\"cartvalue\" to 10)\nvwoClient?.trackEvent(\"vwoevent\", context, properties)\n```\n\nSee [Tracking Conversions](https://developers.vwo.com/v2/docs/fme-android-metrics#usage) documentation for more information.\n\n### Pushing Attributes\n\nUser attributes provide rich contextual information about users, enabling powerful personalization. The `setAttribute` method provides a simple way to associate these attributes with users in VWO for advanced segmentation. Here's what you need to know about the method parameters:\n\n| Parameter        | Description                                                            | Required | Type   | Example                 |\n|------------------|------------------------------------------------------------------------| -------- |--------|-------------------------|\n| `attributes`     | Map of attribute key and value to be set                               | Yes      | Object | `mapOf(\"price\" to 99)`  |\n| `context`        | Object containing user identification and other contextual information | Yes      | Object | `VWOUserContext()`      |\n\nExample usage:\n\n```kotlin\nval context = VWOUserContext()\ncontext.id = USER_ID\nval attributes = mapOf(\"price\" to 99)\nvwoClient?.setAttribute(attributes, context)\n```\n\nSee [Pushing Attributes](https://developers.vwo.com/v2/docs/fme-android-attributes#usage) documentation for additional information.\n\n### Polling Interval Adjustment\n\nThe `pollInterval` is an optional parameter that allows the SDK to automatically fetch and update settings from the VWO server at specified intervals. Setting this parameter ensures your application always uses the latest configuration.\n\n```kotlin\nval vwoInitOptions = VWOInitOptions()\nvwoInitOptions.sdkKey = SDK_KEY\nvwoInitOptions.accountId = ACCOUNT_ID\nvwoInitOptions.pollInterval = 60000\n\n// Create VWO instance with the vwoInitOptions\ninit(vwoInitOptions, object : IVwoInitCallback {\n    override fun vwoInitSuccess(vwoClient: VWO, message: String) {\n        this@MyActivity.vwoClient = vwoClient\n    }\n\n    override fun vwoInitFailed(message: String) {\n        //Initialization failed\n    }\n})\n```\n\n### Storage\n\nThe SDK operates in a stateless mode by default, meaning each `getFlag` call triggers a fresh evaluation of the flag against the current user context.\n\nTo optimize performance and maintain consistency SDK will use internal storage if application context is provided. You can implement a custom storage mechanism by passing a `storage` parameter during initialization. This allows you to persist feature flag decisions in your preferred data store.\n\nKey benefits of implementing storage:\n\n- Improved performance by caching decisions\n- Consistent user experience across sessions\n- Reduced load on your application\n\nThe storage mechanism ensures that once a decision is made for a user, it remains consistent even if campaign settings are modified in the VWO Application. This is particularly useful for maintaining a stable user experience during A/B tests and feature rollouts.\n\n```kotlin\nclass StorageConnector: Connector() {\n\n    /**\n     * Stores the data in the storage.\n     *\n     * @param data A map containing the data to be stored.\n     */\n    override fun set(data: Map\u003cString, Any\u003e) {\n        // Set data corresponding to a featureKey \u0026 user id\n    }\n\n    /**\n     * Retrieves the data from the storage.\n     *\n     * @param featureKey The feature key for the data.\n     * @param userId The user ID for the data.\n     * @return The data if found, or null otherwise.\n     */\n    override fun get(featureKey: String?, userId: String?): Any? {\n        // return await data (based on featureKey and userId)\n    }\n}\n\nval vwoInitOptions = VWOInitOptions()\nvwoInitOptions.sdkKey = SDK_KEY\nvwoInitOptions.accountId = ACCOUNT_ID\nvwoInitOptions.storage = StorageConnector()\n\ninit(vwoInitOptions, object : IVwoInitCallback {\n    override fun vwoInitSuccess(vwoClient: VWO, message: String) {\n        // Success\n        this@MainActivity.vwoClient = vwoClient\n    }\n\n    override fun vwoInitFailed(message: String) {\n        // Log error here\n    }\n})\n```\n\n### Logger\n\nVWO by default logs all `ERROR` level messages to logcat. To gain more control over VWO's logging behaviour, you can use the `logger` parameter in the `init` configuration.\n\n| **Parameter** | **Description**                        | **Required** | **Type** | **Example**           |\n| ------------- | -------------------------------------- | ------------ | -------- | --------------------- |\n| `level`       | Log level to control verbosity of logs | Yes          | String   | `DEBUG`               |\n| `transport`   | Custom logger implementation           | No           | Object   | See example below     |\n\n#### Example 1: Set log level to control verbosity of logs\n```kotlin\nval vwoInitOptions = VWOInitOptions()\nvwoInitOptions.sdkKey = SDK_KEY\nvwoInitOptions.accountId = ACCOUNT_ID\nvwoInitOptions.logger = mutableMapOf\u003cString, Any\u003e().apply { put(\"level\", \"TRACE\") }\n\ninit(vwoInitOptions, object : IVwoInitCallback {\n    override fun vwoInitSuccess(vwoClient: VWO, message: String) {\n        // Success\n        this@MainActivity.vwoClient = vwoClient\n    }\n\n    override fun vwoInitFailed(message: String) {\n        // Log error here\n    }\n})\n```\n#### Example 2: Implement custom transport to handle logs your way\n\nThe `transport` parameter allows you to implement custom logging behavior by providing your own logging functions. You can define handlers for different log levels (TRACE, DEBUG, INFO, WARN, ERROR) to process log messages according to your needs.\nFor example, you could:\n\n- Send logs to a third-party logging service\n- Write logs to a file\n- Format log messages differently\n- Filter or transform log messages\n\nThe transport object should implement `defaultTransport` handler to customize.\n\n```kotlin\nval vwoInitOptions = VWOInitOptions()\nvwoInitOptions.sdkKey = SDK_KEY\nvwoInitOptions.accountId = ACCOUNT_ID\nval logger: MutableList\u003cMap\u003cString, Any\u003e\u003e = mutableListOf()\nval transport: MutableMap\u003cString, Any\u003e = mutableMapOf()\ntransport[\"defaultTransport\"] = object : LogTransport {\n    override fun log(level: LogLevelEnum, message: String?) {\n        if (message == null) return\n        Log.d(\"FME\", message)\n    }\n}\nlogger.add(transport)\nvwoInitOptions.logger = mutableMapOf\u003cString, Any\u003e().apply {\n    put(\"level\", \"TRACE\")\n    put(\"transports\", logger)\n}\n```\n\n### Running Unit Tests\n\nThe SDK includes a comprehensive test suite to ensure reliability and functionality. To run the unit tests:\n\nUsing Android Studio:\n   - Right-click on the `test` directory in the project view\n   - Select \"Run Tests in 'test'\"\n\nThe test suite includes:\n- Unit tests for core functionality\n- Integration tests for API interactions\n- Mock tests for external dependencies\n- Coverage reports for code quality assurance\n\n## 📊 Analytics Integration with Mixpanel\n\nVWO FME SDK provides integration capabilities with analytics platforms like Mixpanel. This allows you to track feature flag evaluations and events in your analytics dashboard.\n\n### Kotlin Implementation\n\n```kotlin\n// 1. Create a MixpanelIntegration class\nimport android.content\nimport com.mixpanel.android.mpmetrics.MixpanelAPI\nimport org.json.JSONObject\n\nclass MixpanelIntegration private constructor(context: Context, projectToken: String) {\n    private val mixpanel: MixpanelAPI = MixpanelAPI.getInstance(context, projectToken, true)\n\n    companion object {\n        @Volatile\n        private var instance: MixpanelIntegration? = null\n\n        fun getInstance(context: Context, projectToken: String): MixpanelIntegration {\n            return instance ?: synchronized(this) {\n                instance ?: MixpanelIntegration(context, projectToken).also { instance = it }\n            }\n        }\n    }\n\n    fun trackEvent(eventName: String, properties: Map\u003cString, Any\u003e) {\n        val props = JSONObject()\n        properties.forEach { (key, value) -\u003e\n            props.put(key, value)\n        }\n        mixpanel.track(\"vwo_fme_track_event\", props)\n    }\n\n    fun trackFlagEvaluation(properties: Map\u003cString, Any\u003e) {\n        mixpanel.trackMap(\"vwo_fme_flag_evaluation\", properties)\n    }\n}\n\n// 2. Initialize Mixpanel and set up integration callback\nval mixpanelToken = BuildConfig.MIXPANEL_PROJECT_TOKEN\nmixpanelIntegration = MixpanelIntegration.getInstance(context, mixpanelToken)\n\ninitOptions.integrations = object : IntegrationCallback {\n    override fun execute(properties: Map\u003cString, Any\u003e) {\n        // Check if this is a flag evaluation or event tracking\n        if (properties[\"api\"] == \"track\") {\n            // This is event tracking\n            val eventName = properties[\"eventName\"] as String\n            mixpanelIntegration?.trackEvent(eventName, properties)\n        } else if (properties.containsKey(\"featureName\")) {\n            // This is a flag evaluation\n            mixpanelIntegration?.trackFlagEvaluation(properties)\n        }\n    }\n}\n```\n\n### Java Implementation\n\n```java\n// 1. Create a MixpanelIntegration class\nimport android.content.Context;\nimport com.mixpanel.android.mpmetrics.MixpanelAPI;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport java.util.Map;\n\npublic class MixpanelIntegration {\n    private static volatile MixpanelIntegration instance;\n    private final MixpanelAPI mixpanel;\n\n    private MixpanelIntegration(Context context, String projectToken) {\n        mixpanel = MixpanelAPI.getInstance(context, projectToken, true);\n    }\n\n    public static MixpanelIntegration getInstance(Context context, String projectToken) {\n        if (instance == null) {\n            synchronized (MixpanelIntegration.class) {\n                if (instance == null) {\n                    instance = new MixpanelIntegration(context, projectToken);\n                }\n            }\n        }\n        return instance;\n    }\n\n    public void trackEvent(String eventName, Map\u003cString, Object\u003e properties) {\n        JSONObject props = new JSONObject();\n        for (Map.Entry\u003cString, Object\u003e entry : properties.entrySet()) {\n            try {\n                props.put(entry.getKey(), entry.getValue());\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n        mixpanel.track(\"vwo_fme_track_event\", props);\n    }\n\n    public void trackFlagEvaluation(Map\u003cString, Object\u003e properties) {\n        mixpanel.trackMap(\"vwo_fme_flag_evaluation\", properties);\n    }\n}\n\n// 2. Initialize Mixpanel and set up integration callback\nString mixpanelToken = BuildConfig.MIXPANEL_PROJECT_TOKEN;\nfinal MixpanelIntegration mixpanelIntegration = MixpanelIntegration.getInstance(context, mixpanelToken);\n\nVWOInitOptions initOptions = new VWOInitOptions();\ninitOptions.setIntegrations(new IntegrationCallback() {\n    @Override\n    public void execute(Map\u003cString, Object\u003e properties) {\n        // Check if this is a flag evaluation or event tracking\n        if (\"track\".equals(properties.get(\"api\"))) {\n            // This is event tracking\n            String eventName = (String) properties.get(\"eventName\");\n            mixpanelIntegration.trackEvent(eventName, properties);\n        } else if (properties.containsKey(\"featureName\")) {\n            // This is a flag evaluation\n            mixpanelIntegration.trackFlagEvaluation(properties);\n        }\n    }\n});\n```\n\n### Integration Data\n\nWhen using the integration callback, you'll receive the following data:\n\n- **For flag evaluations**:\n  ```\n  {\n    featureName: \"yourFlagName\",\n    featureId: 5,\n    featureKey: \"yourFlagKey\",\n    userId: \"0duMh1j7krRB\",\n    ...\n  }\n  ```\n\n- **For event tracking**:\n  ```\n  {\n    eventName: \"yourEventName\",\n    api: \"track\"\n  }\n  ```\n\nDon't forget to add your Mixpanel project token to your `local.properties` file:\n```\nMIXPANEL_PROJECT_TOKEN=YOUR_PROJECT_TOKEN\n```\n\n### Version History\n\nThe version history tracks changes, improvements and bug fixes in each version. For a full history, see the [CHANGELOG.md](https://github.com/wingify/vwo-fme-android-sdk/blob/master/CHANGELOG.md).\n\n## Contributing\n\nWe welcome contributions to improve this SDK! Please read our [contributing guidelines](https://github.com/wingify/vwo-fme-android-sdk/blob/master/CONTRIBUTING.md) before submitting a PR.\n\n## Code of Conduct\n\n[Code of Conduct](https://github.com/wingify/vwo-fme-android-sdk/blob/master/CODE_OF_CONDUCT.md)\n\n## License\n\n[Apache License, Version 2.0](https://github.com/wingify/vwo-fme-android-sdk/blob/master/LICENSE)\n\nCopyright (c) 2024-2025 Wingify Software Pvt. Ltd.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwingify%2Fvwo-fme-android-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwingify%2Fvwo-fme-android-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwingify%2Fvwo-fme-android-sdk/lists"}