Skip to main content
← Back to blog
Felix Cameron··9 min read

How to Track App Installs in Your Flutter App

Add cross-platform install and revenue tracking to your Flutter app in under 10 minutes. One SDK, one integration, installs tracked on both iOS and Android.

Single codebase, complete install insight

With Flutter, you maintain just one codebase for both iOS and Android, and your tracking should reflect that unity. Integrate the Instally Flutter SDK just once, and you’ll track where installs and revenue come from across both platforms, all from one dashboard.

No separate platform code, no conditional imports. Any iOS-Android mismatch is resolved internally by the SDK, keeping your Dart code simple and consistent. For native-only flows, compare the iOS (Swift) guide and Android (Kotlin) guide. For the full framework behind per-link install tracking, see tracking app installs with links.

This tutorial covers the complete integration, from dependencies through install tracking, plus optional revenue tracking with RevenueCat. See the full RevenueCat integration walkthrough if you need dashboard screenshots.

What you need

RequirementDetails
Instally accountFree tier works. Sign up here
Flutter 3.16+Dart 3.2 or later
iOS deployment target15.0+ (set in ios/Podfile)
Android min SDKAPI 23 (set in android/app/build.gradle)
App on App Store and/or Google PlayBundle ID and package name registered with Instally
10 minutesOne integration, both platforms

Step 1: Add the dependency

Add the Instally Flutter SDK to your project’s pubspec.yaml file:

Flutter example:

dependencies:
  flutter:
    sdk: flutter
  instally_flutter: ^1.0.0

Then fetch the package:

flutter pub get

The SDK bundles all required native dependencies. iOS relies on CocoaPods, and Android uses Maven Central. Nothing further needs to be configured.

Platform-specific configuration

iOS: Ensure your ios/Podfile specifies a deployment target of at least 15.0:

platform :ios, '15.0'

Next, update your pods:

cd ios && pod install && cd ..

Android: Confirm your android/app/build.gradle sets minSdkVersion to 23:

android {
    defaultConfig {
        minSdkVersion 23
    }
}

No further Android settings are necessary. All required native dependencies are pulled in automatically.

Step 2: Initialize the SDK on launch

Call Instally.configure() before invoking trackInstall. The optimal location is inside your main() function, right after WidgetsFlutterBinding.ensureInitialized().

Flutter example:

import 'package:flutter/material.dart';
import 'package:instally_flutter/instally_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Instally.configure(apiKey: 'your_api_key_here');
  runApp(const MyApp());
}

Locate your API key in the Instally dashboard under Settings > API Keys. Use the production key for release builds and the test key while developing.

Step 3: Register the install

After configuring Instally, call trackInstall() at app launch. Because the SDK performs internal deduplication, you can safely call it on every launch.

Flutter example:

import 'package:instally_flutter/instally_flutter.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String _source = 'loading...';

  @override
  void initState() {
    super.initState();
    _trackInstall();
  }

  Future<void> _trackInstall() async {
    try {
      final installData = await Instally.trackInstall();
      setState(() {
        _source = installData.linkSlug ?? 'organic';
      });
    } catch (e) {
      setState(() {
        _source = 'error';
      });
      debugPrint('Install tracking failed: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Install source: $_source'),
      ),
    );
  }
}

The installData object contains:

FieldTypeDescription
linkSlugString?The slug of the Instally link that drove the install. null if organic
installyUserIdStringUnique Instally user ID for this install. Use this for revenue tracking
countryString?Two-letter country code (e.g., US, GB)
platformStringios or android
isNewInstallbooltrue on first launch, false on subsequent calls

Platform behavior at a glance

The Instally Flutter SDK automatically handles the platform-specific differences. You call a single Dart method — trackInstall() — and the SDK returns the associated link slug (or null for organic installs). No platform branching in your code.

iOSAndroid
Requires user consentNoNo
Requires IDFA / Ad IDNoNo
ATT prompt requiredNoN/A
Attribution accuracyHighHighest
Works on sideloaded appsYesBest-effort

Step 4: Record monetization (optional)

Monetization tracking attributes in-app purchases and recurring subscriptions to the specific Instally link responsible for the original user acquisition. That means you can get answers to things like “Who is the top YouTube creator for bringing in paying users?” or “Did the link in my email send a customer to subscribe, or did the link in my Twitter bio?”

Option A: RevenueCat webhook (recommended)

Simplest integration: just syncing the user ID; no need to modify existing logic.

Set up the webhook in your RevenueCat dashboard under Integrations -> Webhooks:

    • URL: https://api.instally.io/webhooks/revenuecat
    • Header: X-Instally-Api-Key: your-api-key
    • Events: INITIAL_PURCHASE, RENEWAL, PRODUCT_CHANGE
You will also need to update your app to send the Instally User ID to RevenueCat when a user makes their first app install:

Flutter:

import 'package:instally_flutter/instally_flutter.dart';
import 'package:purchases_flutter/purchases_flutter.dart';

Future<void> _initTracking() async {
  final installData = await Instally.trackInstall();

  // Send Instally user ID to RevenueCat
  await Purchases.logIn(installData.installyUserId);
}

