Getting Started
Integrate the Measure SDK on Android, iOS, Flutter, React Native or Kotlin Multiplatform to get started. Create an app in the dashboard, add the SDK and verify installation.
1. Create an App
Create a new app by visiting the Apps section on the dashboard.
Once the app is created, note the API URL & API Key for your app. This will be used in the SDK configuration
in later steps.

2. Set Up the SDK
Android
Add the API Key & API URL
Add the API URL & API Key to your application's AndroidManifest.xml file.
<application>
<meta-data android:name="sh.measure.android.API_KEY" android:value="YOUR_API_KEY"/>
<meta-data android:name="sh.measure.android.API_URL" android:value="YOUR_API_URL"/>
</application>Add the Gradle Plugin
Add the following plugin to your project.
plugins {
id("sh.measure.android.gradle") version "0.13.0"
}or, use the following if you're using build.gradle.
plugins {
id 'sh.measure.android.gradle' version '0.13.0'
}Add the SDK
Add the following to your app's build.gradle.kts file.
implementation("sh.measure:measure-android:0.19.0")or, add the following to your app's build.gradle file.
implementation 'sh.measure:measure-android:0.19.0'Initialize the SDK
Add the following to your app's Application class onCreate method.
To be able to detect early crashes and accurate launch time metrics, initialize the SDK as soon as possible in
Application onCreate method.
Measure.init(
context, MeasureConfig()
)See the troubleshooting section if you face any issues.
iOS
Install the SDK
Measure SDK supports CocoaPods and Swift Package Manager (SPM) for installation.
Using CocoaPods
CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions,
visit their website. To integrate MeasureSDK into your Xcode project using CocoaPods, specify it in your Podfile:
pod 'measure-sh'MeasureSDK must be linked statically. If you are using use_frameworks! in your Podfile, you will need to ensure measure-sh is linked statically, as dynamic linking is not supported.
CocoaPods does not natively support per-pod linkage overrides. You will need to install the cocoapods-pod-linkage plugin:
gem install cocoapods-pod-linkageThen add the plugin and linkage option to your Podfile:
plugin 'cocoapods-pod-linkage'
target 'YourApp' do
use_frameworks!
pod 'measure-sh', :linkage => :static
# ... rest of your pods
endAlternatively, if all your pods can be linked statically, you can use:
use_frameworks! :linkage => :staticUsing Swift Package Manager
The Swift Package Manager is a tool for automating the distribution of Swift code
and is integrated into the swift compiler.
Add Measure as a dependency by adding dependencies value to your Package.swift or the Package list in Xcode.
dependencies: [
.package(url: "https://github.com/measure-sh/measure.git", branch: "ios-v0.12.1")
]Initialize the SDK
Add the following to your AppDelegate's application(_:didFinishLaunchingWithOptions:) to capture early crashes and
launch time metrics.
To detect early crashes and ensure accurate launch time metrics, initialize the SDK as soon as possible
in application(_:didFinishLaunchingWithOptions:).
import Measure
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = BaseMeasureConfig()
let clientInfo = ClientInfo(apiKey: "<apiKey>", apiUrl: "<apiUrl>")
Measure.initialize(with: clientInfo, config: config)
return true
}
#import <Measure/Measure.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ClientInfo *clientInfo = [[ClientInfo alloc] initWithApiKey:@"<apiKey>" apiUrl:@"<apiUrl>"];
BaseMeasureConfig *config = [[BaseMeasureConfig alloc] initWithEnableLogging:YES
autoStart:YES
requestHeadersProvider:NULL
maxDiskUsageInMb:50
enableFullCollectionMode:NO
enableDiagnosticMode:NO
enableDiagnosticModeGesture:NO];
[Measure initializeWith:clientInfo config:config];
return YES;
}
Flutter
The Flutter SDK currently supports only Android and iOS targets and is not available for web or desktop. The SDK depends on the native Android and iOS SDKs, so all the minimum requirements for Android and iOS apply to the Flutter SDK as well.
Install the SDK
Add the following dependency to your pubspec.yaml file:
dependencies:
measure_flutter: ^0.6.0Initialize the SDK
To initialize the SDK, you need to call the Measure.instance.init method in your main function.
- Run app inside the callback passed to the
initmethod. This ensures that the Measure SDK can set up error handlers to track uncaught exceptions. - Wrap your app with the
MeasureWidget, this is required for gesture tracking and screenshots.
To detect early native crashes and to ensure accurate launch time metrics, initialize the Android SDK in
Application class as described in the Android section and the iOS SDK in AppDelegate as
described in
the iOS section. It is highly recommended to initialize both native SDKs even when using the
Flutter SDK.
Future<void> main() async {
await Measure.instance.init(
() =>
runApp(
// wrap your app with MeasureWidget
MeasureWidget(child: MyApp()),
),
// SDK configuration
config: const MeasureConfig(
enableLogging: true,
),
);
}This does the following:
- Initializes the Measure SDK with the provided
config. - Wraps your app with the
MeasureWidgetfor gesture detection and layout snapshots. - Sets up the error handlers to track uncaught exceptions.
Flutter Android Setup
Measure Flutter SDK depends on the native Android SDK, so you need to follow all the steps mentioned in the Android section to set up the Android SDK properly.
Flutter iOS Setup
Measure Flutter SDK depends on the native iOS SDK, so you need to follow all the steps mentioned in the iOS section to set up the iOS SDK properly.
Track navigation
See Navigation Monitoring for instructions on how to track navigation events.
Track http requests
See Network Monitoring for instructions on how to track HTTP requests.
Gesture tracking & Layout Snapshots
The Flutter SDK automatically captures gestures like clicks, long clicks and scrolls. It also captures layout snapshots
on every click to help visualize user interactions. To enable these features, simply wrap your app with the
MeasureWidget as shown in the initialization step above.
Read more about adding custom widget names in the layout snapshots in Gesture Tracking & Layout Snapshots.
React Native
The React Native SDK supports both Expo and Vanilla React Native projects on Android and iOS.
Install the SDK
npm install @measuresh/react-native@0.2.0or with yarn:
yarn add @measuresh/react-native@0.2.0Expo
The recommended setup for Expo projects uses the Measure config plugin, which automates the native configuration for both Android and iOS.
1. Add the plugin to app.json
{
"expo": {
"plugins": [
[
"@measuresh/react-native",
{
"androidApiKey": "<android-api-key>",
"androidApiUrl": "<android-api-url>",
"iosApiKey": "<ios-api-key>",
"iosApiUrl": "<ios-api-url>"
}
]
]
}
}The plugin automatically handles:
Android
- Injects
sh.measure.android.API_KEYandsh.measure.android.API_URLintoAndroidManifest.xml - Adds the Measure Gradle plugin to the project build files
- Adds the
measure-androiddependency toapp/build.gradle
iOS
- Adds the
MeasureReactNativepod toPodfile - Adds
export SOURCEMAP_FILE="$(pwd)/main.jsbundle.map"to the "Bundle React Native code and images" build phase so a sourcemap is generated on every Release build - Adds an "Upload Measure Symbol Files" build phase that automatically uploads dSYM files and the JavaScript sourcemap after each Release build
2. Run prebuild
npx expo prebuild3. Initialize the SDK
Call Measure.init as early as possible in your app entry point:
import { Measure, MeasureConfig } from "@measuresh/react-native";
import { useEffect } from "react";
export default function App() {
useEffect(() => {
Measure.init({
config: new MeasureConfig({ autoStart: true }),
});
}, []);
// ...
}4. Build and run
# Android
npx expo run:android
# iOS
npx expo run:iosVanilla React Native
Android setup
Step 1 — Add API credentials to AndroidManifest.xml
<manifest>
<application>
<meta-data
android:name="sh.measure.android.API_KEY"
android:value="<android-api-key>" />
<meta-data
android:name="sh.measure.android.API_URL"
android:value="<android-api-url>" />
</application>
</manifest>Step 2 — Add the Gradle plugin
In your project-level build.gradle:
buildscript {
dependencies {
classpath("sh.measure.android.gradle:sh.measure.android.gradle.gradle.plugin:0.13.0")
}
}In your app-level build.gradle (after all other plugins):
apply plugin: "sh.measure.android.gradle"The Gradle plugin automatically uploads ProGuard/R8 mapping files and JavaScript sourcemaps after every assembleRelease or bundleRelease build — no manual upload step is needed.
iOS setup
Step 1 — Add the pod
In your Podfile:
pod 'MeasureReactNative', :path => '../node_modules/@measuresh/react-native'Then run:
pod installBy default, the measure-sh iOS framework is integrated via Swift Package Manager (SPM) on React Native 0.75 and above. On older React Native versions it is integrated as a CocoaPods dependency automatically. If you'd prefer to integrate it as a CocoaPods dependency instead, add the following to the top of your Podfile:
$MeasureDisableSPM = trueStep 2 — Enable sourcemap generation
In Xcode, open your target → Build Phases → "Bundle React Native code and images" and add this line at the top of the script:
export SOURCEMAP_FILE="$(pwd)/main.jsbundle.map"Step 3 — Add the upload build phase
Add a new Run Script build phase after the bundle phase:
"$SRCROOT/../node_modules/@measuresh/react-native/scripts/upload_build_phase.sh" \
"<ios-api-url>" \
"<ios-api-key>"This script automatically uploads dSYM files and the JavaScript sourcemap after each Release build. See the caution note below about when to run it.
The upload script runs on every build in the configuration you add it to. To restrict it to Archive builds only, wrap the script content in:
if [ "$ACTION" = "archive" ]; then
# script content here
fiInitialize the SDK
Call Measure.init as early as possible in your app entry point:
import { Measure, MeasureConfig } from "@measuresh/react-native";
import { useEffect } from "react";
export default function App() {
useEffect(() => {
Measure.init({
config: new MeasureConfig({ autoStart: true }),
});
}, []);
// ...
}Build and run
# Android
npx react-native run-android
# iOS
npx react-native run-iosTrack navigation
See Navigation Monitoring for instructions on how to track navigation events.
Track http requests
See Network Monitoring for instructions on how to track HTTP requests.
Kotlin Multiplatform
The KMP SDK provides access to Measure API from shared Kotlin code (commonMain) on Android and iOS.
It is a thin wrapper over the native Android and iOS SDKs, so all the minimum requirements for Android
and iOS apply to the KMP SDK as well.
Minimum Requirements
| Name | Version |
|---|---|
| Kotlin | 2.x |
| Measure Android SDK | 0.18.0 |
| Measure iOS SDK | 0.11.0 |
The SDK is built with Kotlin 2.3.20. Use a compatible Kotlin 2.x toolchain in your project.
Add the Native SDKs
The KMP SDK does not have its own initialization API. You initialize each native SDK in its own platform
target (as described in the Android and iOS sections), and then use
sh.measure.kmp.Measure from shared code.
Add KMP SDK
Add the dependency to the commonMain source set of your shared module's build.gradle.kts file:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("sh.measure:measure-kmp:0.1.0")
}
}
}Use the SDK from shared code
Once both native SDKs are initialized, you can call any API from sh.measure.kmp.Measure in commonMain:
import sh.measure.kmp.Measure
import sh.measure.kmp.attributes.StringAttr
Measure.trackScreenView("CheckoutScreen")
Measure.trackEvent(
name = "checkout_completed",
attributes = mapOf("source" to StringAttr("kmp")),
)Crashes from shared Kotlin code on iOS
Crashes from unhandled exceptions in shared Kotlin code are captured automatically on iOS, no extra setup is required. The SDK installs a Kotlin exception hook on load and forwards the crash, with its Kotlin stack frames preserved.
3. Verify Installation
Launch the app with the SDK integrated and navigate through a few screens. The data is sent to the server periodically,
so it may take a few seconds to appear. Checkout the Usage section in the dashboard or navigate to the
Session Timelines tab to see the data.
🎉 Congratulations! You have successfully integrated Measure into your app!
4. Review Configuration Options
There are several configuration options available to customize the SDK behavior. Some options can be set during SDK initialization, while others can be configured remotely from the dashboard. Review the Configuration Options section to learn more about these options and how to use them effectively.
By default, all data is collected without sampling, so you can verify your installation right away. In release builds, you can adjust the sampling rates and other settings as needed to balance signal vs noise and optimize costs.
5. Uploading Symbols
Stack traces from crashes are obfuscated and need to be symbolicated. To symbolicate them, you need to upload the relevant mapping or symbol files, ProGuard/R8 mappings on Android, dSYMs on iOS and JavaScript sourcemaps for React Native (including Over-The-Air updates).
See Uploading Symbols for platform-specific setup.
Troubleshoot
Verify API URL and API Key
If you are not seeing any data in the dashboard, verify that the API URL and API key are set correctly in your app.
Flutter iOS — MeasureSDK must be linked statically
Flutter adds use_frameworks! to the iOS Podfile by default, which causes CocoaPods to link all pods dynamically. MeasureSDK must be linked statically and will not work correctly with dynamic linking.
To fix this, follow the CocoaPods static linking instructions in the iOS setup section.
Connecting to Locally-hosted Server (for self-host customers)
iOS
If you are running the measure-sh server on your machine, setting the API_URL to localhost:8080 will work on the simulator because it can access localhost. However, a physical device cannot access your computer's localhost.
To resolve this, you can use ngrok or a similar service to provide a public URL to your local server. This allows your physical device to connect to the server.
Android
For Android, if your device is on the same network as your computer, you can use your computer's local IP address (e.g.,
192.168.1.X:8080) as the API_URL. Alternatively, you can set up ADB port forwarding with the command adb reverse tcp: 8080 tcp:8080 to allow the device to connect to the server.
When using an Android emulator, you can set the API_URL to http://10.0.2.2:8080 to access the server running on your machine.
Alternatively, you can use ngrok or a similar service to provide a public URL to your local server. This allows your Android emulator or physical device to connect to the server.
Enable Logs
Connecting to a Self-hosted Server
If you are hosting the server in cloud. Make sure the API URL is set to the public URL of your server.
For example: set the API URL to https://measure-api.<your-domain>.com, replacing <your-domain> with your own domain.
Contact Support
If none of the above steps resolve the issue, feel free to reach out to us on Discord for further assistance.
Enable Diagnostic Mode
If you're experiencing issues with the SDK and need to share detailed logs with us, enable diagnostic mode. This writes all internal SDK logs to files on disk which can then be pulled from the device and shared when reporting a bug.
These files only contain Measure SDK logs, not your app's logs.
Step 1: Enable diagnostic mode
Step 2: Reproduce the issue
Run the app and reproduce the issue you're facing. The SDK will write logs to files in the app's internal storage.
Step 3: Pull the log files
Step 4: Share the files
Share the pulled log files on Discord or send them to us via email for us to investigate.
Step 5: Disable diagnostic mode
Once you've collected the logs, disable diagnostic mode by removing the enableDiagnosticMode flag
or setting it to false. You can also delete the log files from the device:
Think this page can be better?
Open an issue