activity_flow 0.0.16 copy "activity_flow: ^0.0.16" to clipboard
activity_flow: ^0.0.16 copied to clipboard

Flutter SDK for VTEX Activity Flow analytics, providing session tracking, event collection, and deep link capture capabilities.

example/example.md

import 'package:activity_flow/activity_flow.dart';
import 'package:flutter/material.dart';
import 'package:example/screens/favorite.dart';
import 'package:example/screens/products.dart';
import 'package:example/screens/profile.dart';

void main() {
  runApp(ExampleApp());
}

/// A MaterialApp with a custom theme and routes.
///
/// The routes are defined in the [routes] property.
/// The theme is defined in the [theme] property.
class ExampleApp extends StatelessWidget {
  ExampleApp({super.key});

  initActivityFlow(accountName: 'your_account_name'); // Activity Flow initialization

  final afObserver = PageViewObserver();

  @override
  Widget build(BuildContext context) {
    return TouchDetector( // Touch event here
      accountName: accountName,
      child: MaterialApp(
        title: 'Example App',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        routes: {
          '/': (context) => const MyHomePage(),
          '/products': (context) => const ProductsScreen(),
          '/profile': (context) => const ProfileScreen(),
          '/favorites': (context) => const FavoriteScreen(),
        },
        initialRoute: '/',
        navigatorObservers: [afObserver], // Screen view event here
      ),
    );
  }
}

/// A home screen with buttons to navigate to other screens.
class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  final List<Map> _routes = const [
    {
      'name': 'Products',
      'route': '/products',
    },
    {
      'name': 'Profile',
      'route': '/profile',
    }
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Home Screen'),
      ),
      body: Center(
          child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
        ..._routes.map((route) => ButtonTemplate(
              title: route['name'],
              route: route['route'],
            )),
            const SizedBox(
              child: Image(
                image: AssetImage('sneakers.jpg'),
              ),
            ).addAdsListener({
              'productName': 'Sneakers',
              'productPrice': '59.99',
              'adID': '1123',
            }), // Ad event here
      ])),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.favorite),
            label: 'Favorites',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.list),
            label: 'Products',
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: (index) {
          _onItemTapped(index);
          final label = items[index].label ?? 'Tab-$index';

          // We capture pageView manually since the BottomNavigationBar does not update the route
          screenViewChange(label);
        },
      );
    );
  }
}

/// A template for creating buttons.
///
/// Receives a [title], [icon], and [route] to navigate to.
/// Returns an [ElevatedButton.icon] with the given parameters.
class ButtonTemplate extends StatelessWidget {
  const ButtonTemplate({
    super.key,
    required this.title,
    required this.route,
  });

  final String title;
  final String route;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => Navigator.pushNamed(context, route),
      child: Text(title),
    );
  }
}

Click event #

Use addClickListener on any widget to capture taps. Fires a click event when the user taps (not drags) on the element.

elementSource is required. If absent or empty, the event will not be sent.

ElevatedButton(
  onPressed: () => Navigator.pushNamed(context, '/checkout'),
  child: const Text('Buy Now'),
).addClickListener({
  'elementSource': 'buy-now-button', // required
  'productId': product.id,
  'productName': product.name,
});

View event #

Use addViewListener to fire a view event once the widget has been at least 50% visible for 1 second (IAB standard). The event fires once per app session — it does not re-fire if the widget scrolls off-screen and back, or if the user navigates away and returns.

elementSource is required. If absent or empty, the event will not be sent.

ProductCard(product: product).addViewListener({
  'elementSource': 'product-card', // required
  'productId': product.id,
});

You can chain addImpressionListener and addViewListener on the same widget:

content
  .addImpressionListener({
    'elementSource': 'product-card', // required
    'productId': product.id,
  })
  .addViewListener({
    'elementSource': 'product-card', // required
    'productId': product.id,
  });

Impression event #

Use addImpressionListener to fire an impression event immediately when the widget is first constructed.

elementSource is required. If absent or empty, the event will not be sent.

Image.asset(product.imageUrl).addImpressionListener({
  'elementSource': 'product-image', // required
  'productId': product.id,
  'productName': product.name,
});
2
likes
150
points
448
downloads

Documentation

API reference

Publisher

verified publishervtex.com

Weekly Downloads

Flutter SDK for VTEX Activity Flow analytics, providing session tracking, event collection, and deep link capture capabilities.

Repository (GitHub)

License

MIT (license)

Dependencies

flutter, http, shared_preferences, visibility_detector

More

Packages that depend on activity_flow

Packages that implement activity_flow