Automatic Screen Tracking
The Conviso Flutter SDK provides automatic screen tracking through a NavigatorObserver that monitors route changes in your app.
Overview
When enabled, the screen tracker will automatically:
- ✅ Track all screen views in your app
- ✅ Store anonymous screen views until a user is identified
- ✅ Associate anonymous screen views with users once they are identified
- ✅ Include screen name, route, and timestamp in the tracking data
Setup
Step 1: Enable in Configuration
Set autoTrackScreens: true in your SDK configuration:
await OpenCDPSDK.initialize(
config: OpenCDPConfig(
cdpApiKey: 'your-api-key',
autoTrackScreens: true, // Enable automatic screen tracking
// ... other config options
),
);
Step 2: Add Navigator Observer
Add the screen tracker to your app's navigator observers in your MaterialApp:
MaterialApp(
navigatorObservers: [
OpenCDPSDK.instance.screenTracker!,
],
// ... other app configuration
home: MyHomePage(),
);
Both steps are required for automatic screen tracking to work. The configuration enables the feature, and the navigator observer performs the actual tracking.
Complete Example
Here's a complete example showing screen tracking setup:
import 'package:flutter/material.dart';
import 'package:open_cdp_flutter_sdk/open_cdp_flutter_sdk.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize SDK with screen tracking enabled
await OpenCDPSDK.initialize(
config: OpenCDPConfig(
cdpApiKey: 'your-api-key',
autoTrackScreens: true,
debug: true,
),
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
// Add the screen tracker observer
navigatorObservers: [
OpenCDPSDK.instance.screenTracker!,
],
home: HomePage(),
routes: {
'/profile': (context) => ProfilePage(),
'/settings': (context) => SettingsPage(),
},
);
}
}
How It Works
Anonymous Screen Views
Before a user is identified, screen views are stored locally:
// User navigates to a screen (not yet identified)
Navigator.pushNamed(context, '/products');
// Screen view is stored locally as anonymous
Identified Screen Views
Once a user is identified, all screen views (past and future) are associated with that user:
// Identify the user
await OpenCDPSDK.instance.identify(
identifier: 'user123',
properties: {'email': '[email protected]'},
);
// All previous anonymous screen views are now associated with user123
// Future screen views are automatically tracked with user123
Manual Screen Tracking
You can also manually track screen views if needed:
await OpenCDPSDK.instance.trackScreenView(
title: 'Product Details',
properties: {
'product_id': '123',
'category': 'Electronics',
'source': 'search',
},
);
Tracked Data
Each screen view event includes:
- Screen Name: The route name or title
- Route: The full route path
- Timestamp: When the screen was viewed
- Custom Properties: Any additional properties you provide
Best Practices
1. Use Named Routes
Named routes provide better screen names in your tracking data. Auto-track uses RouteSettings.name only — it never falls back to route.toString(), so unnamed routes are skipped (they will not appear in the in-app Include / Exclude catalog).
// ✅ Good - Named route / GoRouter path
Navigator.pushNamed(context, '/product-details');
// or GoRouter: context.go('/product-details');
// ✅ Good - Explicit name on a custom route
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: '/product-details'),
builder: (context) => ProductDetailsPage(),
),
);
// ❌ Skipped by auto-track — no RouteSettings.name
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsPage()),
);
Name dialogs and sheets
Modals and bottom sheets need an explicit name if you want them in page rules:
showModalBottomSheet(
context: context,
routeSettings: const RouteSettings(name: '/sheet/filters'),
builder: (_) => FiltersSheet(),
);
showDialog(
context: context,
routeSettings: const RouteSettings(name: '/dialog/confirm'),
builder: (_) => ConfirmDialog(),
);
Recommended shapes: path-like (/profile), short labels (Home), or segments (checkout/payment). Avoid framework class dumps.
2. Add Custom Properties
Enhance screen view tracking with custom properties:
await OpenCDPSDK.instance.trackScreenView(
title: 'Product Details',
properties: {
'product_id': product.id,
'category': product.category,
'price': product.price,
'source': 'search', // How the user got here
},
);
3. Identify Users Early
Identify users as soon as possible to minimize anonymous screen views:
// Identify immediately after login
await handleLogin(email, password);
await OpenCDPSDK.instance.identify(
identifier: userId,
properties: {'email': email},
);
Disabling Automatic Tracking
If you want to manually control screen tracking, simply:
- Set
autoTrackScreens: falsein your configuration - Don't add the navigator observer
- Use
trackScreenView()manually when needed
OpenCDPConfig(
cdpApiKey: 'your-api-key',
autoTrackScreens: false, // Disable automatic tracking
// ... other config
)
In-app page rules catalog
Each screen_view (automatic or trackScreenView) also feeds the workspace screen catalog used by Include / Exclude screens in the Conviso in-app editor. The backend stores unique properties.screen values per workspace; it does not treat screen_view as a normal analytics event for BigQuery or campaign triggers.
- Use stable screen titles so dashboard picks match
setCurrentScreen/ sync?screen=. - Until traffic reports views, the editor list may be empty — marketers can still type names manually.
- Unnamed Flutter routes and technical
toString()dumps are not catalogued. See Automatic Screen Tracking. - In the editor, All screens + Exclude means “everywhere except…”. Empty include is the persisted form of All.
Troubleshooting
Screen Views Not Tracking
If screen views aren't being tracked:
- ✅ Verify
autoTrackScreens: truein configuration - ✅ Verify you added the navigator observer to MaterialApp
- ✅ Check debug logs for errors
- ✅ Ensure the SDK is initialized before runApp()
Navigator Observer Not Found
If you get a null error accessing screenTracker:
// ❌ Wrong - screenTracker is null when autoTrackScreens is false
navigatorObservers: [
OpenCDPSDK.instance.screenTracker!, // Will throw if autoTrackScreens is false
]
// ✅ Correct - Check if it exists first
navigatorObservers: [
if (OpenCDPSDK.instance.screenTracker != null)
OpenCDPSDK.instance.screenTracker!,
]