math_flutter

Flutter plugin for QuestionPro CX SDK integration on Android and iOS.

Collect customer feedback and display surveys in your Flutter app using the QuestionPro CX platform.


🚀 Quick Start

1. Add to pubspec.yaml

dependencies:
  math_flutter: ^0.9.9

2. Get Your API Key

Get your QuestionPro CX API key from your QuestionPro account.

3. Platform Setup

Android Setup

Add the API key to your app's android/app/src/main/AndroidManifest.xml:

<application>
    <!-- Your existing config -->
    
    <!-- Add QuestionPro CX API key -->
    <meta-data
        android:name="cx_manifest_api_key"
        android:value="YOUR_API_KEY_HERE" />
</application>

That's it for Android! The plugin reads the API key from the manifest automatically.

iOS Setup

No additional configuration needed - API key is provided at runtime via code.

4. Initialize in Your App

import 'dart:io' show Platform;
import 'package:math_flutter/math_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize QuestionPro CX SDK
  if (Platform.isIOS) {
    // iOS: API key required as parameter
    await MathFlutter.initializeSurvey(
      apiKey: 'YOUR_API_KEY_HERE',
      dataCenter: 'US', // or 'EU'
    );
  } else {
    // Android: Reads from AndroidManifest.xml
    await MathFlutter.initializeSurvey(
      dataCenter: 'US', // or 'EU'
    );
  }
  
  runApp(MyApp());
}

5. Launch Surveys

// Display a survey to your users
await MathFlutter.launchSurvey('your_survey_id');

// Example: Add a button
ElevatedButton(
  onPressed: () async {
    await MathFlutter.launchSurvey('123456789');
  },
  child: Text('Take Survey'),
)

6. Track Screen Views (Optional)

Use the View Count rule to trigger surveys based on user navigation:

// Log when users visit specific screens
await MathFlutter.viewCount('Check_out');

// On iOS, pass the API key
if (Platform.isIOS) {
  await MathFlutter.viewCount(
    'Shopping_Cart',
    apiKey: 'your_api_key',
  );
} else {
  await MathFlutter.viewCount('Shopping_Cart');
}

Configure the View Count rule in your QuestionPro CX admin dashboard to trigger surveys after a specific number of screen views.

7. Set Custom User Data (Optional) 🆕

Send custom user attributes to personalize surveys and track responses:

// Set user data for personalization
await MathFlutter.setDataMappings(
  {
    'firstName': 'John',
    'lastName': 'Doe',
    'email': 'john@example.com',
    'userType': 'Premium',
  },
  apiKey: Platform.isIOS ? 'your_api_key' : null,
);

This data can be used to:

  • Personalize survey questions
  • Pre-fill form fields
  • Segment responses by user attributes
  • Track feedback from specific users

📖 API Reference

initializeSurvey()

Initializes the QuestionPro CX SDK. Call this once during app startup.

Future<String> initializeSurvey({
  String? apiKey,
  String dataCenter = 'US',
})

Parameters:

  • apiKey (optional): Your QuestionPro CX API key
    • Required for iOS (no manifest file)
    • Optional for Android (reads from AndroidManifest.xml)
  • dataCenter (optional): 'US' or 'EU'. Defaults to 'US'

Returns: Success message from the SDK

Platform-Specific Examples:

// Android - reads API key from AndroidManifest.xml
await MathFlutter.initializeSurvey(dataCenter: 'US');

// iOS - requires API key parameter  
await MathFlutter.initializeSurvey(
  apiKey: 'your_api_key_here',
  dataCenter: 'US',
);

// Cross-platform approach
if (Platform.isIOS) {
  await MathFlutter.initializeSurvey(
    apiKey: 'your_api_key',
    dataCenter: 'US',
  );
} else {
  await MathFlutter.initializeSurvey(dataCenter: 'US');
}

launchSurvey()

Displays a survey to the user.

Future<void> launchSurvey(String surveyId)

Parameters:

  • surveyId (required): The ID of the survey to display (as a string)

Example:

await MathFlutter.launchSurvey('123456789');

viewCount() 🆕

Tracks screen view events for the View Count rule. Use this to monitor when users navigate to specific screens in your app.

Future<String> viewCount(String screenName, {String? apiKey})

Parameters:

  • screenName (required): The name of the screen to log (must match the screen_name configured in your QuestionPro CX admin dashboard's View Count rule)
  • apiKey (optional): Your QuestionPro CX API key
    • Required for iOS
    • Optional for Android (automatically reads from AndroidManifest.xml)

Returns: Success message from the SDK

Platform-Specific Examples:

// Android - reads API key from AndroidManifest.xml
await MathFlutter.viewCount('Check_out');

// iOS - requires API key parameter  
await MathFlutter.viewCount(
  'Check_out',
  apiKey: 'your_api_key_here',
);

// Cross-platform approach
if (Platform.isIOS) {
  await MathFlutter.viewCount(
    'Shopping_Cart',
    apiKey: 'your_api_key',
  );
} else {
  await MathFlutter.viewCount('Shopping_Cart');
}

Setting up View Count Rule:

  1. Go to your QuestionPro CX admin dashboard
  2. Navigate to Rules set-up section
  3. Create a new View Count rule
  4. Configure the rule with:
    • screen_name: The screen name you want to monitor (e.g., "Check_out", "Shopping_Cart")
    • count: The view threshold before the intercept is triggered
  5. Use viewCount() in your Flutter app at the desired event logging points

Example Use Cases:

// Track checkout page views
class CheckoutPage extends StatefulWidget {
  @override
  void initState() {
    super.initState();
    _logScreen();
  }
  
  Future<void> _logScreen() async {
    try {
      await MathFlutter.viewCount('Check_out');
    } catch (e) {
      print('Error logging screen: $e');
    }
  }
}

// Track product page views
Navigator.push(context, MaterialPageRoute(
  builder: (context) => ProductPage(),
)).then((_) async {
  await MathFlutter.viewCount('Product_Detail');
});

setDataMappings() 🆕

Sends custom user attributes to QuestionPro CX for survey personalization and user-specific analytics.

Future<String> setDataMappings(
  Map<String, String> customVariables, 
  {String? apiKey}
)

Parameters:

  • customVariables (required): Map of key-value pairs representing user attributes
    • Keys: Attribute names (e.g., 'firstName', 'email', 'userType')
    • Values: Attribute values (all must be strings)
  • apiKey (optional): Your QuestionPro CX API key
    • Required for iOS
    • Optional for Android (automatically reads from AndroidManifest.xml)

Returns: Success message from the SDK

Platform-Specific Examples:

// Android - reads API key from AndroidManifest.xml
await MathFlutter.setDataMappings({
  'firstName': 'Sarah',
  'lastName': 'Johnson',
  'email': 'sarah@company.com',
  'department': 'Sales',
  'membershipTier': 'Gold',
});

// iOS - requires API key parameter  
await MathFlutter.setDataMappings(
  {
    'firstName': 'Sarah',
    'email': 'sarah@company.com',
  },
  apiKey: 'your_api_key_here',
);

// Cross-platform approach
await MathFlutter.setDataMappings(
  {
    'firstName': userName,
    'email': userEmail,
    'accountType': accountType,
  },
  apiKey: Platform.isIOS ? 'your_api_key' : null,
);

When to Use:

  1. After User Login

    void onLoginSuccess(User user) async {
      await MathFlutter.setDataMappings(
        {
          'userId': user.id,
          'email': user.email,
          'firstName': user.firstName,
          'accountCreated': user.createdAt.toString(),
        },
        apiKey: Platform.isIOS ? apiKey : null,
      );
    }
    
  2. After Purchase/Transaction

    void onPurchaseComplete(Order order) async {
      await MathFlutter.setDataMappings(
        {
          'lastPurchaseAmount': order.total.toString(),
          'lastPurchaseDate': DateTime.now().toString(),
          'totalOrders': user.orderCount.toString(),
        },
        apiKey: Platform.isIOS ? apiKey : null,
      );
         
      // Then show feedback survey
      await MathFlutter.launchSurvey('post_purchase_survey_id');
    }
    
  3. Profile Updates

    void onProfileUpdate(UserProfile profile) async {
      await MathFlutter.setDataMappings(
        {
          'phoneNumber': profile.phone,
          'location': profile.city,
          'preferences': profile.interests.join(','),
        },
        apiKey: Platform.isIOS ? apiKey : null,
      );
    }
    

Benefits:

  • 📊 Analytics: Link survey responses to specific users
  • 🎯 Targeting: Show different surveys to different user segments
  • Personalization: Use user data in survey questions ("Hi Sarah, how was your experience?")
  • 📝 Pre-filling: Reduce user effort by pre-populating form fields
  • 🔍 Segmentation: Analyze feedback by user attributes (Premium vs Free users, etc.)

Important Notes:

  • Call this before launching surveys for the data to be included
  • Data persists for the entire app session
  • All values must be strings (convert numbers/dates to strings)
  • The data is sent to QuestionPro's servers and associated with survey responses

🏗️ Architecture Overview

Communication Flow

┌─────────────────────────────────────────────────────────┐
│  Flutter/Dart Layer (MathFlutter)                       │
│  ─────────────────────────────────────────────────      │
│  MethodChannel('math_flutter')                          │
│  └─> initializeSurvey(apiKey: '...')                    │
│  └─> launchSurvey(surveyId: '...')                      │
│  └─> setDataMappings(customVariables: {...}) [v0.9.5]   │
│                                                           │
│  MethodChannel('Cx_Callback')                           │
│  └─> viewCount(screenName: '...')                       │
└───────────────────┬─────────────────────────────────────┘
                    │
                    ▼  Platform Channel
┌─────────────────────────────────────────────────────────┐
│  Native Platform (Android/iOS)                          │
│  ─────────────────────────────────────────────────      │
│  • Initializes QuestionPro CX SDK                       │
│  • Launches InteractionActivity/Survey View             │
│  • Logs screen visits for View Count rules              │
│  • Sets custom user data mappings for personalization   │
└─────────────────────────────────────────────────────────┘

Key Components

Android:

  • MathFlutterPlugin.kt: Handles method channel communication and SDK initialization
  • AndroidManifest.xml: Contains API key metadata and declares InteractionActivity
  • InteractionActivity: Native activity provided by QuestionPro SDK for displaying surveys

iOS:

  • MathFlutterPlugin.swift: Handles method channel communication and SDK initialization
  • QuestionProCXFramework: Native iOS SDK from QuestionPro

Flutter/Dart:

  • MathFlutter: Main plugin class with static methods
  • MethodChannel: Bridge for Flutter ↔ Native communication

🔒 Security Best Practices

Protecting Your API Key

Android

Your API key is stored in AndroidManifest.xml which is compiled into your app. Best practices:

✅ Do:

  • Add AndroidManifest.xml API key configuration to your app repository (it's required for the app to work)
  • Use different API keys for development and production builds
  • Consider using build variants or flavors with different manifests for different environments
  • Rotate API keys periodically in your QuestionPro account

❌ Don't:

  • Share your production API key publicly
  • Use the same API key across multiple unrelated apps
  • Commit sensitive survey configurations to public repositories

iOS

Your API key is passed at runtime. Best practices:

✅ Do:

  • Store API keys in secure configuration files
  • Use environment variables or build configurations
  • Use different API keys for development and production

❌ Don't:

  • Hardcode production API keys in source code
  • Commit API keys to public repositories
  • Include API keys in client-side code that gets published

Use dart-define or environment-specific configuration:

// Pass via dart-define when building:
// flutter build --dart-define=QUESTIONPRO_API_KEY=your_key

const apiKey = String.fromEnvironment('QUESTIONPRO_API_KEY', defaultValue: '');

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  if (Platform.isIOS) {
    await MathFlutter.initializeSurvey(
      apiKey: apiKey,
      dataCenter: 'US',
    );
  } else {
    // Android reads from manifest
    await MathFlutter.initializeSurvey(dataCenter: 'US');
  }
  
  runApp(MyApp());
}

For Android, use different AndroidManifest.xml files per build variant:

android/app/src/
  ├── main/AndroidManifest.xml
  ├── debug/AndroidManifest.xml   (dev API key)
  └── release/AndroidManifest.xml (prod API key)

📋 Requirements

  • Flutter: >=3.0.0
  • Dart: >=3.0.0 <4.0.0
  • Android: minSdkVersion 24 (Android 7.0+)
  • iOS: iOS 14.0+

🐛 Troubleshooting

Android Issues

Q: App crashes on launch or "MISSING_API_KEY" error

  • Ensure you've added the API key metadata to your app's AndroidManifest.xml (under <application> tag)
  • Verify the metadata name is exactly: cx_manifest_api_key
  • Make sure the value is not empty

Q: Survey doesn't display

  • Check that you've called initializeSurvey() before launchSurvey()
  • Verify the survey ID is correct
  • Check that internet permissions are granted
  • Ensure the survey is active in your QuestionPro account
  • Check Android logcat for QuestionPro SDK error messages

Q: Screen view logging not working or "MISSING_API_KEY" error

  • Ensure you've added the API key metadata to your app's AndroidManifest.xml
  • Verify the metadata name is exactly: cx_manifest_api_key
  • Make sure the View Count rule is configured in your QuestionPro CX admin dashboard
  • Check that the screen_name in your code matches the rule configuration

iOS Issues

Q: Build fails with CocoaPods error

  • Run cd ios && pod install && cd ..
  • Try pod deintegrate then pod install

Q: Survey doesn't appear

  • Ensure you've called initializeSurvey() with a valid API key
  • Check the survey ID matches your QuestionPro configuration
  • Verify iOS deployment target is 14.0+

Q: Screen view logging fails on iOS

  • Make sure you're passing the apiKey parameter in viewCount()
  • Verify the API key is valid and matches your QuestionPro account
  • Check that the View Count rule is configured in your admin dashboard
  • Ensure the screen_name matches your rule configuration

📦 Example App

See the /example folder for a complete working example.

cd example
flutter pub get
flutter run

📄 License

MIT License - see LICENSE file for details.


🔗 Resources

Libraries

math_flutter