API v2.0

Welcome to the apoorv developer hub. You'll find comprehensive guides and documentation to help you start working with apoorv as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Search results for "{{ search.query }}"

No results found for "{{search.query}}". 
View All Results
Suggest Edits

Introduction to VWO REST API

 

About the Document

This document will help you understand the basics of VWO APIs. VWO API is organized around REST and encodes data in JSON. Understanding VWO API will allow developers to create and manage VWO accounts, campaigns and variations.

Target Audience

This document assumes technical proficiency. If you wish to develop a new app or plugin for a new target, or have any questions, reach out to us at api@vwo.com.

Suggest Edits

Request Types

 

Request Types

The most commonly-used HTTP methods are POST, GET, PATCH, and DELETE that correspond to create, read, update, and delete (or CRUD) operations. You can add the following endpoints after the version in the API URL.

Method
Description
Result

GET

Used to retrieve an entity or list of entities. GET requests are always read-only. To retrieve a single entity, use its id in the URL. To retrieve multiple entities, leave it blank.

Upon successful execution, GET method returns the data in the body and a 200 OK code.

POST

Used to create an entity in VWO. For example, a variation in a campaign.
POST requests have a JSON encoded body and the Content-Type: application/json header.

Upon successful execution, POST method returns the created entity as JSON in the body, including a new id argument, and a 201 CREATED code.

PATCH

Used to update an entity in VWO. The URL includes the id of the entity to update.

Upon successful execution, PATCH method returns a 200 OK code and the data in the body.

DELETE

Used to remove an entity in VWO. The URL includes the id of the entity to delete. No data is sent in the body.

The response includes a 204 NO CONTENT code.

Suggest Edits

Response Codes

 

Response

Upon successful request, the response includes data and 200 OK (GET), 201 CREATED (POST), 200 OK (PATCH), or 204 NO CONTENT (DELETE) as the HTTP code. If the request fails, the response is one of the following error codes:

Response
What triggers the response?

400
(Bad Request)

If the request is not sent in valid JSON. Specify a Content-Type: application/json header in your request. If you sent valid JSON, the error may also mean specific fields that were invalid.

401
(Unauthorized)

If your API token was missing or included in the body rather than the header.

403
(Forbidden)

If you provided an API token but it was invalid or revoked, or if you don't have read/write access to the entity you're trying to view/edit.

404
(Not Found)

If the id used in the request was inaccurate or you don't have permission to view/edit it.

429
(Too Many Requests)

If you hit a rate limit for the API. If you receive this response, we recommend waiting at least 60 seconds before re-attempting the request.

503
(Service Unavailable)

If the API is overloaded or down for maintenance. If you receive this response, we recommend waiting at least 60 seconds before re-attempting the request.

Suggest Edits

API Rate Limits

 

We rate limit 1 request per second for every token. Applications are not rate limited, though the limit is applied upon the token generated for an account. If the application users/VWO users intend to use the API beyond the rate limits mentioned, then please drop us a mail at api@vwo.com with your requirement details.

Suggest Edits

Authentication and Authorization

 

VWO's API lets you interact with a user’s VWO account and allows you to act on your user's behalf to perform multiple operations. To do so, your application first needs to request authorization from users.

Each API request is authenticated by a token in the request header. If you provide a wrong token, or include a token in the request body rather than the header, the response will be an Authentication Failed error.

IMPORTANT
A user authentication token authorized to your application is not time-bound and is valid indefinitely without requiring you to re-authorize. You can revoke the token from its Control Panel.

Suggest Edits

Authentication for personal use of API

 

Authentication for Personal Use of API

Please visit app.vwo.com/#/developers/tokens to generate an API token and use the token as part of every API request's header.

Suggest Edits

Authentication for third-party applications

 

Authentication for Third-Party Applications

For Third Party Applications, create an application via our Developers Dashboard
http://app.vwo.com/#/developers/applications
After creating the application, redirect the user to the following Authorization URL(shared below).

Path Syntax:
http://app.vwo.com/#/authorize/:applicationId

Example:
http://app.vwo.com/#/authorize/123456

*where the Application getting authorized has the applicationId as 123456

Authorization URL redirects the user to VWO, where an interface allows the user to authorize an application. The interface allows the user to choose the account for which the application will get the required access. On successful authorization, the user is redirected back to the application (if the redirect url has been specified) along with the authentication token as part of the query parameters. Although, if the redirect url has not been specified in the application settings, then, upon successful authorization, the user sees the authentication token for use in the application which initiated the authorization.

The authentication token can then be used with every API call to perform all operations available via API.

Draft exposes its data through a REST API using JSON serialization and protected with OAuth 2. Using API, you can fetch all or specific draft, update or delete an existing test in VWO.

Suggest Edits

Get all drafts campaigns

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/drafts
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/drafts
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/drafts' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/drafts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/drafts");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/drafts"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": [
    {
      "draftId": 14597,
      "type": "ab",
      "status": "draft",
      "platform": "website",
      "createdOn": 1412649106,
      "currentDraftStepIndex": 2,
      "name": "Campaign 142",
      "urls": [
        {
          "value": "http:\/\/wingify.com"
        }
      ],
      "createdBy": {
        "id": 1,
        "name": "Backend Testing"
      }
    }
  ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Get Current / Sub Account Drafts.

Request URI for Sub Account

GET /accounts/1/drafts
Suggest Edits

Get specific draft campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/drafts/draft_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/drafts/draft_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/drafts/draft_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/drafts/draft_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "draftId": 14597,
    "createdBy": 1,
    "platform": "website",
    "isAdvancedMode": false,
    "currentDraftStepIndex": 2,
    "type": "ab",
    "urls": [
      {
        "type": "url",
        "value": "http:\/\/wingify.com"
      }
    ],
    "primaryUrl": "http:\/\/wingify.com",
    "globalSegment": {
      "segmentationType": "pre",
      "platform": "website",
      "id": "1",
      "type": "predefined",
      "name": "Direct",
      "description": "Segment to allow only direct traffic"
    },
    "variations": [
      {
        "platform": "website",
        "id": 1,
        "name": "Control",
        "editorData": {
          "stack": []
        },
        "deployContent": []
      },
      {
        "platform": "website",
        "id": 2,
        "name": "Variation 1",
        "editorData": {
          "stack": [
            {
              "el": 0,
              "op": {
                "opName": "html",
                "html": "The company  pioneered easy A\/B testing"
              },
              "depending": false,
              "XPath": "BODY > NOSCRIPT:first-child + SCRIPT + HEADER#top_header + SECTION > DIV:first-child > DIV:first-child > H2:first-child",
              "parentTag": "DIV"
            }
          ]
        },
        "deployContent": [
          {
            "jsString": "var ctx=vwo_$(x);ctx.html(\"The company  pioneered easy A\/B testing\");",
            "cssSelector": "HEADER#top_header + SECTION > DIV:first-child > DIV:first-child > H2:first-child"
          }
        ]
      }
    ],
    "status": "draft",
    "goals": [
      {
        "id": 1,
        "name": "Goal 1",
        "type": "visitPage",
        "isPrimary": true,
        "urls": [
          {
            "type": "url",
            "value": "http:\/\/wingify.com"
          }
        ],
        "cssSelectors": []
      }
    ],
    "name": "Campaign 142",
    "newCampaignName": "Campaign 142",
    "percentTraffic": 100,
    "isHeatmapEnabled": true
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

draft_id
int32
required

Draft Id

 

Get specific draft of Current / Sub Account.

Request URI for Sub Account

GET /accounts/1/drafts/14597
Suggest Edits

Create a draft

 
posthttps://app.vwo.com/api/v2/accounts/account_id/drafts
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/drafts
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/drafts' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/drafts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/drafts");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/drafts"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "draftId": 14599,
    "createdOn": 1416225457,
    "createdBy": {
      "id": 1,
      "name": "Backend Testing"
    },
    "newCampaignName": "Campaign 142"
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 
{
  "platform": "website",
  "isAdvancedMode": false,
  "currentDraftStepIndex": 0,
  "type": "ab",
  "urls": [
    {
      "type": "url",
      "value": "http:\/\/wingify.com"
    }
  ],
  "primaryUrl": "http:\/\/wingify.com",
  "globalSegment": {
    "segmentationType": "pre",
    "platform": "website",
    "id": "1",
    "type": "predefined",
    "name": "Direct",
    "description": "Segment to allow only direct traffic"
  },
  "status": "draft",
  "percentTraffic": 100,
  "isHeatmapEnabled": true
}

Create a draft in Current / Sub Account.

Request URI for Sub Account

POST /accounts/1/drafts

Request Format

Suggest Edits

Update draft campaigns

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/drafts/draft_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/drafts/draft_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/drafts/draft_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/drafts/draft_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "draftId": 14597,
    "createdOn": 1416225457,
    "createdBy": {
      "id": 1,
      "name": "Backend Testing"
    }
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

draft_id
int32
required

Draft Id

 

Request Format

{
  "draftId": 14597,
  "createdBy": 1,
  "platform": "website",
  "isAdvancedMode": false,
  "currentDraftStepIndex": 3,
  "type": "ab",
  "urls": [
    {
      "type": "url",
      "value": "http:\/\/wingify.com"
    }
  ],
  "primaryUrl": "http:\/\/wingify.com",
  "globalSegment": {
    "segmentationType": "pre",
    "platform": "website",
    "id": "1",
    "type": "predefined",
    "name": "Direct",
    "description": "Segment to allow only direct traffic"
  },
  "variations": [
    {
      "platform": "website",
      "id": 1,
      "name": "Control",
      "editorData": {
        "stack": []
      },
      "deployContent": [],
      "segmentEligibility": "ALL",
      "segment": {
        "type": "custom",
        "eligibility": "ALL"
      },
      "percentSplit": 50
    },
    {
      "platform": "website",
      "id": 2,
      "name": "Variation 1",
      "editorData": {
        "stack": [
          {
            "el": 0,
            "op": {
              "opName": "html",
              "html": "The company  pioneered easy A\/B testing"
            },
            "depending": false,
            "XPath": "BODY > NOSCRIPT:first-child + SCRIPT + HEADER#top_header + SECTION > DIV:first-child > DIV:first-child > H2:first-child",
            "parentTag": "DIV"
          }
        ]
      },
      "deployContent": [
        {
          "jsString": "var ctx=vwo_$(x);ctx.html(\"The company  pioneered easy A\/B testing\");",
          "cssSelector": "HEADER#top_header + SECTION > DIV:first-child > DIV:first-child > H2:first-child"
        }
      ],
      "segmentEligibility": "ALL",
      "segment": {
        "type": "custom",
        "eligibility": "ALL"
      },
      "percentSplit": 50
    }
  ],
  "status": "draft",
  "goals": [
    {
      "id": 1,
      "name": "Goal 1",
      "type": "visitPage",
      "isPrimary": true,
      "urls": [
        {
          "type": "url",
          "value": "http:\/\/wingify.com"
        }
      ],
      "cssSelectors": []
    }
  ],
  "name": "test Campaign",
  "newCampaignName": "Campaign 142",
  "percentTraffic": 100,
  "isHeatmapEnabled": true,
  "numVariationsWithEligibilitySeg": 0,
  "isCustomSplitEnabled": false,
  "integrations": {
    "ga": {
      "enabled": false,
      "slot": 4,
      "prefix": ""
    },
    "clicktale": {
      "enabled": false
    },
    "ua": {
      "enabled": false,
      "dimension": 1,
      "prefix": ""
    },
    "gtm": {
      "enabled": false
    },
    "isGaPremium": false
  },
  "isPostSegmentationEnabled": false
}

Update draft of Current / Sub Account.

Request URI for Sub Account

PATCH /accounts/1/drafts/14597
Suggest Edits

Delete draft campaigns

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/drafts/draft_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/drafts/draft_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/drafts/draft_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/drafts/draft_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/drafts/draft_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

draft_id
int32
required

Draft Id

 

Delete draft of Current / Sub Account.

Request URI for Sub Account

DELETE /accounts/1/drafts/14597
Suggest Edits

Campaigns

 

Developers can programmatically access test resources, get details of a test, create, update, and share links of your campaigns.

Suggest Edits

Campaign resource representation

 
Property
Type
Description
Editable

id

integer

Campaign Id

No

name

string

Campaign Name

Yes

type

string

Campaign type

Valid values include ab, multivariate, heatmap, conversion, split

Yes

status

string

Campaign status

Yes

createdOn

timestamp

Campaign creation time

No

labels

Nested Object

See CampaignLabel resource

Yes

percentTraffic

float

Percentage traffic allocated to the campaign

Yes

isCrossDomainEnabled

boolean

Tracking conversions across multiple domains

Yes

createdBy

NestedObject

Contains the information of user who created the campaign

createdBy.id

integer

User Id

No

createdBy.name

string

User name

No

createdBy.imageUrl

link

User gravatar link

No

urls

Nested Object

Urls to be included in the campaign

Yes

urls.{index}.type

String

Url type

Valid values include url,startsWith, endsWith,contains,pattern,regex

Yes

urls.{index}.value

Link

Url value

Yes

excludedUrls

Nested Object

Urls to be excluded in the campaign

Yes

excludedUrls.{index}.type

String

Url type

Yes

excludedUrls.{index}.value

Link

Url value

Yes

primaryUrl

link

Url on which test needs to be created

Yes

integrations

Nested Object

See integration resource for more details

Yes

thresholds

Nested Object

Thresholds for campaign data collection

thresholds.winningPercent

Float

Threshold for winning variation

Yes

thresholds.losingPercent

Float

Threshold for losing variation

Yes

thresholds.visitors

integer

Threshold for number of visitors

Yes

device

string

Device for which the campaign was created

No

variations

Nested Object

See variation resource for details

Yes

sections

Nested Object

See section resource for details

Yes

goals

Nested Object

See goal resource for details

Yes

dataIntervalRange

Nested Object

Date Range for collected campaign range

dataIntervalRange.intervalSize

timestamp

Size of intervals for which data is shown

No

dataIntervalRange.startTime

timestamp

Campaign data start time which is selected

No

dataIntervalRange.endTime

timestamp

Campaign data end time which is selected

No

dataIntervalRange.limitingStartTime

timestamp

Campaign data start time for which overall data is collected

No

dataIntervalRange.limitingEndTime

timestamp

Campaign data end time for which overall data is collected

No

variationGoalData

Nested Object

Campaign data for each variation-goal combination

No

variationGoalData.variation

integer

Variation Id

No

variationGoalData.goal

integer

Goal Id

No

variationGoalData.aggregated

Nested Object

Aggregated data for variation-goal combination

No

variationGoalData.aggregated.visitorCount

integer

visitor count

No

variationGoalData.aggregated.conversionCount

integer

conversion count

No

variationGoalData.aggregated.conversionRate

float

conversion rate

No

variationGoalData.aggregated.standardError

float

standard error

No

variationGoalData.aggregated.totalRevenue

integer

total revenue if revenue type goal is selected

No

variationGoalData.aggregated.revenuePerVisitor

float

revenue per visitor

No

variationGoalData.aggregated.revenuePerConversion

float

revenue per conversion

No

variationGoalData.aggregated.revenuePerVisitorStandardError

float

revenue per visitor standard error

No

variationGoalData.aggregated.revenuePerConversionStandardError

float

revenue per conversion standard error

No

variationGoalData.isLoser

boolean

if variation-goal combination is loser

No

variationGoalData.isWinner

boolean

if variation-goal combination is winner

No

variationGoalData.intervalWise

Nested Object

Interval wise data for variation-goal combination

No

variationGoalData.intervalWise.{index}.interval

timestamp

interval time

No

variationGoalData.intervalWise.{index}.visitorCount

integer

visitor count

No

variationGoalData.intervalWise.{index}.conversionCount

integer

conversion count

No

variationGoalData.intervalWise.{index}.totalCount

integer

total count

No

stats.conversionRate

integer

Conversion rate for the campaign (Default :0.05)

Yes

stats.certaintyMode

integer

Certainty Modes
High Certainty: 0.01
Balanced Mode: 0.075
Quick Learnings: 0.20

(Default : 0.01)

Yes

stats.expectedMonthlyVisitors

integer

Monthly expected Visitors on the website whose campaign is created (Default : 300000)

Yes

stats.expectedRevenuePerVisitor

integer

Expected Revenue per visitor (Default : 2)

Yes

stats.liftInConversionRate

integer

Expected lift in Improvement Rate to be achieved by this campaign
(Default : 0.05)

Yes

Suggest Edits

Get all campaigns in an account / sub-account

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        [{
            "id": 7,
            "name": "Campaign 35",
            "type": "ab",
            "platform": "website",
            "status": "NOT_STARTED",
            "createdOn": 1417421529,
            "isDeleted": false,
            "createdBy": {
                "id": 44349,
                "name": "Sample",
                "imageUrl": "//gravatar.com/avatar/f4fedd3b67d066bfcce237a11da14825?s=24&d=https%3A%2F%2Fapp.vwo.com%2Fassets%2Fimages%2Favatar-new.png"
            },
            "primaryUrl": "http://wingify.com",
            "urls": [{
                "type": "url",
                "value": "http://wingify.com"
            }],
            "labels": [],
            "goals": {
                "partialCollection": [{
                    "id": 2,
                    "isPrimary": true,
                    "name": "New name",
                    "type": "visitPage",
                    "averageData": []
                }],
                "offset": 0,
                "totalCount": 3
            },
            "primaryGoal": 2,
            "variations": {
                "partialCollection": [],
                "totalCount": 3
            }
        }]
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

Query Params

limit
int32

Limit the number of campaigns to be returned

offset
string

Offset where campaign should be fetched from

 

Get the campaigns of an account

Note:

Data will be returned wrapped in the partialCollection along with count of total campaigns if the campaign count exceed the limit.

Request URI for Sub Account

GET /accounts/40505/campaigns
Suggest Edits

Get details of a specific campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 7,
    "name": "Campaign 7",
    "type": "ab",
    "status": "NOT_STARTED",
    "createdOn": 1472036883,
    "labels": [],
    "percentTraffic": 100,
    "createdBy": {
      "id": 40505,
      "name": "Sample",
      "imageUrl": "*****"
    },
    "urls": [
      {
        "type": "url",
        "value": "http://wingify.com"
      }
    ],
    "excludedUrls": [],
    "primaryUrl": "http://wingify.com",
    "integrations": {
      "ga": {
        "enabled": false,
        "slot": 4,
        "prefix": ""
      },
      "clicktale": {
        "enabled": false
      },
      "ua": {
        "enabled": false,
        "dimension": 1,
        "prefix": ""
      },
      "gtm": {
        "enabled": false
      }
    },
    "thresholds": {
      "winningPercent": 0.95,
      "losingPercent": 0.05,
      "visitors": 20
    },
    "device": "desktop",
    "variations": [
      {
        "id": 1,
        "name": "Control",
        "isControl": true,
        "isDisabled": false,
        "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_256_1_calc-0.png",
        "screenshots": {
          "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/256_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
        },
        "percentSplit": 100,
        "editorData": {
          "stack": null
        },
        "isBase": true
      }
    ],
    "goals": [
      {
        "id": 1,
        "isPrimary": true,
        "name": "New goal",
        "excludedUrls": [],
        "isCreatedInEditor": false,
        "type": "visitPage",
        "urls": [
          {
            "type": "url",
            "value": "http://wingify.com"
          }
        ],
        "averageData": []
      }
    ],
    "dataIntervalRange": [],
    "variationGoalData": [],
    "schedules": [],
    "isCrossDomainEnabled": false,
    "stats": {
      "conversionRate": "0.05",
      "liftInConversionRate": "0.05",
      "certaintyMode": "0.01",
      "expectedMonthlyVisitors": 300000,
      "expectedRevenuePerVisitor": "2"
    }
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Get details of a specific campaign

Request URI for Sub Account

GET /accounts/40505/campaigns/7
Suggest Edits

Create a campaign

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/campaigns
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/campaigns");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 15,
        "status": "NOT_STARTED",
        "goals": [
            {
                "id": 1,
                "name": "New goal"
            }
        ]
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Request Format

{
  "type" : "ab",
  "urls": [
            {
                "type": "url",
                "value": "http://wingify.com"
            }
        ],
  "primaryUrl" : "http://wingify.com",
  "goals":[{  
      "name":"New goal",
      "type":"visitPage",
      "urls":[  
         {  
            "type":"url",
            "value":"http://wingify.com"
         }
      ]
   }],
  "stats" : {
   	  "conversionRate" : 0.05,
      "certaintyMode" : 0.01,
      "expectedMonthlyVisitors" : 300000,
      "expectedRevenuePerVisitor" : 2,
      "liftInConversionRate" : 0.05
  }
}

Create a campaign

Note:

If stats are not provided, default value for stats (same as given in this request) are used for the campaign created.

Note:

For split campaign creation, two or more variations must be present in the request with urls for which the split campaign needs to be run.

Request URI for Sub Account

POST /accounts/40505/campaigns
Suggest Edits

Update a campaign

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 15,
    "name": "New name",
    "type": "ab",
    "status": "NOT_STARTED",
    "createdOn": 1472631589,
    "labels": [],
    "percentTraffic": 100,
    "createdBy": {
      "id": 40505,
      "name": "Sample",
      "imageUrl": "*****"
    },
    "urls": [
      {
        "type": "url",
        "value": "http://wingify.com"
      }
    ],
    "excludedUrls": [],
    "primaryUrl": "http://wingify.com",
    "integrations": {
      "ga": {
        "enabled": false,
        "slot": 4,
        "prefix": ""
      },
      "clicktale": {
        "enabled": false
      },
      "ua": {
        "enabled": false,
        "dimension": 1,
        "prefix": ""
      },
      "gtm": {
        "enabled": false
      }
    },
    "thresholds": {
      "winningPercent": 0.95,
      "losingPercent": 0.05,
      "visitors": 20
    },
    "device": "desktop",
    "variations": [
      {
        "id": 1,
        "name": "Control",
        "isControl": true,
        "isDisabled": false,
        "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_257_1_calc-0.png",
        "screenshots": {
          "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/257_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
        },
        "percentSplit": 100,
        "editorData": {
          "stack": null
        },
        "isBase": true
      }
    ],
    "goals": [
      {
        "id": 1,
        "isPrimary": true,
        "name": "New goal",
        "excludedUrls": [],
        "isCreatedInEditor": false,
        "type": "visitPage",
        "urls": [
          {
            "type": "url",
            "value": "http://wingify.com"
          }
        ],
        "averageData": []
      }
    ],
    "dataIntervalRange": [],
    "variationGoalData": [],
    "schedules": [],
    "stats": {
      "conversionRate": "0.05",
      "liftInConversionRate": "0.05",
      "certaintyMode": "0.01",
      "expectedMonthlyVisitors": 300000,
      "expectedRevenuePerVisitor": "2"
    }
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request Format

{
  "campaigns" : {
  		"name" : "New name"
  }
}

Update a campaign

Request URI for Sub Account

PATCH /accounts/40505/campaigns/15
Suggest Edits

Update campaign status

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/campaigns/status
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/status
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/status' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/status")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/campaigns/status");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/status"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "status": "STOPPED",
        "ids": [
            14,
            15
        ]
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Request Format

{
  "ids" : [14, 15],
  "status" : "TRASHED"
}

Update campaign status

Note:

Valid status changes include TRASHED, RESTORED, RUNNING, STOPPED, PAUSED

Request URI for Sub Account

PATCH /accounts/40505/campaigns/status
Suggest Edits

Goal resource representation

 
Property
Type
Description
Editable

id

Int

Goal Id

No

type

string

Goal Type

Valid values include visitPage, engagement, formSubmit, clickLink, clickElement, revenue, custom-conversion

Note:Please take caution while changing type, it might impact the data collection

Yes

name

string

Goal Name

Yes

isPrimary

boolean

Flag which signifies if the goal is primary goal or not

No

urls

Nested Object

Contains the url related information on which goal will be triggered.

See Campaign resource for more details on this

Yes

cssSelectors

list

Goal path

cssSelector.0

string

selector path

Yes

isCreatedInEditor

boolean

Flag if the goal was created in editor or not

No

Note:

urls is not required for engagement type goal

Note:

Multiple cssSelectors should be added as array values, like ["selector1, selector2"]

Suggest Edits

Get all goals of a campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/goals
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 2,
            "isPrimary": true,
            "name": "Goal 2",
            "urls": [
                {
                    "type": "url",
                    "value": "http://wingify.com"
                }
            ],
            "excludedUrls": [],
            "cssSelectors": [
                null
            ],
            "isCreatedInEditor": false,
            "type": "visitPage"
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Get all the goals of a campaign

Request URI for Sub Account

GET /accounts/40505/campaigns/7/goals
Suggest Edits

Get details of a specific goal in a campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/goals/goal_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals/goal_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals/goal_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals/goal_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals/goal_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/goals/goal_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 2,
        "isPrimary": true,
        "name": "Goal 2",
        "urls": [
            {
                "type": "url",
                "value": "http://wingify.com"
            }
        ],
        "excludedUrls": [],
        "cssSelectors": [
            null
        ],
        "isCreatedInEditor": false,
        "type": "visitPage"
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

goal_id
int32
required

Goal Id

 

Get details of a specific goal in a campaign

Request URI for Sub Account

GET /accounts/40505/campaigns/7/goals/2
Suggest Edits

Create a campaign goal

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/campaign/campaign_id/goals
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 3,
        "isPrimary": false,
        "name": "New goal",
        "urls": [
            {
                "type": "url",
                "value": "http://wingify.com"
            }
        ],
        "excludedUrls": [],
        "cssSelectors": [
            null
        ],
        "isCreatedInEditor": false,
        "type": "visitPage"
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request URI for Sub Account

POST /accounts/40505/campaigns/7/goals

Request Format

{  
   "goals":{  
      "name":"New goal",
      "type":"visitPage",
      "urls":[  
         {  
            "type":"url",
            "value":"http://wingify.com"
         }
      ]
   }
}

Create a campaign goal

Note:

  • valid type includes visitPage, engagement, formSubmit, clickLink, clickElement, revenue, custom-conversion
  • name is a required property
  • for type clickElement, cssSelectors is required
  • for type visitPage, formSubmit, clickLink, revenue, custom-conversion, urls is required
  • valid url type includes url, startsWith, endsWith, contains, pattern, regex, cssSelector

-

Suggest Edits

Update a campaign goal

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/campaign/campaign_id/goals/goal_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 2,
        "isPrimary": true,
        "name": "New name",
        "urls": [
            {
                "type": "url",
                "value": "http://wingify.com"
            }
        ],
        "excludedUrls": [],
        "cssSelectors": [
            null
        ],
        "isCreatedInEditor": false,
        "type": "visitPage"
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

goal_id
int32
required

Goal Id

 

Request URI for Sub Account

PATCH /accounts/40505/campaigns/7/goals/2

Request Format

{  
   "goals": {  
      "name":"New name"
   }
}

Update a campaign goal

Suggest Edits

Delete a campaign goal

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/campaign/campaign_id/goals/goal_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaign/campaign_id/goals/goal_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

goal_id
int32
required

Goal Id

 

Delete a campaign goal

Request URI for Sub Account

DELETE /accounts/40505/campaigns/7/goals/2
Suggest Edits

Variations

 
Suggest Edits

Variation resource representation

 
Property
Type
Description
Editable

id

Int

Variation Id

Note: Please ensure that variation Id is serial. For eg, if you have variations with ids 1,2,3 and you delete variation id 2, now you would have the variation ids 1, 2; 3 would be updated to 2

No

name

string

Variation Name

Yes

isControl

boolean

Flag which signifies if the variation is control variation

No

isDisabled

boolean

Flag which signifies if the variation is disabled

Note: Please set the percentSplit to 0 for the given variation to disable it

No

percentSplit

float

Percentage Traffic allocated for variation

Yes

editorData

Nested Object

Contains the JS/CSS changes created for the variation

No

editorData.stack

list

stack contains the list of the changes for the variation

No

heatmapThumbUrl

link

Link for the heatmap thumbnail

No

screenshots

list

Contains the link of screenshots for the selected browsers for the variation

No

sectionId

int

Section Id

Note: This would be 1 except the MULTIVARIATE campaign. It would be meaningful in that case only.

No

Note:

For adding js/css changes in variations, please use changes property in request body. These changes will be override any previous changes, if any.

Note

Variation splitPercent will be equally distributed among all variations on the creation of a new variation, which can be updated via update request

Suggest Edits

Get all variations of a campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/variations
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 1,
            "name": "Control",
            "isControl": true,
            "isDisabled": false,
            "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-40505_7_1_calc-0.png",
            "screenshots": {
                "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/40505/7_1_8cf9ad535ba453c84abd4c38617f93b4.png"
            },
            "percentSplit": 50,
            "editorData": {
                "stack": []
            },
            "sectionId": 1
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Get all the variations of a campaign

Request URI for Sub Account

GET /accounts/40505/campaigns/7/variations
Suggest Edits

Get details of a specific campaign variation

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/variations/variation_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 1,
        "name": "Control",
        "isControl": true,
        "isDisabled": false,
        "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-40505_7_1_calc-0.png",
        "screenshots": {
            "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/40505/7_1_8cf9ad535ba453c84abd4c38617f93b4.png"
        },
        "percentSplit": 50,
        "editorData": {
            "stack": []
        },
        "sectionId": 1
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

variation_id
string
required

Use sectionId,variationId for the MULTIVARIATE campaign

 

Get details of a specific campaign variation

Request URI for Sub Account

GET /accounts/40505/campaigns/7/variations/1
Suggest Edits

Create a campaign variation

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/variations
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 3,
        "name": "New shiny variation",
        "isControl": false,
        "isDisabled": false,
        "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-40505_7_3_calc-0.png",
        "screenshots": {
            "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/40505/7_3_8cf9ad535ba453c84abd4c38617f93b4.png"
        },
        "percentSplit": 33.3333,
        "editorData": {
            "stack": null
        }
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request Format

{
  "variations" : {
		"name": "New shiny variation"
  }
}

Create a campaign variation

Info:

To add changes to the variation, please add changes under the key 'changes'. For e.g. to show an alert in variation

{
"variations" : {
.
.
"changes" : "<script>alert('Hello World');</script>"
.
.
}
}

Request URI for Sub Account

POST /accounts/40505/campaigns/7/variations
Suggest Edits

Update a campaign variation

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/variations/variation_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 1,
        "name": "New name",
        "isControl": true,
        "isDisabled": false,
        "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-40505_7_1_calc-0.png",
        "screenshots": {
            "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/40505/7_1_8cf9ad535ba453c84abd4c38617f93b4.png"
        },
        "percentSplit": 50,
        "editorData": {
            "stack": []
        },
        "sectionId": 1
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

variation_id
string
required

Use sectionId,variationId for the MULTIVARIATE campaign

 

Request Format

{  
   "variations": {  
      "name":"New name"
   }
}

Update a campaign variation

Request URI for Sub Account

PATCH /accounts/40505/campaigns/7/variations/1
Suggest Edits

Delete a campaign variation

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/variations/variation_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/variations/variation_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

variation_id
string
required

Use sectionId,variationId for the MULTIVARIATE campaign

 

Delete a campaign variation

Note:

Please ensure that variation Id is serial. For example, if you have variations with ids 1,2,3 and you delete variation id 2, now you would have the variation ids 1, 2, whereas 3 would be updated to 2. So, issue a GET /variations after the delete which would return the updated variations.

Request URI for Sub Account

DELETE /accounts/40505/campaigns/7/variations/1
 
Suggest Edits

Section resource representation

 
Property
Type
Description
Editable

id

int

Section Id

No

name

string

Section Name

Yes

cssSelector

string

Section Path

No

variations

nested object

See variation resource

Note:

Only allowed for the MULTIVARIATE campaign

Suggest Edits

Get all sections of a campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/sections
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 1,
            "name": "Baja Baja",
            "cssSelector": "DIV#js-header-fixed-trigger + SECTION > DIV:first-child > DIV:first-child > DIV:first-child",
            "variations": [
                {
                    "id": 1,
                    "name": "Control",
                    "isControl": true,
                    "isDisabled": false,
                    "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_2905_1_calc-0.png",
                    "screenshots": {
                        "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/2905_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
                    },
                    "editorData": {
                        "stack": []
                    }
                }
            ]
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to specify Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Get all sections of a campaign

Request URI for Sub Account

GET /accounts/40505/campaigns/8/sections
Suggest Edits

Get details of a specific campaign section

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/sections/section_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 1,
        "name": "Baja Baja",
        "cssSelector": "DIV#js-header-fixed-trigger + SECTION > DIV:first-child > DIV:first-child > DIV:first-child",
        "variations": [
            {
                "id": 1,
                "name": "Control",
                "isControl": true,
                "isDisabled": false,
                "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_2905_1_calc-0.png",
                "screenshots": {
                    "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/2905_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
                },
                "editorData": {
                    "stack": []
                }
            }
        ]
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

section_id
int32
required

Section Id

 

Get details of a specific campaign section

Request URI for Sub Account

GET /accounts/40505/campaigns/8/sections/1
Suggest Edits

Create a campaign section

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/sections
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 2,
            "name": "New shiny section",
            "cssSelector": "DIV#js-header-fixed-trigger + SECTION > DIV:first-child > DIV:first-child > DIV:first-child",
            "variations": [
                {
                    "id": 1,
                    "name": "Control",
                    "isControl": true,
                    "isDisabled": false,
                    "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_2905_1_calc-0.png",
                    "screenshots": {
                        "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/2905_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
                    },
                    "editorData": {
                        "stack": []
                    }
                }
            ]
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request Format

{
  "sections" : {
    "name": "New shiny section",
    "cssSelector": "DIV#js-header-fixed-trigger + SECTION > DIV:first-child > DIV:first-child > DIV:first-child",
    "variations" : [
      	{
      		"name" : "New shiny variation"
    	}
    ]
  }
}

Create a campaign section

Request URI for Sub Account

POST /accounts/40505/campaigns/8/sections
Suggest Edits

Update a campaign section

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/sections/section_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "id": 1,
        "name": "New name",
        "cssSelector": "DIV#js-header-fixed-trigger + SECTION > DIV:first-child > DIV:first-child > DIV:first-child",
        "variations": [
            {
                "id": 1,
                "name": "Control",
                "isControl": true,
                "isDisabled": false,
                "heatmapThumbUrl": "//heatmap.visualwebsiteoptimizer.com/h/viswebopt-1_2905_1_calc-0.png",
                "screenshots": {
                    "quick": "//s3.amazonaws.com/wfyss.visualwebsiteoptimizer.com/1/2905_1_c9dd0f600be0b9fc8490bcd85ae0f95d.png"
                },
                "editorData": {
                    "stack": []
                }
            }
        ]
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

section_id
int32
required

Section Id

 

Request Format

{
  "sections" : {
    "name" : "New name"
  }
}

Get details of a specific campaign section

Request URI for Sub Account

PATCH /accounts/40505/campaigns/8/sections/1
Suggest Edits

Delete a campaign section

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/sections/section_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/sections/section_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

section_id
int32
required

Section Id

 

Delete a campaign section

Request URI for Sub Account

DELETE /accounts/40505/campaigns/8/sections/2
 

You can manage your current account or sub-accounts via the following API Endpoints.
To understand accounts resource in depth, read our knowledge base article on VWO Accounts.

Suggest Edits

Retrieve all accounts

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts
import requests

url = "https://app.vwo.com/api/v2/accounts"

headers = {
    'token': "96ca71826128162811321nnjadsdjnsadkf33c4c03660a2398abd93f60c74ef1b442a434",
    'cache-control': "no-cache"
    }

response = requests.request("GET", url, headers=headers)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": [
    {
      "id": 916,
      "name": "New account",
      "createdOn": 1271158169,
      "enabled": true
    },
    {
      "id": 874,
      "name": "Test Account",
      "createdOn": 1269942600,
      "enabled": true
    }
  ]
}
 

Request URI

GET /accounts
Suggest Edits

Retrieve specific account

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 1,
    "name": "Main Account",
    "createdOn": 1257680705,
    "timezone": "Asia\/Dhaka",
    "company": {
      "name": "",
      "website": "",
      "size": ""
    },
    "enabled": true
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

To retrieve information of a specific account, enter the associated campaign ID.

Request URI for Sub Account

GET /accounts/1
Suggest Edits

Create a sub-account

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts
var request = require("request");

var options = { method: 'POST', url: 'https://app.vwo.com/api/v2/accounts' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 40506,
    "name": "API Sub Account Name",
    "createdOn": 1415966384,
    "timezone": "GMT"
  }
}

Body Params

name
string
required

Sub-account name

 

Request URI

POST /accounts
Suggest Edits

Update account

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/account_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/account_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/account_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/account_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/account_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "name": "API Account Name",
    "timezone": "Asia\/Kolkata",
    "enabled": true,
    "company": {
      "name": "API Company Name",
      "website": "http:\/\/wingify.com",
      "size": "1-200",
      "industry": {
        "type": "saas"
      }
    }
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

Body Params

name
string

Account Name

timezone
string

Timezone associated with the Account e.g. \"Asia\/Kolkata\"

enabled
boolean

Disable/Enable Account

company
object
 
company.name
string

Company name associated with the Account

company.website
string

Website URL of the Company, if any

company.size
string

Choose among these options ["1-200","201-500","501-1000","1001-2000","2000+"]

company.industry
object
 
company.industry.type
string

Industry Type of the Company

 

Update details of Account.

Category
Value to be passed in API

eCommerce / Internet Retail

ecommerce

Software / SaaS / Downloads

saas

Media / Publishers / Blog

media

Digital Marketing / Agency / Web Development Shop

agency

Travel and Tourism / Hotels / Hospitality

travel

Non-government / Charity

ngo

Entertainment

entertainment

Banking / Financial Services / Insurance

banking

Business Consulting

businessConsulting

Healthcare / Medicine / Bio

health

Education / Training

education

Telecom

telecom

Use enabled field to Enable/Disable account with Caution.

Request URI for Sub Account

PATCH /accounts/1

Request Format

{
  "name": "API Account Name",
  "timezone": "Asia\/Kolkata",
  "enabled": true,
  "company": {
    "name": "API Company Name",
    "website": "http:\/\/wingify.com",
    "size": "1-200",
    "industry": {
      "type": "saas"
    }
  }
}
Suggest Edits

Get all users

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/users
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/users
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/users' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/users")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/users");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/users"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": [
    {
      "id": 1,
      "name": "Backend Testing",
      "email": "dev+testing@wingify.com",
      "account": 1,
      "permission": "Admin",
      "createdOn": 1257680705,
      "phone": "FALSE",
      "country": "",
      "department": "",
      "title": ""
    },
    {
      "id": 951,
      "name": "Browse Only",
      "email": "browse-only@wingify.com",
      "permission": "Browse",
      "account": 1,
      "createdOn": 1271320843,
      "phone": "FALSE",
      "country": "",
      "department": "",
      "title": ""
    }
  ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Get Current / Sub Account Users.

Request URI for Sub Account

GET /accounts/1/users
Suggest Edits

Get user details

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/users/user_id
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/users/user_id
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/users/user_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/users/user_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/users/user_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/users/user_id"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 874,
    "name": "Test User",
    "email": "test-account@wingify.com",
    "createdOn": 1269942600,
    "permission": "Admin",
    "phone": "FALSE",
    "country": "",
    "department": "",
    "title": ""
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

user_id
int32
required

User Id

 

Get specific user of Current / Sub Account.

Request URI for Sub Account

GET /accounts/1/users/874
Suggest Edits

Create a user

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/users
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/users
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/users' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/users")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/users");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/users"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 44350,
    "name": "Test via API",
    "email": "test+api@wingify.com",
    "createdOn": 1415876399,
    "permission": "Admin",
    "phone": "9999988877",
    "country": "India",
    "department": "Software Engineering",
    "title": "API Evangelist"
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Create User in Current / Sub Account.

Request URI for Sub Account

POST /accounts/1/users
{
  "name": "Test via API",
  "email": "test+api@wingify.com",
  "password": "*password*",
  "confirmPassword": "*password*",
  "phone": "9999988877",
  "country": "India",
  "department": "Software Engineering",
  "title": "API Evangelist",
  "permission": "Admin"
}
Suggest Edits

Update user details

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/users/user_id
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/current/users/user_id
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/current/users/user_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/users/user_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/current/users/user_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/users/user_id"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "id": 874,
    "name": "Test User",
    "email": "test-account@wingify.com",
    "createdOn": 1269942600,
    "permission": "Admin",
    "phone": "FALSE",
    "country": "",
    "department": "",
    "title": ""
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

user_id
int32
required

User Id

Body Params

name
string

Name of User

phone
string

Contact number of User

country
string

Country of User

department
string

Work department of User

title
string

Designation of User

permission
string

Select the permission of user among "Browse","Design","Publish","Admin"

 
{
  "name": "API User Name",
  "phone": "9999988877",
  "country": "India",
  "department": "Software Engineering",
  "title": "API Evangelist",
  "permission": "Browse"
}

Update specific user of Current / Sub Account.

Request URI for Sub Account

PATCH /accounts/1/users/874

Request Format

Suggest Edits

Delete users

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/users/user_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/users/user_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/users/user_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/users/user_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/users/user_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/users/user_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

user_id
int32
required

User Id

 

DELETE specific user of Current / Sub Account.

Request URI for Sub Account

DELETE /accounts/1/users/874
Suggest Edits

Tracking Code

 

The VWO smart code snippet that you add to your pages contacts VWO server whenever a visitor lands on a test page. The server sends its response in two parts - static JavaScript code for running the test and dynamic test-specific data. Both the static and dynamic parts of the response are cached heavily at the server back-end, thereby minimizing the response time. With code minification and gzipping, the size of response decreases even further.

To understand more about VWO smart code, read our knowledge base article on VWO Accounts.

Suggest Edits

Get Smart Code of accounts

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/tracking-code
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/tracking-code
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/tracking-code' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/tracking-code")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/tracking-code");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/tracking-code"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": {
        "sync": "<!-- Start Visual Website Optimizer Synchronous Code -->\n<script type='text/javascript'>\nvar _vis_opt_account_id = 874;\nvar _vis_opt_protocol = (('https:' == document.location.protocol) ? 'https://' : 'http://');\ndocument.write('<s' + 'cript src=\"' + _vis_opt_protocol +\n'dev.visualwebsiteoptimizer.com/deploy/js_visitor_settings.php?v=1&a='+_vis_opt_account_id+'&url='\n+encodeURIComponent(document.URL)+'&random='+Math.random()+'\" type=\"text/javascript\">' + '<\\/s' + 'cript>');\n</script>\n\n<script type='text/javascript'>\nif(typeof(_vis_opt_settings_loaded) == \"boolean\") { document.write('<s' + 'cript src=\"' + _vis_opt_protocol +\n'd5phz18u4wuww.cloudfront.net/vis_opt.js\" type=\"text/javascript\">' + '<\\/s' + 'cript>'); }\n// if your site already has jQuery 1.4.2, replace vis_opt.js with vis_opt_no_jquery.js above\n</script>\n\n<script type='text/javascript'>\nif(typeof(_vis_opt_settings_loaded) == \"boolean\" && typeof(_vis_opt_top_initialize) == \"function\") {\n        _vis_opt_top_initialize(); vwo_$(document).ready(function() { _vis_opt_bottom_initialize(); });\n}\n</script>\n<!-- End Visual Website Optimizer Synchronous Code -->",
        "async": "<!-- Start Visual Website Optimizer Asynchronous Code -->\n<script type='text/javascript'>\nvar _vwo_code=(function(){\nvar account_id=874,\nsettings_tolerance=2000,\nlibrary_tolerance=2500,\nuse_existing_jquery=false,\n// DO NOT EDIT BELOW THIS LINE\nf=false,d=document;return{use_existing_jquery:function(){return use_existing_jquery;},library_tolerance:function(){return library_tolerance;},finish:function(){if(!f){f=true;var a=d.getElementById('_vis_opt_path_hides');if(a)a.parentNode.removeChild(a);}},finished:function(){return f;},load:function(a){var b=d.createElement('script');b.src=a;b.type='text/javascript';b.innerText;b.onerror=function(){_vwo_code.finish();};d.getElementsByTagName('head')[0].appendChild(b);},init:function(){settings_timer=setTimeout('_vwo_code.finish()',settings_tolerance);this.load('//dev.visualwebsiteoptimizer.com/j.php?a='+account_id+'&u='+encodeURIComponent(d.URL)+'&r='+Math.random());var a=d.createElement('style'),b='body{opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important;}',h=d.getElementsByTagName('head')[0];a.setAttribute('id','_vis_opt_path_hides');a.setAttribute('type','text/css');if(a.styleSheet)a.styleSheet.cssText=b;else a.appendChild(d.createTextNode(b));h.appendChild(a);return settings_timer;}};}());_vwo_settings_timer=_vwo_code.init();\n</script>\n<!-- End Visual Website Optimizer Asynchronous Code -->"
    }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Get Synchronous/Asynchronous Tracking Code for Current / Sub Account

Request URI for Sub Account

GET /accounts/874/tracking-code
Suggest Edits

Account Thresholds

 

Account threshold values indicate the level of confidence you can have on a variation to perform better as compared to the control (original) version of a website. VWO determines a winning variation in a campaign by calculating the Chance to beat original (CTBO) metric. The level of confidence in a variation is indicated by a value between 0%-100 percent.

You can set the threshold for winning variation, losing variation, and minimum visitors required to calculate which variation wins or loses.

Suggest Edits

Get account thresholds

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/thresholds
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/thresholds
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/thresholds' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/thresholds")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/thresholds");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/thresholds"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "winningPercent": 95,
    "losingPercent": 5,
    "visitors": 20
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Get threshold for current and sub-accounts.

Request URI for Sub Account

GET /accounts/1/thresholds
Suggest Edits

Update account thresholds

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/thresholds
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/account_id/thresholds
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/account_id/thresholds' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/account_id/thresholds")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/account_id/thresholds");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/account_id/thresholds"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "winningPercent": 95,
    "losingPercent": 5,
    "visitors": 21
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

Body Params

winningPercent
int32

Winning Percent

losingPercent
int32

Losing Percent

visitors
int32

Number of visitors

 

Update account Thresholds.

Request URI for Sub Account

PATCH /accounts/1/thresholds

Request Format:

{
  "winningPercent": 95,
  "losingPercent": 5,
  "visitors": 21
}
Suggest Edits

Third-party Integrations

 

Third-party integration allows you to integrate your VWO data with other analytics tools, providing a deeper insight into your campaign reports.

To understand third-party integration supported in VWO, read our knowledge base articles on VWO Integration.

Suggest Edits

Get integration settings of Current / Sub Account

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/integrations
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/account_id/integrations
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/account_id/integrations' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/account_id/integrations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/account_id/integrations");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/account_id/integrations"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "ga": {
      "enabled": false,
      "slot": 4,
      "prefix": ""
    },
    "clicktale": {
      "enabled": false
    },
    "ua": {
      "enabled": false,
      "dimension": 1,
      "prefix": ""
    },
    "gtm": {
      "enabled": false
    },
    "isGaPremium": false
  }
}

Path Params

account_id
string
required

Account Id

 

Get Third Party Integrations for Current / Sub Account.

Request URI

GET /accounts/:account_id/integrations
Suggest Edits

Update integration settings for specific account

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://app.vwo.com/api/v2/accounts/account_id/integrations
curl --request PATCH \
  --url https://app.vwo.com/api/v2/accounts/account_id/integrations
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://app.vwo.com/api/v2/accounts/account_id/integrations' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/account_id/integrations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PATCH", "https://app.vwo.com/api/v2/accounts/account_id/integrations");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/account_id/integrations"

response = requests.request("PATCH", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "ga": {
      "enabled": true,
      "slot": 4,
      "prefix": ""
    },
    "ua": {
      "enabled": false,
      "dimension": 1,
      "prefix": ""
    },
    "gtm": {
      "enabled": false
    },
    "clicktale": {
      "enabled": false
    },
    "isGaPremium": false
  }
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

Body Params

ga
object
 
ga.
array of mixed types

Information regarding Google Analytics

ga.enabled
boolean

Google Analytics whether enabled or not

ga.slot
int32

Google Analytics Slot

ga.prefix
string

Google Analytics Account prefix

ua
object
 
ua.
array of mixed types

Universal Analytics Settings

ua.enabled
string

Universal Analytics whether enabled or not

ua.dimension
string

Custom Dimension used inside Google Analytics

ua.prefix
string

Google Analytics Account prefix

gtm
object
 
gtm.
string

Settings for Google Tag Manager

gtm.enabled
boolean

Google Tag Manager whether enabled or not

clicktale
object
 
clicktale.
array of mixed types

ClickTale Settings

clicktale.enabled
boolean

Clicktale whether enabled or not

isGaPremium
boolean

Whether Google Analytics is premium

 

Update Third Party Integrations. Here's an example of the request params:

Request URI for Sub Account

PATCH /accounts/1/integrations

Request Format

{
  "ga": {
    "enabled": true,
    "slot": 4,
    "prefix": ""
  },
  "ua": {
    "enabled": false,
    "dimension": 1,
    "prefix": ""
  },
  "gtm": {
    "enabled": false
  },
  "clicktale": {
    "enabled": false
  },
  "isGaPremium": false
}
 
Suggest Edits

Get billing details of accounts

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/billing-details
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/billing-details
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/billing-details' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/billing-details")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/billing-details");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/billing-details"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "paymentProcessor": "2Checkout",
    "customerName": "",
    "billingAddress": "<br \/>",
    "changeBillingUrl": "https:\/\/www.2checkout.com\/va\/sales\/customer\/change_billing_method?sale_id=4491073920",
    "creditCardNumber": "-XXXX-XXXX-XX",
    "paymentMethod": "credit-card"
  }
}
 

Get Billing details for Account.

GET /accounts/billing-details
Suggest Edits

Get billing cycle details of accounts

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/billing-cycles
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/billing-cycles
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/billing-cycles' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/billing-cycles")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/billing-cycles");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/billing-cycles"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": [
    {
      "id": 1,
      "from": 1271924465,
      "to": 1275264000,
      "visitorsAllowed": 101000,
      "invoice": null,
      "plan": {
        "id": 1,
        "type": "FREE",
        "price": 0,
        "description": "Free account for existing beta users",
        "isEnterprise": false,
        "totalVisitors": 100000,
        "isUnlimitedPlan": false,
        "isTopVisitorPlan": false
      },
      "isCurrent": false,
      "visitorsUsed": 7,
      "usages": [
        {
          "account": 1,
          "visitorsUsed": 7
        },
        {
          "account": 874,
          "visitorsUsed": 0
        },
        {
          "account": 916,
          "visitorsUsed": 0
        },
        {
          "account": 1413,
          "visitorsUsed": 0
        },
        {
          "account": 2904,
          "visitorsUsed": 0
        }
      ]
    }
  ]
}
 

Get Billing Cycle details of Current Account.

GET /accounts/billing-cycles
Suggest Edits

Get account invoices

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/invoice
curl --request GET \
  --url 'https://app.vwo.com/api/v2/accounts/invoice?billing-cycle=billing-cycle'
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/invoice',
  qs: { 'billing-cycle': 'billing-cycle' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/invoice?billing-cycle=billing-cycle")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/invoice?billing-cycle=billing-cycle");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/invoice"

