Reference

Flagship class

To run experiments with Flagship, you will need to start the SDK using:

Start method

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

No

Object that represents client's configuration

📘

You can get your own envId & API Key in the Flagship Platform.

  1. Navigate to SettingsAPI Key & Settings

  2. Copy the environment ID & API Key

Flagship uses predefined context keys to help you retrieve data in the reporting, those keys can be the language, Flagship version but can also be some device information.

That's the reason you have to « wait » the device information 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");

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.

SdkStatusChanged :

This callback is triggered when SDK status has changed.

  • ConfigBuilder onSdkStatusChanged(SdkStatusChanged pSdkStatusChanged)

The SdkStatusChanged is defined as :

  • typedef SdkStatusChanged = void Function(FSSdkStatus newStatus)?

Parameter
Type
Description

pSdkStatusChanged

SdkStatusChanged

Indicate the actual status of the sdk. It 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 the detail of log's level 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 reports 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 makes 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);

Visitor Exposed Callback

In some cases, you'll need to send information 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 represents the visitor exposed

fromFlag

ExposedFlag

This class represent the flag exposed. (The flag that has triggered the exposition)

VisitorExposed

The class VisitorExposed gives 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 a Map or dictionary depend on the language

ExposedFlag

The class ExposedFlag gives us the flag's information

Parameter
Type
Description

key

String

key for flag

value

Any

value for the flag

defaultValue

Any

default value

metadata()

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:

newVisitor method

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 newVisitor({required String visitorId, required bool hasConsented,Instance instanceType = Instance.SINGLE_INSTANCE})

Parameter
Type
Required
Description

visitorId

String

yes

Unique visitor identifier

hasConsented

bool

yes

* *true**when visitor has given consent,**false** otherwise.

instanceType

Instance

no

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:

Represents 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

  • 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 uses predefined context keys to help you retrieve data in the reporting, those keys can be the location, IP but can also be some device information.

That's the reason you have to « wait for » the process to gather the device's information.

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(visitorId:"visitor_1",hasConsented: true)
              .withContext({"isVip": true})
              .isAuthenticated(true).build();

Visitor flags status callback

Flag Status Changed

  • VisitorBuilder withOnFlagStatusChanged(OnFlagStatusChanged pCallback)

OnFlagStatusChanged is typedef

Parameter
Type
Description

pCallback

OnFlagStatusChanged

This callback will be triggered each time the fetchStatus has changed

typedef OnFlagStatusChanged = void Function(FlagStatus newStatus)?

// Start The sdk
Flagship.start("envId", "apiKey");

// Create visitor with withOnFlagStatusChanged callback
Flagship.newVisitor(visitorId: "userId", hasConsented: true)
.withOnFlagStatusChanged((status) {
  switch (status) {
    case FlagStatus.FETCHED:
    // TODO: Handle this case
    break;
    case FlagStatus.FETCHING:
    // TODO: Handle this case.
    break;
    case FlagStatus.FETCH_REQUIRED:
    // TODO: Handle this case.
    break;
    case FlagStatus.NOT_FOUND:
    // TODO: Handle this case.
    break;
    case FlagStatus.PANIC:
    // TODO: Handle this case.
    break;
  }
});

Flag Status FetchRequired

  • VisitorBuilder withOnFlagStatusFetchRequired(OnFlagStatusFetchRequired pCallback)

OnFlagStatusFetchRequired is typedef

Parameter
Type
Description

pCallback

OnFlagStatusFetchRequired

This callback will be triggered each time the fetchStatus is equal to FETCH_REQUIRED.

typedef OnFlagStatusFetchRequired = void Function(FetchFlagsRequiredStatusReason reason)?

Parameter
Type
Description

reason

Represent the reason for the required status.

// Start The sdk
Flagship.start("envId", "apiKey");

// Create visitor with withOnFlagStatusFetchRequired callback
Flagship.newVisitor(visitorId: "userId", hasConsented: true)
.withOnFlagStatusFetchRequired((reason) {
  switch(reason){
    case FetchFlagsRequiredStatusReason.FLAGS_NEVER_FETCHED:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.VISITOR_CONTEXT_UPDATED:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.VISITOR_AUTHENTICATED:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.VISITOR_UNAUTHENTICATED:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.FLAGS_FETCHING_ERROR:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.FLAGS_FETCHED_FROM_CACHE:
    // TODO: Handle this case.
    break;
    case FetchFlagsRequiredStatusReason.NONE:
    // TODO: Handle this case.
    break;
  }
});

Flag Status Fetched

  • VisitorBuilder withOnFlagStatusFetched(OnFlagStatusFetched pCallBack)

OnFlagStatusFetched is typedef

Parameter
Type
Description

pCallback

OnFlagStatusFetched

this callback will be triggered each time the fetchStatus is equal to FETCHED.

typedef OnFlagStatusFetched = void Function()?

// Start The sdk
Flagship.start("envId", "apiKey");

// Create visitor with withOnFlagStatusFetched callback
Flagship.newVisitor(visitorId: "userId", hasConsented: true)
	.withOnFlagStatusFetched(() {
          // Add your code 
  });

Get & Set the current visitor method

Most of the time, your Flutter application will handle only 1 visitor at any given time. For this use case, Flagship implements 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(visitorId: "visitor_1",hasConsented: true, instanceType: Instance.NEW_INSTANCE)
        						.withContext({"isVip": true})
        						.isAuthenticated(true)
        						.build();

// Set as current visitor
Flagship.setCurrentVisitor(newVisitor);

static Visitor? getCurrentVisitor()

Returns 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();

getStatus method

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 :

FSSdkStatus
Description

SDK_NOT_INITIALIZED

The SDK has not been started.

SDK_INITIALIZING

The SDK is still starting. In bucketing mode the sdk needs to download the ressources (bucketing file) before starting. if the file already exists, this status is skipped.

SDK_INITIALIZED

The SDK is ready to be used.

SDK_PANIC

The SDK is ready, but it is running in Panic mode: All visitor's features are disabled except 'fetchFlags' which refreshes this status.

// Get the current status for the SDK
   var currentStatus = Flagship.getStatus();

// Using getStatus to check if the SDK is SDK_INITIALIZED

// Create the visitor 
   var visitor = Flagship.newVisitor(visitorId: "user1", hasConsented: true).withContext({"isVip":true}).build();

// Fetch Flags the modifications 
   visitor.fetchFlags().whenComplete(() {
    
// Get the status and check the mode
   Status currentState =  Flagship.getStatus();
    if (currentState == Status.SDK_INITIALIZED) {
      // The SDK is INITIALIZED
    }
  });

Visitor class

updateContext method

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 or int

    • 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");

clearContext method

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();

fetchFlags method

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.

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

flagStatus property

FlagStatus enum parameter belongs to the visitor instance, and it reflects the status of the visitor's fetching workflow.

  • FETCHED The flags are fetched from the API or re-evaluated in bucketing mode and up to date.

  • FETCHING Flags are currently being fetched from the API or re-evaluated in bucketing mode.

  • FETCH_REQUIRED Flags need to be re-fetched due to a change in the visitor context, visitor authentication or because the flags were loaded from cache.

  • PANIC The SDK is in PANIC mode: All features are disabled except for the one to fetch flags. Flags default value will be returned.

enum FlagStatus { 
  // The flags are fetched from the API or re-evaluated in bucketing mode and up to date.
  FETCHED, 
  // Flags are currently being fetched from the API or re-evaluated in bucketing mode.
  FETCHING, 
  // Flags need to be re-fetched due to a change in the visitor context, visitor authentication or because the flags were loaded from cache.
  FETCH_REQUIRED,
  // The SDK is in PANIC mode: All features are disabled except for the one to fetch flags. Flags default value will be returned.
  PANIC 
}

fetchReasons property

Speaking of flagStatus values related to workflow, we noticed that FETCH_REQUIRED is confusing sometimes because it may come from different scenarios.

The SDK provides a new smart indicator that gives you the main reason why visitor flags need to be re-evaluated. FetchFlagsRequiredStatusReason enum belongs to the visitor instance with these possible values:

  • FLAGS_NEVER_FETCHED Indicate that the visitor has been created for the first time or without cache. VISITOR_CONTEXT_UPDATED Indicates that a context has been updated or changed.

  • VISITOR_AUTHENTICATED Indicates that the XPC method 'authenticate' has been called.

  • VISITOR_UNAUTHENTICATED Indicates that the XPC method 'unauthenticate' has been called.

  • FLAGS_FETCHING_ERROR Indicates that fetching flags has failed.

  • FLAGS_FETCHED_FROM_CACHE Indicates that flags have been fetched from the cache.

  • NONE No reason; the state should be FETCHED, FETCHING, PANIC.


enum FetchFlagsRequiredStatusReason {
  // Indicate that the visitor is created for the first time or without cache
  FLAGS_NEVER_FETCHED,
  // Indicates that a context has been updated or changed.
  VISITOR_CONTEXT_UPDATED,
  // Indicates that the XPC method 'authenticate' has been called.
  VISITOR_AUTHENTICATED,
  // Indicates that the XPC method 'unauthenticate' has been called.
  VISITOR_UNAUTHENTICATED,
  // Indicates that fetching flags has failed.
  FLAGS_FETCHING_ERROR,
  // Indicates that flags have been fetched from the cache.
  FLAGS_FETCHED_FROM_CACHE,
  // No reason; the state should be  FETCHED,  FETCHING, PANIC
  NONE
}

getFlag method

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

// 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)

Retrieve a Flag object by its key. If no flag matches 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.

getFlags method

Return a collection that contains all current flags on the SDK. Go to FlagCollection for more information.

  • FlagCollection getFlags()

setConsent method

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(visitorId: "user1", hasConsented: false).withContext({"isVip":true}).build()
// Set the consent to true on run time
visitor.setConsent(true);

authenticate method

There are 2 ways to authenticate a visitor:

  1. Set isAuthenticated to true when creating a new visitor

  2. Use authenticate method of Visitor instance Authenticate anonymous visitor

  • authenticate(String visitorId)

Parameter
Type
Description

visitorId

String

id of the new authenticated visitor.

unauthenticate method

This function change authenticated visitor to anonymous visitor.

  • unauthenticate()

Experience Continuity - Code example

Dealing with anonymous and logged-in users, experience continuity allows you to maintain consistency between sessions and devices.

Let's assume basic scenario to understand how things work:

  1. 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(visitorId: "random_Id", hasConsented: true).withContext({"isVip": true}).build();
// Fetch flags
  visitor.fetchFlags().whenComplete(() {
    // .. Do things
  });

The actual random_Id will be what we call the anonymous id.

  1. 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 an 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 giving you the same flags as before being logged in.

  1. 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(visitorId: "random_Id", hasConsented: true).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 ....
});

SendHit method

Future<void> SendHit(hit HitProtocol)

This function sends hits to flagship servers for reporting; go to the hit section for more information.

Parameter
Type
Description

event

HitProtocol

event can be Screen, Transaction, Item, Event See Hit Tracking

Flag class

value method

To retrieve the flag's current value, simply call the value() method of the Flag object.

  • dynamic value<T>(T? defaultValue, {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
Description

defaultValue

Generic

Represents a fallback value if something goes wrong.

visitorExposed

bool

Tells Flagship: The visitor has been exposed and has seen this flag. This will increment the visits for the current variation on your campaign reporting. If needed, it is possible to set this parameter to false and call visitorExposed() afterward when the visitor has really been exposed to it.

Return

Generic

Returns the flag value or the fallback.

📘

The default value for visitorExposed is true.

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");
     // Use this flag value to enable displaying the vip feature
     // The default value is false
     bool shouldDisplayVipFeature = flag.value(false);
   });

📘

When the value of flag is null , the value() method returns the defaultValue

metadata method

