Skip to content

klaviyo/klaviyo-flutter-sdk

Repository files navigation

Klaviyo Flutter SDK

A Flutter plugin that wraps the native Klaviyo iOS and Android SDKs, enabling you to integrate Klaviyo's marketing automation features into your Flutter apps.

Table of Contents

Features

  • Profile Management — Set user profiles, emails, phone numbers, and custom properties
  • Event Tracking — Track custom events and user interactions
  • Push Notifications — Register for and handle push notifications with automatic token handling
  • In-App Forms — Display and manage in-app forms for lead capture
  • Deep Linking — Handle custom URL schemes, universal links, and Klaviyo tracking links
  • Geofencing — Observe geofences for location-based event tracking

Requirements

Platform Minimum Version
Flutter 3.x
Dart 3.x
iOS 15.0+
Android minSdkVersion 23+
Android compileSdkVersion 34+
Kotlin 1.8.0+

Installation

Add klaviyo_flutter_sdk to your pubspec.yaml:

dependencies:
  klaviyo_flutter_sdk: ^0.1.0

A complete working example is available in the example/ directory.

Initialization

import 'package:klaviyo_flutter_sdk/klaviyo_flutter_sdk.dart';

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

  await KlaviyoSDK().initialize(
    apiKey: 'YOUR_KLAVIYO_PUBLIC_API_KEY',
  );

  runApp(MyApp());
}

Platform Setup

The Flutter plugin depends on the native Swift and Android SDKs, which are automatically installed by the plugin. On Android, required permissions are also automatically added via manifest merging.

The sections below cover required native configuration for push notification handling.

iOS Setup

1. Install Pods

cd ios && pod install

2. Enable Capabilities

Open your project in Xcode (ios/Runner.xcworkspace), select the Runner target, go to Signing & Capabilities, and add:

  • Push Notifications (Required for APNs push notifications)
  • Background Modes → check Remote notifications (Required for silent push updates)

3. AppDelegate Setup

To display push notifications in the foreground and track "Open" events, update your ios/Runner/AppDelegate.swift:

  1. Import the plugin module: import klaviyo_flutter_sdk
  2. Set the notification delegate: Assign UNUserNotificationCenter.current().delegate = self in application(_:didFinishLaunchingWithOptions:)
  3. Implement (or update) the userNotificationCenter methods to forward events to the Klaviyo SDK (see example code below)

Note on Push Token Handling: The plugin automatically intercepts didRegisterForRemoteNotificationsWithDeviceToken to capture the APNs token. If you override this method (e.g., for another push provider), call super:

override func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
    // Your custom token handling here
}

Full AppDelegate example:

import UIKit
import Flutter
import klaviyo_flutter_sdk

@main
@objc class AppDelegate: FlutterAppDelegate {

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        UNUserNotificationCenter.current().delegate = self

        // ... Your existing setup code ...

        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    // Handle foreground notifications
    override func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        // Show banner, sound, and badge even when the app is open
        completionHandler([.banner, .sound, .badge])

        // ... Your custom logic (if any) ...
    }

    // Forward tap events to Klaviyo
    override func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        // Forward the "Open" event to the Klaviyo SDK
        KlaviyoFlutterSdkPlugin.shared.handleNotificationResponse(response)

        // ... Your custom logic (if any) ...

        // Complete the system callback
        completionHandler()
    }

    // Handle silent push notifications (optional)
    override func application(
        _ application: UIApplication,
        didReceiveRemoteNotification userInfo: [AnyHashable: Any],
        fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
    ) {
        // This method fires for both pure silent pushes (content-available: 1, no alert)
        // and standard pushes that include content-available. Only forward pure silent
        // pushes to the Klaviyo plugin — standard pushes are handled by willPresent/didReceive.
        // Per the APNs spec, title/body are nested inside alert, so checking alert covers
        // all visible-content cases.
        let apsPayload = userInfo["aps"] as? [String: Any]
        let hasVisibleContent = apsPayload?["alert"] != nil
        if !hasVisibleContent {
            KlaviyoFlutterSdkPlugin.shared.handleSilentPush(userInfo: userInfo)
        }

        // ... Your custom logic (if any) ...

        // You MUST call the completion handler within ~30 seconds.
        // Failing to do so will cause iOS to throttle or stop delivering
        // silent push notifications to your app.
        completionHandler(.newData)
    }
}

Android Setup

1. MainActivity Setup

To track push notification opens, handle intents in your MainActivity (at android/app/src/main/kotlin/.../MainActivity.kt). See the example MainActivity.kt for reference.

import android.content.Intent
import android.os.Bundle
import com.klaviyo.analytics.Klaviyo
import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Handle notification intent on cold start
        intent?.let { Klaviyo.handlePush(it) }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        // Handle notification intent on warm start
        Klaviyo.handlePush(intent)
    }
}

2. KlaviyoPushService Declaration

Declare KlaviyoPushService in your android/app/src/main/AndroidManifest.xml inside the <application> tag. This ensures Klaviyo processes FCM messages before Flutter's default FirebaseMessagingService, enabling open tracking and rich push features.

<service
    android:name="com.klaviyo.pushFcm.KlaviyoPushService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

See the example AndroidManifest.xml for a complete implementation.

Profile Management

// Set a complete profile
final profile = KlaviyoProfile(
  email: 'user@test.com',
  firstName: 'John',
  lastName: 'Doe',
  phoneNumber: '+2125557890',
  properties: {
    'plan': 'premium',
    'signup_date': DateTime.now().toIso8601String(),
  },
);
await KlaviyoSDK().setProfile(profile);
// Set individual properties
await KlaviyoSDK().setEmail('user@example.com');
await KlaviyoSDK().setPhoneNumber('+1234567890');
await KlaviyoSDK().setExternalId('user123');
await KlaviyoSDK().setProfileProperties({
  'preferences': {'notifications': true},
});

Event Tracking

// Track a predefined event
final openedAppEvent = KlaviyoEvent(
  name: EventMetric.openedApp,
  properties: {
    'source': 'home_screen',
  },
);
await KlaviyoSDK().createEvent(openedAppEvent);
// Track a custom event
final customEvent = KlaviyoEvent.custom(
  metric: 'User Completed Tutorial',
  properties: {
    'tutorial_id': 'intro_v2',
    'completion_time_seconds': 245,
  },
);
await KlaviyoSDK().createEvent(customEvent);
// Track a purchase event with value
final purchaseEvent = KlaviyoEvent.custom(
  metric: 'Purchase Completed',
  properties: {
    'currency': 'USD',
    'product_id': 'prod_123',
    'product_name': 'Premium Subscription',
  },
  value: 99.99,
);
await KlaviyoSDK().createEvent(purchaseEvent);

Push Notifications

Prerequisites

Platform-specific setup:

Key requirements:

  • Firebase project configured (for both platforms)
  • google-services.json (Android) and GoogleService-Info.plist (iOS) added to your project
  • Push notifications configured in your Klaviyo account settings

Requesting Notification Permissions

Permission can be managed from Flutter code or platform-specific native code. Either approach informs the Klaviyo SDK of the permission change. For Flutter-side handling, use a third-party package such as firebase_messaging or permission_handler.

Token Collection

The Klaviyo SDK needs to register the device's push token. Choose one of the following approaches:

Option A: Manual Token Management with Firebase Messaging (Recommended)

Best if you already use firebase_messaging, or if you need more control over token handling (such as to send the token to multiple push providers).

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:logging/logging.dart';

final _logger = Logger('MyApp');

