# Getting Started * [1. Create an App](#1-create-an-app) * [2. Set Up the SDK](#2-set-up-the-sdk) * [Android](#android) * [iOS](#ios) * [Flutter](#flutter) * [3. Verify Installation](#3-verify-installation) * [Troubleshoot](#troubleshoot) > [!IMPORTANT] > > Make sure the measure-sh server is running. For setup instructions on your local machine or in the cloud, refer to the > [hosting guide](hosting/README.md). ## 1. Create an App Create a new app by visiting the _Apps_ section on the dashboard. ![Create new app](features/assets/create-app.png) 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. ![Get API Key and URL](features/assets/get-api-key.png) ## 2. Set Up the SDK * [Android](#android) * [iOS](#ios) * [Flutter](#flutter) ## Android
Minimum Requirements | Name | Version | |-----------------------|-----------------| | Android Gradle Plugin | `8.0.2` | | Min SDK | `21` (Lollipop) | | Target SDK | `35` |
Self-host Compatibility | SDK Version | Minimum Required Self-host Version | |---------------------|------------------------------------| | >=`0.13.0` | `0.9.0` | | `0.10.0` - `0.12.0` | `0.6.0` | | `0.9.0` | `0.5.0` |
### Add the API Key & API URL Add the API URL & API Key to your application's `AndroidManifest.xml` file. ```xml ```
Configure API Keys for Different Build Types You can use [manifestPlaceholders](https://developer.android.com/build/manage-manifests#inject_build_variables_into_the_manifest) to configure different values for different build types or flavors. In the `build.gradle.kts` file: ```kotlin android { buildTypes { debug { manifestPlaceholders["measureApiKey"] = "YOUR_API_KEY" manifestPlaceholders["measureApiUrl"] = "YOUR_API_URL" } release { manifestPlaceholders["measureApiKey"] = "YOUR_API_KEY" manifestPlaceholders["measureApiUrl"] = "YOUR_API_URL" } } } ``` or in the `build.gradle` file: ```groovy android { buildTypes { debug { manifestPlaceholders = ["measureApiKey": "YOUR_API_KEY"] manifestPlaceholders = ["measureApiUrl": "YOUR_API_URL"] } release { manifestPlaceholders = ["measureApiKey": "YOUR_API_KEY"] manifestPlaceholders = ["measureApiUrl": "YOUR_API_URL"] } } } ``` Then add the following in the `AndroidManifest.xml` file: ```xml ```
### Add the Gradle Plugin Add the following plugin to your project. ```kotlin plugins { id("sh.measure.android.gradle") version "0.11.0" } ``` or, use the following if you're using `build.gradle`. ```groovy plugins { id 'sh.measure.android.gradle' version '0.11.0' } ```
Configure Variants By default, the plugin is applied to all variants. To disable the plugin for specific variants, use the `measure` block in your build file. > [!IMPORTANT] > Setting `enabled` to `false` will disable the plugin for that variant. This prevents the plugin from > collecting `mapping.txt` file and other build information about the app. Features like tracking app size, > de-obfuscating > stack traces, etc. will not work. For example, to disable the plugin for `debug` variants, add the following to your `build.gradle.kts` file: ```kotlin measure { variantFilter { if (name.contains("debug")) { enabled = false } } } ``` or in the `build.gradle` file: ```groovy measure { variantFilter { if (name.contains("debug")) { enabled = false } } } ```
### Add the SDK Add the following to your app's `build.gradle.kts` file. ```kotlin implementation("sh.measure:measure-android:0.15.1") ``` or, add the following to your app's `build.gradle` file. ```groovy implementation 'sh.measure:measure-android:0.15.1' ``` ### Initialize the SDK Add the following to your app's Application class `onCreate` method. > [!IMPORTANT] > To be able to detect early crashes and accurate launch time metrics, initialize the SDK as soon as possible in > Application `onCreate` method. ```kotlin Measure.init( context, MeasureConfig( // Set to 1 to track all sessions // useful to verify the installation samplingRateForErrorFreeSessions = 1f, ) ) ``` See the [troubleshooting](#troubleshoot) section if you face any issues. ## iOS
Minimum Requirements | Name | Version | |-------------------------|---------| | Xcode | 15.0+ | | Minimum iOS Deployments | 12.0+ | | Swift Version | 5.10+ |
Self-host Compatibility | SDK Version | Minimum Required Self-host Version | |-------------|------------------------------------| | >=0.1.0 | 0.6.0 | | >=0.7.0 | 0.9.0 |
### Install the SDK Measure SDK supports **CocoaPods** and **Swift Package Manager (SPM)** for installation. #### Using CocoaPods [CocoaPods](https://cocoapods.org) 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`: ```ruby pod 'measure-sh' ``` #### Using Swift Package Manager The [Swift Package Manager](https://swift.org/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. ```swift dependencies: [ .package(url: "https://github.com/measure-sh/measure.git", branch: "ios-v0.8.1") ] ``` ### Initialize the SDK Add the following to your AppDelegate's `application(_:didFinishLaunchingWithOptions:)` to capture early crashes and launch time metrics. > [!IMPORTANT] > To detect early crashes and ensure accurate launch time metrics, initialize the SDK as soon as possible > in `application(_:didFinishLaunchingWithOptions:)`. ```swift import Measure func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let config = BaseMeasureConfig( // Set to 1 to track all sessions // useful to verify the installation samplingRateForErrorFreeSessions: 1 ) let clientInfo = ClientInfo(apiKey: "", apiUrl: "") Measure.initialize(with: clientInfo, config: config) return true } ``` ```objc #import - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ClientInfo *clientInfo = [[ClientInfo alloc] initWithApiKey:@"" apiUrl:@""]; BaseMeasureConfig *config = [[BaseMeasureConfig alloc] initWithEnableLogging:YES samplingRateForErrorFreeSessions:1.0 traceSamplingRate:1.0 trackHttpHeaders:YES trackHttpBody:YES httpHeadersBlocklist:@[] httpUrlBlocklist:@[] httpUrlAllowlist:@[] autoStart:true trackViewControllerLoadTime:true screenshotMaskLevel:ScreenshotMaskLevelObjcAllText requestHeadersProvider:nil]; [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.
Minimum Requirements | Name | Version | |---------|---------| | Flutter | `3.10` |
Self-host Compatibility | SDK Version | Minimum Required Self-host Version | |-------------|------------------------------------| | `0.1.0` | `0.8.0` |
### Install the SDK Add the following dependency to your `pubspec.yaml` file: ```yaml dependencies: measure_flutter: ^0.3.1 ``` ### 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. - Set the `sessionSamplingRate` and `samplingRateForErrorFreeSessions` in the `MeasureConfig` as per your requirements. Ideally, set to `1` for debug. - Provide different API Keys for iOS and Android by creating two separate apps on the dashboard. > [!IMPORTANT] > To detect early native crashes and to ensure accurate launch time metrics, initialize the Android SDK in > `Application` class as described in the [Android](#initialize-the-sdk) section and the iOS SDK in `AppDelegate` as described in > the [iOS](#initialize-the-sdk-1) section. It is highly recommended to initialize both native SDKs even when using the Flutter SDK. ```dart Future main() async { await Measure.instance.init( () => runApp( MeasureWidget(child: MyApp()), // wrap your app with MeasureWidget ), config: const MeasureConfig( // SDK configuration traceSamplingRate: 1, samplingRateForErrorFreeSessions: 1, ), clientInfo: ClientInfo( // API Key & URL apiKey: Platform.isAndroid ? "ANDROID_API_KEY" : "IOS_API_KEY", apiUrl: "YOUR_API_URL", ), ); } ``` This does the following: * Initializes the Measure SDK with the provided `clientInfo` and `config`. * Wraps your app with the `MeasureWidget`. * Sets up the error handlers to track uncaught exceptions. * Initializes the native Measure SDKs for Android and iOS with the same `clientInfo` and `config`. ### Setup Android Gradle Plugin To ensure stacktraces in crash reports are symbolicated correctly, you need to add the Measure Android Gradle Plugin to your `android/build.gradle` file. This plugin automatically uploads the Flutter symbol files to the Measure server when you build your app. See the [Add the Gradle Plugin](#add-the-gradle-plugin) section above for instructions. ### Setup Android Manifest Add the API URL & API Key to your application's `AndroidManifest.xml` file. This is required by the Android Gradle Plugin to upload mapping and symbol files automatically to the Measure server. ```xml ``` ### Track navigation See [Navigation Monitoring](features/feature-navigation-lifecycle-tracking.md) for instructions on how to track navigation events. ### Track http requests See [Network Monitoring](features/feature-network-monitoring.md) for instructions on how to track HTTP requests. ## 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 `Sessions` tab to see the sessions being tracked. 🎉 Congratulations! You have successfully integrated Measure into your app! _______ ## Troubleshoot ### Verify Sampling Rate Try setting `samplingRateForErrorFreeSessions` to `1`, which would enforce all sessions to be sent to the server. It's typically a good idea to set this to `1` for debug builds.
Android ```kotlin val config = MeasureConfig( samplingRateForErrorFreeSessions = 1f, // Set to 1 to track all sessions ) Measure.init(context, config) ```
iOS ```swift let config = BaseMeasureConfig( // Set to 1 to track all sessions // useful to verify the installation samplingRateForErrorFreeSessions: 1 ) Measure.initialize(with: clientInfo, config: config) ```
Flutter ```dart await Measure.instance.init( () => runApp( MeasureWidget(child: MyApp()), ), config: const MeasureConfig( // Set to 1 to track all sessions // useful to verify the installation samplingRateForErrorFreeSessions: 1, ), clientInfo: ClientInfo( apiKey: "YOUR_API_KEY", apiUrl: "YOUR_API_URL", ), ); ```
### 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.
Android If logs show any of the following errors, make sure you have added the API URL and API key in your `AndroidManifest.xml` file. ``` sh.measure.android.API_URL is missing in the manifest sh.measure.android.API_KEY is missing in the manifest ```
iOS Verify the API URL and API key are set correctly in the `ClientInfo` object when initializing the SDK. ```swift let config = BaseMeasureConfig() let clientInfo = ClientInfo(apiKey: "", apiUrl: "") Measure.initialize(with: clientInfo, config: config) ```
Flutter Verify the API URL and API key are set correctly in the `ClientInfo` object when initializing the SDK. ```dart await Measure.instance.init( () => runApp( MeasureWidget(child: MyApp()), ), config: const MeasureConfig( samplingRateForErrorFreeSessions: 1, ), clientInfo: ClientInfo( apiKey: "YOUR_API_KEY", apiUrl: "YOUR_API_URL", ), ); ``` When running on Android do ensure the same API URL and API key are set in the `AndroidManifest.xml` file as well as it's required for the Android Gradle Plugin to upload mapping and symbol files automatically to the Measure server.
### Connecting to Locally-hosted Server **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](https://ngrok.com/) 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](https://ngrok.com/) 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
Android Enable logging during SDK initialization. All Measure SDK logs use the tag `Measure`. ```kotlin val config = MeasureConfig(enableLogging = true) Measure.init(context, config) ```
iOS Enable logging during SDK initialization. ```swift let config = BaseMeasureConfig(enableLogging: true) Measure.initialize(with: clientInfo, config: config) ```
Flutter Enable logging during SDK initialization. ```dart await Measure.instance.init( () => runApp( MeasureWidget(child: MyApp()), ), config: const MeasureConfig( enableLogging: true, ), ); ```
### 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..com`, replacing with your own domain. ### Contact Support If none of the above steps resolve the issue, feel free to reach out to us on [Discord](https://discord.gg/f6zGkBCt42) for further assistance.