Documentation
Flutter
The plugin, the one Podfile line iOS still needs, and the purchase field per store.
1. Add the plugin
# pubspec.yaml
dependencies:
roas_flutter:
git:
url: https://github.com/harsh-vasundhara/roas-sensor-flutter.git
ref: v0.1.8No Gradle line: the plugin pins the native Android SDK itself. iOS needs one line in ios/Podfile, because the native SDK is served from git and a podspec cannot name a git source for its own dependency. Without it pod install fails with *"Unable to find a specification for RoasSensor"*, which reads like a broken plugin and is really a missing source:
pod 'RoasSensor', :git => 'https://github.com/rishabhrk2345/Roas-ios-SDK.git', :tag => '0.1.10'2. Initialise, after runApp
import 'package:roas_flutter/roas_flutter.dart';
const kAppSecret = String.fromEnvironment('ROAS_APP_SECRET');
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp()); // UI first; tracking must never block it
_initTracking();
}
Future<void> _initTracking() async {
try {
await Roas.initialize(
publicKey: Platform.isIOS ? 'IOS_PUBLIC_KEY' : 'ANDROID_PUBLIC_KEY',
baseUrl: 'https://api.roassensor.com', // from the panel
appSecret: kAppSecret.isEmpty ? null : kAppSecret, // empty must mean absent
requestTrackingAuthorization: false, // iOS: ask later with Roas.requestTracking()
);
} catch (e) {
debugPrint('Roas init failed (tracking off, app unaffected): $e');
}
}Pass the secret at build time so it never lands in source control: flutter build appbundle --dart-define=ROAS_APP_SECRET=…, and the same flag on flutter build ipa. Editing the value means rebuilding.
3. Bind purchases to the install
The store gives you one field for a buyer identifier; put ours in it. The two stores accept different shapes:
// iOS -- StoreKit / in_app_purchase: applicationUserName
final token = await Roas.appAccountToken(); // a UUID; null on Android
// Android -- Play Billing / in_app_purchase: the obfuscated account id
final accountId = await Roas.visitorId(); // "rs" + 32 hexappAccountToken is a UUID derived from the visitor id, not a separate identifier; the server reconstructs the vid from it. Skip this and every sale arrives with nothing tying it to an ad click: the revenue lands, the spend counts, and ROAS reads low.
4. Deep links and the rest
// Whatever delivers your links (app_links, uni_links, go_router): forward the URL
Roas.handleDeepLink(uri.toString());
await Roas.identify(email: user.email); // hashed on device
await Roas.track('begin_checkout', properties: {'product_id': productId});
Roas.setLogLevel(RoasLogLevel.debug); // logcat / Xcode consoleproduct_id must equal the store product id so the funnel and the sale line up. Events are never revenue.
Check it worked
- Run once on a device. The console shows
first-open -> 201from the native SDK. - The app's Overview tab shows an install row with
signed = true.signed = falsemeans--dart-definewas not on the build command. - Then Testing a mobile integration.