// Get token from Firebase and pass to Klaviyo
if (Platform.isIOS) {
  String? apnsToken = await FirebaseMessaging.instance.getAPNSToken();

  if (apnsToken != null) {
    await KlaviyoSDK().setPushToken(apnsToken);
    _logger.info('Sent APNs token to Klaviyo');
  } else {
    _logger.warning('APNs token was null. Waiting for refresh...');
  }
} else if (Platform.isAndroid) {
  String? fcmToken = await FirebaseMessaging.instance.getToken();

  if (fcmToken != null) {
    await KlaviyoSDK().setPushToken(fcmToken);
    _logger.info('Sent FCM token to Klaviyo');
  }
}

// Listen for Token Refreshes (Important for long-running apps)
// Note: On iOS, this stream returns the FCM token, not APNs.
// Native APNs token changes are rare, but for Android this is crucial.
if (Platform.isAndroid) {
  FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
    KlaviyoSDK().setPushToken(newToken);
  });
// On iOS, if the APNs token changes, the OS usually relaunches the app
// or triggers distinct native callbacks.
}

Option B: Built-in Registration

The simplest approach — the SDK automatically fetches the push token without requiring firebase_messaging as a direct dependency:

// iOS: Triggers APNs registration and forwards token to Klaviyo
// Android: Fetches the FCM token and registers it with Klaviyo
await KlaviyoSDK().registerForPushNotifications();

For visibility into push token events, subscribe to the onPushNotification stream:

// Listen for token events
KlaviyoSDK().onPushNotification.listen((event) {
  switch (event['type']) {
    case 'push_token_received':
      final token = event['data']['token'];
      _logger.info('Token received: $token');
      break;
    case 'push_token_error':
      final error = event['data']['error'];
      _logger.warning('Token error: $error');
      break;
  }
});

Handling Push Notification Opens

KlaviyoSDK().onPushNotification.listen((event) {
  if (event['type'] == 'push_notification_opened') {
    _logger.info('Notification opened: ${event['data']}');
  }
});

Identifying Klaviyo Notifications

Use the isKlaviyoNotification extension to check whether a push notification payload originated from Klaviyo:

void handlePushPayload(Map<String, dynamic> payload) {
  if (payload.isKlaviyoNotification) {
    // This is a Klaviyo notification
  }
}

Silent Push

Silent push notifications (content-available: 1) deliver data to your app in the background without showing a banner. They are commonly used to prefetch content, sync state, or trigger background tasks.

iOS requirement: Enable "Remote notifications" under Background Modes in Xcode (covered in iOS Setup).

iOS

iOS delivers silent pushes via didReceiveRemoteNotification:fetchCompletionHandler: in your AppDelegate.swift. The setup in iOS Setup already handles this — it differentiates pure silent pushes from standard pushes that carry content-available and forwards only the former to the Klaviyo plugin.

Dart-Side Listener

Subscribe to onPushNotification to react to silent push events in Flutter:

KlaviyoSDK().onPushNotification.listen((event) {
  if (event['type'] == 'silent_push_received') {
    final payload = Map<String, dynamic>.from(event['data'] as Map);
    // Perform background work: refresh content, sync state, etc.
  }
});

Note: This event fires only for pure silent pushes (no visible content). Standard notifications that include content-available are handled by willPresent/didReceive and will not trigger this event.

Rich Push

Rich Push lets you add images and videos (iOS only) to push notifications.

Badge Count (iOS Only)

Klaviyo supports setting or incrementing the badge count on iOS push notifications. This requires a notification service extension and app group — see the Swift SDK installation instructions and badge count documentation.

Android handles badge counts automatically.

In-App Forms

// Register with default session timeout (1 hour)
await KlaviyoSDK().registerForInAppForms();
// Register with a custom session timeout
final config = InAppFormConfig(
  sessionTimeoutDuration: Duration(minutes: 30),
);
await KlaviyoSDK().registerForInAppForms(configuration: config);
// Register with infinite session timeout (no timeout)
final infiniteConfig = InAppFormConfig.infinite();
await KlaviyoSDK().registerForInAppForms(configuration: infiniteConfig);
// Unregister from in-app forms
await KlaviyoSDK().unregisterFromInAppForms();
// Listen for form events
KlaviyoSDK().onFormEvent.listen((event) {
  _logger.info('Form event: ${event['type']}');
});