querystring = {"billing-cycle":"billing-cycle"}

response = requests.request("GET", url, params=querystring)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

billing-cycle
int32
required

Use the Billing Cycle Id

 

Returns PDF as response.

GET /accounts/invoice
Suggest Edits

Get labels

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/labels
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/labels
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/labels' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/labels")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/labels");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/labels"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": [
    {
      "id": 1,
      "name": "Demo"
    },
    {
      "id": 2,
      "name": "Real"
    },
    {
      "id": 3,
      "name": "Personal"
    }
  ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

 

Get labels for Current / Sub Accounts.

Request URI for Sub Account

GET /accounts/1/labels
Suggest Edits

Get labels of a specific campaign

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/labels
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 1,
            "name": "Demo"
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request URL for Sub Account

GET /accounts/1/campaigns/72/labels

Get all the labels associated with a campaign

Suggest Edits

Add labels to a campaign

 

Header Auth

 Authentication is required for this endpoint.
posthttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/labels
curl --request POST \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels
var request = require("request");

var options = { method: 'POST',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
    "_data": [
        {
            "id": 1,
            "name": "Demo"
        },
        {
            "id": 2,
            "name": "Real"
        },
        {
            "id": 4,
            "name": "New shiny label"
        }
    ]
}

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

 

Request URI for Sub Account

POST /accounts/1/campaigns/72/labels

Request Format

{
    "labels": [
      {
        "name" : "New shiny label"
      }
    ]
}

Add labels to a campaign

Note: Mention id for associating existing account labels to campaign and name for creating a new label

Suggest Edits

Delete a campaign label

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://app.vwo.com/api/v2/accounts/account_id/campaigns/campaign_id/labels/label_id
curl --request DELETE \
  --url https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels/label_id
var request = require("request");

var options = { method: 'DELETE',
  url: 'https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels/label_id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels/label_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels/label_id");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/current/campaigns/campaign_id/labels/label_id"

response = requests.request("DELETE", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

account_id
string
required

Use 'current' keyword to refer to the Main Account or the Integer Sub Account Id

campaign_id
int32
required

Campaign Id

label_id
int32
required

Label Id

 

Request URL for Sub Account

DELETE accounts/1/campaigns/72/labels/1

Delete a campaign label

Suggest Edits

Campaign labels

 

VWO Campaign labels are keywords or tags you associate with your campaigns. Adding a label helps you to easily identify campaigns and eliminates the need to browse the entire list when searching for a specific campaign.

 
Suggest Edits

Get partner details

 

Header Auth

 Authentication is required for this endpoint.
gethttps://app.vwo.com/api/v2/accounts/partners
curl --request GET \
  --url https://app.vwo.com/api/v2/accounts/partners
var request = require("request");

var options = { method: 'GET',
  url: 'https://app.vwo.com/api/v2/accounts/partners' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://app.vwo.com/api/v2/accounts/partners")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://app.vwo.com/api/v2/accounts/partners");

xhr.send(data);
import requests

url = "https://app.vwo.com/api/v2/accounts/partners"

response = requests.request("GET", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

{
  "_data": {
    "freeUsers": 1,
    "paidUsers": 1,
    "sales": 49,
    "commissionPercent": "0.15",
    "totalCommission": 7.35,
    "commissionDisbursed": 12.35,
    "referralCode": "pc"
  }
}
 

Get partner details associated with an account.

GET /accounts/partners
Suggest Edits

Quick Start Guide

 

Create an Account

You can create a free VWO account from the signup page.

Create an iOS App

Registering your iOS app on VWO is a one-time process.
Adding your app generates an Api Key which is used by VWO servers to recognise your app.

Select the Mobile App A/B option under the test menu.
Click Create, and then click Add New App. Write a name for your app, and then choose iOS as a platform.
Note the api key generated by the system.

Create a Campaign

Click Create, and then select your app.

Define Variations

Variations are different versions of an app. These versions can be represented by difference in settings of the app, a different value for a settings key. Settings are represented by JSON.

Write JSON for the changes you want to A/B test.
For this example, we will consider a generic key and a value.

{
  "key": "value" 
}

Define Goals

In the next step, define at least one goal. Goal is a conversion matrix that we want to optimize.

conversionGoal

Finalize

In the Finalize step, we can set the percentage of users that we want to include in the campaign.
Under the Advanced option, we can also target the campaign for specific user types, enable scheduling, or change traffic allocation for each variation.
For quick setup, we can leave the settings in Advanced as default.

To run the campaign, click Finish > Start Now.

Installing SDK

You can use Cocoapods to install the VWO iOS SDK.
For Cocoapods installation, add pod 'VWO' to your Pod file.
Run the pod install command.

Refer detail installation instructions here.

Code changes in mobile app

1. Initialising the SDK

After installing the SDK, you can initialize it.
It is done in the AppDelegate file in the didFinishLaunchingWithOptions method.
Import the VWO header file, and then call the launchForAPIKey method with your app key.

// importing the VWO module
@import VWO;

// initialising the SDK
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [VWO launchForAPIKey:@"<your-api-key>" completion:^{
  		//Code executed after launch is complete
	} failure:^(NSString * _Nonnull error) {
		// Failure handling
	}];
  return YES;
}
// importing the header file
import VWO

// initialising the SDK
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
VWO.launch(apiKey: "<your-api-key>",
  completion: {
	   //Code executed after launch is complete     
	}, failure: { error in
      print(error)
})
return true
}

2. Using campaigns

To use the variation defined during campaign creation, use the following code to get value for the campaign keys.

id variation = [VWO variationForKey:@"your-campaign-key" defaultValue:@"default-value"];
let value: Any? = VWO.variationFor(key: "your-campaign-key", defaultValue: "defaultValue")

When the variationForKey:defaultValue: method is invoked, the SDK checks if the targeting conditions hold true for the user.
If targeting/segmentation conditions hold true, the user is made part of the campaign and the visitor count in the report section increments by 1.

3. Triggering goals

We would want to track the effect of this campaign on our conversion metric.
Earlier, we defined conversionGoal as a goal.
We need to tell VWO SDK when this conversion happens. Use the code below to trigger this goal.

[VWO trackConversion:@"conversionGoal"];
VWO.trackConversion("conversionGoal")

Reports

From the Mobile App A/B menu option, select your campaign and then click DETAILED REPORTS to see the reports of your campaign.

Source Code

VWO iOS SDK code is available on GitHub:
https://github.com/wingify/vwo-ios-sdk

Next Steps

As the next step, look at SDK Reference to explore more advanced options of using the SDK.
We would look forward to hear from you about any question or feedback at support@vwo.com.

Suggest Edits

SDK Reference

 

This section is a full reference for VWO's iOS SDK.

Read further to find out how to install iOS SDK, preview your changes, and run optimization tests.

Suggest Edits

Adding an App

 

Before you can A/B test your mobile app, register it with VWO.
Registering an app is a one-time process.

From the Test menu, select Mobile App A/B.
(https://app.vwo.com/#/test/mobile-ab)

Click Create in the upper-right corner of the page.

Click Add New App.

Type the name of your app and then select iOS as the platform type.
Next, click Add App.

As you type the name of your app, you can see an auto-generated ApiKey.
You will use this ApiKey during app initialisation.

Your app will start appearing in the app list.

To see the list of all the added apps:
http://app.vwo.com/#/settings/custom-content/mobile-apps

Suggest Edits

SDK Installation

 

The iOS SDK can be installed by using CocoaPods.

Cocoapods Installation

To integrate your mobile application using CocoaPods, you must first create a Podfile.
If you are new to CocoaPods, please refer to CocoaPods instruction guide.

1. Add the following line to the Podfile.

 target 'Your App' do
     pod 'VWO'
 end

2. Run command.

pod install

pod install will install the SDK in your project. The SDK does not have any external library dependency.

VWO/Core

Tu reduce the size of SDK pod 'VWO/Core' can be added to the Podfile.
This will make sure that all the extra code that is required only while development, is not shipped with the app.

Source Code

The VWO iOS SDK code is available on GitHub:
https://github.com/wingify/vwo-ios-sdk

Suggest Edits

Launching the SDK

 

After installing the SDK, you can initialize the VWO SDK in your mobile app.

Api Key

To initialize the SDK, we will use the ApiKey generated while Adding an App .

You can also get the list of all apps with ApiKey from the settings section in the VWO dashboard.

Initializing of the SDK is done in the AppDelegate file.

@import "VWO";
import VWO

SDK can be launched in two ways:
asynchronous and synchronous.

Asynchronous initialization does NOT block code execution while SDK fetches settings from the VWO content distribution network, but a synchronous call blocks code execution.
We recommend asynchronous initialization, as it does not affect the UI of your app.

Asynchronous

Asynchronous initialization is available in two modes:

Asynchronous initialization with callback

[VWO launchForAPIKey:@"<your-api-key>" config:nil completion:^{
  //Code executed after launch is complete
} failure:^(NSString * _Nonnull error) {
	// Failure handling
}];

VWO.launch(apiKey: "<your-api-key>", config: nil
  completion: {
	   //Code executed after launch is complete     
	}, failure: { error in
      print(error)
})

Launch configuration can be passed to while launching the SDK. More info here
The completion callback method is used after SDK fetches settings from the VWO content distribution network and processes those settings.
Use callback when you want to get notified that the SDK is ready.

Use case for using the callback method:
You are testing whether showing a pop-up of discounted in-app purchase on the first screen of your app leads to increase in purchases.
It would be best to show this user on the first screen of the app, as soon as the app loads. In this A/B test, your code would want to know whether this user should see a pop-up or not.
You can use the callback method and then show the first screen on completion. You are now confident that when you ask the SDK for the settings of this campaign, the SDK will be ready with the data.

Synchronous

[VWO launchSynchronouslyForAPIKey:@"your-api-key" timeout:3.0 config: nil];
VWO.launchSynchronously(apiKey: "your-api-key", timeout: 3.0)

If settings can't be fetched in given time, the SDK uses old settings for already saved campaigns and falls back to the defaultValue or nil for new campaign keys.

Synchronous Initialization

In synchronous initialization, a network call is done on the main thread.
We do not recommend using the synchronous mode of initialization. The synchronous method of initialization can lead to freezing of UI.

Launch the SDK Once

On launchForAPIKey or launchSynchronouslyForAPIKey calls, the SDK fetches campaign settings from the VWO content distribution network.
In case the settings cannot be fetched, SDK doesn't retry to fetch the settings during an ongoing app session.
This is done to keep the app behavior consistent during an app session.

You should launch the SDK only using the appDidFinishLaunchingWithOptions method.

Suggest Edits

Launch Configuration

 

You can setup VWO Config while initializing your VWO SDK. This is helpful if you want to do the following:

VWOConfig *config = [VWOConfig new];
config.optOut = YES;
config.customVariables = @{@"user" : @"free"};
config.disablePreview = YES;

[VWO launchForAPIKey:@"<your-api-key>" config:config completion:^{
  //Code executed after launch is complete
} failure:^(NSString * _Nonnull error) {
	// Failure handling
}];
let config = VWOConfig()
config.optOut = true;
config.customVariables = ["user" : "free"]
config.disablePreview = true;

VWO.launch(apiKey: "<your-api-key>", config: config
  completion: {
	   //Code executed after launch is complete     
	}, failure: { error in
      print(error)
})
Suggest Edits

Using Campaigns

 

Each campaign consists of two or more variations.
Each variation represents a different version of the app. These versions can be represented by the difference in settings of the app and a different value for a settings key. Settings are represented by JSON.

For example, consider a gaming app for which we want to A/B test the user engagement level with the number of free lives.

By default, we offer three lives and want to test the behavior with five lives.
You would create a campaign, and then add a variation with the following JSON.

{
  "freeLives": 5
}

Now we will use this key freeLives in our code.
VWO SDK method for it:

[VWO variationForKey:@"freeLives" defaultValue:@3];
VWO.variationFor(key: "freeLives", defaultValue:3)

Role of Default Settings(defaultValue)

defaultValue helps your write consistent code, without introducing checks for nil.
defaultValue is passed as a parameter to method variationForKey.

The SDK returns defaultValue in below scenarios:

User becomes part of control

Every campaign has a control and one or more variation.
Control is the default behaviour of the app.
You define the JSON only for variations, not for control.
If the user is made part of control version of the app, the SDK will return whatever defaultValue you pass it to.

Settings could not be fetched from VWO's content distribution network

The SDK fetches campaign settings, from VWO's content distribution network, at the launch of the app.
Sometimes settings could not be fetched due to poor or no internet connection.

For example, a campaign is running with key campaignKey with variation value as variationValue, but these settings couldn't be fetched by the SDK.

If your code invokes variationForKey: defaultValue: method for campaignKey, SDK will return defaultValue.

User is not included in the campaign

If the user doesn't become part of the campaign, due to segmentation conditions or campaign currently being paused, then default object is returned.

Suggest Edits

Trigger Goals

 

For any campaign, we want to track conversion changes because of the A/B test.

From the example of a gaming app from the Using Campaign section, we would want to track if the users are more interested in doing an in-app purchase and buying extra lives.

A goal for this test is user clicking Get More Lives. We would have defined this goal in the VWO dashboard during the campaign setup.

getMoreLive

Whenever a user clicks Get More Lives, you can inform the SDK about this goal.

[VWO trackConversion:@"getMoreLive"];
VWO.trackConversion(goal: "getMoreLive")

In the above example, a user may click the Get More Live button multiple times. The SDK takes care to count the conversions only once per user.

Type of goals

  • Triggers custom conversion
    A custom conversion goal is used for generic events when we want to record an event for a conversion. The above example was for this goal type.
  • Generates Revenue
    This goal is useful when we want to track a revenue value with the conversion event.
    For example, if we are testing a purchase button, we would want to track the item value.
    Code sample for generates revenue goal:
[VWO trackConversion:@"getMoreLive" withValue:@100];
VWO.trackConversion(goal: "getMoreLive", value: 100)

Note

Your code can trigger a goal multiple times for a user, but the SDK makes sure that a conversion is only counted once per user.
This is done to avoid multiple counting and to keep the campaign results consistent.

Suggest Edits

Preview Mode

 

The preview functionality is helpful while you make changes in your app code for a campaign. It is used to verify that a campaign is set up correctly.

Enabling preview mode

The preview option is automatically enabled when the application is running on simulator or if test device is connected to Xcode. Preview mode can also be enabled by tapping with 5 fingers for 2 seconds while application is open. The preview button appears on the VARIATIONS and GOALS step of campaign creation.
As you can have multiple apps added to your account, make sure to select the app which you want to A/B test.

Disabling the preview mode

You can disable the preview mode from VWOConfig and passing that config during SDK Launch.

let config = VWOConfig()
config.disablePreview = true

VWO.launch(apiKey: "api_key", config: config, completion: {
    //Completion code
}) { (errorString) in
    //Error code
}
VWOConfig *config = [VWOConfig new];
config.disablePreview = YES;

[VWO launchForAPIKey:@"api_key" config:config completion:^{
    //completion code
} failure:^(NSString * _Nonnull error) {
    //error code
}];

Skip socket library

Preview functionality is socket based and the socket library is installed by default. While releasing you can skip the socket library by adding pod 'VWO/Core' to Podfile.

Previewing Variations

For an e-commerce mobile app, a valid use case is to test the layout of product items.
In the Demo App, by default, we are showing the same layout for both control and variation.

The variation for this campaign defines a layout as a key and grid as a value.

{
  "layout": "grid"
}

When you are on the VARIATIONS step, a drop-down appears next to the Preview On Device button.

Clicking this drop-down shows the list of devices on which your app is currently being run from Xcode.

Select your device from the list; it will appear as highlighted.
Next, click Preview On Device button. A variation is sent to your device.
In this example, clicking the Refresh button in the Demo App shows grid layout on the right side of the app.

Previewing Goals

From the above example, we would want to track how many users actually click the product tile.
The goal is:

productView

On the Goals step of the campaign, we have an option to verify the goals.

Click Verify; a pop-up is displayed.
Use the drop-down on the right to select your device. Also, Select Variation 1 from the left drop-down.

Click the Refresh button in the demo app to set up the variation version of the campaign.

Click any product tile on the right, this should trigger the code for:

[VWO trackConversion:@"productView"];
VWO.trackConversion("productView")

Goal 1 will change from NOT VERIFIED to VERIFIED.

We have an option to verify that the goal is working fine for control and variations of the campaign.

If you wish to verify the goal against Control, then:

  • Refresh the browser.
  • Click VERIFY.
  • Select Control from the drop-down.
  • Select your device from the device drop-down list.

Click Refresh in the app. Now, click any product tile. The goal is verified for the control.

Previewing a Running Campaign

You can also preview the variations for an existing campaign. Select your campaign from the campaign list, and then select variations under the Settings option.

Suggest Edits

Targeting Visitor Groups

 

We can target a campaign for specific users of the app.
To do this, under Advanced Options of the Finalize step of campaign creation, select Enable campaign for a specific user group.

You can target the app according to the following options:

  • Phone Users
  • Tablet Users
  • New Users
  • Returning Users
  • App Version
  • Android Version
  • Day of Week
  • Hour of the Day

Please note that all the above targeting options do not require any code changes.

If you want to do custom targeting such as running a campaign only for paid users of your app, then select Custom Variable.

Custom Variable

Custom variable is useful when you want to target the campaign on variables and conditions which are set by your code.
To use a custom variable, define a variable name and a corresponding value in the dashboard.
In your app code, set customVariables in VWOConfig before launching

VWOConfig *config = [VWOConfig new];
config.customVariables = @{@"user" : @"paid"};

[VWO launchForAPIKey:@"<your-api-key>" config:config completion:^{
  //Code executed after launch is complete
} failure:^(NSString * _Nonnull error) {
	// Failure handling
}];
let config = VWOConfig()
config.customVariables = ["user" : "paid"]

VWO.launch(apiKey: "<your-api-key>", config: config
  completion: {
	   //Code executed after launch is complete     
	}, failure: { error in
      print(error)
})

When to set custom variables

  • If you have specified certain custom variables in the campaign, those values have to be set in the code before calling the getVariationForKey(String key, String value) method.

  • If you have selected Make user part of the campaign on app launch in the VWO dashboard, then custom variables should be set before launching the SDK. This is required, because the SDK will try to make the user a part of the campaign on the app launch.

Suggest Edits

Integrations

 

You can send VWO's campaign information to third-party analytics platforms by using notification listeners. You can then segment the analytics report by using VWO's campaign id, campaign name, variation id, or name.

Next, you will find suggested implementations for some common analytics platforms. Feel free to use these as showcased or adapt them to meet your specific needs.

Notification listeners also allow for flexibility to implement an integration with a platform that is not listed here.

Notification Listener

The code can listen to a NSNotification on the key VWOUserStartedTrackingInCampaignNotification.

Notification Data

  • On receiving the notification, you can get the campaign data from the notification object, which is passed in the callback.

It contains the following keys:

  • vwo_campaign_id: Identifier of the campaign; this is generated by VWO. This is unique for your account.
  • vwo_campaign_name: Name of the campaign, as set by you. This is not necessarily unique.
  • vwo_variation_id: Identifier of the variation in the campaign of which the user became a part. Variation Id is unique for its campaign, but it is not unique across different campaigns.
  • vwo_variation_name: Name of the variation in the campaign, as set by you. This is not necessarily unique.

Amplitude

Please refer to the Amplitude iOS guide if you are getting started with Amplitude.

In the following suggested approach for Amplitude, we use Events.

We add a notification listener to listen to the notification with the key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Amplitude when a user becomes a part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

Events in Amplitude take an event name and event properties in the form of a dictionary.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
   NSDictionary *campaign = note.userInfo;
   NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
   [Amplitude.instance logEvent:event withEventProperties:campaign];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaign = notification.userInfo as? [String : String] {
      let event = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
       Amplitude.instance().logEvent(event, withEventProperties: campaign)
   }
}

Flurry

Please refer to the Flurry iOS guide if you are getting started with Flurry.

In the following suggested approach for Flurry, we use Custom Events.

We add a notification listener to listen to NSNotification with the key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Flurry when a user becomes part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

Events in Flurry have a two-level structure. The highest level is the specific action, in this case, VWO. The second level in the Events structure is the Event parameter.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

Per Flurry, prior to logging any events, you must initiate the session with one of the startSession method variants . Any events logged prior to session initialization will not be recorded.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
   NSDictionary *campaign = note.userInfo;
   NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
   [Flurry logEvent:event withParameters:campaign];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaign = notification.userInfo as? [String : String] {
      let event = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      Flurry.logEvent(event, withParameters: campaign)
   }
}

Google Analytics

Please refer to the Google Analytics iOS guide, if you are getting started with Google Analytics.

In the following approach for Google Analytics, we use Events.

We add a notification listener to listen to NSNotification with the key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Google Analytics when a user becomes a part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

The next step is to build segments for each variation of your campaign. In the segment-builder user interface, look under Advanced and add a new Condition. Filter Users by Event Action and Event Label, enter a name for the segment, and then click Save.

Finally, build a report of metrics you are interested in.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    NSDictionary *campaign = notification.userInfo
    NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
    NSString *action = [NSString stringWithFormat:@"%@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
    NSString *label = [NSString stringWithFormat:@"%@ - %@", campaign[@"vwo_variation_name"], campaign[@"vwo_variation_id"]];
  
    id<GAITracker> tracker = [GAI sharedInstance].defaultTracker;
    [tracker send:[[GAIDictionaryBuilder
                    createEventWithCategory:category
                                     action:action
                                      label:label
                                      value:nil] build]];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaign = notification.userInfo as? [String : String] {
      let category = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      let action = "\(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      let label = "\(campaign["vwo_variation_name"]!) - \(campaign["vwo_variation_id"]!)"

      if let builder = GAIDictionaryBuilder.createEvent(withCategory: category, action: action, label: label, value: nil),
         let tracker = GAI.sharedInstance().defaultTracker {
            tracker.send(builder.build() as! [AnyHashable : Any]!)
         }   
    }
}

Google Custom Dimension

Google also offers Custom Dimensions which enables association of metadata with hits, users, and sessions in Google Analytics.

In the above approach, we only send an event to Google Analytics. You may choose to set the custom dimension. For this, refer to the Custom Dimension and Metrics section in Google Analytics and then set the custom dimension in the notification callback.

The next step is to make changes in Google Analytics. Look for the Admin option in the menu bar, and then select the appropriate account and a property. Under Property, click Custom Definitions > New Custom Dimension. Enter a unique name for the dimension, select User for the scope, and then click Create.

You can now see the reports according to the custom dimension.

Localytics

Please refer to the Localytics iOS guide if you are getting started with Localytics.

In the following suggested approach for Localytics, we use Custom event with attributes.

We add a notification listener to listen to NSNotification with key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Localytics when a user becomes part of a campaign. In the event, we send the campaign name and id, along with the variation name and id.

Localytics also offers a way to set user attributes. You can set user attributes for VWO's campaign data as well.

The custom event in Localytics has an event name and attributes.
If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
   NSDictionary *campaign = note.userInfo;
   NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
   [Localytics tagEvent:event attributes:campaign];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaign = notification.userInfo as? [String : String] {
      let event = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      Localytics.tagEvent(event, attributes: campaign)
   }
}

Mixpanel

Please refer to the Mixpanel iOS guide if you are getting started with Mixpanel.

In the following suggested approach for Mixpanel, we use Events. Mixpanel also offers a way to set super properties and user profiles.

We add a notification listener to listen to NSNotification with key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Mixpanel when a user becomes part of a campaign. In the event, we send the campaign name and id, along with the variation name and id.

If you need to use super properties or people properties, modify the following code and send appropriate values to Mixpanel.

The next step is to look for VWO events in your Mixpanel account. You can look at the funnels with the VWO event or look at the segment data.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
   NSDictionary *campaign = note.userInfo;
   NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
   [Mixpanel.sharedInstance track:event properties:campaign];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaign = notification.userInfo as? [String : String] {
      let event = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      Mixpanel.mainInstance().track(event: event, properties: campaign)
   }
}

Segment

Please refer to the Segment iOS guide if you are getting started with Segment.

Segment has a spec for A/B testing events.

We add a notification listener to listen to NSNotification with the key VWOUserStartedTrackingInCampaignNotification. When the callback is requested, we send an event to Segment when a user becomes part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as Experiment Viewed. We also send event parameters as experimentId, experimentName, variationId, and variationName.

[NSNotificationCenter.defaultCenter addObserverForName:VWOUserStartedTrackingInCampaignNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
   NSDictionary *campaign = note.userInfo;
   NSString *event = [NSString stringWithFormat:@"VWO Campaign - %@ - %@", campaign[@"vwo_campaign_name"], campaign[@"vwo_campaign_id"]];
   NSDictionary *properties = @{
       @"experimentId"   : campaign[@"vwo_campaign_id"],
       @"experimentName" : campaign[@"vwo_campaign_name"],
       @"variationId"    : campaign[@"vwo_variation_id"],
       @"variationName"  : campaign[@"vwo_variation_name"]
    };
    [SEGAnalytics.sharedAnalytics track:event properties:properties];
}];
NotificationCenter.default.addObserver(forName: NSNotification.Name.VWOUserStartedTrackingInCampaign, object: nil, queue: nil) { (notification) in
   if let campaignDict = notification.userInfo as? [String : String] {
      let event = "VWO Campaign - \(campaign["vwo_campaign_name"]!) - \(campaign["vwo_campaign_id"]!)"
      let properties = [
         "experimentId"   : campaign["vwo_campaign_id"]!,
         "experimentName" : campaign["vwo_campaign_name"]!,
         "variationId"    : campaign["vwo_variation_id"]!,
         "variationName"  : campaign["vwo_variation_name"]!
      ]
      SEGAnalytics.shared().track(event, properties: properties)
   }
}
 

To enable logging in SDK, use [VWO.setLogLevel: level].
You can set different log levels depending upon the priority of logging as follows:

  • Debug: Gives detailed logs.
  • Info: Informational logs
  • Warning: Warning is a message level indicating a potential problem.
  • Error: Indicates Error
  • None: No logs are printed

The different methods set the log level of the message. VWO will only print messages with a log level that is greater to or equal to it's current log level setting. So a logger with a level of Warning will only output log messages with a level of Warning, or Error.

[VWO.setLogLevel: VWOLogLevelWarning];
VWO.logLevel = .warning
 

To opt out of tracking by VWO, use setOptOut:YES method on users you don’t want to be tracked.

VWOConfig *config = [VWOConfig new];
config.optOut = YES;

[VWO launchForAPIKey:@"<your-api-key>" config:config completion:^{
  //Code executed after launch is complete
} failure:^(NSString * _Nonnull error) {
	// Failure handling
}];
let config = VWOConfig()
config.optOut = true;

VWO.launch(apiKey: "<your-api-key>", config: config
  completion: {
	   //Code executed after launch is complete     
	}, failure: { error in
      print(error)
})

A user by default will be tracked by VWO.

 

Using the VWO demo app, you can try Mobile App A/B testing.
To try the demo app, you will need ApiKey.

Running the Demo App

Clone the demo app from https://github.com/wingify/vwo-ios-sdk
Browse to vwo-ios-sdk/VWO\ Demo
Run pod install

Enter ApiKey

You need to add an app to your VWO account. Please refer to Adding an App for details.
Copy your ApiKey.
Run the app from Xcode. You can choose either a simulator or your iPhone.

When the app is running, click the Menu icon in the upper-left corner.

Select Enter API Key from the menu options, and then paste your api key.
If you using a simulator, you can use Command ⌘ + Shift ⇧ + V to paste your api key in the text box.
If you are using iPhone, you can email the ApiKey to yourself and copy from there.

Layout Campaign

Showing a list of items is a common requirement for many apps.
How do you know if grid vs. list (1 column) layout is better? What better way to tell than to A/B test!

Defining Variation

Steps to run Layout Campaign:

  1. Under Mobile App A/B, click Create Menu and then choose your mobile app.
  2. On the Variations screen, define the following JSON as Variation 1.
{
	"layout": "grid"
}

If all goes well in VWO, you should see:

Select your device from the drop-down menu, and then select Preview on Device.

In your app, click the Refresh icon located in the upper-right corner of the navigation bar.
The variation section of the demo app will change.

Defining Goals

Click Next, and then define a goal using the following goal identifier.

productView

We can see if the goals work correctly.
Click Verify.

Select your device from the drop-down menu.

Click the Refresh icon in the app.
On selecting any product (phone) from the variation list, you can see the product details.

When you select the product, Goal 1 becomes Verified.

This happens because in ListGridVC.swift, we have placed VWO.trackConversion( "productView") code upon selecting a product.

If you want to verify the goal for variation, select Variation from the drop-down menu, select refresh in the app, and then repeat the same process.

Finalize Campaign

Click Next to move to the final stage of campaign creation. You can set percentage traffic allocation and then do advance targeting.

To start the campaign, click Finish.

Onboarding Campaign

How do you know if your app should have login mandatory or optional for users.
Login is a common requirement for mobile apps, but what is the right time to ask a user to login? Is it at the beginning of the app? Is it when doing a transaction?
This campaign helps us test against mandatory login, optional login, and Facebook login.

Defining Variation

Steps to run Layout Campaign:

  1. Under Mobile App A/B, click Create and then choose your mobile app.
  2. In the Variations screen, define the following JSON for Variations 1 and 2.
{
  "skip": true,
  "socialMedia": false
}
{
  "skip": false,
  "socialMedia": true
}

If you have performed the above steps correctly, you will see the following:

Select your device from the drop-down, and then select Preview on Device.

In your app, click the Refresh icon located in the upper-right corner of the menu bar.
The variation section of the demo app will change.

Note that the Variation of app shows the Skip and Continue option.
Next, preview Variation 2. It has the Login with Facebook option.

Defining Goals

Click Next and then define a goal using the following goal identifier.

landingPage

We can see if goals work correctly.
Click Verify.

From the device drop-down menu, select your device.

Click the Refresh icon in the app.
Touch Login under the variation. The Login Successful page is displayed.

When you touch Login, Goal 1 becomes Verified.

This happens because in LoginVC.swift, we have placed VWO.markConversionFor(goal: "landingPage") code on touching the button.

If you want to verify the goal for the variation, select Variation from the Control drop-down menu and then select Refresh in the app. Repeat the same process.

Finalize Campaign

To move to the final stage of campaign creation, click Next. Now, you can set percentage traffic allocation and perform advance targeting.

To start the campaign, click Finish.

Q. What's the minimum iOS version supported by the SDK?

iOS SDK supports iOS version 8.0 and later.

Does VWO support apps written in Swift?

Yes, the SDK works with Swift. This documentation mentions all the Swift methods.

Q. What happens if there is no internet connectivity?

A user will become part of a test only if the device has internet connectivity. If there is no connectivity, the user sees the default version (Control) of the app.

If the user is part of the test and connectivity is lost, the user will see locally cached changes. In this case, the VWO SDK captures the user data, stores it locally, and resends the data to the VWO server when the device gets connected to the Internet again.

Q. How much size does the VWO Mobile SDK add to my app size?

Please refer to iOS Impact Analysis section to see the impact of different parameters on your app.

Q. How do I deactivate the SDK?

You can either comment out the SDK initialization function call or remove the VWO SDK for deactivating the SDK.

Q. Can I run simultaneous tests on the same app?

Yes, you can run simultaneous tests on the same app. A user accessing the app will automatically become part of all the tests running on your app, subject to target segment conditions.

Q. Can I test multiple apps?

Yes, you can test unlimited apps and create unlimited campaigns on these apps.

Suggest Edits

Impact Analysis

 

This page tracks the impact of VWO iOS SDK for different parameters on your app.

Launch Time

The SDK can be initialised in two ways: synchronous and asynchronous.

  • Asynchronous Initialisation: has no impact on the launch time of your app, as SDK is launched in the background. Asynchronous initialisation is the recommended method.
  • Synchronous Initialisation: In Synchronous initialisation the SDK makes a networking call to fetch settings from VWO's CDN. This can block the main thread. The thread resumes to normal execution after response from the CDN.

API Calls

VWO SDK makes three types of API calls to VWO CDN.

  • To fetch settings at the time of SDK initialization. The SDK makes only one call to fetch settings. If this call fails, the SDK does not retry to fetch settings during an ongoing app session. This is done to keep the app behaviour consistent during an ongoing session.
  • To inform VWO when a user becomes part of a campaign. If this call fails, the SDK keeps a track of it and try to send it again after some time.
  • To inform VWO when a user converts a goal in a campaign. If this call fails, the SDK keeps a track of it and try to send it again after some time.

The SDK makes call to CDN every 20 seconds.

Disk Space

Upon pod install, VWO code takes approximately 272 KB of disk space.

Increase in IPA file size

The increase in the size of IPA file is around 285 KB. If you are using enable bitcode then VWO adds around 285 KB size.

RAM Usage

Method
Memory usage (in KBs approx)

launchForAPIKey:config:completion:

300

launchSynchronouslyForAPIKey

350

variationForKey: defaultValue:

less than 1

trackConversion

less than 1

trackConversion: withValue:

less than 1

If you want to know the impact of any other parameter or if you want to understand anything around it, please reach out to us: support@vwo.com

Suggest Edits

Quick Start Guide

 

Create an Account

You can create a free account with us from the signup page.

Create an Android App

Registering your Android app on VWO is a one-time process.
Adding your app generates an API Key, which is used by VWO servers to recognise your app.

Select the Mobile App A/B option under the test menu.
Click CREATE and then Add New App. Write a name for your app and then choose Android as a platform.
Note the API key generated by the system.

Create a Campaign

Click CREATE, and then choose your app.

Define Variations

Variations are different versions of the app. These versions can be represented by the difference in settings of the app, a different value for a settings' key. Settings are represented by JSON.

Write down JSON for the changes which you want to A/B test.
For this example, we will consider a generic key and a value.

{
  "key": "value" 
}

Define Goals

On the next step, define at least one goal. Goal is a conversion matrix which we want to optimize.

conversionGoal

Finalize

On the FINALIZE step we can set the percentage of users whom we want to include in the campaign.
Under the advanced option, we can also target the campaign for specific user types, enable scheduling or change traffic allocation for each variation.
For the quick setup, we can leave those settings to default.

Click on FINISH and START NOW to run the campaign.

Installing SDK

VWO android SDK can be installed by using Gradle plugin.

  • Define repository URL in your project-level build.gradle file, you can use the following code snippet
maven { 
  url 'https://raw.githubusercontent.com/wingify/vwo-mobile-android/master/' 
}
  • Define dependency in your app-level build.gradle file, you can use the following code snippet
dependencies {
    compile 'com.vwo:mobile:2.3.1@aar'
    compile ('io.socket:socket.io-client:1.0.0') {
        // excluding org.json which is provided by Android
        exclude group: 'org.json', module: 'json'
    }  
  	// Skip this if you are already including support library in your app.
    compile 'com.android.support:support-core-utils:27.1.1'
}

Add following permissions to your AndroidManifest.xml file

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Code changes in mobile app

1. Initialising the SDK

After installing the SDK, you would want to initialise it.
SDK can be initialized in your application's onCreate() method or your Activity's onCreate() method, in following ways:

I. Launching VWO SDK in Asynchronous mode with callback

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.vwo.mobile.VWO;

public class MainActivity extends AppCompatActivity {
    private static final String VWO_API_KEY = "YOUR_VWO_API_KEY";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      // Start VWO SDK in Async mode with callback
      VWO.with(this, VWO_API_KEY).launch(new VWOStatusListener() {
          @Override
          public void onVWOLoaded() {
              // VWO loaded successfully
          }
          @Override
          public void onVWOLoadFailure(String reason) {
              // VWO not loaded
          }
      });
    }
  }
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.vwo.mobile.VWO
  
class MainActivity : AppCompatActivity() {
    private val VWO_API_KEY = "YOUR_VWO_API_KEY"

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Start VWO SDK in Async mode with callback
        VWO.with(this, VWO_API_KEY).launch(object : VWOStatusListener {
            override fun onVWOLoaded() {
                TODO("not implemented")
            }

            override fun onVWOLoadFailure(error: String?) {
                TODO("not implemented")
            }

        })
    }
}

II. Launching VWO SDK in synchronous mode

Launching VWO in Synchronous mode requires you to pass a timeout in milliseconds as a parameter. This request should be used carefully as it executes on UI thread and may lead to Application Not Responding(ANR.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import com.vwo.mobile.VWO;

public class MainActivity extends AppCompatActivity {
    private static final String VWO_API_KEY = "YOUR_VWO_API_KEY";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      // Start VWO SDK in Sync mode
      VWO.with(this, VWO_API_KEY).launchSynchronously(3000);
    }
}
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.vwo.mobile.VWO
  
class MainActivity : AppCompatActivity() {
    private val VWO_API_KEY = "YOUR_VWO_API_KEY"

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Start VWO SDK in Async mode with callback
        VWO.with(this, VWO_API_KEY).launchSynchronously(3000)
    }
}

Advanced SDK Configuration

You can setup VWO Config while initialising your VWO SDK. This is helpful if you want to do custom targeting under Targeting Visitor Groups.

Map<String, String> userSegmentationMapping = new HashMap<>();
userSegmentationMapping.put("key", "value");

VWOConfig vwoConfig = new VWOConfig
  .Builder()
  .setCustomVariables(userSegmentationMapping)
  .disablePreview()                               // To disable preview mode
  .setOptOut(true)                                // To opt out of VWO SDK
  .build();
val userSegmentationMapping: HashMap<String, String> = HashMap()
userSegmentationMapping["key"] = "value"

val vwoConfig = VWOConfig.Builder()
	.setCustomSegmentationMapping(userSegmentationMapping)
  .disablePreview()                               // To disable preview mode
  .setOptOut(true)                                // To opt out of VWO SDK
  .build()

This configuration can set during SDK initialization as follows:

VWO.with(this, VWO_API_KEY).config(vwoConfig).launch(null);
VWO.with(this, VWO_API_KEY).config(vwoConfig).launch(null)

Segmentation key value and also be set using following code

Map<String, String> userSegmentationMapping = new HashMap<>();
userSegmentationMapping.put("userType", "free");

VWOConfig vwoConfig = new VWOConfig
  .Builder()
  .setCustomVariables(userSegmentationMapping)
  .build();

VWO.with(this, VWO_API_KEY).config(vwoConfig).launch(null);
val userSegmentationMapping = HashMap<String, String>()
userSegmentationMapping["userType"] = "free"

val vwoConfig = VWOConfig.Builder()
  .setCustomVariables(userSegmentationMapping)
  .build()

