Swift/iOS via REST Helper
Overview
Conductrics provides a Swift helper library to make it easy to work with our Runtime API from within your iOS project. Behind the scenes, the wrapper will communicate with Conductrics via HTTPS just as any other application would.
This is just a helper libraryThis helper library is just here to make things a bit easier. If you prefer, you are welcome to call our Runtime API directly from your code, or fork/adapt this helper library to suit your needs.
See also: the corresponding Java/Android Helper Library and our Implementation Options for Mobile page.
Installation
Using CocoaPods
Add an entry to your project's Podfile:
target 'MyApp' do
# any existing pod dependencies will be here already
pod 'Conductrics'
end
The 'MyApp' target will be specific to the name of your project, and you can optionally specify a version number when requiring the pod with pod 'Conductrics', '~> 0.0.3', or similar.
Once you have the Podfile edited, open a Terminal and cd to your project directory (the directory should contain the Podfile and a folder named MyApp.xcodeproj), then:
> pod install
Analyzing dependencies
Downloading dependencies
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.
If you didn't have a workspace already this will generate one, and ask you to re-open XCode and launch the project via the workspace. If asked, do this now.
Now from anywhere in your workspace, you can get started with:
import Conductrics
Getting Started with a Simple Example
Before you start, you'll want the following from your Conductrics account, which you can get from the Conductrics Admin. Go to Settings > Distribution, then hit Setup for your API "Deploy Target" (it may be named "Server-Side API" or similar). From there, make a note of your:
- Runtime API Key (looks like
api-xxxxxxxxxxxxx) - REST API Endpoint URL (will start with something like
https://api-v3.conductrics.com, but depends on region and whether your company is using a dedicated Conductrics environment).
Basic Implementation Steps
Let's say you want to instrument a basic A/B test in your application. Let's assume that you've created an agent in the Conductrics console with an id of my-first-test, and that it is configured with two variations: A and B.
The basic steps in your code are:
- Initialize an instance of the main class:
let api : Conductrics = Conductrics(
apiUrl:"https://api-v3.conductrics.com/ac-xxxxxxx/v3/agent-api",
apiKey:"apikey-1234567890"
)
- Create an instance of RequestOptions, providing it with a unique identifier for the visitor if possible. See the "About Session Identifiers" note below.
let options = Conductrics.RequestOptions( "my-visitor-id" )
- Call api.select() to ask for a selection from your agent. You'll get back a SelectResponse object which includes the variation ("A" or "B") that was selected, plus some other information. You use this to display or present the appropriate variation content/functionality in your application.
let agentCode : String = "a-r1j09aj0";
api.select( options, agentCode, { response in
let variationCode : String = response.getCode();
})
- Later, when one of your conversion events occur, call api.reward() to send a small reward value to a Goal code. This is how Conductrics will measure the success rate of each variation as the test proceeds.
let goalCode : String = "g-example";
api.reward( options, goalCode )
Let's put that all together into a basic example:
let api = Conductrics(
apiUrl: "https://api-v3.conductrics.com/ac-xxxxxxx/v3/agent-api",
apiKey: "apikey-1234567890"
);
// sessionId can come from your visitor data, or be a random string
// it should be stable for at least as long as the tested experience
let sessionId = "my-visitor-id";
// the agent API code comes the Agent page (under the Agent title)
// or any "Glance" view of an Agent, its at the top
let agentCode = "a-r1j09aj0";
// the goal API code comes from any Goal edit page/modal
let goalCode = "g-jX091lhk";
// Get ready to call Conductrics
// You can also pass Visitor Traits, timeouts, and other options at this point
let options = RequestOptions(sessionId);
// Get a variation assignment (A or B, etc) from Conductrics
api.select(options, agentCode, { response in
let variation = response.getCode(); // "A" or "B"
// here's where you do whatever is needed in your app
// to display/expose the variation content/functionality
if (variation == "B" ) {
debugPrint("Time to show the 'B' Variation");
} else {
debugPrint("Time to show the 'A' Variation");
}
});
// Later, in response to successful conversion (as defined by you)
api.reward(options, goalCode);
About Session IdentifiersAs shown in the example above, you can provide an identifier to the RequestOptions constructor. We call this a "session" identifier, but if you have a stable visitor identifier, you can provide that, which will cause variation selections to "stick" to the given visitor/user. That will cause Conductrics to keep the visitor assigned to the same variations, and you can do things like select a variation in your app but have the conversion event be on a web page or vice-versa (as long as you can keep the identifier consistent via logging in or some other means).
Alternatively, you can omit the session identifier, which will cause this helper library to make up a random one internally which will be used for the lifetime of the RequestOptions instance. This gives you a way to do "anonymous" testing/optimizations. Note that, if used this way, you must provide the same RequestOptions instance to both select() and reward() for goal/conversion events to be registered.
Calls to select() with the same Session Identifier and the same agent code, will return the same variation code, and
response.getPolicy()will returnPolicy.Sticky.
How to get a Persistent Session ID
If you want a session identifier that will persist after your app has been closed and re-opened, you can use this example Swift code:
func getSessionID() -> String {
let key:String = "Conductrics-Session-ID";
let storage = UserDefaults.standard;
if let id:String = storage.string( forKey: key) {
return id;
} else {
let id:String = UUID().uuidString;
storage.set(id, forKey: key);
return id;
}
}You would apply this when creating the RequestOptions, like this:
let options = Conductrics.RequestOptions(self.getSessionID());More About Getting Selections
The first example (above) shows a very simple usage scenario. That may cover most of your needs, at least at first. The following sections discuss some other things this helper library provides with respect to getting variation selections for your tests/agents.
Using Variation Meta-Data
As the examples above show, you can get the selected variation ("A" or "B", etc) easily using the SelectResponse.getCode() method. But it can often be handy to get additional information back from Conductrics along with the selected variation code. You can use Variation Meta-Data for this purpose.
For instance, if your variations are about changing the text of a button, it might be helpful for the text itself to live in your Conductrics agent. In such a case, you could use the Conductrics Admin to provide a piece of meta-data called text or cta-text for each variation. Then, in your iOS / Swift code, you can use the SelectResponse.getMeta() method to get the value as a string:
let ctaText : String = response.getMeta("cta-text");
You could do the same for some other aspects of the variations, such as the CTA color, or conceptual "foreign keys" like offer, article, or property identifiers. See "Using Variation Meta-Data" in the Runtime API Reference page for more details about adding meta-data to your variations.
Getting Selections from Multiple Agents
You may have multiple agents/tests running at the same time in your app. You can ask for multiple selections by using the [String] form of the select() method. This will cause the helper library to get all the selections from Conductrics in one HTTP request (rather than multiple HTTP requests), which will be more efficient.
You'll get back a [String:SelectResponse] filled with SelectResponse instances for each of the agent codes you specified:
let agents = ["my-agent-x", "my-agent-y"]
api.select( options, agents, { outcomes in
let responseX = outcomes["my-agent-x"]
let variationX = responseX.getCode()
let responseY = outcomes["my-agent-y"]
let variationY = responseY.getCode()
}
})Working with Multivariate Tests (MVT)
In a Multivariate Testing (MVT) scenario, you bundle two or more "normal" API agents into an MVT "Group". See Multivariate (MVT) Agents for details about how Conductrics treats multivariate scenarios.
Just as a simple example, let's say you wanted to run an MVT test that tried different combinations of CTA Color and CTA Text:
-
In the Conductrics Admin, create one agent for each aspect of the test. Let's say those agents are called
cta-colorandcta-text. -
Also in the Conductrics Admin, group the two agents together as a MVT Agent. Your two agents are now displayed as conceptual "children" of the MVT "parent" agent.
-
In your code, call both of the child agents simultaneously, as described in the "Getting Selections from Multiple Agents" section above. Selections and rewards will get counted at both the "child" agent level, and also at the MVT level so you can see whether CTA Color or Text (or whatever you are testing) is more informative and so on. See the MVT Report doc page for details.
Please make sure to ask for all of the "child" agents at the same time via the[String]form of the select() method when instrumenting an MVT test.
Providing Custom Visitor Traits
Conductrics lets you provide custom "visitor traits", which will show up in the Conductrics so you can evaluate the results of your tests for various visitor segments and so on. They can also be used in targeting rules and include/exclude conditions. See Custom Visitor Traits for more information about visitor traits in general.
To use visitor traits with this helper library, provide them via the RequestOptions.setTrait() method, for instance:
options.setTrait("tier", "silver").setTrait("interest", "music");
Note that you'll need to declare the visitor traits ahead of time in the Conductrics Admin, or they will be silently ignored at runtime. See Custom Visitor Traits for more information about visitor traits in general.
Providing Custom Input Params
Similarly to Custom Visitor Traits (see above), you can also provide ad-hoc information to Conductrics via Custom Input Params. Unlike Visitor Traits, these input params are not retained between calls as part of the visitor's "session" and don't show up in the reporting. But they can be used in conditions for include/exclude rules and targeting rules.
To use custom input params with this helper library, provide them via the RequestOptions.setInput() method. For instance, you could use options.setInput("dollar-value", 50), which would make it possible to use the "dollar-value" params in your conditions in the Conductrics Admin. See Custom Input Params for details.
Using Provisional Selections
You may sometimes have a situation when you want a variation to be selected for a visitor, but where you don't yet know whether it will be possible to actually display/render/provide the selected experience to the visitor. For instance, let's say you want to run an A/B test, where "A" means waiting 30 seconds before displaying an offer or prompt of some kind, and "B" means waiting 60 seconds. But you know that the user may very well move on before either 30 or 60 seconds elapse.
In such a case, you can use options.setProvisional(true) before calling select() to indicate that you want a "provisional selection" for the visitor. Then, if you are able to actually display the variation, you can "confirm" the selection by calling select() for the same agent again, this time using options.setConfirm(). Only then will the selection be counted in the Conductrics reporting and optimization.
See Using Provisional Selections for details about provisional selections.
let opts = new RequestOptions("session-id")
.setProvisional(true);
api.select(opts, "a-example", { response in
assert outcome.getStatus() == Status.Provisional;
});
// sometime later... make sure to use the same session id as before
// or you can re-use the same options instance.
let opts = new RequestOptions("session-id")
.setConfirm(true);
api.select(opts, "a-example", { response in
assert outcome.getStatus() == Status.Confirmed;
});Forcing Selections and QA
You'll likely want to QA your variations, which generally means needing to force your app into a particular variation. There are a few ways you can do this:
-
You can use the QA Sessions window in the Conductrics Console to pre-select the desired variation(s) for a given session identifier. Assuming that you know the identifier that your app will be providing to RequestOptions(), you can provide that same identifier to create a QA Session on the Conductrics side. Conductrics will reply with the variation(s) you specify, and you'll be able to view a history of the calls made to the Conductrics servers, with debugging messages and variation selections for each call. See Using QA Sessions for details.
-
You can provide an ad-hoc flag of your own choosing as a "custom input param", via the RequestOptions.setInput() method. For example, you might do something like
options.setInput("qa-group", "alpha"), and then add a targeting rule at the agent level (in the Conductrics Console) to always pick "B" for the "qa-group" input is set to "alpha". Such selections would returnPolicy.Fixedif you call getPolicy() on the SelectResponse. See setInput() in the reference section below, and Custom Input Params for info about custom input parameters in general. -
Alternatively, you can simply "pause" the agent at a given variation. This will immediately cause all calls to the agent (including for the general public) to return that variation. If you call SelectResponse.getPolicy() on a paused agent, you'll get back
Policy.Paused(see reference section below). Please note that variation selections made while an agent is paused are NOT counted in the reporting, and do not qualify for goals/rewards. -
You can also use
options.setAllowedVariants()to constrain the possible selections.
options.setAllowedVariants("example-agent", ["B"]);
api.select(options, "example-agent", ... )
This will still send a network request to Conductrics, and will still record the selection in our reporting, but will always select variation "B". The resulting SelectResponse.getPolicy() will (usually) be Policy.Random (or sometimes Policy.Control, Policy.Adaptive, etc depending on the rest of the agent configuration).
- Finally, you can put the SDK into offline mode, with a specific default:
options.setDefault("example-agent", "B").setOffline(true);
api.select(options, "example-agent", ... )
This will immediately select "B" and will not cause any network requests. The resulting SelectResponse.getPolicy() will be Policy.None.
RequestOptions.forceOutcome() skips the actual network call to Conductrics (it's a "short circuit"). Compare to setDefault() which tells this library what to return in the case of a network error or timeout, etc. See the "Fallbacks and Timeouts" section below.
Fallbacks and Timeouts
Under normal conditions, calls to the select() method will interact with Conductrics quickly, and return the corresponding SelectResponse object to your callback. But what if the network connection is slow or offline, or some other error occurs?
When requesting a variation selection with select()
When you call select(), this helper library attempts to make a call to the Conductrics REST API (via HTTPS). If the connection is unsuccessful (perhaps due to a network error or slow connection, or because your app is offline), the library will return a SelectResponse that gives you a "fallback" selection. In such a case:
-
response.getCode()will return "A" by default. If you want a different variation code to be returned in error/timeout/fallback cases, you can calloptions.setDefault(agentCode, variationCode)before calling theapi.select(options, ...)method. -
Calls to
response.getMeta()will returnnil. -
response.getError()will provide the immediate Error that caused the fallback response (network timeout, no connection, malformed API URL, etc). -
In some cases
response.getExecResponse().getError()will provide a lower level Error, and can help when diagnosing unexpected errors. -
response.getPolicy()will returnPolicy.None.
Adjusting the timeoutBy default, the timeout is set to 2000 milliseconds (two seconds). You can provide a different timeout via the RequestOptions.setTimeout() method (see reference below).
More About Sending Rewards
Dealing with Multiple Goals / Rewards
You can have multiple goal types associated with a given test/agent, and each goal may be associated with multiple agents. Just call reward() whenever the actual events occur in your app. Conductrics will "credit" the appropriate variation(s) for the given visitor accordingly.
Providing a Numeric Value
In some types of applications, it makes sense to associate a numeric value with each goal/conversion event. An obvious example is e-commerce, where you might want to be able to evaluate the efficacy of your variations with respect to the amounts of actual purchases.
In such a case, turn on the option to accept numeric rewards for the Goal (you can do this in the Conductrics Admin). You'll be able to set a minimum and maximum value that should be accepted, as a sanity check at runtime. See the Goals / Conversions doc page for more details.
Then provide the numeric value as the value argument when you call reward(). For instance, if you have a Goal with identifier purchase, you might call api.reward(opts, "purchase", 19.99) depending on the actual amount of the purchase.
If you don't provide a numeric value when calling reward(), a default value of1.0is assumed.
Knowing whether the Reward was accepted
In many cases, you may think of your calls to reward() in a "fire and forget" manner, because the responses from reward() aren't really "actionable" - that is, your app doesn't necessarily need to store or do anything with the responses for purposes of instrumenting a test or optimization correctly.
However, you may want to know whether your calls to reward() were actually counted on the Conductrics side for QA or logging purposes. For instance, by default most goals only accept a reward once per agent, per visitor. So, if your app calls reward() multiple times for the same goal, the first one would typically be counted but the second one would be (correctly) ignored.
To know whether the reward was accepted, provide a callback when calling reward() and check GoalResponse.getAcceptedValue() within your callback handler. If accepted, the value will be 1 (or the numeric value for the goal per the "Providing a Numeric Value" section above), indicating that the goal will be counted in the Conductrics reporting for the agent. If the value is zero, the goal was not accepted/counted.
Reasons why a goal might not be accepted for a given test/agent:
-
A reward has already been accepted for the given agent (for this visitor). If you want Conductrics to accept multiple goals/rewards for a given agent/visitor, you can change the "Accept Up To" limit at the Goal type level in the Conductrics Admin. See Goals / Conversions for details.
-
The Goal is not associated with the agent in the Conductrics Admin.
-
If the Goal uses numeric reward values, the numeric value you sent is outside of that range.
-
The Goal code in question no longer exists.
-
The Agent in question no longer exists or is no longer Running.
Library Reference
The Conductrics package defines these classes:
Conductrics- The main class which exposes the core select(), reward(), and exec() methods.RequestOptions- Used to provide information about the visitor context and other options.SelectResponse- Returned by a call to select(), providing info about the selected variationRewardResponse- Returned by a call to reward(), providing feedback about how the conversion event was processed.ExecResponse- Returned by a call to exec(), providing feedback about how the provided commands were processed.
Conductrics Instance Methods | Arguments | Description |
|---|---|---|
select | options : RequestOptions | Ask an agent to make a selection for this user session, call back with a SelectResponse. The callback is required. |
select | options : RequestOptions | Ask multiple agents to make selections for this user session, call back with a Map of agent codes to their corresponding SelectResponse. The callback is required. |
reward | options : RequestOptions | Send a reward to a goalCode, call back with a GoalResponse. Optionally, you may provide a numeric value (see "Providing a Numeric Value" section above). The callback is optional. |
exec | options : RequestOptions | Execute any commands supported by the Runtime API, call back with an ExecResponse. The callback is required. |
RequestOptions | Description |
|---|---|
setSession sessionID: String | Set the value that will identify this user/visitor session. Repeated calls to Select() with the same sessionID will get the same result. |
setInput | Use to provide ad-hoc information as custom "input" values, which you can then use in conditions/rules in the Conductrics Admin to include/exclude visitors or target certain variations to certain users, etc. See Custom Input Params for details. |
setTrait | Use to specify custom Visitor Traits for the visitor. Visitor Traits show up in the Conductrics reporting, and can also be used in conditions/rules to include/exclude visitors or target certain variations to certain users, etc. Traits must be declared in the Conductrics Admin; any unknown traits will be silently ignored. See Custom Visitor Traits for details. |
setParam | Sets an arbitrary URL parameter for the API request. You can use this to set additional/future parameters that are supported by the underlying REST API that aren't explicitly included in this helper library. |
setTimeout | The number of milliseconds to wait for a response from the Conductrics API Server. Default is 2000 if not provided. See the "Fallbacks and Timeouts" section above. |
setDefault | Use to provide the "fallback" variation code that should be returned if select() encounters a timeout or network error, etc. See the "Fallbacks and Timeouts" section above. |
setUserAgent | Provide a custom user-agent string. You can base conditions/rules in the Conductrics admin to include/exclude visitors based on the user agent, if needed. |
setProvisional | Set whether select() should request provisional variations. |
setConfirm | Set whether select() will be used to confirm a prior selection. |
setOffline | Indicate that no network requests should be made. Calls to select() will always respond with the default variation. |
SelectResponse Method | Description |
|---|---|
getAgent() -> String | The agent code that was provided given to select(). |
getCode() | The variation code selected by the agent. |
getPolicy() | The Selection Policy used to make the selection, one of:
|
getMeta | If the selection variation has custom meta-data saved in the Conductrics Console, you can access it here after a selection is made. Returns null if no meta-data exists for the given See notes about meta-data in the sections above, and the "Using Variation Meta-Data" section on the Runtime API Reference page. |
getError() | If an error occurred, such as a timeout, the exception returned here will describe it. |
getExecResponse() | The underlying message that this SelectResponse was built from. Example: |
GoalResponse | Description |
|---|---|
getGoalCode() -> String | The goal code given to Reward(). |
getAcceptedValue(agentCode) | The amount of value that was acknowledged by a particular agent. The Agent screen of the Console must have this Goal selected in order to accept value. |
getError() | If an error occurred, such as a timeout, the exception returned here will describe it. |
getExecResponse() | Return the underlying ExecResponse that contained this GoalResponse. |
ExecResponse | Description |
|---|---|
getSelection agentCode: String -> SelectResponse | Extracts the corresponding selection message from the response. |
getReward | Extracts the corresponding reward message from the response. |
getLog() | For debugging purposes. Will be populated with debugging-style messages, if you set |
getTraits() | Returns a list of Custom Visitor Traits that are associated with this session. For debugging purposes only; Conductrics is not designed to be used as a system of record for custom visitor traits. |
getError() | If an error occurred, such as a timeout, the exception returned here will describe it. |
getJSON() | The underlying JSON response from the Conductrics server. See API Usage via REST API for details. |
Updated about 1 year ago