RevenueCat will send events like INITIAL_PURCHASE to the webhook and Instally will use the user ID from that event to match the purchase against an Instally installation.

Option B: Client-side revenue reporting

Or, if you are using a different payment provider than RevenueCat, or if you are just handling your payments directly (say, for a web app), you can report revenue directly in your app:

Flutter:

await Instally.trackRevenue(
  amount: 9.99,
  currency: 'USD',
  productId: 'pro_monthly',
  transactionId: purchaseDetails.purchaseID,
);

It should work with any purchase flow. Call it after any successful transaction.

Option C: Stripe or Adapty webhook

If you are using Stripe or Adapty, you need to also add a webhook to your dashboard:

Instally supports:

ProviderWebhook URLEvents to enable
RevenueCathttps://api.instally.io/webhooks/revenuecatINITIAL_PURCHASE, RENEWAL
Stripehttps://api.instally.io/webhooks/stripecheckout.session.completed, invoice.paid
Adaptyhttps://api.instally.io/webhooks/adaptyTransaction events
Superwallhttps://api.instally.io/webhooks/superwallTransaction events

Step 5: Test integration

After integrating the SDK, build and release your app. Go to the Instally Dashboard and create a new link, then click through your app stores and check your dashboard – both the click and install should show up within a second or two.

Make sure to test it on a real iOS or Android device. You may also want to test on both platforms if you plan to support both. The linking works a bit differently depending on the platform you install from, and it is good to double check everything is working on both.

If it looks like something is not syncing you may want to turn on verbose logging in the SDK to see what’s happening on the device:

Flutter:

Instally.configure(
  apiKey: 'ik_live_abc123',
  logLevel: InstallyLogLevel.verbose,
);

This will print a log to your development console showing the various signal types we received and whether a match occurred.

Full integration example

Below is a working example of the entire Instally integration in Flutter using RevenueCat:

import 'package:flutter/material.dart';
import 'package:instally_flutter/instally_flutter.dart';
import 'package:purchases_flutter/purchases_flutter.dart';
import 'dart:io' show Platform;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Instally
  await Instally.configure(
    apiKey: ‘ik_live_abc123’,
    logLevel: InstallyLogLevel.error,
  );

  // Initialize RevenueCat
  final rcApiKey = Platform.isIOS ? ‘appl_xyz789’ : ‘goog_xyz789’;
  await Purchases.configure(PurchasesConfiguration(rcApiKey));

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String _source = ‘loading...’;
  String _platform = ‘’;

  @override
  void initState() {
    super.initState();
    _initTracking();
  }

  Future<void> _initTracking() async {
    try {
      final install = await Instally.trackInstall();

      setState(() {
        _source = install.linkSlug ?? ‘organic’;
        _platform = install.platform;
      });

      // Sync user ID with RevenueCat for revenue tracking
      await Purchases.logIn(install.installyUserId);
    } catch (e) {
      setState(() {
        _source = ‘error’;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text(‘My App’)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(‘Install source: $_source’),
            Text(‘Platform: $_platform’),
          ],
        ),
      ),
    );
  }
}

FAQ

Does the Flutter SDK work on both iOS and Android?

Yes, it does. The SDK implements the iOS and Android SDKs through platform channels. You write your code in Dart and the SDK automatically handles all platform-specific matching.

Do I need to write any native code?

No, you only need to declare a dependency in pubspec.yaml. The SDK automatically sets up CocoaPods on iOS and Gradle on Android. No extra native code, Swift, Kotlin, or platform-specific configurations (beyond the minimum required SDK versions defined above) are necessary.

Can I use this with other state management solutions?

Yes. These examples use StatefulWidget as a straightforward way to show tracking results, but since trackInstall returns a Future, you can easily integrate it into any state management system: Provider, Riverpod, Bloc, GetX, plain ValueNotifier, etc.

What if my app also supports web?

Instally Flutter SDK currently only supports iOS and Android. Web app tracking can be handled separately using Instally’s JavaScript snippet. See docs for web integration guide.

Is there a performance impact?

The SDK will only make a single HTTP request when it runs for the first time and will then store the result in memory (which will then be cleared when you stop the app). If you call trackInstall a second time (and the result was previously cached), then it’ll just immediately return the result and will not re-request it from Instally’s servers. In normal scenarios, this HTTP request will only take less than 200ms to complete. There will be no background polling or continuous connections that run in the background after Instally’s initialization.

How do I handle errors in production?

The SDK will only throw an exception if there are actual issues with the network or a misconfigured API key. In production, simply wrap your code in a try-catch and fail gracefully. You should never let install tracking slow down your app.

---

When you make the move to Flutter, you’ll be able to ship to all platforms. You should be able to track installs across app stores from a single dependency. One pubspec.yaml change, one configure call, and one trackInstall call, it’s that easy to track installs across both the iOS and Android App Stores. View pricing and start tracking your app installs in minutes!

Ready / v1.0

Stop guessing. Start shipping.

Track clicks, installs, and revenue from every link. Set up in five minutes.

Get started free