# Flutter

Track screens, goals and signed-in users in Flutter apps on iOS and Android, attributed to the deep link or Play Store campaign behind each install.

`productlense_analytics` sends screen views, goals and `identify` from your Flutter app to ProductLense. It works on iOS and Android, needs no device identifiers, and reports app traffic next to your website: the Hostname breakdown shows your bundle id beside your domain.

## 1. Add your app ID

In ProductLense, open **Settings → General → App IDs** and add your iOS bundle identifier and Android application id, for example `com.example.app`. Events from any other app id are rejected.

## 2. Install

```yaml title="pubspec.yaml"
dependencies:
  productlense_analytics: ^0.1.0
```

## 3. Start ProductLense and track screens

```dart title="lib/main.dart" {1,5-6,9}
import 'package:productlense_analytics/productlense_analytics.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  ProductLense.init(const ProductLenseOptions(siteId: 'YOUR_SITE_ID', appId: 'com.example.app'));
  runApp(MaterialApp(
    routes: {'/': (_) => const Home(), '/settings': (_) => const Settings()},
    navigatorObservers: [ProductLenseNavigatorObserver()],
  ));
}
```

`siteId` is on **Settings → Snippet**. The observer sends a screen view for every named route the user opens or returns to. For routes without a name, pass `ProductLenseNavigatorObserver(nameOf: (route) => ...)`, or call `ProductLense.screen('Checkout')` yourself. With go_router, add the observer to `GoRouter(observers: [ProductLenseNavigatorObserver()])`.

ProductLense stores the install id, the opt-out choice and unsent events with `shared_preferences`, and sends them when the app goes to the background.

## 4. Goals and users

```dart
ProductLense.track('signup', {'plan': 'pro'});
ProductLense.identify(user.id, name: user.name, email: user.email);
```

Call `identify` after sign-in with the user id your billing provider stores on the customer, so app visits, web visits and payments join up. See [how payments are attributed](/docs/revenue/attribution).

## In-app purchases

Connect [RevenueCat](/docs/revenue/revenuecat), then pass ProductLense's install id to it once, after both SDKs are configured:

```dart
await Purchases.setAttributes(await ProductLense.revenueCatAttributes());
```

This sets the `pl_install_id` subscriber attribute, so each App Store or Google Play purchase lands on the channel that brought the install. Payments your backend takes through a [billing connection](/docs/revenue/connect-billing) are attributed through `identify`.

## Attribution

- **Deep links**: with the `app_links` package, attach it once and every link that opens the app (cold start or while running) attributes the next screen:

```dart
final links = AppLinks();
ProductLenseDeepLinks.attach(initial: links.getInitialLink(), links: links.uriLinkStream);
```

  With another router, pass each link to `ProductLense.openURL(uri.toString())` yourself. Only `utm_*`, `ref`, `via`, `source` and click ids leave the device.
- **Play Store**: on Android, read the install referrer with the `play_install_referrer` package and pass it once:

```dart
ProductLense.init(ProductLenseOptions(
  siteId: 'YOUR_SITE_ID',
  appId: 'com.example.app',
  installReferrer: () async => (await PlayInstallReferrer.installReferrer).installReferrer,
));
```

- **App Store**: Apple shares no referrer; App Store installs count as Direct unless they open through a tagged universal link.

## Privacy

- The SDK creates a random install id on first launch. It is not the advertising id, so no App Tracking Transparency prompt is needed for ProductLense. ProductLense stores only a hash of it.
- `ProductLense.optOut()` stops collection, deletes unsent events and forgets the install id; `ProductLense.optIn()` resumes with a new one.
- App Store privacy label: **Product Interaction**, used for **Analytics**, **not used for tracking**.

## Verify your installation

1. Run the app on a device or simulator and open a few screens.
2. Open the Live page in the ProductLense dashboard. Your device appears within a few seconds.
3. Open **Events**: each screen is a `pageview` row with your bundle id as the hostname and `iOS app` or `Android app` as the browser.
4. Pass `debug: true` in `ProductLenseOptions` to log dropped events and failed sends.

If nothing appears, check the app id in Settings and follow [Verify your installation](/docs/install/verify).