The sessionTimeoutDuration controls how long forms remain eligible to display after app backgrounding. For more details, see the native SDK documentation: Android | iOS

Deep Linking

Klaviyo supports Deep Links for tracking link clicks and navigating to specific content within your app. This works with push notifications, in-app messages, and Klaviyo tracking links.

Prerequisites

  1. Set up deep linking in your Flutter app using a routing package:

  2. Configure platform-specific deep linking (see below).

iOS Deep Linking

Custom URL Schemes (e.g., myapp://product/123)

Follow steps 1 & 2 ("Register the URL scheme" and "Whitelist your URL scheme") under the Handling URL Schemes section of the Swift SDK README.

FlutterAppDelegate handles application(_:open:options:) and forwards custom URL scheme deep links to Flutter automatically. No additional native code is required.

Klaviyo Universal Tracking Links (e.g., https://trk.yourdomain.com/u/abc123)

Follow steps 1 & 2 ("Configure Universal Links in your Klaviyo account" and "Add the Associated Domains Entitlement") under the Handling Universal Links section of the Swift SDK README.

FlutterAppDelegate implements application(_:continue:restorationHandler:) and forwards universal links to Flutter automatically.

Once universal links are arriving in your Flutter app, call handleUniversalTrackingLink from your router to let the Klaviyo SDK resolve tracking URLs. See the go_router integration section for an example.

Android Deep Linking

The example AndroidManifest.xml demonstrates all three types of deep links:

Custom URL Schemes (e.g., myapp://product/123)

Add to your MainActivity in AndroidManifest.xml:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="YOUR_CUSTOM_SCHEME" />
</intent-filter>

Additionally, this can be configured natively on Flutter. Just be sure that the deeplink path you use for actions matches your app package schema.

App Links (e.g., https://yourdomain.com/product/123)

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" />
    <data android:host="yourdomain.com" />
</intent-filter>

Klaviyo Universal Tracking Links (e.g., https://trk.yourdomain.com/u/abc123)

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" />
    <data android:host="trk.send.yourdomain.com" />
    <data android:pathPrefix="/u/" />
</intent-filter>

Testing deep links:

# Custom URL scheme
adb shell am start -W -a android.intent.action.VIEW -d "myapp://product/123" com.your.package

# App link
adb shell am start -W -a android.intent.action.VIEW -d "https://yourdomain.com/product/123" com.your.package

For complete Android App Links setup including domain verification, see the Android SDK Deep Linking Guide.

Handling Tracking Links with go_router

Use go_router's redirect callback to pass URLs to Klaviyo for tracking:

import 'package:go_router/go_router.dart';
import 'package:klaviyo_flutter_sdk/klaviyo_flutter_sdk.dart';

final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => HomeScreen(),
      routes: [
        GoRoute(
          path: 'product/:id',
          builder: (context, state) => ProductScreen(
            productId: state.pathParameters['id']!,
          ),
        ),
      ],
    ),
  ],
  redirect: (context, state) {
    // Fire-and-forget — Klaviyo tracks the link in the background
    KlaviyoSDK().handleUniversalTrackingLink(state.uri.toString());
    return null;
  },
);

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

  await KlaviyoSDK().initialize(apiKey: 'YOUR_API_KEY');

  runApp(MaterialApp.router(routerConfig: router));
}

How It Works

  1. URL arrives via go_router's routing system
  2. redirect callback fires with the URL
  3. Call handleUniversalTrackingLink() - validates and returns immediately
  4. Returns true if it's a Klaviyo tracking link (format: https://domain/u/...), false otherwise
  5. Native SDK tracks the click event in the background (fire-and-forget)
  6. Native SDK resolves the link and your Flutter routing library handles the final destination

Note: handleUniversalTrackingLink() is synchronous - it validates the URL and returns a bool immediately, while the native tracking happens asynchronously in the background.

Geofencing

The Klaviyo Flutter SDK supports geofencing for location-based event tracking. The full location module is not included by default — see Enabling Geofencing to opt in.

// Start monitoring geofences (requires location permissions)
await KlaviyoSDK().registerGeofencing();
// Stop monitoring all geofences
await KlaviyoSDK().unregisterGeofencing();

Without the full location module enabled, geofencing methods return error code GEOFENCING_NOT_AVAILABLE with instructions to enable it.

Optional Module Configuration

Enabling Geofencing

The SDK includes lightweight location interfaces by default but requires the full location module for geofencing to work.

Android — add to android/gradle.properties:

klaviyoIncludeLocation=true

This includes the full location module with Google Play Services and adds the following permissions to your merged manifest:

  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.ACCESS_BACKGROUND_LOCATION

iOS — add to ios/Podfile before flutter_install_all_ios_pods:

ENV['KLAVIYO_INCLUDE_LOCATION'] = 'true'

This includes the KlaviyoLocation pod. You'll also need location permission descriptions in Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location for geofencing features.</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need background location for geofence monitoring.</string>

Disabling In-App Forms

In-app forms are enabled by default. To opt out (for a smaller SDK footprint):

Android — add to android/gradle.properties:

klaviyoIncludeForms=false

iOS — add to ios/Podfile before flutter_install_all_ios_pods:

ENV['KLAVIYO_INCLUDE_FORMS'] = 'false'

Without the forms module, forms methods will log an error and no-op gracefully (error code: FORMS_NOT_AVAILABLE).

Profile Reset (Logout)

// Reset profile when user logs out
await KlaviyoSDK().resetProfile();

API Reference

KlaviyoSDK

The main SDK class. All methods are accessed via KlaviyoSDK().

Initialization

Method Description
initialize({required String apiKey}) Initialize the SDK

Profile

Method Description
setProfile(KlaviyoProfile profile) Set a complete user profile
setEmail(String email) Set user email
setPhoneNumber(String phoneNumber) Set user phone number
setExternalId(String externalId) Set external user ID
getEmail() Get user email
getPhoneNumber() Get user phone number
getExternalId() Get external user ID
setProfileProperties(Map<String, dynamic> properties) Set custom profile properties
setProfileAttribute(String propertyKey, dynamic value) Set a single profile attribute
resetProfile() Reset user profile (logout)

Events

Method Description
createEvent(KlaviyoEvent event) Track a profile activity event

Push Notifications

Method Description
registerForPushNotifications() Register for push (iOS: APNs, Android: FCM)
setPushToken(String token) Set push token manually
getPushToken() Get current push token
setBadgeCount(int count) Set badge count (iOS only)

In-App Forms

Method Description
registerForInAppForms({InAppFormConfig? configuration}) Register for in-app forms
unregisterFromInAppForms() Unregister from in-app forms

Geofencing

Method Description
registerGeofencing() Begin monitoring geofences
unregisterGeofencing() Stop monitoring geofences

Deep Linking

Method Description
handleUniversalTrackingLink(String url) Handle Klaviyo tracking links, returns bool

Other

Method Description
setLogLevel(KlaviyoLogLevel logLevel) Set logging level (Flutter-side only)
dispose() Clean up resources

Properties

Property Type Description
isInitialized bool Whether the SDK is initialized
apiKey String? Current API key
onPushNotification Stream<Map<String, dynamic>> Push notification events
onFormEvent Stream<Map<String, dynamic>> In-app form events

Models

KlaviyoProfile

KlaviyoProfile({
  String? email,
  String? phoneNumber,
  String? externalId,
  String? firstName,
  String? lastName,
  String? organization,
  String? title,
  String? image,
  KlaviyoLocation? location,
  Map<String, dynamic>? properties,
})

KlaviyoEvent

KlaviyoEvent({
  required EventMetric name,
  Map<String, dynamic>? properties,
  double? value,
  String? uniqueId,
})

// Convenience constructor for custom events
KlaviyoEvent.custom({
  required String metric,
  Map<String, dynamic>? properties,
  double? value,
  String? uniqueId,
})

KlaviyoLocation

KlaviyoLocation({
  double? latitude,
  double? longitude,
  String? address1,
  String? address2,
  String? city,
  String? region,
  String? country,
  String? zip,
  String? timezone,
})

InAppFormConfig

// Default configuration (1 hour session timeout)
InAppFormConfig({
  Duration? sessionTimeoutDuration,
})

// Infinite session timeout (no timeout)
InAppFormConfig.infinite()

Enums

KlaviyoLogLevel

none | error | warning | info | debug | verbose

EventMetric

Predefined metrics:

  • EventMetric.openedApp
  • EventMetric.viewedProduct
  • EventMetric.addedToCart
  • EventMetric.startedCheckout

Custom metrics:

  • EventMetric.custom(String name)

Extensions

KlaviyoNotificationMap (on Map<String, dynamic>)

Property Description
isKlaviyoNotification bool — whether the map is a Klaviyo push notification payload

Exceptions

All SDK exceptions extend KlaviyoException:

Exception Description
KlaviyoNotInitializedException SDK used before initialize()
KlaviyoInvalidApiKeyException Invalid API key provided
KlaviyoNetworkException Network request failed (includes statusCode, responseBody)
KlaviyoProfileException Profile operation failed
KlaviyoEventException Event tracking failed
KlaviyoPushException Push notification operation failed
KlaviyoFormException In-app forms operation failed
KlaviyoConfigurationException Configuration error
KlaviyoPermissionException Missing required permission

Troubleshooting

Android

Push opens not tracked — Verify Klaviyo.handlePush(intent) is called in both onCreate and onNewIntent. Use singleTop or singleTask launch mode. See the example MainActivity.

Push notifications not displaying — Check Firebase setup (google-services.json, plugin applied in build.gradle). On Android 13+, runtime notification permission is required. Test with Firebase Console first to rule out Klaviyo-specific issues.

Push tokens not being set — Ensure Firebase is initialized before calling FirebaseMessaging.instance.getToken(). Initialize the SDK before calling setPushToken().

Deep links not working — Verify intent filters in AndroidManifest.xml. Test with adb shell am start -W -a android.intent.action.VIEW -d "yourscheme://path" com.your.package. For App Links, verify assetlinks.json is accessible.

Build failures — Ensure minSdkVersion 23+. Remove direct references to com.klaviyo:klaviyo-android-sdk from your gradle files (the plugin includes it automatically).

Debug logging — Add to AndroidManifest.xml:

<meta-data android:name="com.klaviyo.core.log_level" android:value="1" />

iOS

For iOS-specific troubleshooting, refer to the iOS SDK documentation.

Common Issues

Events not in dashboard — Wait 5-10 minutes for processing. Verify your API key and that a profile is set (email, phone, or external ID) before tracking events. Verify that your Klaviyo account is active.

"Not initialized" errors — Call KlaviyoSDK().initialize() in main() before runApp(), and ensure you await the call:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await KlaviyoSDK().initialize(apiKey: 'YOUR_API_KEY');
  runApp(MyApp());
}

Getting Help

When reporting issues, include: SDK version, Flutter version, platform and OS version, steps to reproduce, relevant logs (with debug logging enabled), and code snippets.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

License

This project is licensed under the MIT License — see the LICENSE file for details.

About

Flutter SDK for integrating Klaviyo’s push notifications, in-app messaging, geofencing, event tracking, and user profile management into flutter applications.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors