Dart Quickstart
The Eppo SDK enables feature flags and experiments in your Dart and Flutter applications with only a few lines of code.
The SDK handles all the complexity of feature flag evaluation and experiment assignment locally in your application. This guide will walk you through installing the SDK and implementing your first feature flag, experiment, and contextual bandit.
Installation
First, add the SDK to your pubspec.yaml file:
dependencies:
  eppo: ^1.0.0
If using Dart, run:
dart pub get
If using Flutter, run:
flutter pub get
Feature Flags
Feature flags are a way to toggle features on and off without needing to deploy code.
Initialize the SDK
Create an SDK key if you don't already have one.
import 'package:eppo/eppo.dart';
// Initialize the SDK
await Eppo.initialize(
  'your-sdk-key',
  SubjectEvaluation(
    subject: Subject(
      subjectKey: 'user-identifier'
    )
  )
);
The SDK key is different from the project API key. You can find your SDK key in the SDK Keys section of the Eppo interface.
How assignments work
On session start, the SDK retrieves precomputed evaluation of configuration rules from the Eppo Edge server that define how your subject should be allocated to variants. The configuration is cached locally; when you call an assignment function, the SDK evaluates these rules locally without making additional network requests.
Initializing the SDK requires:
- SDK Key: Authorizes the SDK to connect to the Eppo environment
- Subject Evaluation: Contains the subject key and optional attributes
- Client Configuration: Contains SDK platform and optional loggers
Each assignment requires:
- Flag Key: Identifies which set of configuration rules to use
- Default Value: Fallback value if assignment fails or rules don't match
// Make an assignment
final String variation = Eppo.getStringAssignment(
  'my-neat-feature',
  'default-value',
);
Assignment Types
The SDK provides different assignment functions based on the type of value you need:
| Function | Return Type | 
|---|---|
| getBooleanAssignment() | bool | 
| getIntegerAssignment() | int | 
| getNumericAssignment() | num | 
| getStringAssignment() | String | 
| getJSONAssignment() | Map<String, dynamic> | 
Using Assignments
After receiving an assignment, your application should implement logic to modify the user experience accordingly:
final String variation = Eppo.getStringAssignment(
  'my-neat-feature',
  'default-value',
);
// Render different components based on assignment
switch(variation) {
  case 'landing-page-a':
    return renderLandingPageA();
  case 'landing-page-b':
    return renderLandingPageB();
  default:
    return renderLandingPageC();
}
Experiments
While feature flags are useful, they do not let you evaluate the impact of your feature on the users interacting with it. Experiments provide a way to collect data about these interactions using whichever logging and data warehousing system you prefer.
To log events through the SDK, you need to provide a logger when initializing the client:
/// Represents an assignment event.
class AssignmentEvent {
  /// The allocation the subject was assigned to
  final String? allocation;
  /// The experiment identifier
  final String? experiment;
  /// The feature flag identifier
  final String featureFlag;
  /// The format of the assignment
  final String format;
  /// The variation key that was assigned
  final String? variation;
  /// The subject identifier
  final String subject;
  /// The timestamp of the assignment
  final String timestamp;
  /// The subject attributes
  final Map<String, dynamic>? subjectAttributes;
  /// Additional metadata
  final Map<String, dynamic>? metaData;
}
// Implement your own `AssignmentLogger`
class MyAssignmentLogger implements AssignmentLogger {
  @override
  void logAssignment(AssignmentEvent event) {
    // Your logging logic here
    print('Assignment logged: ${event.toJson()}');
  }
}
// Initialize the SDK with a custom assignment logger
await Eppo.initialize(
  'your-sdk-key',
  SubjectEvaluation(subject: subject),
  ClientConfiguration(
    assignmentLogger: MyAssignmentLogger(),
  ),
);
For your production application, we have documentation on how to set up logging with multiple popular data warehouses and logging systems in the Assignment page.
Contextual Bandits
For bandits, a separate logger handles its logging, you supply the available actions and subject attributes, and the SDK provides an API to query the bandit for an action:
/// Represents a bandit event.
class BanditEvent {
  /// The timestamp when the event occurred
  final String timestamp;
  /// The feature flag key
  final String featureFlag;
  /// The bandit key
  final String bandit;
  /// The subject key
  final String subject;
  /// The action associated with the bandit
  final String? action;
  /// The probability of the action
  final double? actionProbability;
  /// The optimality gap
  final double? optimalityGap;
  /// The model version
  final String? modelVersion;
  /// Numeric attributes of the subject
  final Map<String, double>? subjectNumericAttributes;
  /// Categorical attributes of the subject
  final Map<String, String>? subjectCategoricalAttributes;
  /// Numeric attributes of the action
  final Map<String, double>? actionNumericAttributes;
  /// Categorical attributes of the action
  final Map<String, String>? actionCategoricalAttributes;
  /// Metadata about the SDK
  final Map<String, dynamic> metaData;
}
// Implement your own `BanditLogger`
class MyBanditLogger implements BanditLogger {
  @override
  void logBanditEvent(BanditEvent event) {
    // Your logging logic here
    print('Bandit event logged: ${event.toJson()}');
  }
}
// Create subject with attributes
final subject = Subject(
  subjectKey: 'user-identifier',
  subjectAttributes: ContextAttributes(
    categoricalAttributes: {'country': 'US'},
  ),
);
// Create subject evaluation with bandit actions
final subjectEvaluation = SubjectEvaluation(
  subject: subject,
  banditActions: {
    'flag-with-shoe-bandit': {
      'nike': {
        'brand_affinity': 0.4,
        'from': 'usa',
      },
      'adidas': {
        'brand_affinity': 2.0,
        'from': 'germany',
      },
    },
  },
);
// Initialize the SDK with a custom bandit logger
await Eppo.initialize(
  'your-sdk-key',
  subjectEvaluation,
  ClientConfiguration(
    banditLogger: MyBanditLogger(),
  ),
);
Query the bandit for actions
Instead of making simple assignments with a bandit, you will want to query the bandit for actions:
// Get bandit action
final result = Eppo.getBanditAction(
  'flag-with-shoe-bandit',
  'default'
);
if (result.action != null) {
  // Follow the Bandit action
  renderShoeAd(result.action!);
} else {
  // User was not selected for a Bandit.
  // A variation is still assigned.
  renderDefaultShoeAd(result.variation);
}
For full steps to create a bandit including UI steps, see the bandit quickstart.
Flutter Integration
Ensure the Eppo SDK is initialized when the app is launched or resumed from the background.
Use the Flutter AppLifecycleListener to initialize the SDK when the app is launched:
// An example of an EppoObserver that initializes the SDK when the app is launched
class EppoObserver extends WidgetsBindingObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    switch (state) {
      case AppLifecycleState.resumed:
        // Create subject and configuration
        final subject = Subject(subjectKey: 'user-identifier');
        final subjectEvaluation = SubjectEvaluation(subject: subject);
        final clientConfiguration = ClientConfiguration(sdkPlatform: SdkPlatform.flutter);
        
        // Initialize the SDK
        await Eppo.initialize('your-sdk-key', subjectEvaluation, clientConfiguration);
        break;
    }
  }
}
// Add the EppoObserver to the WidgetsBinding
@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(EppoObserver());
}
More details about Flutter integration can be found in the Flutter Integration page.
Next Steps
Now that you've seen how to make assignments with the Eppo Dart SDK, we strongly recommend familiarizing yourself with the following topics: