Measure logo

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.

Create new app

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-linkage

Then 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
end

Alternatively, if all your pods can be linked statically, you can use:

use_frameworks! :linkage => :static

Using 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.0

Initialize 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 init method. 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 MeasureWidget for 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.

  1. Add API Key & API URL to Android Manifest
  2. Add Android Gradle Plugin
  3. Initialize the SDK

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.

  1. Install the SDK using CocoaPods or SPM
  2. Initialize the SDK

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.0

or with yarn:

yarn add @measuresh/react-native@0.2.0

Expo

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_KEY and sh.measure.android.API_URL into AndroidManifest.xml
  • Adds the Measure Gradle plugin to the project build files
  • Adds the measure-android dependency to app/build.gradle

iOS

  • Adds the MeasureReactNative pod to Podfile
  • 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 prebuild

3. 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:ios

Vanilla 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 install

By 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 = true

Step 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
fi

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 }),
    });
  }, []);

  // ...
}

Build and run

# Android
npx react-native run-android

# iOS
npx react-native run-ios

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.

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

NameVersion
Kotlin2.x
Measure Android SDK0.18.0
Measure iOS SDK0.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