Reference
Flagship
class
Flagship
classThe SDK is represented by the Flagship
class. It simplifies the process of creating new visitors and configuration
Start
method
Start
methodTo run experiments with Flagship, you will need to start the SDK.
Flagship uses a sharedInstance
then create a visitor to activate experiments and track events.
func start(envId:String, apiKey:String, config:FSConfig)
envId
String
Yes
Identifies your Flagship account and environment (pre-prod or prod).
apiKey
String
Yes
Identifies your Flagship api key (pre-prod or prod)
config
FSConfig
No
Object that represent configuration client
import Flagship
//Start the Flagship SDK in Api mode and 5 seconds for timeout.
Flagship.sharedInstance.start(envId:"_ENV_ID_", apiKey: "_API_KEY_",
config: FSConfigBuilder().DecisionApi()
.withTimeout(5000)
.withLogLevel(.ALL).build())
//Start the Flagship SDK in Bucketing mode with custom cache manager
Flagship.sharedInstance.start(envId: "_ENV_ID_", apiKey: "_API_KEY_", config: FSConfigBuilder().Bucketing()
.withTimeout(5000)
.withLogLevel(.INFO)
.withCacheManager(FSCacheManager(customCacheManager))
.build())
Configuration
FlagshipConfig class help you to configure the SDK via the following two available config implementations: DecisionApi and Bucketing. See Decision Mode section.
Timeout
This delay only concerns the request on fetching campaigns under the api mode. If the API didn't answer during this interval of time, the SDK will not wait longer for it and will use the flag values already present on device's cache. If there is no cache yet, the default values will be returned from the getFlag function.
**
func withTimeout(_ timeout:TimeInterval)->FSConfigBuilder
**
timeout
TimeInterval
Milliseconds, default value is 2000 ms
Log Level
func withLogLevel(_ logLevel:FSLevel)->FSConfigBuilder
Specifies a log level to filter logs emitted by the SDK.
level
FSLevel
The levels in ascending order are : NONE(0), EXCEPTIONS(1), ERROR(2), WARNING(3), DEBUG(4), INFO(5), ALL(6).
Decision Mode
DecisionApi
When the SDK is running in DecisionApi mode, the campaign assignments and targeting validation take place on 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 on 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. Learn more
OnSdkStatusChanged
This listener is called when SDK status has changed.
func withOnSdkStatusChanged(_ onSdkStatusChanged: @escaping (_ newStatus: FSSdkStatus)->Void)->FSConfigBuilder
onSdkStatusChanged
is a callback with one parameter FSSdkStatus
Polling Interval Time
Only available for Bucketing Mode:
func withBucketingPollingIntervals(_ pollingTime:TimeInterval)->FSConfigBuilder
Define time interval between two bucketing updates. Default is 60 seconds.
pollingTime
TimeInterval
interval time, default is 60 seconds.
Tracking Config Manager
func withTrackingManagerConfig(_ trackingMgrConfig: FSTrackingManagerConfig)->FSConfigBuilder
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.
Pool Max Size Specifies the maximum number of hits in the pool.
Cache Strategy Define a strategy to adopt, there are two strategies represented by an enum BatchCachingStrategy.
1 - 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 local database.
2 - 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
// Create FSTrackingManagerConfig
// - Time Intreval : 20
// - Maximum size pool : 20
// - Strategy : BATCH_CONTINUOUS_CACHING
let trackingConfig = FSTrackingManagerConfig(poolMaxSize: 20, batchIntervalTimer: 20, strategy: .CONTINUOUS_CACHING)
// Create FlagshipConfig
let conf: FlagshipConfig = FSConfigBuilder().withTrackingConfig(trackingConfig).build()
// Start the SDK Flagship
Flagship.sharedInstance.start(envId: "your_env_id", apiKey: "your_api_key", config: conf)
Cache Management
Use a default cache Management provided by the SDK or create your own custom cache manager .
func withCacheManager(_ customCacheManager:FSCacheManager)->FSConfigBuilder
customCacheManager
FSCacheManager
Managing the cache
FSCacheManager
This class affords two protocols to handle the cache management.
** init(_ visitorCacheImp: FSVisitorCacheDelegate? = nil, _ hitCacheImp: FSHitCacheDelegate? = nil, visitorLookupTimeOut: TimeInterval = 0.2, hitCacheLookupTimeout: TimeInterval = 0.2)**
visitorLookupTimeOut
TimeInterval
200 ms
The time duration milliseconds given to lookup visitor, over this delay the operation is stopped
hitCacheLookupTimeout
TimeInterval
200 ms
The time duration milliseconds given to lookup hits, over this delay the operation is stopped
Developer Usage Tracking
func withDisableDeveloperUsageTracking(_ disableDeveloperUsageTracking: Bool)->FSConfigBuilder
disableDeveloperUsageTracking
Collects information about the usage of SDK. By default the value is set to false otherwise set to true to disable this feature.
Bool
// Create config and disabled usage tracking
let customConfig: FlagshipConfig = FSConfigBuilder().withDisableDeveloperUsageTracking(false).build()
// Start SDK
Flagship.sharedInstance.start(envId: "_ENV_ID_", apiKey: "_API_KEY_", config: customConfig)
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 party tools.
To centralize it, the sdk provides a callback in the configuration option of the SDK.
**
func withOnVisitorExposed(_ onVisitorExposed: OnVisitorExposed)->FSConfigBuilder
**
This callback is triggered each time:
The visitorExposed() method is successfully called through the flag instance.
The value() method is called through the flag instance with "true" as parameter (default).
The OnVisitorExposed callback is a function with two parameters
typealias OnVisitorExposed = ((_ visitorExposed: VisitorExposed, _ fromFlag: ExposedFlag)-> Void)?
visitorExposed
FSVisitorExposed
This class represent the visitor exposed
fromFlag
FSExposedFlag
This class represent the flag exposed. \n(The flag that has triggered the exposition)
FSVisitorExposed
The class FSVisitorExposed give us the visitor's information
id
String
VisitorId
context
Dictionary
The current visitor’s context
FSExposedFlag
The class FSExposedFlag give us the flag's information
key
String
key for flag
value
Any
value for flag
defaultValue
Any
default value
metadata
[FSFlagMetadata](#Getting flags campaigns metadata)
Campaign information metadata, this class already existed
For both class FSVisitorExposed & FSVisitorExposed use toJson() method to get the Json string representation and toDictionary() method to get a dictionary representation.
// Inside the callBack we use toJson() method to get the json String representation.
// This block is a part of confuguration builder, for more information
// go to #flagship-configuration-options section
.withOnVisitorExposed { fromFlag, visitorExposed in
print(fromFlag.toJson() ?? "")
print(visitorExposed.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
}
}
Here is an example on how to use this callback:
newVisitor
method
newVisitor
methodThe visitor
instance is an object that lets you manage the context, activate experiments and track events.
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.
For example, if you wanted to enable or disable a specific feature based on VIP status, you would pass that attribute as a key-value pair in the visitor context so that the Decision API can enable or disable the corresponding feature flag for the visitor.
import Flagship
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"userId", hasConsented:true)
.withContext(context: ["isVip":true])
.isAuthenticated(true)
.build()
public func newVisitor(visitorId: String, hasConsented: Bool, instanceType: Instance = .SHARED_INSTANCE) -> FSVisitorBuilder
visitorId
String
Unique visitor identifier.
hasConsented
Bool
true when visitor has given consent, false otherwise.
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. Use Flagship.sharedInstance.sharedVisitor
to retrieve the instance. NEW_INSTANCE: The newly created visitor instance wont be saved and will simply be returned.
Visitor Builder methods
Context
func withContext(context:[String:Any])->FSVisitorBuilder
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: Number, Boolean, String.
context
[String:Any]
initial context
Consent
func hasConsented(hasConsented:Bool)->FSVisitorBuilder
Specify if the visitor has consented to personal data usage. When false
some features will be deactivated; the cache will be deactivated and cleared. The default value is true
.
hasConsented
Bool
true
when visitor has given consent, false
otherwise
Authenticate
func isAuthenticated(_ autenticated:Bool)->FSVisitorBuilder
The visitorId will be considered as authenticated if true
otherwise is anonymous.
autenticated
Bool
true
for authenticated visitor, false
for anonymous.
Visitor flags status callback
func withFetchFlagsStatus(_ pCallback: OnFetchFlagsStatusChanged)->FSVisitorBuilder
Define a callback to be informed about fetchStatus changes.
OnFetchFlagsStatusChanged is an alias
pCallback
OnFetchFlagsStatusChanged (typealias)
this callback will be triggered each time the **fetchStatus
** has changed.
typealias OnFetchFlagsStatusChanged = ((_ newStatus: FSFetchStatus, _ reason: FSFetchReasons)-> Void)?
OnFetchFlagsStatusChanged is an alias and the signature contain the fetchStatus ans the reason
// 1 - Create visitor
let visitor = Flagship.sharedInstance.newVisitor(visitorId: "visitorId", hasConsented:true).withFetchFlagsStatus { newStatus, reason in
// 2 - In this bloc will have the new fetchState and the reason
}.build()
getStatus
method
getStatus
methodIt is possible to get the current status via the method getStatus() from the Flagship class.
func getStatus() -> FSSdkStatus
Return the current SDK status
List of the possible SDK status :
SDK_NOT_INITIALIZED
The SDK has not been started.
SDK_INITIALIZING
The SDK still starting, in_ bucketing mode_ the sdk needs to download the ressources (bucketing file) before start. if the file exist already this status is skipped.
SDK_INITIALIZED
The SDK is ready to use.
SDK_PANIC
The SDK is ready but is running in Panic mode: All visitor's features are disabled except 'fetchFlags' which refreshes this status.
\
close
method
close
methodWhen your application is about to terminate, you can call the close method of Flagship class, by doing this, the batch process one last time before stop.
But don't worry if the close function is not invoked the data is stored in cache and will be processed on the next start
func close()
// Process one last time the batch process then stop.
Flagship.sharedInstance.close()
Visitor
class
Visitor
classfetchStatus
property
fetchStatus
propertypublic internal(set) var fetchStatus: FetchStatus
This Enum parameter belongs to the visitor instance, and it reflects the status of the visitor's fetching workflow.
All possible value are listed below
FETCHED &#xNAN;Flags have been successfully fetched from the API or re-evaluated in bucketing mode and are up-to-date..
FETCHING &#xNAN;Flags are currently being fetched from the API or re-evaluated in bucketing mode.
FETCH_REQUIRED &#xNAN;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 &#xNAN;The SDK is in PANIC mode: All features are disabled except for the one to fetch flags. Flags default value will be returned.
// The parameter that reflect the status user's workflow
public internal(set) var fetchStatus: FSFetchStatus
// Enum of possible value
public enum FSFetchStatus: String {
// The flags have been successfully fetched from the API or re-evaluated in bucketing mode.
case FETCHED
// The flags are currently being fetched from the API or re-evaluated in bucketing mode.
case FETCHING
// The flags need to be re-fetched due to a change in context, or because the flags were loaded from cache or XPC.
case FETCH_REQUIRED
// The SDK is in PANIC mode: All features are disabled except for the one to fetch flags
case PANIC
}
requiredFetchReason
property
requiredFetchReason
propertypublic internal(set) var requiredFetchReason: FSFetchReasons
Speaking of FetchStatus 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 visitors flags need to be re-evaluated.
This Enum parameter belongs to the visitor instance with these possible values:
VISITOR_CREATE &#xNAN;Indicate that the visitor is created for the first time or without cache.
UPDATE_CONTEXT &#xNAN;Indicates that a context has been updated or changed.
AUTHENTICATEG &#xNAN;Indicates that the XPC method 'authenticate' has been called.
UNAUTHENTICATE &#xNAN;Indicates that the XPC method 'unauthenticate' has been called.
FETCH_ERROR &#xNAN;Indicates that fetching flags has failed.
FETCHED_FROM_CACHE &#xNAN;Indicates that flags have been fetched from the cache.
NONE &#xNAN;No Reason, the state should be FETCHED, FETCHING, PANIC
enum FSFetchReasons: String {
// Indicate that the visitor is created for the first time or without cache
case VISITOR_CREATE
// Indicates that a context has been updated or changed.
case UPDATE_CONTEXT
// Indicates that the XPC method 'authenticate' has been called.
case AUTHENTICATE
// Indicates that the XPC method 'unauthenticate' has been called.
case UNAUTHENTICATE
// Indicates that fetching flags has failed.
case FETCH_ERROR
// Indicates that flags have been fetched from the cache.
case FETCHED_FROM_CACHE
// No Reason, the state should be FETCHED, FETCHING, PANIC
case NONE
}
The fetchStatus & fetchReason are also used by a callback described before
Scenarios when a fetch is required:
updateContext
UPDATE_CONTEXT
FETCH_REQUIRED
authenticate
AUTHENTICATE
FETCH_REQUIRED
unAuthenticate
UNAUTHENTICATE
FETCH_REQUIRED
on failed to fetch
FETCH_ERROR
FETCH_REQUIRED
On create visitor instance and load flags from cache
FETCHED_FROM_CACHE
FETCH_REQUIRED
On create visitor for the first time or without cached flags
NONE
FETCH_REQUIRED
on panic mode is detected
NONE
PANIC
while fetching
NONE
FETCHING
on fetched with success
NONE
FETCHED
fetchFlags
method
fetchFlags
methodThe fetchFlags() method of the visitor instance automatically updates the campaign assignments according to the current visitor context and retrieves applicable flags.
func fetchFlags(onFetchCompleted: @escaping ()-> Void)
This function will call the decision api and update all the campaigns flags from the server according to the visitor context.
onFetchCompleted
Code
Block to execute once the sync is completed
import Flagship
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId: "visitor_1", hasConsented:true).build()
// Update context
visitor1.updateContext("isVip", true)
// Fetch flags
visitor1.fetchFlags {
// Fetch completed , you can retreive your flags
}
getFlag
method
getFlag
methodOnce the campaign has been assigned and fetched, all the flags are stored in the SDK.
You can retrieve flags using the following functions from the Visitor instance:
func getFlag(key:String)->FSFlag
Retrieve a FSFlag 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.
key
String
key associated to the flag
import Flagship
// Create the visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented:true).build()
// Fetch flags
visitor1.fetchFlags {
// Ex: get flag for vip feature
let flag = visitor1.getFlag(key: "displayVipFeature")
// Use this flag to display the vip feature
}
getFlags
method
getFlags
methodReturn a collection which is containing all current flags on the SDK. Go to FSFlagCollection for more information
func getFlags() -> FSFlagCollection
import Flagship
// Create the visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented:true).build()
// Return the collection of the available flags in the sdk
let collectionFlag = visitor1.getFlags()
// Retreive flag, assume we have a flag with "btnColor" as key
let flag = collectionFlag["btnColor"]
updateContext
method
updateContext
methodThe 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.
import Flagship
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"userId", hasConsented:true)
.withContext(context: ["age" : 32, "isVip":true])
.build()
// Update the visitor context with lastPurchaseDate key and the value is 1615384464
visitor1.updateContext("lastPurchaseDate", 1615384464)
func updateContext(_ key:String, _ newValue:Any)
Upsert the visitor context values, matching the given keys, used for targeting. Only Integer, String, Boolean, Double typed values are accepted.
key
String
Context key
newValue
Any
Context value
func updateContext(_ context:[String:Any])
Update visitor context using dictionary which contain several keys/values
context
[String:Any]
Only Integer, String, Boolean, Double typed values are accepted.
❗️
Visitor context values must have a type of Integer, String, Boolean, Double.
func updateContext(_ flagshipContext:FlagshipContext, _ value:Any)
flagshipContext
FlagshipContext
Predefined context key
value
Any
value of the associated Predefined key
import Flagship
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented:true")
.withContext(context: ["age" : 32, "isVip":true])
.build()
// Update the visitor context with predefined key
visitor1.updateContext(.CARRIER_NAME, "SFR")
clearContext
method
clearContext
methodfunc clearContext()
Clear all the visitor context values used for targeting.
import Flagship
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented: true)
.withContext(context: ["age" : 32, "isVip":true])
.isAuthenticated(true)
.build()
// Clear the context
visitor1.clearContext()
getContext
method
getContext
methodfunc getContext()->[String:Any]
Get visitor current context key / values.
import Flagship
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented:true)
.withContext(context: ["age" : 32, "isVip":true])
.build()
// Get the current context for the visitor1
let currentContexct = visitor1.getCurrentContext()
setConsent
method
setConsent
methodThe Visitor
class provides a method to let you manage visitor consent for data privacy usage. When false
, campaign activation and hits will be disabled and cache cleared.
func setConsent(hasConsented:Bool)
hasConsented
Bool
true
Set visitor consent for private data usage. When false
some features will be deactivated, cache will be deactivated and cleared.
import Flagship
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1",hasConsented:true).build()
visitor1.setConsent(hasConsented: false)
🚧
When consent is not given:
Hits and Activations will be deactivated
All the cached visitor data will be cleared until consent is given again
Only consent tracking requests will be sent in order to clear server-side cached dat
authenticate
method
authenticate
methodDealing with anonymous and logged-in visitor, 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.
There are 2 ways to authenticate a visitor:
Set key isAuthenticated to true when creating a new visitor
Use authenticate method of Visitor instance
Authenticate anonymous visitor
func authenticate(visitorId:String)
visitorId
String
id of the new authenticated visitor.
🚧
Because visitor data data has been updated, fetchFlag
method need to be called afterward to update the decision from Flagship.
The targeting / Flags could be different for the visitor.
unauthenticate
method
unauthenticate
methodThis function change authenticated Visitor to anonymous visitor.
func unauthenticate()
🚧
Because visitor data data has been updated, fetchFlag
method need to be called afterward to update the decision from Flagship.
The targeting / Flags could be different for the visitor.
Experience continuity - 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
let visitor = Flagship.sharedInstance.newVisitor(visitorId: "random_Id", hasConsented:true).withContext(context: ["key":
"value"]).build()
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: "visitorId")
// Since your visitor has changed (is now logged-in)
// You have to check if the proper targeting and flags are set
visitor.fetchFlags {
// ... 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{
// ... Do things ....
}
Final implementation example
// Create a visitor
let visitor = Flagship.sharedInstance.newVisitor(visitorId:"randomId", hasConsented:true).withContext(context: ["key": "value"]).build()
// Call the authenticate function
visitor.authenticate(visitorId: "visitorId");
// Fetch the flags to update the visitor decision
visitor.fetchFlags(){
// ... Do things ....
}
// If you want to unauthenticate the visitor
visitor.unauthenticate()
// Fetch the flags to update the visitor decision
visitor.fetchFlags{
// ... Do things ....
}
SendHit
method
SendHit
methodfunc sendHit<T: FSTrackingProtocol>(_ event:T)
This function send hit to Flagship servers for reporting, go to hit section for more informations
Flag
class
Flag
classmetadata
property
metadata
propertyYou 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.
func metadata()->FSFlagMetadata
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 Flagship
// Create visitor "visitor1" and fetch flags
// Get flag for vip feature
// Ex: get flag for vip feature
let flag = visitor1.getFlag(key: "displayVipFeature")
// Use this flag to get the metadata
let metadata = flag.metadata()
// Get the dictionary for metadata
let campaign_info = metadata.toJson()
The metadata
you can access to are the following one:
campaignId
String
""
id of the campaign
campaignName
String
""
Campaign name
variationGroupId
String
""
Id of the variation group
variationGroupName
String
""
Variation group name
variationId
String
""
id of the variation assigned
variationName
String
""
Variation name
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
Flag status
property
Flag status
propertypublic var status: FSFlagStatus
The flag status represents the state of FLAG and is basically the same as fetchStatus; it is a kind of shortcut to get the status information from the flag instance.
This Enum parameter belongs to the Flag instance and can have one of these possible values:
FETCHED &#xNAN;The flags are fetched from the API or re-evaluated in bucketing mode and up to date.
FETCH_REQUIRED &#xNAN;Visitor context, visitor authentication have been updated while flags have not been re-evaluated
NOT_FOUND &#xNAN;The flag was not found when creating the flag instance.
PANIC &#xNAN;The SDK is in PANIC mode, default flags values will be returned.
// This state represent the flag entity
public enum FSFlagStatus: String {
// The flags are fetched from the API or re-evaluated in bucketing mode.
case FETCHED
// The visitor updated the context but never retrieved or re-evaluated
case FETCH_REQUIRED
// The flag was not found when creating the flag instance.
case NOT_FOUND
// The SDK is in PANIC mode
case PANIC
}
getValue
method
getValue
methodTo retrieve flag current value, simply call value() method of the Flag object.
func value<T>(defaultValue:T?,visitorExposed: Bool = true)->T?
Return the value from the assigned campaign variation or the Flag default value if the Flag does not exist, or if types are different.
defaultValue
T
Generic
Represent a fallback value if something goes wrong.
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. \nIf needed it is possible to set this param to false and call visitorExposed() afterward when the visitor has really been exposed to it.
Return
T
Generic
Return the flag value or the fallback.
/// Create visitor
FSVisitor * visitor1 = [[[[Flagship sharedInstance] newVisitorWithVisitorId:@"visitor_1" hasConsented:@YES instanceType:InstanceSHARED_INSTANCE] withContextWithContext:@{@"age":@18} ] build];
/// Fetch flags
[visitor1 fetchFlagsOnFetchCompleted:^{
// Ex: get flag for vip feature
FSFlag * flag = [visitor1 getFlagWithKey:@"displayVipFeature" defaultValue:FALSE];
// Use this flag value to enable displaying the vip feature
BOOL shouldDisplayVipFeature = [flag valueWithUserExposed:YES];
}];
🚧
Default value must be one of the following type : String, Boolean, Integer,Double Array, Dictionary.
visitorExposed
method
visitorExposed
methodBy 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:
Pass
visitorExposed = true
parameter to thevalue()
method.Use the following
visitorExposed()
method from the Flag instance.func visitorExposed()
import Flagship
// Create visitor "visitor1" and fetch flags
// Get flag for vip feature
// Ex: get flag for vip feature
let flag = visitor1.getFlag(key: "displayVipFeature")
// Read the value without exposing it
let shouldDisplayVipFeature = flag.value(defaultValue: false, visitorExposed: false)
// Expose this flag later in the code
flag.visitorExposed()
exists
method
exists
methodfunc exists()->Bool
This method will returntrue
if a Flag has been returned by Flagship.
// Get Flag for "flag_key"
let flag = user.getFlag(key: "flag_key")
// Ex:Check if flag exists
flag.exists() // Return a boolean - true if the flag exist
FSFlagCollection
This class represent a collection of<String:FSFlag>
Instance Subscript
subscript(key: Key) -> FSFlag { get set }
key
String
The key representing the flag in dictionary
Return
FSFlag
The value associated with key if key is in the dictionary; otherwise, Return an empty FSFlag
object.
Getting keys
Return all keys present and available in the SDK
func keys()->[String]
Return
Array
array of string keys associated to flag
Getting metadata
Return array of metadata
func metadatas()->[FSFlagMetadata]
Return
Array
Array of FSFlagMetadata
toJson
Provide a json object that represent all metadata
func toJson()->String
Return
String
JSON Representation. Return an empty string if no metadata available
Assume we have two flags btnColor
, btnColor
the returned string from this call toJson()
{
{
"key":"btnColor",
"campaignId": "xxxxxxxxxx",
"campaignName": "xxxxxxx",
"variationGroupdId": "xxxxxxxxxx",
"variationGroupName": "xxxxxxxxx",
"variationId": "xxxxxxxxxx",
"isReference": false,
"campaignType": "ab",
"slug": "xxxx",
},
{
"key":"btnTitle",
"campaignId": "xxxxxxxxxx",
"campaignName": "xxxxxxx",
"variationGroupdId": "xxxxxxxxxx",
"variationGroupName": "xxxxxxxxx",
"variationId": "xxxxxxxxxx",
"isReference": false,
"campaignType": "ab",
"slug": "xxxx",
}
}
Filtering
Returns a new dictionary containing the key-value pairs of the dictionary that satisfy the given predicate.
func filter(_ isIncluded: (String, FSFlag) throws -> Bool) rethrows -> FSFlagCollection
isIncluded
Bool
A closure that takes a key-value pair as its argument and returns a Boolean value indicating whether the pair should be included in the returned dictionary.
Return
FSFlagCollection
The key-FSFlag pairs that isIncluded allows.
// User get all flag
let allFlag = user.getFlags()
// Apply filter
let result = allFlag.filter { (key: String, value: FSFlag) in
return value.metadata().variationName == "Original"
}
// result will contain a flag that correspond to the condition : variationName == "Original"
Iterator
Returns an iterator over the dictionary’s key-value pairs.
func makeIterator() -> DictionaryIterator<String, FSFlag>
Return
iterator
An iterator over the dictionary with elements of type (key: Key, value: FSFlag).
// User get all flag
let allFlag = user.getFlags()
// Apply forEach
// Expose flags associated with the variationName == "Original"
allFlag.forEach { (key: String, value: FSFlag) in
if value.metadata().variationName == "Original"{
value.visitorExposed()
}
}
isEmpty
A Boolean value that indicates whether the dictionary is empty.
var isEmpty: Bool {get}
count
The number of key-value pairs in the dictionary.
var count: Int { get }
Expose ALL
Form the collection instance we are able to expose all flags in one call
func exposeAll()
Hit Tracking
This section helps you track your visitors in your application and learn how to build hits in order to feed campaign goals. For more information about our measurement protocol, read our Universal Collect documentation.
There are four different types of Hits available:
Screen
Transaction
Item
Event
They must all be sent with the following function through the visitor instance
func sendHit<T: FSTrackingProtocol>(_ event:T)
Common Parameters
These parameters can be sent with any type of hit.
userIp
String
No
Current user IP address
screenResolution
String
No
Screen Resolution
userLanguage
String
No
User Language
currentSessionTimeStamp
Int64
No
Current Session Timestamp
sessionNumber
Int
No
Session Number
///////////////////////////////////////////////////
/////// Create event with common parameters ///////
///////////////////////////////////////////////////
let eventScreen = FSScreen("loginScreen")
// Fill data for event screen
eventScreen.userIp = "168.192.1.0"
eventScreen.sessionNumber = 12
eventScreen.screenResolution = "750 x 1334"
eventScreen.screenColorDepth = "#fd0027"
eventScreen.sessionNumber = 1
eventScreen.userLanguage = "fr"
eventScreen.sessionEventNumber = 2
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send Event
visitor1.sendHit(eventScreen)
Screen
This hit should be sent each time a visitor arrives on a new interface.
The FSScreen class represents this hit and it requires location
as a string parameter.
init(_ location:String)
location
String
Yes
location name
///////////////////////////////////
/////// Create Screen Hit ///////
///////////////////////////////////
// Usage: this hit is usually sent when changing screens in the app
let eventScreen = FSScreen("loginScreen")
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send screenhit
visitor1.sendHit(eventScreen)
Page
This hit should be sent each time a visitor visits a new local or web page in an embedded web view.
The FSPage class represent Page hit and requires location
as a string parameter.
location
String
Yes
Valid url
///////////////////////////////////
/////// Create Page Hit ///////
///////////////////////////////////
// Usage: This hit should be sent each time a visitor arrives on a new url page
let eventPage = FSPage("https://www.my_domain_com/my_page")
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send screenhit
visitor1.sendHit(eventPage)
Transaction
Hit to send when a visitor completes a Transaction.
FSTransaction represents it and requires a unique transactionId
and affiliation
name.
init(transactionId:String, affiliation:String)
transactionId
String
Yes
Transaction unique identifier.
affiliation
String
Yes
Transaction name. Name of the goal in the reporting.
revenue
Float
No
Total revenue associated with the transaction. This value should include any shipping or tax costs.
shipping
Float
No
Specifies the total shipping cost of the transaction.
tax
Float
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.
shippingMethod
String
No
Specifies the shipping method of 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.
//////////////////////////////////////
/////// Create Transaction Hit ///////
//////////////////////////////////////
// The affiliation is the name of transaction that should appear in the report
let transacEvent:FSTransaction = FSTransaction(transactionId:"transacId", affiliation:"BasketTransac")
transacEvent.currency = "EUR"
transacEvent.itemCount = 0
transacEvent.paymentMethod = "PayPal"
transacEvent.shippingMethod = "Fedex"
transacEvent.tax = 2.6
transacEvent.revenue = 15
transacEvent.shipping = 3.5
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send Transaction hit
visitor1.sendHit(transacEvent)
Item
Hit to send an item with a transaction. It must be sent after the corresponding transaction.
FSItem represents this hit and requires transactionId
and product name.
init(transactionId:String, name:String, code:String)
transactionId
String
Yes
Transaction unique identifier
name
String
Yes
Product name
price
Float
No
Specifies the item price
code
String
Yes
Specifies the item code or SKU
category
String
No
Specifies the item category
quantity
Int
No
Specifies the item quantity
//////////////////////////////////////
/////// Create Item Hit //////////////
//////////////////////////////////////
// Item usually represents a product. An item must be associated with a transaction event.
// Create item hit
let itemHit = FSItem(transactionId: "idTransaction", name: "itemName", code: "codeSku")
// Set price
itemHit.price = 20
// Set category
itemHit.category = "shoes"
// Set quantity
itemHit.quantity = 2
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send Item
visitor1.sendHit(itemHit)
Event
Hit which represents an event. It can be anything you want: for example a click on an Add to Cart button or a newsletter subscription.
FSEvent represents this hit and requires a category event and action name string.
FSCategoryEvent can be Action_Tracking
or User_Engagement
.
init(eventCategory:FSCategoryEvent, eventAction:String)
category
FSCategoryEvent
Yes
Category of the event (Action_Tracking
or User_Engagement
).
action
String
yes
Name of the event.
label
String
No
Description of the event.
eventValue
UInt
No
Value of the event, must be an unsigned integer value
//////////////////////////////////////
/////// Create Event Hit /////////////
//////////////////////////////////////
/// Create action tracking category event
let actionEvent:FSEvent = FSEvent(eventCategory: FSCategoryEvent.Action_Tracking, eventAction: "cta_Shop")
actionEvent.label = "cta_Shop_label"
actionEvent.eventValue = 1
// Create visitor
let visitor1 = Flagship.sharedInstance.newVisitor(visitorId:"visitor_1", hasConsented:true).build()
// Send Event Tracking
visitor1.sendHit(actionEvent)
Managing visitor cache
By default, the Flagship iOS SDK provides a default cache manager implementation.
This feature helps to cache visitors' data, to cache non-sent hits due to internet failures or server errors, to cache campaign assignations for offline mode and to prevent reallocation in Bucketing mode.
Indeed as the assignation is made on a local device in bucketing mode, changing campaign allocation in the platform would make visitors see different variations if there's no cache.
The default cache manager uses a local database.
Custom Cache Manager
It's possible to provide a custom cache implementation using the following protocols
protocol FSVisitorCacheDelegate
This protocol specifies the methods to implement in order to cache visitors' information.
func cacheVisitor(visitorId: String, _ visitorData: Data)
This method is called when the SDK needs to cache visitor information in your database.
visitorId
String
Visitor unique identifier from which data need to be cached.
visitorData
Data
Visitor data to cache
func lookupVisitor(visitorId: String) -> Data?
This method is invoked when the SDK needs to get visitor information from database. This method must to respect a time delay which is configurable.
visitorId
String
Visitor unique identifier from which data need to be loaded.
Return visitor data respecting the expected format.
func flushVisitor(visitorId: String)
This method is called when the SDK needs to flush visitor information in your database. For example, when the visitor hasn't given his consent this method will be called.
visitorId
String
Visitor unique identifier from which data need to be cleared.
protocol FSHitCacheDelegate
This interface specifies the methods to implement in order to cache visitors' hits when they failed to be sent.
func cacheHits(hits: [String: [String: Any]])
This method will be called to cache hits depending on the cache strategy used.
hits
Dictionary
key is a unique Id for each hit \n \n- value is an Dictionary that represent hit
func lookupHits() -> [String: [String: Any]]
This method will be called to load all hits present in database. This method have to respect a time duration, over this delay the operation is cancelled.
return
Dictionary
key is a unique Id for each hit \n \n- value is an Dictionary that represent hit
** func flushHits(hitIds: [String])**
This method is called when the SDK needs to flush tracking hits in your database except the consent ones. For example when the visitor hasn't given his consent this method will be invoked.
hitIds
Array
list of hit's id to remove from database
func flushAllHits()
This method will be called to erase all hits in your database without exception.
// Implement the protocol FSVisitorCacheDelegate
public class CustomVisitorCache: FSVisitorCacheDelegate {
public func cacheVisitor(visitorId: String, _ visitorData: Data) {
// Save the Data that represent the information for visitorId
}
public func lookupVisitor(visitorId: String) -> Data? {
// Return the saved data of visitorId
return Data()
}
public func flushVisitor(visitorId: String) {
// Remove the data for visitorId
}
}
// Implement the protocol FSHitCacheDelegate
public class CustomHitCache: FSHitCacheDelegate {
// Save the dictionary that represent hits
public func cacheHits(hits: [String: [String: Any]]) {}
// Return the saved hit in your database
public func lookupHits() -> [String: [String: Any]] {
return [:]
}
// Remove the hit's id given with List
public func flushHits(hitIds: [String]) {}
// Remove all hits in database
public func flushAllHits() {}
}
// Instanciate Custom cache manager
let customCacheManager = FSCacheManager(CustomVisitorCache(), CustomHitCache())
// Start the Flagship sdk
Flagship.sharedInstance.start(envId: "_ENV_ID_", apiKey: "_API_KEY_", config: FSConfigBuilder()
.DecisionApi()
.withCacheManager(customCacheManager)
.build())
Predefined visitor context keys
The Flagship SDK contains predefined visitor 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.
FIRST_TIME_INIT
First init of the app
sdk_firstTimeInit
Boolean
Yes
true (false if the init isn’t the first one)
LOCALE
Language of the device
sdk_deviceLanguage
String
Yes
fr_FR
DEVICE_TYPE
Type of the device (Tablet/Mobile/Watch)
sdk_deviceType
String
Yes
mobile
DEVICE_MODEL
Model of the device
sdk_deviceModel
String
Yes
iPhone12,8
LOCATION_CITY
City geolocation
sdk_city
String
No
toulouse
LOCATION_REGION
Region geolocation
sdk_region
String
No
occitanie
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
OS_VERSION_NAME
Name of OS
sdk_osVersionName
String
Yes
iOS / tvOS
MVNO / carrierName
(Mobile virtual network operator)"
sdk_carrierName
String
No
orange
DEV_MODE
Is the app in debug mode?
sdk_devMode
Boolean
No
true
INTERNET_CONNECTION
What is the internet connection
sdk_internetConnection
String
No
3g
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
Number (int)
No
40
FLAGSHIP_VERSION
Version of the Flagship SDK
sdk_fsVersion
String
Yes
1.1.2
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?