Flutter V3.1.X
Introduction
SDK overview
Welcome to the Flagship Flutter SDK documentation!
The following documentation helps you run Flagship on your Flutter app using our client library.
Feel free to contact us if you have any questions regarding this documentation.
SDK features
This SDK version will help you:
- Set a visitor ID
- Update visitor context
- Synchronize campaigns via the Decision API
- Get a flag value
- Send a hit to our Data Collect
Prequisites
- Flagship SDK supports Dart 2.12.0 minimum or higher
- Flagship is null safety
Good to know
- Latest Version
- Github repository
- Dart code supported
Getting Started
Our Flagship flutter SDK is available for distribution through pub.dev
Installing
Run this command:
flutter pub add flagship
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):
dependencies:
flagship: ^3.1.2
Initialization
To run experiments with Flagship, you will need to start the SDK using:
start(String envId, String apiKey, {FlagshipConfig? config}) async
Parameter | Type | Required | Description |
---|---|---|---|
envId | String | Yes | Identifies your Flagship account and environment (preprod or prod). Find this ID |
apiKey | String | Yes | Identifies your Flagship api key (preprod or prod). Find this api key |
config | FlagshipConfig | No | Object that represent client's configuration |
You can get your own envId & API Key in the Flagship Platform.
- Navigate to Settings⟶API Key & Settings
- Copy the environment ID & API Key
Flagship use predefined context keys to help you retrieve datas in the reporting, those keys can be the language, Flagship version but can also be some device informations.
That's the reason you have to « wait » the device informations gathering process.
Here is an example on how to start the SDK:
// import package
import 'package:flagship/flagship.dart';
//////////////////////////////////////////////
/////// Start sdk with default options ///////
//////////////////////////////////////////////
await Flagship.start("your_env_id", "your_api_key");
//import package
import 'package:flagship/flagship.dart';
/////////////////////////////////////////////////////////////
// Create visitor when SDK is ready, using the statusListener
/////////////////////////////////////////////////////////////
FlagshipConfig customConfig = ConfigBuilder()
.withMode(Mode.DECISION_API)
.withStatusListener((newStatus) {
// When the status is Ready
if (newStatus == Status.READY) {
// Do things ...
}
})
.withTimeout(2500)
.withLogLevel(Level.ALL)
.build();
// Start SDK
Flagship.start(
"your_env_id", "your_api_key",
config: customConfig);
Advanced Configuration
The sdk provides the FlagshipConfig object in the start function as an optional parameter where we can set the desired configuration
Decision Mode :
ConfigBuilder withMode(Mode newMode)
DECISION_API
When the SDK is running in DecisionApi mode, the campaign assignments and targeting validation take place server-side. In this mode, each call to the fetchFlags method to refresh the flags will create an HTTP request.
BUCKETING
When the SDK is running in BUCKETING mode, the SDK downloads all the campaigns configurations at once in a single bucketing file so that variation assignment can be computed client-side by the SDK. This bucketing file is stored in cache and will only be downloaded again when campaign configurations are modified in the Flagship interface.
Timeout :
This delay only concerns the request for fetching campaigns under the API mode. If the API didn't answer during this interval of time, the default values will be returned from value function.
ConfigBuilder withTimeout(int newTimeout)
Parameter | Type | Description |
---|---|---|
newTimeout | int | Milliseconds, default value is 2000 ms |
The unit of measure for the timeout is Millisecond.
statusListener :
This listener is called when SDK status has changed.
ConfigBuilder withStatusListener(StatusListener listener)
Parameter | Type | Description |
---|---|---|
listener | StatusListener | Indicate the actual status of the sdk, this listener is called when the status change |
logLevel :
ConfigBuilder withLogLevel(Level newLevel)
Parameter | Type | Description |
---|---|---|
newLevel | Level | Level of detail, default value is Level.ALL |
You can change log's level of detail during the runtime void setLoggerLevel(Level newLevel)
Polling Interval Time :
Only available for Bucketing Mode:
Define time interval between two bucketing updates.
ConfigBuilder withBucketingPollingIntervals(int newPollingTime)
Parameter | Type | Description |
---|---|---|
newPollingTime | int | time interval between two bucketing updates, default value is 60s |
//////////////////////////////////////////////
/////// Start SDK with custom options ///////
//////////////////////////////////////////////
// - timeout = 2500 ms
// - level = warning message
// - statusListener callback
FlagshipConfig customConfig = ConfigBuilder()
.withMode(Mode.DECISION_API)
.withStatusListener((newStatus) {
// Do things when status change ...
})
.withTimeout(2500)
.withLogLevel(Level.WARNING)
.build();
// Start SDK
await Flagship.start("your_env_id", "your_api_key", config: customConfig);
Config Tracking Manager
ConfigBuilder withTrackingConfig(TrackingManagerConfig trackingManagerConfig)
The SDK through the TrackingManager class report analytics event using batching process, each time a visitor emits a hit, the tracking manager will stack it in the event pool.
When the time interval batchIntervals is over or pool Maximum Size poolMaxSize is reached, the batch process is triggered and the pool emptied.
In the meantime, the caching process depends on the cache strategy adopted.
The advantages:
- Use less network traffic
- Avoid data loss
- Catch all hits that would fail
The TrackingManager stand on three options to setup
Time Interval
Time interval to process and send event through batch
The batchIntervals parameter is an integer, default value is 5 seconds
Pool Max Size
Specifies the maximum number of hit in the pool
The poolMaxSize parameter is an integer, default value is 10
Cache Strategy
Define a strategy to adopt, we have two strategies represented by an enum BatchCachingStrategy.
1 - BATCH_CONTINUOUS_CACHING
Each time a visitor emits an event, this strategy duplicates events in cache using cacheHit (see InterfaceCache), on completion batching process the saved hits are removed from the cache.
Note: The SDK has a default cache implementation using a database
Note: recommended for client side applications
2 - BATCH_PERIODIC_CACHING
This strategy periodically make a copy in the cache of the existing event in the pool, those events will be removed once the batching process completed and succeed
Note: recommended for server-side applications
//////////////////////////////////////////////
/////// Start SDK with custom options ///////
//////////////////////////////////////////////
// Create a config manager with a custom settings:
// - timeout = 1500 ms
// - level = warning message
// - statusListener callback
// - Time Intreval : 20
// - Maximum size pool : 20
// - Strategy : BATCH_CONTINUOUS_CACHING
// Create a custom tracking manager
var customTrackingConfig = TrackingManagerConfig(
batchIntervals: 20,
poolMaxSize: 20,
batchStrategy: BatchCachingStrategy.BATCH_CONTINUOUS_CACHING);
// Create customConfig config manager
FlagshipConfig customConfig = ConfigBuilder()
.withMode(Mode.DECISION_API)
.withStatusListener((newStatus) {
// Do things when status change ...
})
.withTimeout(1500)
.withLogLevel(Level.WARNING)
.withTrackingConfig(customTrackingConfig)
.build();
// Start SDK with a custom configuration
Flagship.start("your_env_id", "your_api_key", config: customConfig);
}
Developer Usage Tracking
ConfigBuilder withDisableDeveloperUsageTracking(bool disableDeveloperUsageTracking)
Parameter | Type | Description |
---|---|---|
disableDeveloperUsageTracking | bool | Collects information about the usage of SDK. By default the value is set to false otherwise set to true to disable this feature. |
// Create config and disabled usage tracking
FlagshipConfig customConfig = ConfigBuilder().withDisableDeveloperUsageTracking(true)
.build();
// Start SDK
await Flagship.start("your_env_id", "your_api_key", config: customConfig);
In the start function the config parameter is optional, The SDK will run with default settings.
SDK Status
It's possible to get the current status via the method getStatus() from the Flagship class.
static Status getStatus()
Return an enum that represent the current SDK status
List of the possible SDK status :
Status | Description |
---|---|
NOT_INITIALIZED | Flagship SDK has not been started or initialized successfully. |
PANIC_ON | Flagship SDK is ready but is running in Panic mode: All visitor's features are disabled except 'fetchFlags' which refreshes this status. |
READY | Flagship SDK is ready to use. |
// Get the current status for the SDK
var currentStatus = Flagship.getStatus();
// Using getStatus to check if the SDK is READY
// Create the visitor
var visitor = Flagship.newVisitor("user1",{"isVip":true});
// Fetch Flags the modifications
visitor.fetchFlags().whenComplete(() {
// Get the status and check the mode
Status currentState = Flagship.getStatus();
if (currentState == Status.READY) {
// The SDK is ready
}
});
onVisitorExposed
In some cases, you'll need to send informations about the exposition (When a flag has been seen by your visitor), like sending visitor and flag data to third parties.
To centralize it, we provide a callback in the configuration option of the SDK.
This callback is triggered each time the function visitorExposed is called and success.
-ConfigBuilder withOnVisitorExposed(OnVisitorExposed pOnVisitorExposed)
The OnVisitorExposed callback is a function with two parameters
typedef OnVisitorExposed = void Function(VisitorExposed visitorExposed, ExposedFlag fromFlag)?;
Parameter | Type | Description |
---|---|---|
visitorExposed | VisitorExposed | This class represent the visitor exposed |
fromFlag | ExposedFlag | This class represent the flag exposed. (The flag that has triggered the exposition) |
VisitorExposed
The class VisitorExposed give us the visitor's information
Parameter | Type | Description |
---|---|---|
id | String | VisitorId |
anonymousId | String | anonymous id, used with Experience Continuity |
context | Map or Dictionary | The current visitor’s context, can be Map or dictionary depend on the language |
ExposedFlag
The class ExposedFlag give us the flag's information
Parameter | Type | Description |
---|---|---|
key | String | key for flag |
value | Any | value for the flag |
defaultValue | Any | default value |
metadata() | Flagmetadata | Campaign information metadata, this class already existed |
For both class VisitorExposed & ExposedFlag use toJson() method to get the json representation .
// Inside the callBack we use toJson() method to get the json representation.
// This block is a part of confuguration builder, for more information
// go to #flagship-configuration-options section
.withOnVisitorExposed((exposedUser, fromFlag) {
// Get the json representation
print(fromFlag.toJson());
print(exposedUser.toJson());
})
// Representation of VisitorExposed
{
"id": "visitor_1",
"anonymousId": null,
"context": {
"sdk_firstTimeInit": false,
"sdk_deviceLanguage": "fr_US",
"sdk_deviceType": "Mobile",
"sdk_deviceModel": "iPhone",
"sdk_osName": "ios",
"sdk_osVersionName": "ios",
"sdk_fsVersion": "2.1.0,",
"customer": "QA",
"country": "FR"
}
}
// Representation of ExposedFlag
{
"key": "btnColor",
"value": "Green",
"metadata": {
"campaignId": "cfv24sokqu3h6tka0sv0",
"variationGroupId": "cfv24sokqu3h6tka0t00",
"variationId": "cfv24sokqu3h6tka0t10",
"isReference": false,
"campaignType": "ab",
"slug": null
}
}
The onVisitorExposed callback is triggered ONLY when the visitorExpose() method is called and success.
Here is an example on how to use this callback:
Create a visitor
Once Flagship SDK is initialized, you can create a visitor.
The Visitor instance is an object that lets you manage the context, activate experiments and track events.
VisitorBuilder(this.visitorId, {this.instanceType = Instance.SINGLE_INSTANCE});
Parameter | Type | Description |
---|---|---|
visitorId | String | Unique visitor identifier |
instanceType | Instance | How Flagship SDK should handle the newly created visitor instance. (Default is SINGLE_INSTANCE) SINGLE_INSTANCE : The newly created visitor instance will be returned and saved into the Flagship singleton. Call Flagship.getCurrentVisitor() to retrieve the instance. NEW_INSTANCE: The newly created visitor instance wont be saved and will simply be returned. |
Visitor Builder methods:
Represent the visitor's initial context key/values used for targeting.
Context keys must be String, and values types must be one of the following: String, bool, int, double, Boolean, String.
VisitorBuilder withContext(Map<String, Object> context)
Parameter | Type | Description |
---|---|---|
context | Map<String, Object> | initial context |
VisitorBuilder hasConsented(bool hasConsented)
Specify if the visitor has consented to personal data usage. When false some features will be deactivated. The default value is true.
Parameter | Type | Description |
---|---|---|
hasConsented | bool | true when visitor has given consent, false otherwise. |
isAuthenticated(bool authenticated)
The visitorId will be considered as authenticated if true otherwise is anonymous.
Parameter | Type | Description |
---|---|---|
authenticated | bool | true for authenticated visitor, false for anonymous. |
Flagship use predefined context keys to help you retrieve datas in the reporting, those keys can be the location, IP but can also be some device informations.
That's the reason you have to « wait » the device informations gather process.
Here is an example on how to start the SDK and create visitor :
// import package
import 'package:flagship/flagship.dart';
//////////////////////////////////////////////
/////// Create visitor ///////
//////////////////////////////////////////////
// Start SDK
await Flagship.start("your_env_id", "your_api_key");
Visitor visitor1 =
Flagship.newVisitor("visitor_1")
.withContext({"isVip": true})
.hasConsented(true)
.isAuthenticated(true).build();
// import package
import 'package:flagship/flagship.dart';
/////////////////////////////////////////////////////////////
// Create visitor when SDK is ready, using the statusListener
/////////////////////////////////////////////////////////////
FlagshipConfig customConfig = ConfigBuilder()
.withMode(Mode.DECISION_API)
.withStatusListener((newStatus) {
// When the status is Ready
if (newStatus == Status.READY) {
// Get the current visitor
if (Flagship.getCurrentVisitor() == null) {
// Create new visitor when the current visitor is null
// By default the created visitor is a shared instance
Flagship.newVisitor("user")
.withContext({"isVip": true})
.hasConsented(true)
.isAuthenticated(true)
.build();
}
// Fetch flags
Flagship.getCurrentVisitor()?.fetchFlags().whenComplete(() {
// Do things
});
}
})
.withTimeout(2500)
.withLogLevel(Level.ALL)
.build();
// Start SDK
Flagship.start(
"your_env_id", "your_api_key",
config: customConfig);
Get & Set the current visitor
Most of the time, your Flutter application will handle only 1 visitor at any given time.
For this use case, Flagship implement 2 useful methods to store the created visitor as the current singleton visitor instance.
static setCurrentVisitor(Visitor visitor)
Stores the current visitor instance created at the newVisitor.
// import package
import 'package:flagship/flagship.dart';
//////////////////////////////////////////
/////// set the current visitor //////////
//////////////////////////////////////////
// Create not shared instance visitor
Visitor newVisitor = Flagship.newVisitor("visitor_1", instanceType: Instance.NEW_INSTANCE)
.withContext({"isVip": true})
.hasConsented(true)
.isAuthenticated(true)
.build();
// Set as current visitor
Flagship.setCurrentVisitor(newVisitor);
static Visitor? getCurrentVisitor()
Return the current visitor instance stored when setting the current visitor.
// import package
import 'package:flagship/flagship.dart';
//////////////////////////////////////////
/////// Get the current visitor //////////
//////////////////////////////////////////
var visitor = Flagship.getCurrentVisitor();
This method returns a nullable Visitor (in case the current visitor has not been previously set).
Make sure to check whether it is null or not before using it.
Updating the visitor context
The visitor context is a property dataset that defines the current visitor of your app. This dataset is sent and used by the Flagship Decision API as targeting criteria for campaign assignment.
The following method from the Visitor
instance allows you to set new context values matching the given keys.
void updateContext(String key, Object value)
Update the visitor context values, matching the given keys, used for targeting.
Only String, bool, int, double typed values are accepted.
Parameter | Type | Description |
---|---|---|
key | String | Context key. |
value | Object | Context value. |
void updateContextWithMap(Map<String, Object> context)
Update the visitor context values, matching the given keys, used for targeting.
Only String, bool, double and int type values are accepted.
Parameter | Type | Description |
---|---|---|
context | Map<String, Object> | Map of keys, values. |
- User context keys must have a type of
String
- User context values must have a type of
String
,bool
,double
orint
- User context keys and values are case sensitive
void updateFlagshipContext<T>(FlagshipContext flagshipContext, T value)
Update the context with a predefined context see FlagshipContext
Parameter | Type | Description |
---|---|---|
flagshipContext | FlagshipContext | Predefined context key, see FlagshipContext |
value | T | value of the associated Predefined key |
// import package
import 'package:flagship/flagship.dart';
//////////////////////////////
/////// Update context ///////
//////////////////////////////
var currentVisitor = Flagship.getCurrentVisitor();
// Update context with key/value
currentVisitor?.updateContext("lastPurchaseDate", 1615384464);
// Update context with Map
currentVisitor?.updateContextWithMap({"isVip": true, "key1": 12.5, "key2": "title", "key3": 2});
// Update the location country
currentVisitor?.updateFlagshipContext(FlagshipContext.LOCATION_COUNTRY, "FRANCE");
// Update the carrier name
currentVisitor?.updateFlagshipContext(FlagshipContext.CARRIER_NAME, "SFR");
void clearContext()
Clear the visitor context values, used for targeting.
// Import package
import 'package:flagship/flagship.dart';
/////////////////////////////
/////// Clear context ///////
/////////////////////////////
var currentVisitor = Flagship.getCurrentVisitor();
currentVisitor?.clearContext();
Managing visitor campaigns and theirs flags
Fetching Flags
The fetchFlags()
method of the visitor
instance automatically calls the Flagship Decision API to run campaign assignments according to the current visitor context and retrieve applicable flags.
These flags are updated asynchronously when fetchFlags()
is called.
/////////////////////////////////////////
/////// Fetch Flags ///////
/////////////////////////////////////////
import 'package:flagship/flagship.dart';
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch Flags
currentVisitor?.fetchFlags().whenComplete(() {
// The fetch is done.
// If the panic mode is ON or the fetch fail for another reason
// the value for flag will be a default value
});
Future<void> fetchFlags() async
This function will call the decision api and update all the campaigns flags from the server according to the visitor context.
Getting flags
Once the campaign has been assigned and fetched, all the flags are stored in the SDK.
You can retrieve these flags using the following functions from the Visitor
instance:
////////////////////////////////
/////// Get Flag ///////
////////////////////////////////
import 'package:flagship/flagship.dart';
import 'package:flagship/model/flag.dart';
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch flags
currentVisitor?.fetchFlags().whenComplete(() {
// Ex: get flag for vip feature
Flag flag = currentVisitor.getFlag("displayVipFeature",false);
});
// The getFlag function can be directly called through the "currentVisitor" instance if you
// already fetched it elsewhere in the application
Flag getFlag<T>(String key, T defaultValue)
Retrieve a Flag object by its key. If no flag match the given key an empty flag will be returned. Call exists() to check if the flag has been found.
Parameter | Type | Required | Description |
---|---|---|---|
key | String | Yes | Key associated to the modification. |
defaultValue | T | Yes | Flag default value to return. |
Getting flags current values
To retrieve flag current value, simply call value() method of the Flag object.
dynamic value({bool visitorExposed: true})
Returns the value from the assigned campaign variation or the Flag default value if the Flag does not exist, or if types are different.
Parameter | Type | Default value | Description |
---|---|---|---|
visitorExposed | bool | true | Tells Flagship the visitor have been exposed and have seen this flag. This will increment the visits for the current variation on your campaign reporting. If needed it is possible to set this param to false and call visitorExposed() afterward when the visitor has really been exposed to it. |
import 'package:flagship/flagship.dart';
import 'package:flagship/model/flag.dart';
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch flags
currentVisitor?.fetchFlags().whenComplete(() {
// Ex: get flag for vip feature
Flag flag = currentVisitor.getFlag("displayVipFeature", false);
// Use this flag value to enable displaying the vip feature
bool shouldDisplayVipFeature = flag.value();
});
When the value of flag is null the value() method return the defaultValue
Getting flags campaigns metadata
You may need to send campaign's informations to a third-party for reporting and/or analytics purposes. The metadata
method returns a dictionary with values you can use.
FlagMetadata metadata()
Return the campaign metadata or an empty object if the Flag doesn't exist or if the default value type does not correspond to the Flag type in Flagship.
import 'package:flagship/flagship.dart';
import 'package:flagship/model/flag.dart';
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch flags
currentVisitor?.fetchFlags().whenComplete(() {
// Ex: get flag for vip feature
Flag flag = currentVisitor.getFlag("displayVipFeature", false);
// Use this flag value to enable displaying the vip feature
bool shouldDisplayVipFeature = flag.value();
// Use this flag to get the metadata
FlagMetadata metadata = flag.metadata();
});
The metadata
you can access to are the following one:
FSFlagMetadata | Type | Default value | Description |
---|---|---|---|
campaignId | String | "" | id of the campaign |
campaignName | String | "" | Name of the campaign |
variationGroupId | String | "" | Id of the variation group |
variationGroupName | String | "" | Name of the variation group |
variationId | String | "" | id of the variation assigned |
variationName | String | "" | Name of the variation |
isReference | bool | false | if true that means the assigned variation is the reference, otherwise it's not. |
campaignType | String | "" | Type of the campaign. Ex: AB |
slug | String | "" | campaign slug or empty string if not configured in the platform |
Report a Flag exposition
Deprecated
The userExposed method is deprecated since the version 2.1.0. please use visitorExposed instead.
By default when the method value()
is called, the SDK considers that the visitor has seen your Flag unless you pass false
to value()
. In this last case, you will have to call the visitorExposed()
method.
There are two options for exposing a visitor to a flag:
1 - Pass an visitorExposed = true parameter to the value() method.
2 - Use the following visitorExposed() method from the Flag instance.
Future<void> visitorExposed() async
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch flags
currentVisitor?.fetchFlags().whenComplete(() {
// Ex: get flag for vip feature
Flag flag = currentVisitor.getFlag("displayVipFeature", false);
// Use this flag value to enable displaying the vip feature with expose to false
bool shouldDisplayVipFeature = flag.value(visitorExposed: false);
// Expose this flag later in the code
flag.visitorExposed();
});
Reminder
The onVisitorExposed is triggered when this callback is defined in configuration options
and the visitorExpose() method success.
Check if a Flag exists
bool exists()
This method will returntrue
if a Flag has been returned by Flagship.
// Get the current visitor
var currentVisitor = Flagship.getCurrentVisitor();
// Fetch flags
currentVisitor?.fetchFlags().whenComplete(() {
// Ex: get flag for vip feature and check if it exists
bool isDisplayVipFeatureExists = currentVisitor.getFlag("do_not_exists", false).exists();
});
}
Managing visitor consent
The Visitor class provides a method to let you manage visitor consent for data privacy usage. When false the activation and hits will be disabled.
//////////////////////////////////////
/////// Manage visitor consent ///////
//////////////////////////////////////
// Create visitor with no consent
var visitor = Flagship.newVisitor(visitorIdController.text, visitorContext, hasConsented:false);
// Set the consent to true on run time
visitor.setConsent(true);
Experience Continuity
Dealing with anonymous and logged-in users, experience continuity allows you to maintain consistency between sessions and devices.
Make sure that the experience continuity option is enabled on the flagship platform before using those methods.
Authenticate
There are 2 ways to authenticate a visitor:
- Set isAuthenticated to true when creating a new visitor
- Use authenticate method of Visitor instance
Authenticate anonymous visitor
authenticateVisitor(String pVisitorId)
Parameter | Type | Description |
---|---|---|
pVisitorId | String | id of the new authenticated visitor. |
Because we have changed the visitor data, we have to call the fetchFlags method after calling this one to update the decision from Flagship.
The targeting / Flags could be different for the visitor.
Unauthenticate
This function change authenticated Visitor to anonymous visitor
unAuthenticateVisitor()
Because we have changed the visitor datas, we have to call the fetchFlags method after calling this one to update the decision from Flagship.
The targeting / Flags could be different for the visitor.
code Example
Let's assume basic scenario to understand how things work:
- Your visitor arrives on your app for the first time.
We need to initialize the visitor but as we don't know anything about this visitor, we'll create a random_Id. You can also specify some visitor context if necessary.
// Create visitor with random_Id
Visitor visitor = Flagship.newVisitor("random_Id").withContext({"isVip": true}).build();
// Fetch flags
visitor.fetchFlags().whenComplete(() {
// .. Do things
});
The actual random_Id will be what we call the anonymous id.
- Your visitor is signing in.
To tell the SDK about this status modification, you'll have to call the authenticate function which takes the required visitor id as argument.
// Example
// You fetch the visitor_id from your DB
// let visitorId = db.getUserId();
// Authenticate
visitor.authenticate("visitorId");
// Since your visitor has changed (is now logged-in)
// You have to check if the proper targeting and flags are set
visitor.fetchFlags().whenComplete(() {
// .. Do things
});
The visitor is updated as authenticated, keeping the previous variations from campaigns that are still matched and thus gives you same flags as before being logged in.
- Your visitor decides to sign out.
If you want to keep the same visitor experience, then you should do:
// Unauthenticate
visitor.unauthenticate();
// Since your visitor has changed (is now logged-out)
// You have to check if the proper targeting and flags are set
visitor.fetchFlags().whenComplete(() {
// .. Do things
});
Final implementation example
// Create a visitor
Visitor visitor = Flagship.newVisitor("random_Id").withContext({"isVip": true}).build();
// Fetch flags
visitor.fetchFlags().whenComplete(() {
// ... Do things ....
});
// You fetch the visitor_id from your DB
// let visitorId = db.getUserId();
// Call the authenticate function
visitor.authenticate("visitorId");
// Fetch the flags to update the visitor decision
visitor.fetchFlags().whenComplete(() {
// ... Do things ....
});
// If you want to unauthenticate the visitor
visitor.unauthenticate();
// Fetch the flags to update the visitor decision
visitor.fetchFlags().whenComplete(() {
// ... Do things ....
});
Managing visitor cache
The role of cache management is to avoid data lost
and keep SDK working correctly in the offline mode. Also in the bucketing mode will prevent against the Re-allocation
Offline mode
The SDK use the last cached data relative to visitor (campaign assignations) and cache events analytics in order to report them later.
Re-allocation
In Bucketing mode the visitor keeps his initial variation chosen by the bucket process even if the allocation changes.
Flagship's architecture allows the client to set his own custom cache manager by implementing the interfaces IVisitorCacheImplementation and IHitCacheImplementation. see the configuration
Flagship Flutter SDK provide a default cache manager implementation.
Interface IVisitorCacheImplementation
This protocol specifies the methods to implement in order to cache information visitor.
void cacheVisitor(String visitorId, String jsonString)
This method called after each fetchFlags. Must upsert the given visitor jsonString in the database.
Parameter | Type | Description |
---|---|---|
visitorId | String | Visitor ID |
jsonString | String | Represent json visitor data |
Future<String> lookupVisitor(String visitoId)
This method is called right at visitor creation, return a jsonString corresponding to visitor.
Parameter | Type | Description |
---|---|---|
visitorId | String | Visitor ID |
Future | String | Return a future String that represent json of visitor data |
void flushVisitor(String visitorId)
This method is called when the SDK needs to erase the visitor information corresponding to visitor ID in the database.
It will be called every time setConsent get false.
Parameter | Type | Description |
---|---|---|
visitorId | String | Visitor ID |
Interface IHitCacheImplementation
void cacheHits(Map<String, Object> hits)
This method will be called to cache hits depending on the cache strategy used.
Parameter | Type | Description |
---|---|---|
hits | Map<String, Object> | key/value object where the : - key is a unique ID for each hit - value is an object that represent hit |
Future<List<Map>> lookupHits()
This method will be called to load all hits from your database and trying to send them.
Parameter | Type | Description |
---|---|---|
List | List | Return as future a list of hit , each hit represented with Map (key, value) - key : is unique Id for the hits in the database - value : object that represent the cached hit |
void flushHits(List<String> hitIds)
This method will be called to erase all hits in your database without exception.
Parameter | Type | Description |
---|---|---|
hitIds | List | Ids of hits |
void flushAllHits()
This method must remove all hits in the database without exception.
Final implementation example
// Implement IHitCacheImplementation
class CustomCacheHit with IHitCacheImplementation {
@override
void cacheHits(Map<String,Object> hits) {
// Save the Map that represent {"hitId": {data hit}}
}
@override
void flushAllHits() {
// Remove all hits in database
}
@override
void flushHits(List<String> hitIds) {
// Remove the hit's id given with List
}
@override
Future<List<Map>> lookupHits()async {
// Return the saved hit in your database
}
}
// Implement IVisitorCacheImplementation
class CustomVisitorCache with IVisitorCacheImplementation {
@override
void cacheVisitor(String visitorId, String jsonString) {
// Save the json that represent the data information for visitorId
}
@override
void flushVisitor(String visitorId) {
// Remove the data for visitorId
}
@override
Future<String> lookupVisitor(String visitoId) async {
// Return the saved data to visitorId
}
}
// Create a config object and specify the custom hit and custom visitor
var config = ConfigBuilder()
.withCacheHitManager(CustomCacheHit())
.withCacheVisitorManager(CustomVisitorCache())
.build();
// Start the SDK with the config
await Flagship.start("envId", "apiKey", config: config);
Hit Tracking
This section helps send tracking and learn how to build hits in order to track campaign goals.
The different types of Hits are:
They must all be built and sent with the following method of the visitor instance:
Future<void> SendHit(hit HitProtocol)
Common parameters
These parameters can be sent with any type of hit.
Parameter | Type | Description |
---|---|---|
userIp | String | optional User IP |
screenResolution | String | optional Screen Resolution. |
userLanguage | String | optional User Language |
sessionNumber | int | optional Session Number |
Hit types
Screen
This hit should be sent each time a visitor arrives on a new interface.
Hit parameter | Type | Required | Description |
---|---|---|---|
location | String | Yes | Name of the screen |
//////////////////////////
/////// Screen hit ///////
//////////////////////////
var visitor = Flagship.getCurrentVisitor();
// Send screen hit
visitor?.sendHit(Screen(location: "My page"));
Page
This hit should be sent each time a visitor arrives on web page in an embedded web view
Hit parameter | Type | Required | Description |
---|---|---|---|
location | String | Yes | Valid url |
//////////////////////////
/////// Page hit ///////
//////////////////////////
var visitor = Flagship.getCurrentVisitor();
// Send page hit
visitor?.sendHit(Page(location: "https://www.my_domain_com/my_page"));
Transaction
This hit should be sent when a user complete a Transaction.
Hit Parameter | Type | Required | Description |
---|---|---|---|
transactionId | String | Yes | Transaction unique identifier. |
affiliation | String | Yes | Transaction name. Name of the goal in the reporting. |
revenue | double? | No | Total revenue associated with the transaction. This value should include any shipping or tax costs. |
shipping | double? | No | Specifies the total shipping cost of the transaction. |
shippingMethod | String? | No | Specifies the shipping method of the transaction. |
tax | double? | No | Specifies the total taxes of the transaction. |
currency | String? | No | Specifies the currency used for all transaction currency values. Value should be a valid ISO 4217 currency code. |
paymentMethod | String? | No | Specifies the payment method for the transaction. |
itemCount | int? | No | Specifies the number of items for the transaction. |
couponCode | String? | No | Specifies the coupon code used by the customer for the transaction. |
///////////////////////////////
/////// Transaction hit ///////
///////////////////////////////
var visitor = Flagship.getCurrentVisitor();
visitor?.sendHit(Transaction(
transactionId : "YOUR_TRANSACTION_ID",
affiliation : "GOAL_NAME", // The goal name set in Flagship campaign
revenue : 100,
shipping : 10,
tax : 5,
currency : "EUR",
couponCode : "discount",
paymentMethod : "Card",
shippingMethod : "postal",
itemCount : 2,
));
Item
This hit is linked to a transaction. It must be sent after the corresponding transaction.
Hit Parameter | Type | Required | Description |
---|---|---|---|
transactionId | String | Yes | Transaction unique identifier. |
name | String | Yes | Product name. |
code | String | Yes | Specifies the item code or SKU. |
price | double? | No | Specifies the item price. |
category | String? | No | Specifies the item category. |
quantity | int? | No | Specifies the item quantity |
////////////////////////
/////// Item hit ///////
////////////////////////
var visitor = Flagship.getCurrentVisitor();
visitor?.sendHit(Item(
transactionId : "YOUR_TRANSACTION_ID",
name : "item name",
code : "item code",
price : 10.5,
quantity : 5,
category : "item category"
));
Event
This hit can be anything you want: for example a click or a newsletter subscription.
Hit Parameter | Type | Required | Description |
---|---|---|---|
Category | EventCategory | Yes | Category of the event ("Action_Tracking" or "User_Engagement"). |
Action | String | Yes | The event action. Should match the goal name of the campaign |
Label | String | No | Label of the event. |
Value | int | No | Specifies a value for this event. must be non-negative. |
/////////////////////////
/////// Event hit ///////
/////////////////////////
var visitor = Flagship.getCurrentVisitor();
visitor?.sendHit(Event(
action : "Event action", // The name of the goal defined in your campaign
category : EventCategory.Action_Tracking,
label : "custom label",
value : 2
));
Appendix
Predefined user context keys
The Flagship SDK contains predefined user context keys.
The keys marked as Yes in the Auto-set by SDK column will be automatically set, while the ones marked as No need to be set by the client.
They are nevertheless overridable at anytime. Then these predefined context keys-value pairs will be sent to the server and be editable in the Persona section of the Flagship platform.
SDK Variable name | Description | Context Variable name | Type | Auto-set by SDK | Example |
---|---|---|---|---|---|
FIRST_TIME_INIT | First init of the app | sdk_firstTimeInit | bool | Y | true |
DEVICE_LOCAL | Language of the device | sdk_deviceLanguage | String | Yes | fr_FR |
DEVICE_TYPE | Type fo the device | sdk_deviceType | String | Yes | mobile |
LOCATION_CITY | City geolocation | sdk_city | String | No | Paris |
LOCATION_REGION | Region geolocation | sdk_region | String | No | ile de france |
LOCATION_COUNTRY | Country geolocation | sdk_country | String | No | France |
LOCATION_LAT | Current Latitude | sdk_lat | Double | No | 43.623647 |
LOCATION_LONG | Current Longitude | sdk_long | Double | No | 1.445397 |
OS_NAME | Name of the OS | sdk_osName | String | Yes | iOS / macOS |
OS_VERSION_CODE | Version of OS | sdk_osVersionCode | String | Yes | 9.0 |
MVNO / carrierName | Mobile virtual network operator | sdk_carrierName | String | No | orange |
DEV_MODE | Is the app in debug mode? | sdk_devMode | bool | No | true |
INTERNET_CONNECTION | What is the internet connection | sdk_internetConnection | String | No | 4G |
APP_VERSION_NAME | Version name of the app | sdk_versionName | String | No | 1.1.2-beta |
APP_VERSION_CODE | Version code of the app | sdk_versionCode | int | No | 40 |
FLAGSHIP_VERSION | Version of the Flagship SDK | sdk_fsVersion | String | Yes | 3.0 |
INTERFACE_NAME | Name of the interface | sdk_interfaceName | String | No | ProductPage |
Here you can see how a predefined key is used to filter a report in the Flagship interface:
Updated 10 months ago