VWO.with(this, VWO_API_KEY).config(vwoConfig).launch(null)

2. Using campaign

To use the variation defined during campaign creation, use the below code to get value for the campaign keys.

Can be called only after SDK initialization. Otherwise, a null value is returned.

String key2 = "another-campaign-key";
Object variation2 = VWO.getVariationForKey(key2, "default_value");
val key1 = "your-campaign-key"
val variation = VWO.getVariationForKey(key1)

val key2 = "another-campaign-key"
val variation2 = VWO.getVariationForKey(key2, "default_value")

When getVariationForKey(String key, Object defaultObject) method is invoked, the SDK checks if the targeting conditions hold true for the current user.
If targeting/segmentation conditions hold true, the user is made part of the campaign and visitor counts in the report section increments by one(Once per user).

3. Triggering goals

We would track the effect of this campaign on our conversion metric.
Earlier we defined conversionGoal as a goal.
We need to tell VWO SDK when this conversion happens. Use the code below to trigger this goal.

Can be called only after SDK initialization. Otherwise, the goal is not marked.

VWO.trackConversion("conversionGoal");
VWO.trackConversion("conversionGoal")

For triggering revenue goal use method trackConversion(String goal, double revenue)

VWO.trackConversion("conversionGoal", 133.25);
VWO.trackConversion("conversionGoal", 133.25)

Reports

From the Mobile App A/B menu option, select your campaign and click on DETAILED REPORTS to see reports of your campaign.

Source Code

VWO Android SDK code is available on GitHub:
https://github.com/wingify/vwo-android

Next Steps

As a next step, take a look at SDK Reference to look at more advanced options of using the SDK.
We would look forward to hear from you about any question or feedback at support@vwo.com.

Suggest Edits

SDK Reference

 

This section is a full reference for VWO Android SDK.

Read further to find out how to install Android SDK, preview your changes, and run optimization tests.

Suggest Edits

Adding an App

 

Before you can A/B test your mobile app, you need to register it with VWO.
Registering an app is a one-time process.

From the Test menu options, select Mobile App A/B.
(https://app.vwo.com/#/test/mobile-ab)

In the upper-right corner of the page, click Create.

Next, click Add New App.

Type the name of your app, and then select the Android option button.
Next, click Add App.

As you enter the name of your app, you can see an auto-generated ApiKey.
You will use this ApiKey during app initialization.

Your app will start appearing in the app list.

To see the list of all the added apps, click the following link:
http://app.vwo.com/#/settings/custom-content/mobile-apps

Suggest Edits

SDK Installation

 

The SDK can be installed by using Gradle.

Gradle Installation

To integrate your mobile application using Gradle, first create a dependency for VWO functions in the app build.gradle file.

1. Under All Projects > Repositories, add the dependency to your project-level build.gradle.

maven { 
  url 'https://raw.githubusercontent.com/wingify/vwo-mobile-android/master/' 
}

2. To add dependency to your app's build.gradle file, use the following code snippet:

dependencies {
    compile 'com.vwo:mobile:2.3.1@aar'
    compile ('io.socket:socket.io-client:1.0.0') {
        // excluding org.json which is provided by Android
        exclude group: 'org.json', module: 'json'
    }  
  	// Skip this if you are already including support library in your app.
    compile 'com.android.support:support-core-utils:27.0.0'
}

3. Update your project AndroidManifest.xml file to add the INTERNET and ACCESS_NETWORK_STATE permissions.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

ProGuard Configuration to work with VWO

If you are using Proguard for building Android projects, it may cause an error while compiling the build. To avoid such errors, you can add the following code snippet to the proguard-rules.pro file:

# Preserve the line number information for debugging stack traces.
-keepattributes SourceFile,LineNumberTable

# Hide the original source file name.
-renamesourcefileattribute SourceFile

# Support libraries
-keep class android.support.v4.content.LocalBroadcastManager

# VWO module
-keep public class * extends com.vwo.mobile.models.Entry

-keepclassmembers class * extends com.vwo.mobile.models.Entry{
public <init>(android.os.Parcel);
}

# Socket.io
-dontwarn io.socket.**

Source Code

The VWO Android SDK code is available on GitHub:
https://github.com/wingify/vwo-android

Suggest Edits

Launching the SDK

 

After installing the SDK, we will initialize the VWO SDK in our mobile app.

Api Key

To initialize the SDK, we will use the API key generated while Adding an App
You can also get the list of all apps with ApiKey keys from settings section in the VWO dashboard.

Initialization of the SDK is to be done in the onCreate(Bundle) function of the Activity or the Application.

Import VWO in your class first.

import com.vwo.mobile.VWO;
import com.vwo.mobile.VWO

After importing VWO class, we can initialize the SDK.
It can be done in two ways, asynchronous and synchronous.

Asynchronous initialization does NOT block code execution while SDK fetches settings from the VWO content distribution network, but synchronous call blocks main thre executionWe recommend asynchronous initialization, as it does not affect the UI of your app.

Asynchronous

Asynchronous initialization is available in two modes

Asynchronous initialization with callback

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import com.vwo.mobile.VWO;

public class MainActivity extends AppCompatActivity {
    private static final String VWO_API_KEY = "<YOUR_VWO_API_KEY>";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      // Start VWO SDK in Async mode with callback
        VWO.with(this, VWO_APP_KEY)
          .launch(new VWOStatusListener() {
            @Override
            public void onVWOLoaded() {
                // VWO loaded successfully
            }

            @Override
            public void onVWOLoadFailure(String reason) {
                // VWO not loaded
            }
        });
    }
  }
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.vwo.mobile.VWO
  
class MainActivity : AppCompatActivity() {
    private val VWO_API_KEY = "YOUR_VWO_API_KEY"

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Start VWO SDK in Async mode with callback
        VWO.with(this, VWO_API_KEY).launch(object : VWOStatusListener {
            override fun onVWOLoaded() {
                TODO("not implemented")
            }

            override fun onVWOLoadFailure(error: String?) {
                TODO("not implemented")
            }

        })
    }
}

The callback method is called after the SDK fetches settings from the VWO content distribution network and processes those settings.
Callback is used when you want to get notified as soon as the SDK is ready.

Another way for setting callback:

You can set up Callback listener by calling VWO.setVWOStatusListener(VWOStatusListener listener)

VWO.setVWOStatusListener(new VWOStatusListener() {
            @Override
            public void onVWOLoaded() {
                // VWO loaded successfully
            }

            @Override
            public void onVWOLoadFailure(String reason) {
                // VWO not loaded
            }
        });
setVwoStatusListener(object : VWOStatusListener {
            override fun onVWOLoaded() {
                TODO("not implemented")
            }

            override fun onVWOLoadFailure(error: String?) {
                TODO("not implemented")
            }

        })

Synchronous

Launching VWO in Synchronous mode requires you to pass a timeout in milliseconds as a parameter.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import com.vwo.mobile.VWO;

public class MainActivity extends AppCompatActivity {
    private static final String VWO_API_KEY = "<YOUR_VWO_API_KEY>";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      // Start VWO SDK in synchronous mode
      VWO.with(this, VWO_API_KEY).launchSynchronously(3000);
    }
  }
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.vwo.mobile.VWO
  
class MainActivity : AppCompatActivity() {
    private val VWO_API_KEY = "YOUR_VWO_API_KEY"

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Start VWO SDK in Async mode with callback
        VWO.with(this, VWO_API_KEY).launchSynchronously(3000)
    }
}

Synchronous initialization blocks main thread. If settings couldn't be fetched in given timeout, the SDK uses old settings for already saved campaigns and fallbacks to defaultValue or null for new campaign keys.

Warning:

This request should be used carefully as it executes on UI thread and may lead to Application Not Responding(ANR) dialog.

Launch the SDK Once

For the launch(VWOStatusListener listener) and launchSynchronously(Long timeout) calls, the SDK fetches campaign settings from the VWO content distribution network.
If the settings cannot be fetched, SDK doesn't retry to fetch the settings during the ongoing app session.
This is done to keep the app behaviour consistent during an app session.

Suggest Edits

Launch Configuration

Launching the SDK with configuration

 

You can setup VWO Config while initializing your VWO SDK. This is helpful if you want to do the following:

Map<String, String> userSegmentationMapping = new HashMap<>();
userSegmentationMapping.put("user_type", "paid");

VWOConfig vwoConfig = new VWOConfig
  .Builder()
  .setCustomVariables(userSegmentationMapping)
  .disablePreview()
  .setOptOut(true)
  .build();

This configuration can set during SDK initialization as follows:

VWO.with(this, VWO_APP_KEY).config(vwoConfig).launch(null);
VWO.with(this, VWO_API_KEY).config(vwoConfig).launch(null)
Suggest Edits

Using Campaigns

 

Each campaign consists of two or more variations.
Each variation represents a different version of the app. These versions can be represented using the difference in the settings of the app and a different value for a settings key. Settings are represented using JSON.

For example, consider a gaming app for which we want to A/B test the user engagement level with the number of free lives.

By default, we offer three lives and want to test the behaviour with five lives.
You would create a campaign, and then add a variation with the following JSON.

{
  "freeLives": 5
}

Next, we will use this key freeLives in our code.

VWO.getVariationForKey("freeLives", 3);
VWO.getVariationForKey("freeLives", 3)

Role of Default Settings(defaultValue)

defaultValue helps you write consistent code, without introducing checks for null.
defaultValue is passed on as a parameter to the getVariationForKey method.

The SDK returns defaultValue for the following scenarios:

User becomes a part of the control

Every campaign has a control and one or more variation.
Control is the default behaviour of the app.
You define the JSON only for variations, not for the control.
If the user is made a part of control version of the app, the SDK returns whatever defaultObject you pass it to.

Settings could not be fetched from the VWO content distribution network

On launching the app, the SDK fetches campaign settings from the VWO content distribution network.
Sometimes, settings cannot be fetched due to poor or no Internet connection.
For example, a campaign is running with key campaignKey with the variation value as variationValue, but these settings couldn't be fetched by the SDK.

If your code invokes the getVariationForKey(String key, Object defaultObject) method for campaignKey, the SDK will return defaultValue.

User is not included in the campaign

If the user doesn't become a part of the campaign due to segmentation conditions or the campaign currently being paused, then the default object is returned.

Suggest Edits

Trigger Goals

 

For any campaign, we want to track conversion changes for the A/B test.

From the example of the gaming app from the Using Campaign section, we would want to track if users are more interested in doing an in-app purchase and buying extra lives.

A goal for this test is users clicking Get More Lives. We would have defined this goal in the VWO dashboard during the campaign setup.

getMoreLive

Whenever a user clicks the "Get More Lives" button, you can inform the SDK about this goal.

VWO.trackConversion("getMoreLive");
VWO.trackConversion("getMoreLive")

In the above example, a user may click Get More Live at multiple instances. The SDK counts the conversions only once per user.

Type of goals

  • Triggers custom conversion
    The custom conversion goal is used for generic events when we want to record an event for a conversion. The above example was for this goal type.
  • Generates Revenue
    This goal is useful when we want to track a revenue value using the conversion event.
    For example, if we are testing the purchase button, we would want to track the item value.
    Here is the code sample for generating the revenue goal:
VWO.trackConversion("getMoreLive", 100.0);
VWO.trackConversion("getMoreLive", 100.0)

Note

Your code can trigger a goal multiple times for a user, but the SDK makes sure that a conversion is counted only once per user.
This is done to avoid multiple instances of counting the same goal and to keep the campaign results consistent.

Suggest Edits

Preview Mode

 

The preview functionality is helpful while you make changes in your app code for a campaign. It is used to verify that a campaign is set up correctly.

Enabling the preview mode

Add the following dependency to your build.gradle file:

dependencies {
	    ...
        compile ('io.socket:socket.io-client:1.0.0') {
            // excluding org.json which is provided by Android
            exclude group: 'org.json', module: 'json'
        }
	    ...
}

The preview option is automatically enabled when the application is running in debugging mode, either on a device or a simulator. To enable the debugging in release mode, with the application open, shake the device for three or four times. The preview button appears on the VARIATIONS and GOALS step of campaign creation.
As you can have multiple apps added to your account, make sure to select the app which you want to A/B test.

Disabling the preview mode

Preview mode can be disabled by removing the above dependency from your build.gradle file.
OR
You can disable the preview mode by creating VWOConfig object and pass that VWOConfig object during SDK Launch.

VWOConfig vwoConfig = new VWOConfig.Builder()
                             .disablePreview()     // To disable preview mode
                             .build();
                             
VWO.with(Context, VWO_APP_KEY).config(vwoConfig).launch(null);
val vwoConfig = VWOConfig.Builder()
                .disablePreview()    // To disable preview mode
                .build()

VWO.with(Context, VWO_APP_KEY).config(vwoConfig).launch(null)

Previewing Variations

For an e-commerce mobile app, a valid use case is to test the layout of product items.
In the Demo App, by default, we are showing the same layout for both control and variation.

<