You may need to send the campaign's information to a third party for reporting and/or analytics purposes. The metadata method returns a dictionary with values you can use.

  • FlagMetadata metadata() Returns 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:

FlagMetadata
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.

visitorExposed method

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");

   // Use this flag value to enable displaying the vip feature with expose to false
   bool shouldDisplayVipFeature = flag.value(true, 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.

exists method

  • bool exists() This method will return trueif 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").exists();
   });
 }

getFlagStatus method

  • FlagStatus getFlagStatus()

Returns the status of flag.

Parameter
Type
Description

Return

FlagStatus

The status of the flag.

This FlagStatus can have one of these possible values:

  • FETCHED The flags are fetched from the API or re-evaluated in bucketing mode and up to date.

  • FETCH_REQUIRED Visitor context, visitor authentication have been updated while flags have not been re-evaluated.

  • NOT_FOUND The flag was not found when creating the flag instance.

  • PANIC The SDK is in PANIC mode, default flags values will be returned.

FlagCollection class

This class represents a Map<String, Flag>

Instance Subscript

  • Flag operator [](String key)

Parameter
Type
Description

key

String

The key representing the flag in the Map

Return

Flag

The value associated with key if key is in the dictionary; otherwise, return an empty Flag object.

Getting keys

Return all keys present and available in the SDK.

  • Iterable<String> keys()

Parameter
Type
Description

Return

List

List of string keys associated to flag

Getting metadata

Return List of metadata

  • List<FlagMetadata> metadatas()

Parameter
Type
Description

Return

List

List of FlagMetadata

toJson method

  • String toJson()

Provide a string representation of a JSON object that represents all metadata.

parameter
Type
Description

Return

String

JSON Representation. Return an empty string if no metadata is available.

📘

If metadata is not found ===> return an empty string

Assume we have two flags btnTitle and btnColor. The returned string from the call toJson() function is

{
  {
    "key":"btnTitle",
    "campaignId": "xxxxxxxxxx",
    "campaignName": "xxxxxxx",
    "variationGroupdId": "xxxxxxxxxx",
    "variationGroupName": "xxxxxxxxx",
    "variationId": "xxxxxxxxxx",
    "isReference": false,
    "campaignType": "ab",
    "slug": "xxxx"
   },
   {
    "key":"btnColor",
    "campaignId":"xxxxxxxxxx",
    "campaignName": "xxxxxxx",
    "variationGroupdId":"xxxxxxxxxx",
    "variationGroupName":"xxxxxxxxx",
    "variationId":"xxxxxxxxxx",
    "isReference": false,
    "campaignType": "ab",
    "slug": "xxxx"
   }
}

Filetring

Returns a new Map containing the key-value pairs of the Map that satisfy the given condition.

  • FlagCollection filter(bool Function(String, Flag) isIncluded)

Parameter
Type
Description

isIncluded

bool

A Function that takes a key-value pair as its argument and returns a bool value indicating whether the pair should be included in the returned Map.

Return

FlagCollection

The key-Flag pairs that isIncluded allows.

// User get all flag
FlagCollection flagCollection = visitor.getFlags();
// Apply filter
var result = flagCollection.filter((keyFlag, flag){
          return flag.metadata().campaignId == "Original";
 });
 // result will contain a flag that correspond to the condition : variationName == "Original"

Iterator

Applies [action] to each key/value pair of the map.

  • void forEach(void action(String key, Flag value))

Parameter
Type
Description

action

Function

action to each key/value pair of the map.

// User get flag collection
FlagCollection flagCollection = visitor.getFlags();
// Apply forEach
// Expose flags associated with the variationName == "Original"
flagCollection.forEach((keyFlag, flag) {
  if (flag.metadata().campaignName == "Original") {
       flag.visitorExposed();
     }
});

exposeAll method

From the collection instance, we are able to expose all flags in one call.

  • void exposeAll()

isEmpty property

Whether there is no key/value pair in the map. Read only property

count property

The number of key/value pairs in the map. Read only property

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 is 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>

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.

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<String>

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:

Last updated

Was this helpful?