Skip to main content

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'
)
)
);
note

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:

FunctionReturn 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(),
),
);
note

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);
}
note

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: