
GrowthBook - Kotlin SDK
-
Lightweight and fast
-
Kotlin Multiplatform (Android, iOS, JVM, JS, Wasm)
- Android version 21 & above
- JDK 17 & Above
- iOS (iosX64, iosArm64, iosSimulatorArm64)
-
Use your existing event tracking (GA, Segment, Mixpanel, custom)
-
Adjust variation weights and targeting without deploying new code
See CHANGELOG.md for version history.
Setup
App level build.gradle (Groovy DSL):
repositories {
mavenCentral()
}
dependencies {
implementation 'io.growthbook.sdk:GrowthBook:7.2.0'
implementation 'io.growthbook.sdk:NetworkDispatcherKtor:1.0.12'
implementation 'io.growthbook.sdk:NetworkDispatcherOkHttp:1.0.7'
}
If you are not sure which dispatcher to choose we recommend to use network dispatcher based on Ktor.
The main class of NetworkDispatcherKtor artifact is GBNetworkDispatcherKtor while the main class of NetworkDispatcherOkHttp artifact is GBNetworkDispatcherOkHttp.
If you are using other network client for example android-lite-http and don't want to have any other network client in your application,
you can provide your own implementation of NetworkDispatcher based on your network client.
Add Internet Permission to your AndroidManifest.xml, if not already added
<uses-permission android:name="android.permission.INTERNET" />
Integration
Integration is super easy:
- Create a Growth Book API key
- At the start of your app, do SDK Initialization as per below
Now you can start/stop tests, adjust coverage and variation weights, and apply a winning variation to 100% of traffic,
all within the Growth Book App without deploying code changes to your site.
initialize() method should be called in order to obtain SDK instance:
var sdkInstance: GrowthBookSDK = GBSDKBuilder(
apiKey = <API_KEY>,
hostURL = <GrowthBook_URL>,
attributes = < Hashmap >,
trackingCallback = { gbExperiment, gbExperimentResult -> },
encryptionKey = <String?>,
networkDispatcher = <NetworkDispatcher>,
).initialize()
If you are accessing features the first time there will be no features right after initialize() method call because features are not got from Backend yet. If you need to access features as soon as possible, you need to use GBCacheRefreshHandler. You can pass your implementation of GBCacheRefreshHandler through setRefreshHandler() method.
There are additional properties which can be setup at the time of initialization
.setEnabled(true)
.setQAMode(true)
.setForcedVariations(<HashMap>)
.setInitialFeatures(<GBFeatures>)
.initialize()
Bundled fallback features (setInitialFeatures)
For a robust offline-first setup, you can bundle a known-good features payload (snapshotted from the API at build time) and seed the SDK with it at init. This gives flags a valid value from the first millisecond — on first installs, offline launches, and empty/corrupt cache — instead of falling back to hardcoded code defaults.
val bundledFeatures: GBFeatures = mapOf(
"dark-mode" to GBFeature(defaultValue = GBBoolean(false)),
"new-checkout" to GBFeature(defaultValue = GBBoolean(true)),
)
var sdkInstance: GrowthBookSDK = GBSDKBuilder(
apiKey = <API_KEY>,
hostURL = <GrowthBook_URL>,
attributes = hashMapOf(),
trackingCallback = { _, _ -> },
networkDispatcher = GBNetworkDispatcherKtor(),
)
.setInitialFeatures(bundledFeatures)
.initialize()
The seeded features are applied immediately. The normal cache/network refresh still runs on top and overwrites the seed as fresher data arrives. Effective precedence: network > disk cache > seed > code defaults.
Upgrading from 6.x (Android): Persistent caching is only implemented on Android; other platforms do not cache features to disk, so this upgrade note does not apply to them. On Android the cache file is automatically migrated from FeatureCache.txt to the new scoped FeatureCache_<clientKey>.txt on first launch. Single-instance apps migrate transparently with no cold start. Apps that use multiple SDK instances with different clientKeys may see one cold start without cache on the first launch after upgrade — features self-correct after the first successful fetch.
Usage
Models
This SDK operates with such models as GBContext, GBFeature, GBFeatureRule, GBFeatureSource, GBFeatureResult, GBExperiment, GBExperimentResult, etc.
These models can be found in model package. Some entities were put in utils/Constants.kt file. In JS SDK there is only one entity "Result" while in this SDK GBFeatureResult, GBExperimentResult are present.
Attributes
You can specify attributes about the current user and request. These are used for two things:
- Feature targeting (e.g. paid users get one value, free users get another)
- Assigning persistent variations in A/B tests (e.g. user id "123" always gets variation B)
Attributes can be any JSON data type - boolean, integer, float, string, list, or dict.
Proguard (Android)
If you're using ProGuard, you may need to add rules to your configuration file to make it compatible with Obfuscation &
Shriniking tools. These rules are guidelines only and some projects require more to work. You can modify those rules and
adapt them to your project, but be aware that we do not support custom rules.
-keep { *; }
-keep { *; }
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.SerializationKt
-keep,includedescriptorclasses { *; }
-keepclassmembers {
*** Companion;
}
-keepclasseswithmembers {
kotlinx.serialization.KSerializer serializer(...);
}
Remote Evaluation
This mode brings the security benefits of a backend SDK to the front end by evaluating feature flags exclusively on a
private server. Using Remote Evaluation ensures that any sensitive information within targeting rules or unused feature
variations are never seen by the client. Note that Remote Evaluation should not be used in a backend context.
You must enable Remote Evaluation in your SDK Connection settings. Cloud customers are also required to self-host a
GrowthBook Proxy Server or custom remote evaluation backend.
To use Remote Evaluation, set the remoteEval = true property to your SDK instance. A new evaluation API call will be
made any time a user attribute or other dependency changes.
If you would like to implement Sticky Bucketing while using Remote Evaluation, you must configure your remote evaluation
backend to support Sticky Bucketing. You will not need to provide a StickyBucketService instance to the client side SDK.
Sticky Bucketing
By default, GrowthBook does not persist assigned experiment variations for a user.
We rely on deterministic hashing to ensure that the same user attributes always map to the same experiment variation.
However, there are cases where this isn't good enough. For example, if you change targeting conditions
in the middle of an experiment, users may stop being shown a variation even if they were previously bucketed into it.
Sticky Bucketing is a solution to these issues. You can provide a Sticky Bucket Service to the GrowthBook instance
to persist previously seen variations and ensure that the user experience remains consistent for your users.
Sticky bucketing ensures that users see the same experiment variant, even when user session, user login status, or
experiment parameters change. See the Sticky Bucketing docs for more
information. If your organization and experiment supports sticky bucketing, you can implement an instance of
the StickyBucketService to use Sticky Bucketing. For simple bucket persistence using the CachingLayer.
Sticky Bucket documents contain three fields:
- attributeName - The name of the attribute used to identify the user (e.g. id, cookie_id, etc.)
- attributeValue - The value of the attribute (e.g. 123)
- assignments - A dictionary of persisted experiment assignments. For example: {"exp1__0":"control"}
The attributeName/attributeValue combo is the primary key.
Here's an example implementation using a theoretical db object:
License
This project uses the MIT license. The core GrowthBook app will always remain open and free, although we may add some
commercial enterprise add-ons in the future.