Skip to main content
Beta The Cello Flutter SDK allows you to use Cello for iOS and Cello for Android in your Flutter apps. With a plug-n-play mobile component, your users can easily share their invite link with their friends and network using mobile sharing options convenient for them, receive rewards and get paid out.

Installation

A basic installation takes around 15 minutes, but will take a little longer if you want to customize the way the Cello Referral Component is launched. Compatibility
  • The Cello Flutter SDK supports Flutter 3.3.0 and above (Dart 3+).
  • Cello for iOS supports iOS 15+.
  • Cello for Android supports API 21+.

Install Cello

flutter pub add cello_sdk
Or add to your pubspec.yaml:
dependencies:
  flutter:
    sdk: flutter
  cello_sdk: ^0.0.1
Then run:
flutter pub get

Android Setup

The Flutter plugin automatically handles linking for Android. Ensure your app’s android/app/build.gradle has the correct configuration:
android {
  compileSdk 34

  defaultConfig {
    minSdk 21
    // ... other config
  }
}
Ensure your project’s android/build.gradle (or app-level) includes:
repositories {
  google()
  mavenCentral()
}

Internet Permission

Add internet permission in android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />

iOS Setup

The Flutter plugin automatically handles linking for iOS via CocoaPods. From your ios/ directory, run:
cd ios
pod install
cd ..
Ensure your ios/Podfile specifies iOS 15.0+:
platform :ios, '15.0'

Choose an Environment

In your Cello SDK setup, you have the flexibility to select the environment in which your application will run. This feature is especially useful for different stages of development, such as testing in a development or staging environment before going live in production. The available environments are:
  • production or prod (Production) (default)
  • sandbox (Sandbox)
You specify the environment when initializing Cello:
await Cello.initialize(
  CelloInitializeOptions(
    productId: 'your-product-id',
    token: 'your-token',
    environment: 'sandbox', // or 'production'
  ),
);

Customize the Cello Referral Component

The Cello Flutter SDK allows for various levels of customization to better fit into your app’s design and flow. One of the main components you might want to customize is the Referral component

Choose Your Launcher

The library provides two ways to launch the Referral component: Default launcher If you choose to go with the default launcher, you can call the showFab() method from the Cello library to present a Floating Action Button (FAB) within your app. This FAB is pre-styled but may not perfectly match your app’s look and feel.
import 'package:cello_sdk/cello_sdk.dart';

await Cello.showFab();
Custom launcher If the default launcher does not fit your needs, you can implement your own custom launcher. This could be any UI element like a button, menu item, or even a gesture. To open the Referral component using a custom launcher, you can call Cello.openWidget().
import 'package:cello_sdk/cello_sdk.dart';

ElevatedButton(
  onPressed: () async {
    await Cello.openWidget();
  },
  child: Text('Open Referral'),
)

Flutter API

Cello.initialize(CelloInitializeOptions): Future<CelloConfiguration>

Initializes the Cello referral component.

CelloInitializeOptions

PropertyTypeRequiredDescription
productIdStringyesYour product ID from Cello Portal
tokenStringyesUser authentication token
environmentString?noEnvironment: "production" or "sandbox"
productUserDetailsProductUserDetailsnoUser details object (see below)
languageString?noInitial language of the widget
themeModeString?noInitial theme mode: "light", "dark", or "system"

ProductUserDetails

Optional object with user information:
PropertyTypeDescription
firstNameStringUser’s first name
lastNameStringUser’s last name
fullNameStringUser’s full name
emailStringUser’s email address
import 'package:cello_sdk/cello_sdk.dart';

final config = await Cello.initialize(
  CelloInitializeOptions(
    productId: 'your-product-id',
    token: 'your-token',
    environment: 'production',
    productUserDetails: ProductUserDetails(
      firstName: 'John',
      lastName: 'Doe',
      fullName: 'John Doe',
      email: '[email protected]',
    ),
    language: 'de',
    themeMode: 'system',
  ),
);

Cello.showFab(): Future<void>

Shows the default Cello button that launches the Referral Component
await Cello.showFab();

Cello.hideFab(): Future<void>

Hides the default Cello button that launches the Referral Component
await Cello.hideFab();

Cello.openWidget(): Future<void>

Opens the referral component.
await Cello.openWidget();

Cello.hideWidget(): Future<void>

Hides the referral component.
await Cello.hideWidget();

Cello.getActiveUcc(): Future<Map<String, String>>

A method to get an active ucc and related data for the currently logged in user.
final ucc = await Cello.getActiveUcc();
// Returns: { "ucc": "...", "inviteLink": "..." } or empty map

Cello.getCampaignConfig(): Future<Map<String, dynamic>>

A method to get the campaign configuration.
final config = await Cello.getCampaignConfig();
// Returns: Map with campaign settings

Cello.changeLanguage(String language): Future<void>

A method to change the language of the Referral component at runtime without re-initialising it. Note: Requires iOS 14+ on iOS platform.
await Cello.changeLanguage('de');

Cello.setThemeMode(String themeMode): Future<void>

A method to change the theme mode of the Referral component at runtime without re-initialising it. Note: Requires iOS 14+ on iOS platform.
await Cello.setThemeMode('dark');
Parameters:
  • themeMode (String): The theme mode to set. Valid values are "light", "dark", or "system".

Cello.updateToken(String token): Future<void>

Updates the user authentication token without re-initializing. Note: Requires iOS 14+ on iOS platform.
await Cello.updateToken('new-token');

Cello.shutdown(): Future<void>

Shuts down connection to Cello and unmounts the component
await Cello.shutdown();

Cello.tokenEvents: Stream<CelloTokenEvent>

A broadcast stream that emits token lifecycle events.
Cello.tokenEvents.listen((event) {
  switch (event.type) {
    case CelloTokenEventType.tokenAboutToExpire:
      // Refresh your token
      refreshToken();
      break;
    case CelloTokenEventType.tokenHasExpired:
      // Handle expired token
      handleExpiredToken();
      break;
  }
});

Error Handling

Exception types

The Cello Flutter SDK throws PlatformException with specific error codes when operations fail:
CodePlatform(s)TriggerTypical causes
InitializationErroriOS & AndroidCello.initialize completes with native failureInvalid/empty product ID or token, network issues, bad environment
InitializationExceptionAndroidUnexpected exception inside Cello.initializeActivity finishing, SDK not linked correctly, runtime crash
ActivityUnavailableAndroidCello.initialize without an active ActivityInitialization triggered too early (e.g. before app fully ready)
TokenUpdateErroriOSCello.updateToken failureToken expired/invalid, network errors
LanguageChangeErroriOSCello.changeLanguage failureUnsupported language code, network errors
ThemeModeChangeErroriOSCello.setThemeMode failureInvalid theme mode value, network errors
UnavailableiOSFeature requires iOS 14+Device running < iOS 14 when calling token, language, or theme updates
ClientUnavailableAndroidMethod called before initializationSDK not initialized before calling other methods
CelloErrorAndroidGeneric SDK errorVarious SDK-level errors
UccErrorAndroidCello.getActiveUcc threwSDK not initialized, network or serialization errors
CampaignConfigErrorAndroidCello.getCampaignConfig threwSDK not initialized, configuration not ready
InvalidArgumentsiOS & AndroidMissing or invalid method argumentsRequired parameters not provided or have invalid values
Tip: Catch PlatformException and inspect error.code, error.message, and error.details for extra context.

Common error scenarios

1. Initialization exception

Symptoms: InitializationError or InitializationException in the catch block. Fix: Validate credentials, confirm network connectivity, and ensure you selected the right environment (production vs sandbox). Check native logs for additional details.

2. Methods called before initialization

Symptoms: ClientUnavailable error on Android or native console warnings. Fix: Ensure Cello.initialize completes successfully before calling other methods like showFab() or openWidget(). Track initialization state in your app.

3. Platform feature limitations

Cello.changeLanguage, Cello.setThemeMode, and Cello.updateToken require iOS 14+ on iOS. On older devices these methods reject with Unavailable error. Guard these calls with a platform/version check if needed.

Error handling best practices

1. Wrap initialization in try/catch:
import 'package:flutter/services.dart';
import 'package:cello_sdk/cello_sdk.dart';

Future<void> bootstrapCello() async {
  try {
    if (productId.trim().isEmpty || token.trim().isEmpty) {
      throw Exception('Missing credentials');
    }

    final config = await Cello.initialize(
      CelloInitializeOptions(
        productId: productId,
        token: token,
        productUserDetails: productUserDetails,
      ),
    );

    setState(() {
      celloReady = true;
    });

    print('[Cello] Initialized: ${config.rawResponse}');
  } on PlatformException catch (e) {
    print('[Cello] Initialization failed: ${e.code} - ${e.message}');

    // Show user-friendly error
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Referrals unavailable'),
        content: Text('Please check your connection and try again.'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text('OK'),
          ),
        ],
      ),
    );
  } catch (e) {
    print('[Cello] Unexpected error: $e');
  }
}
2. Delay UI interactions: Only call Cello.showFab() or Cello.openWidget() after a successful initialization. Keep a dedicated isCelloReady state flag in your widgets.
ElevatedButton(
  onPressed: celloReady ? () => Cello.openWidget() : null,
  child: Text('Open Referral'),
)
3. Handle token lifecycle: Listen to Cello.tokenEvents and refresh tokens proactively before they expire:
StreamSubscription<CelloTokenEvent>? _tokenSubscription;

@override
void initState() {
  super.initState();

  _tokenSubscription = Cello.tokenEvents.listen((event) {
    if (event.type == CelloTokenEventType.tokenAboutToExpire) {
      // Refresh token from your backend
      _refreshCelloToken();
    }
  });
}

@override
void dispose() {
  _tokenSubscription?.cancel();
  super.dispose();
}

Future<void> _refreshCelloToken() async {
  try {
    // Get fresh token from your API
    final newToken = await fetchFreshToken();

    // Update Cello with new token
    await Cello.updateToken(newToken);

    print('[Cello] Token refreshed successfully');
  } on PlatformException catch (e) {
    print('[Cello] Token refresh failed: ${e.code} - ${e.message}');
  }
}
4. Retry on transient errors: For recoverable failures (network timeouts, InitializationError), schedule a retry with exponential backoff. Limit retries to avoid looping endlessly. 5. Log error details: Capture error codes, messages, and relevant details in your logging/monitoring solution to help support diagnose issues quickly.