Data Exporting¶
To export Apptimize experiment information, such as which variant a user is participating in, use our client-side APIs. Note that we automatically export this information in some of our third party integrations. By accessing this information in your application code you can use or send the data wherever you like. This is most commonly used when you want to send the data to your custom backend. The following events (approximate names) are available to your application:
OnParticipatedInExperimentNotification |
Triggered every time a user participates in an experiment |
OnEnrolledInExperimentNotification |
Triggered anytime metadata or Apptimize configuration changes cause a user to become enrolled in one or more experiments. |
OnUnenrolledInExperimentNotification |
Triggered anytime metadata or Apptimize configuration changes cause a user to become unenrolled from one or more experiments |
Be sure to note the differences between enrolled and participating. Enrolled means Apptimize bucketed the user into the experiment (they met the filtering requirements and randomized allocation) while participating means the user was enrolled and then actually saw the experiment. A user might not participate if they are enrolled but never navigate to the screen that contains the experiment. In most cases we recommend that you use participation information because it is more useful in calculating statistics on your experiments.
Data Exporting - Detailed User Interaction¶
You can also choose to export detailed experiment participation. In order to do that, you would need to set up an Amazon S3 Bucket to which we can upload the export files.
Set up AWS S3¶
Log in to Amazon Web Services. Click Services and go to S3.
Create a bucket. Follow Amazon’s process for creating an S3 bucket, selecting US Standard for S3 Region. For more information on S3 regions, see Amazon Regions.
Grant permissions to your newly-created bucket.
Go to Permissions >> Access Control List.
Click Add Account, and use Apptimize’s ID as the canonical ID / account field:
77cb04d110994f05ffa1eb3eb37642f8283198d4dcd6c49ca5fcd2062c9bdbaf
Select List objects and Write objects. You can select additional permission, but your bucket must have these permissions to support an Airship integration.
Click Save.
Realtime Participation¶
In your application code you can listen for participation events and then forward them wherever you like. Note that these events happen over time as a user participates in your experiment.
import com.apptimize.Apptimize;
import com.apptimize.ApptimizeTestInfo;
import com.apptimize.Apptimize.OnExperimentRunListener;
// Do this before Apptimize.setup called from wherever Apptimize is initialized
Apptimize.setOnTestRunListener(new OnTestRunListener() {
// This method is called by Apptimize whenever the user participates in an experiment
@Override
public void onTestRun(ApptimizeTestInfo testInfo, boolean isFirstParticipation) {
String experimentAndVariantName = testInfo.getExperimentName() + "-" + testInfo.getVariantName();
Map<String, String> exportExperimentInfo = new java.util.HashMap<String, String>(5);
exportExperimentInfo.put("experimentName",testInfo.getExperimentName());
exportExperimentInfo.put("variantName",testInfo.getVariantName());
exportExperimentInfo.put("nameAndVariation",experimentAndVariantName);
exportExperimentInfo.put("experimentId",testInfo.getTestId().toString());
exportExperimentInfo.put("variantId",new Long(testInfo.getEnrolledVariantId()).toString());
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Participated", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent("Participated|" + experimentAndVariantName, exportExperimentInfo);
// Setting the participation as persistent state (dimension/attribute)
// Examples - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
});
// In AppDelegate or equivalent
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(experimentParticipation:)
name:ApptimizeParticipatedInExperimentNotification
object:nil];
- (void)experimentParticipation:(NSNotification*)notification {
// Get the relevant participation info
id<ApptimizeTestInfo> experimentInfo = (id<ApptimizeTestInfo>)[[notification userInfo] objectForKey:ApptimizeTestInfoKey];
NSNumber* isFirstParticipation = (NSNumber*)[[notification userInfo] objectForKey:ApptimizeFirstParticipationKey];
if ( experimentInfo == nil ) {
// Shouldn't happen but just in case
return;
}
NSDictionary *exportExperimentInfo = @{
@"isFirstParticipation" : isFirstParticipation,
@"userId" : [experimentInfo userID],
@"anonymousUserId" : [experimentInfo anonymousUserID],
@"experimentName" : [experimentInfo testName],
@"variantName" : [experimentInfo enrolledVariantName],
@"experimentId" : [experimentInfo testID],
@"variantId" : [experimentInfo enrolledVariantID]};
// Send the participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
[CustomTracking trackEvent:@"Participated" params:exportExperimentInfo];
// Or put the info directly in the event name
NSString *participatedString = [NSString stringWithFormat:@"Participated|%@-%@",
[experimentInfo testName],
[experimentInfo enrolledVariantName]];
[CustomTracking trackEvent:participatedString params:exportExperimentInfo];
// Set participation as persistent state (dimension/attribute)
// Example - depending on how you track state information
[CustomTracking putParticipatingExperiment:experimentAndVariantName];
// or possibly by adding it to an array dimension called "participating"
[CustomTracking addValue:experimentAndVariantName toDimensionArray:@"participating"];
}
// In AppDelegate or equivalent
NotificationCenter.default.addObserver(self,
selector: #selector(experimentParticipation(notification:)),
name: NSNotification.Name.ApptimizeParticipatedInExperiment,
object: nil)
@objc func experimentParticipation(notification: NSNotification) {
guard let experimentInfo = notification.userInfo?[ApptimizeTestInfoKey] as? ApptimizeTestInfo,
let isFirstParticipation = notification.userInfo?[ApptimizeFirstParticipationKey] as? NSNumber else {
return
}
// Get the relevant participation info
let exportExperimentInfo = [
"isFirstParticipation" : isFirstParticipation,
"userId" : experimentInfo.userID(),
"anonymousUserId" : experimentInfo.anonymousUserID(),
"experimentName" : experimentInfo.testName(),
"variantName" : experimentInfo.enrolledVariantName(),
"nameAndVariation" : experimentAndVariantName,
"experimentId" : experimentInfo.testID(),
"variantId" : experimentInfo.enrolledVariantID()] as [String : Any?]
// Send the participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent(eventName:"Participated", params:exportExperimentInfo)
// Or put the info directly in the event name
let participatedString = "Participated|\(experimentInfo.testName())-\(experimentInfo.enrolledVariantName())"
CustomTracking.trackEvent(eventName:participatedString, params:exportExperimentInfo)
// Set participation as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName)
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValue(experimentAndVariantName, toDimensionArray:"participating")
}
// In window.onLoad or equivalent
Apptimize.setOnParticipatedInExperimentCallback(onParticipatedInExperimentCallback);
function onParticipatedInExperimentCallback(variantInfo, isFirstParticipation) {
var experimentAndVariantName = `${variantInfo.getExperimentName()}-${variantInfo.getVariantName()}`;
var exportExperimentInfo = {
"experimentName" : variantInfo.getExperimentName(),
"variantName" : variantInfo.getVariantName(),
"nameAndVariation": experimentAndVariantName,
"experimentId": variantInfo.getExperimentId(),
"variantId": variantInfo.getVariantId()
};
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Participated", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent(`Participated|${experimentAndVariantName}`, exportExperimentInfo);
// Setting the participation as persistent state (dimension/attribute)
// Examples - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
import com.apptimize.Apptimize;
import com.apptimize.VariantInfo;
import com.apptimize.events.OnParticipatedInExperimentListener;
// Do this before Apptimize.setup called from wherever Apptimize is initialized
Apptimize.setOnParticipatedInExperimentCallback(new OnParticipatedInExperimentListener() {
// This method is called by Apptimize whenever the user participates in an experiment
@Override
public void onParticipatedInExperiment (VariantInfo variantInfo, boolean isFirstParticipation) {
String experimentAndVariantName = variantInfo.getExperimentName() + "-" + variantInfo.getVariantName();
Map<String, String> exportExperimentInfo = new java.util.HashMap<String, String>(7);
exportExperimentInfo.put("isFirstParticipation",isFirstParticipation ? "firstParticipation" : "notFirstParticipation");
exportExperimentInfo.put("userId", variantInfo.getUserId());
exportExperimentInfo.put("experimentName",variantInfo.getExperimentName());
exportExperimentInfo.put("variantName",variantInfo.getVariantName());
exportExperimentInfo.put("nameAndVariation",experimentAndVariantName);
exportExperimentInfo.put("experimentId",variantInfo.getExperimentId().toString());
exportExperimentInfo.put("variantId",new Long(variantInfo.getVariantId()).toString());
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Participated", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent("Participated|" + experimentAndVariantName, exportExperimentInfo);
// Setting the participation as persistent state (dimension/attribute)
// Examples - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
});
// Do this before Apptimize.setup called from wherever Apptimize is initialized
Apptimize.setOnParticipatedInExperimentCallback(onParticipatedInExperimentCallback);
function onParticipatedInExperimentCallback(variantInfo, isFirstParticipation) {
var experimentAndVariantName = `${variantInfo.getExperimentName()}-${variantInfo.getVariantName()}`;
var exportExperimentInfo = {
"experimentName" : variantInfo.getExperimentName(),
"variantName" : variantInfo.getVariantName(),
"nameAndVariation": experimentAndVariantName,
"experimentId": variantInfo.getExperimentId(),
"variantId": variantInfo.getVariantId()
};
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Participated", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent(`Participated|${experimentAndVariantName}`, exportExperimentInfo);
// Setting the participation as persistent state (dimension/attribute)
// Examples - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
# Do this before Apptimize.setup called from wherever Apptimize is initialized
def onParticipatedInExperiment(VariantInfo variantInfo):
experimentAndVariantName = variantInfo.getExperimentName() + "-" + variantInfo.getVariantName()
exportExperimentInfo = { "experimentName" : variantInfo.getExperimentName(), "variantName" : variantInfo.getVariantName(),
"userId" : variantInfo.getUserId(), "nameAndVariation" : experimentAndVariantName, "experimentId" : str(variantInfo.getExperimentId()),
"variantId" : str(variantInfo.getVariantId()}
# Sending a participation event
# Examples - depending on how you track events
# Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Participated", exportExperimentInfo)
#Or put the info directly in the event name
CustomTracking.trackEvent("Participated|" + experimentAndVariantName, exportExperimentInfo)
#Setting the participation as persistent state (dimension/attribute)
#Examples - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName)
# or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName)
Apptimize.setOnParticipatedInExperimentCallback(onParticipatedInExperiment)
Realtime Enrollment¶
In your application code you can listen for enrollment events and then forward them wherever you like. Note that these events happen over time as experiment configurations are updated (downloading them from the server either the first time a user runs your application or as they are changed by you in the dashboard), or if you make changes to the Apptimize SDK configuration.
import com.apptimize.Apptimize;
import com.apptimize.ApptimizeTestInfo;
import com.apptimize.Apptimize.OnExperimentRunListener;
// Do this before Apptimize.setup called from wherever Apptimize is initialized
Apptimize.setOnTestEnrollmentChangedListener(new OnTestEnrollmentChangedListener() {
// This method is called by Apptimize whenever the user becomes enrolled in a test
@Override
public void onEnrolledInTest(ApptimizeTestInfo testInfo) {
String experimentAndVariantName = testInfo.getExperimentName() + "-" + testInfo.getVariantName();
Map<String, String> exportExperimentInfo = new java.util.HashMap<String, String>(5);
exportExperimentInfo.put("experimentName",testInfo.getExperimentName());
exportExperimentInfo.put("variantName",testInfo.getVariantName());
exportExperimentInfo.put("nameAndVariation",experimentAndVariantName);
exportExperimentInfo.put("experimentId",testInfo.getTestId().toString());
exportExperimentInfo.put("variantId",new Long(testInfo.getEnrolledVariantId()).toString());
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Enrolled", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent("Enrolled|" + experimentAndVariantName, exportExperimentInfo);
}
// This method is called by Apptimize whenever the user becomes unenrolled in a test
@Override
public void onUnenrolledInTest(ApptimizeTestInfo testInfo, UnenrollmentReason reason) {
String experimentAndVariantName = testInfo.getExperimentName() + "-" + testInfo.getVariantName();
Map<String, String> exportExperimentInfo = new java.util.HashMap<String, String>(5);
exportExperimentInfo.put("experimentName",testInfo.getExperimentName());
exportExperimentInfo.put("variantName",testInfo.getVariantName());
exportExperimentInfo.put("nameAndVariation",experimentAndVariantName);
exportExperimentInfo.put("experimentId",testInfo.getTestId().toString());
exportExperimentInfo.put("variantId",new Long(testInfo.getEnrolledVariantId()).toString());
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Unenrolled", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent("Unenrolled|" + unenrollmentReason +"|" + experimentAndVariantName, exportExperimentInfo);
}
});
// In AppDelegate or equivalent
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(apptimizeUserEnrolledInExperiment:)
name:ApptimizeEnrolledInExperimentNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(apptimizeUserUnenrolledInExperiment:)
name:ApptimizeUnenrolledInExperimentNotification
object:nil];
- (void)apptimizeUserEnrolledInExperiment:(NSNotification*)notification {
// Get the relevant participation info
id<ApptimizeTestInfo> experimentInfo = (id<ApptimizeTestInfo>)[[notification userInfo] objectForKey:ApptimizeTestInfoKey];
if ( experimentInfo == nil ) {
// Shouldn't happen but just in case
return;
}
NSDictionary *exportExperimentInfo = @{
@"userId" : [experimentInfo userID],
@"anonymousUserId" : [experimentInfo anonymousUserID],
@"experimentName" : [experimentInfo testName],
@"variantName" : [experimentInfo enrolledVariantName],
@"experimentId" : [experimentInfo testID],
@"variantId" : [experimentInfo enrolledVariantID]};
// Send the participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
[CustomTracking trackEvent:@"Enrolled" params:exportExperimentInfo];
// Or put the info directly in the event name
NSString *enrolledString = [NSString stringWithFormat:@"Enrolled|%@-%@",
[experimentInfo testName],
[experimentInfo enrolledVariantName]];
[CustomTracking trackEvent:enrolledString params:exportExperimentInfo];
}
- (void)apptimizeUserUnenrolledInExperiment:(NSNotification*)notification {
id<ApptimizeTestInfo> experimentInfo = (id<ApptimizeTestInfo>)[[notification userInfo] objectForKey:ApptimizeTestInfoKey];
NSNumber* unenrollmentReasonValue = (NSNumber*)[[notification userInfo] objectForKey:ApptimizeUnenrollmentReasonKey];
if ( experimentInfo == nil || unenrollmentReasonValue == nil ) {
// Shouldn't happen but just in case
return;
}
UnenrollmentReason unenrollmentReason = (UnenrollmentReason)[unenrollmentReasonValue intValue];
NSDictionary *exportExperimentInfo = @{
@"uenrollmentReason" : unenrollmentReasonValue,
@"userId" : [experimentInfo userID],
@"anonymousUserId" : [experimentInfo anonymousUserID],
@"experimentName" : [experimentInfo testName],
@"variantName" : [experimentInfo enrolledVariantName],
@"experimentId" : [experimentInfo testID],
@"variantId" : [experimentInfo enrolledVariantID]};
// Send the participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
[CustomTracking trackEvent:@"Unenrolled" params:exportExperimentInfo];
// Or put the info directly in the event name
NSString *unenrolledString = [NSString stringWithFormat:@"Enrolled|%@|%@-%@",
unenrollmentReasonValue,
[experimentInfo testName],
[experimentInfo enrolledVariantName]];
[CustomTracking trackEvent:unenrolledString params:exportExperimentInfo];
}
// In AppDelegate or equivalent
NotificationCenter.default.addObserver(self,
selector: #selector(enrolledInExperiment(notification:)),
name: NSNotification.Name.ApptimizeEnrolledInExperiment,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(unenrolledInExperiment(notification:)),
name: NSNotification.Name.ApptimizeUnenrolledInExperiment,
object: nil)
@objc func enrolledInExperiment(notification: NSNotification) {
guard let experimentInfo = notification.userInfo?[ApptimizeTestInfoKey] as? ApptimizeTestInfo else {
return
}
// Get the relevant participation info
let experimentAndVariantName = "\(experimentInfo.testName())-\(experimentInfo.enrolledVariantName())"
let exportExperimentInfo = [
"userId" : experimentInfo.userID(),
"anonymousUserId" : experimentInfo.anonymousUserID(),
"experimentName" : experimentInfo.testName(),
"variantName" : experimentInfo.enrolledVariantName(),
"nameAndVariation" : experimentAndVariantName,
"experimentId" : experimentInfo.testID(),
"variantId" : experimentInfo.enrolledVariantID()] as [String : Any?]
// Send the enrollment event
// Examples - depending on how you track events
// Single enrollment event name and experiment & variant info in the dictionary
CustomTracking.trackEvent(eventName:"Enrolled", params:exportExperimentInfo)
// Or put the info directly in the event name
let enrolledString = "Enrolled|\(experimentInfo.testName())-\(experimentInfo.enrolledVariantName())"
CustomTracking.trackEvent(eventName:enrolledString, params:exportExperimentInfo)
}
@objc func unenrolledInExperiment(notification: NSNotification) {
guard let experimentInfo = notification.userInfo?[ApptimizeTestInfoKey] as? ApptimizeTestInfo,
let unenrollmentReason = notification.userInfo?[ApptimizeUnenrollmentReasonKey] as? UnenrollmentReason else {
return
}
// Get the relevant participation info
let experimentAndVariantName = experimentInfo.testName() + "-" + experimentInfo.enrolledVariantName()
let exportExperimentInfo = [
"unenrollmentReason" : unenrollmentReason,
"userId" : experimentInfo.userID(),
"anonymousUserId" : experimentInfo.anonymousUserID(),
"experimentName" : experimentInfo.testName(),
"variantName" : experimentInfo.enrolledVariantName(),
"nameAndVariation" : experimentAndVariantName,
"experimentId" : experimentInfo.testID(),
"variantId" : experimentInfo.enrolledVariantID()] as [String : Any?]
// Send the enrollment event
// Examples - depending on how you track events
// Single unenrollment event name and experiment & variant info in the dictionary
CustomTracking.trackEvent(eventName:"Unenrolled", params:exportExperimentInfo)
// Or put the info directly in the event name
let unenrolledString = "Unenrolled|\(unenrollmentReason)|\(experimentInfo.testName())-\(experimentInfo.enrolledVariantName())"
CustomTracking.trackEvent(eventName:unenrolledString, params:exportExperimentInfo)
}
// In window.onLoad or equivalent
Apptimize.setOnEnrolledInExperimentCallback(onEnrolledInExperimentCallback);
Apptimize.setOnUnenrolledInExperimentCallback(onUnenrolledInExperimentCallback);
function onEnrolledInExperimentCallback(variantInfo) {
var experimentAndVariantName = `${variantInfo.getExperimentName()}-${variantInfo.getVariantName()}`;
var exportExperimentInfo = {
"experimentName" : variantInfo.getExperimentName(),
"variantName" : variantInfo.getVariantName(),
"nameAndVariation": experimentAndVariantName,
"experimentId": variantInfo.getExperimentId(),
"variantId": variantInfo.getVariantId()
};
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Enrolled", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent(`Enrolled|${experimentAndVariantName}`, exportExperimentInfo);
}
function onUnenrolledInExperimentCallback(variantInfo, unenrollmentReason) {
var experimentAndVariantName = `${variantInfo.getExperimentName()}-${variantInfo.getVariantName()}`;
var exportExperimentInfo = {
"experimentName" : variantInfo.getExperimentName(),
"variantName" : variantInfo.getVariantName(),
"nameAndVariation": experimentAndVariantName,
"experimentId": variantInfo.getExperimentId(),
"variantId": variantInfo.getVariantId()
};
// Sending a participation event
// Examples - depending on how you track events
// Single participating event name and experiment & variant info in the dictionary
CustomTracking.trackEvent("Unenrolled", exportExperimentInfo);
// Or put the info directly in the event name
CustomTracking.trackEvent(`Unenrolled|${unenrollmentReason}|${experimentAndVariantName}`, exportExperimentInfo);
}
Note: Our Server Side SDKs are stateless and hence there is no enrollment state unlike the client side SDKs.
Snapshot Enrollment and Participation¶
You can also lookup the current state of which variants a user is enrolled and participating in. This enables you to check whenever you like to get a snapshot of the state. Although, to be most accurate we recommend that you instead listen for participation events (above) so that you can operate on that data in real-time.
// At some point after Apptimize.setup in your application code where you want to
// take a new snapshot
// Note: in most cases it's better to listen for participation events instead
// Loop through all the enrolled experiments
Map<String, ApptimizeTestInfo> testInfoMap = Apptimize.getTestInfo();
if (testInfoMap == null) {
return;
}
for (String key : testInfoMap.keySet()) {
ApptimizeTestInfo testInfo = testInfoMap.get(key);
String experimentAndVariantName = testInfo.getTestName() + "-" + testInfo.getEnrolledVariantName();
// Set enrollment as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putEnrolledExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "enrolled"
CustomTracking.addValueToDimensionArray("enrolled", experimentAndVariantName);
if(testInfo.userHasParticipated()) {
// Set participation (if applicable) as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
}
// At some point in your application code where you want to take a new snapshot
// Note: in most cases it's better to listen for participation events instead
// Loop through all the enrolled experiments
NSDictionary *apptimizeTestsInfo = [Apptimize testInfo];
for ( NSString *experimentName in apptimizeTestsInfo ) {
id<ApptimizeTestInfo> experimentInfo = apptimizeTestsInfo[experimentName];
if ( experimentInfo == nil ) {
// Shouldn't happen but just in case
return;
}
NSString *experimentAndVariantName = [NSString stringWithFormat:@"%@-%@",
experimentName, experimentInfo.enrolledVariantName];
// Set enrollment as persistent state (dimension/attribute)
// Example - depending on how you track state information
[CustomTracking putEnrolledExperiment:experimentAndVariantName];
// or possibly by adding it to an array dimension called "enrolled"
[CustomTracking addValue:experimentAndVariantName toDimensionArray:@"enrolled"];
// Set participation (if applicable) as persistent state (dimension/attribute)
// Example - depending on how you track state information
if ( experimentInfo.userHasParticipated ) {
[CustomTracking putParticipatingExperiment:experimentAndVariantName];
// or possibly by adding it to an array dimension called "participating"
[CustomTracking addValue:experimentAndVariantName toDimensionArray:@"participating"];
}
}
// At some point in your application code where you want to take a new snapshot
// Note: in most cases it's better to listen for participation events instead.
// Loop through all the enrolled experiments
guard let apptimizeTestsInfo = Apptimize.testInfo() else {
// Shouldn't happen but just in case
return;
}
apptimizeTestsInfo?.forEach({ (experimentName: String, experimentInfo: ApptimizeTestInfo) in
let experimentAndVariantName = experimentName + "-" + experimentInfo.enrolledVariantName()
// Set enrollment as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putEnrolledExperiment(experimentAndVariantName)
// or possibly by adding it to an array dimension called "enrolled"
CustomTracking.addValue(experimentAndVariantName, toDimensionArray:"enrolled")
// Set participation (if applicable) as persistent state (dimension/attribute)
// Example - depending on how you track state information
if ( experimentInfo.userHasParticipated() ) {
CustomTracking.putParticipatingExperiment(experimentAndVariantName)
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValue(experimentAndVariantName, toDimensionArray:"participating")
}
})
// At some point after Apptimize.setup in your application code where you want to
// take a new snapshot
// Note: in most cases it's better to listen for participation events instead
var testInfo = Apptimize.getVariantInfo();
testInfo.forEach(function(variantInfo) {
var experimentAndVariantName = `${variantInfo.getExperimentName()}-${variantInfo.getVariantName()}`;
// Set enrollment as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putEnrolledExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "enrolled"
CustomTracking.addValueToDimensionArray("enrolled", experimentAndVariantName);
if(testInfo.getUserHasParticipated()) {
// Set participation (if applicable) as persistent state (dimension/attribute)
// Example - depending on how you track state information
CustomTracking.putParticipatingExperiment(experimentAndVariantName);
// or possibly by adding it to an array dimension called "participating"
CustomTracking.addValueToDimensionArray("participating", experimentAndVariantName);
}
});
Note
It is not possible to retrieve a snapshot of enrollment and participation with our Server Side SDKs because they are stateless. You can snapshot participation using variantInfo.getParticipationPhase() API on the server SDKs.