Overview

Introduction

The Event API for Optimizely X allows you to send event data to Optimizely’s logging servers from all of your applications, whether they are a web, mobile, or server-side implementations. Once we have your data, we use it to calculate your campaign and experiment metrics and display them on the Results page. The event data is also available in raw format via the Data Export service.

We "consume" our own API: the Optimizely X clients and SDKs send event data with this API. This consistency helps ensure that your data is processed the same way, regardless of how we receive it.

A formal specification of the API can be found at: https://api.optimizely.com/swagger/v1/events.json

Use cases

With the Event API you can send event data from any application without using our native clients or SDKs. There are many reasons why you may need to do this. Here are some examples from Optimizely developers who are using the API today.

  • Offline conversions: You are collecting offline experiment data, such as phone call conversions tracked by third-party software. You would need to store this information locally until the Internet connection is restored. Our SDKs do not currently have this feature built-in.

  • Security: You are working on a restricted environment and are not allowed to load third-party Web snippets or install third-party SDKs. You would need to develop your own method of tracking events and sending them Optimizely.

  • Third-party sources: You want to combine data from third-party sources with your event data. You would need to combine the data before sending it to Optimizely.

  • Communication control: You want your application to have extra control over how events are batched and when they are sent to Optimizely.

  • Integrations and Extensions: You are building a custom Optimizely integration or extension. (Read the Integrations and Extensions sections of the Dev Docs for more information.

Features

  • Maintains data consistency with events sent through our native clients and SDKs
  • Designed to handle billions of events on a daily basis
  • Calculates campaign and experiment metrics in near real-time
  • Supports batching multiple events into a single network call instead of many, which increases application performance and battery life (on mobile devices) while reducing memory and CPU usage
  • Logs raw event data securely in Amazon S3, which can be later accessed via the Data Export service

Important concepts

Before you begin, you must understand the concepts outlined in the article How Optimizely counts conversions. It explains both the underlying theory and mechanism of how event data is connected to experiments and campaigns. If you don't connect your events to your campaigns and experiments correctly in your data, we won't be able to calculate your metrics accurately, and your results will be invalid.

Additional reading

You can learn more about the concepts used in this document by reading the following articles.

Getting Started

This guide will walk through building a data object for the event API. For a complete description of the Event API, consult the Event API reference.

1. Create a new experiment

Create a new experiment from your Optimizely project page and add at least one event and metric. Make sure you start your experiment before proceeding to the next step.

For Web experiments

For Full Stack, Mobile, and OTT experiments

2. Collect the required identifiers

Follow the instructions in Knowledge Base article How to locate IDs for the Optimizely X Event API to locate the required identifiers.

You will need the following identifiers

  • account_id
  • campaign_id
  • experiment_id
  • variation_id
  • entity_id and key

3. Build the JSON data object

If you already know how the elements relate to each other in the JSON object, you can skip this section. You can find an example of the final object in this GitHub Gist. Additionally, we have provided an example of how to build the JSON object sequentially in a later section.

Relationship of identifiers

The required identifiers collected in step 2 relate to each other in the following way.

Your JSON object must describe

  • What account you are using
  • One or more visitor to your site (visitors array)
  • Which variation of an experiment each visitor is bucketed into and what campaign that experiment is part of (decisions array)
  • When each visitor was bucketed (events array) into a variation
  • What action(s) each bucketed visitor takes (also the events array)

Visitors

"visitors": [
  {
    "visitor_id": "unique-visitor-string",
    "snapshots": [ … ]
  }
]

Within the visitors array, the visitor_id must be a string unique to each visitor. Changing the visitor_id between JSON objects will track the events as though they were coming from different visitors. Each element in the visitors array must also contain a "snapshots" array.

Snapshots

Each element in the snapshots array requires two elements: the decisions array and the events array.

"snapshots": [
  {
    "decisions": [ … ],
    "events": [ … ]
  }
]

While snapshots is an array, it's use cases are rare and very few people send multiple elements in it. For now, include only the one element.

Decisions

Each element in the decisions array — not to be confused with a decision event — contains campaign_id, experiment_id, and variation_id. You gathered these IDs in step 2.

"decisions": [
  {
    "campaign_id": "your-campaign-id",
    "experiment_id": "your-experiment-id",
    "variation_id": "your-variation-id"
  }
]

Because a single visitor is only exposed to one variation (of one experiment) within a campaign, each campaign_id will be unique within your decisions array. The decision event (below) relies on this uniqueness.

Events: decision events

The events array contains elements representing two types of events: decision events and conversion events.

The decision event is a special type of event that represents the visitor being bucketed to a particular variation. It must have a timestamp older than the related conversion events as explained in the How Optimizely counts conversions article. Any conversion events with timestamps older than the related decision event will not be counted in the Results page.

"events": [
  {
    "entity_id": "8465488269",
    "type": "campaign_activated",
    "timestamp": 1499647193000,
    "uuid": "be4554a4-d360-442e-936d-80d63cf17260"
  }
]

The type value of a decision event is always set to campaign_activated. Unlike conversion events (below) the decision event's entity_id is the corresponding variation's campaign_id as given in the decisions array (above).

Events: conversion events

A conversion event represents a visitor taking a specific action on your site.

"events": [
  {
    "entity_id": "8480350225",
    "key": "event-api-demo",
    "timestamp": 1499647634000,
    "uuid": "9609803c-8981-40b3-a346-d8a4ff594512",
    "revenue":60000
  }
]

The key and entity_id values of the conversion event are those you located in step 2. The revenue is the amount of revenue in cents, e.g., $1,000 would be sent as 100000.

4. Send data object as POST call

After you build the data object, send it to the Event API as a POST call. Here is sample cURL request.

curl \
-A "test-user-agent"
-H "Content-Type: application/json" \
-X POST -d '{_data_object_}' https://logx.optimizely.com/v1/events

After the API has receives your complete call, it queues your JSON file for processing and returns a response with status code 204. Note: the response does not indicate that your JSON has been validated. Consult the API reference and this full sample object for more guidance.

5. Verify results

Within a few minutes, you will see the data reflected in the Results page. If you don't, read the troubleshooting section to debug common issues that can lead to unexpected results.

Additional Considerations

Please note the following considerations:

  • There is no Auth token requirement to use the API
  • A single JSON object must be 10 MB or less
  • This zip file contains more example JSON objects
    • batch-test-exp4-1.json: Custom event with an attribute for the visitor
    • batch-test-exp5-1.json: Revenue event with an attribute for the visitor
    • batch-test-exp6-1.json: Standard revenue event
    • datafile.json: For reference to view where IDs originated

Build JSON object sequentially

Follow the instructions and code snippets to build an example JSON object. For a complete description of the Event API, consult the Event API reference.

In this example, a single visitor (`java-lover@example.com) will be [bucketed into a variation](#2-add-a-decision-event). Then, the visitor will [perform a tracked action on the site](#3-add-a-conversion-event). Next, the user will [see another variation and take another action](#4-bundle-more-variations-and-events). Finally, [a second visitor (python-ftw@foo.co.uk`) will be bucketed into a variation and perform a tracked action](#5-bundle-more-visitors).

Note

Several of the elements included in the examples were not mentioned in Build the JSON data object of the Getting Started section, but no omitted elements were required. See the full API Reference for more information.

1. Construct the base object

Define the account, visitor, and a variation of an experiment within a campaign.

{
  "account_id": "1887578053",
  "project_id": "7205579439",
  "visitors": [
    {
      "session_id": "",
      "visitor_id": "java-lover@example.com",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "6630810318"
            }
          ]
        }
      ]
    }
  ],
  "anonymize_ip": true,
  "client_name": "Optimizely/event-api-demo",
  "client_version": "1.0.0"
}

Notes

  • The client_name and client_version fields are optional, but we recommend you fill them in for debugging purposes.

2. Add a decision event

The visitor is bucketed and sees a variation.

{
  "account_id": "1887578053",
  "project_id": "7205579439",
  "visitors": [
    {
      "session_id": "",
      "visitor_id": "java-lover@example.com",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "6630810318"
            }
          ],
          "events": [
            {
              "entity_id": "9560823711",
              "type": "campaign_activated",
              "timestamp": 1491519130343,
              "uuid": "3a427b02-7ae0-4b20-8f02-32cc8a067be4"
            }
          ]
        }
      ]
    }
  ],
  "anonymize_ip": true,
  "client_name": "Optimizely/event-api-demo",
  "client_version": "1.0.0"
}

Notes

  • Decision events use campaign_activated for the type value.
  • Their entity_id must match the corresponding variation's campaign_id (9560823711 in this example).
  • The timestamp field must contain the event's timestamp expressed as time since epoch in milliseconds (13 digits).

The decision event informs Optimizely that the visitor is bucketed to a particular variation. It must precede, i.e., have an older timestamp, than the related conversion events as explained in the How Optimizely counts conversions article. If the timestamp value is not older, conversion events preceding the decision event for that visitor will not be properly attributed to the variation.

3. Add a conversion event

While being exposed to a variation, the the visitor performed a tracked action on the site, triggering a conversion event. The action resulted in $1.00 of revenue.

{
  "account_id": "1887578053",
  "project_id": "7205579439",
  "visitors": [
    {
      "session_id": "",
      "visitor_id": "java-lover@example.com",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "6630810318"
            }
          ],
          "events": [
            {
              "entity_id": "9560823711",
              "type": "campaign_activated",
              "timestamp": 1491519130343,
              "uuid": "3a427b02-7ae0-4b20-8f02-32cc8a067be4"
            },
            {
              "key": "4841578001_view_optimizely_dev_docs",
              "revenue": 100,
              "timestamp": 1491519130344,
              "uuid": "145a44a2-6320-48d6-80d6-bff20b32cd65"
            }
          ]
        }
      ]
    }
  ],
  "anonymize_ip": true,
  "client_name": "Optimizely/event-api-demo",
  "client_version": "1.0.0"
}

4. Bundle more variations and events

The visitor has been exposed to another variation and performs another tracked action on the site.

{
  "account_id": "1887578053",
  "project_id": "7205579439",
  "visitors": [
    {
      "session_id": "",
      "visitor_id": "java-lover@example.com",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "6630810318"
            },
            {
              "campaign_id": "7586343465",
              "experiment_id": "8104989762",
              "variation_id": "4439927877"
            }
          ],
          "events": [
            {
              "entity_id": "9560823711",
              "type": "campaign_activated",
              "timestamp": 1491519130343,
              "uuid": "3a427b02-7ae0-4b20-8f02-32cc8a067be4"
            },
            {
              "key": "4841578001_view_optimizely_dev_docs",
              "revenue": 100,
              "timestamp": 1491519130344,
              "uuid": "145a44a2-6320-48d6-80d6-bff20b32cd65"
            },
            {
              "entity_id": "7586343465",
              "type": "campaign_activated",
              "timestamp": 1491519130351,
              "uuid": "bea80b99-22d9-4a7c-b421-3056b34d2070"
            },
            {
              "key": "8766076075_click_view_docs",
              "revenue": 400,
              "timestamp": 1491519130352,
              "uuid": "3bb9371d-c245-4bf8-8086-5fef9f60cd06"
            }
          ]
        }
      ]
    }
  ],
  "anonymize_ip": true,
  "client_name": "Optimizely/event-api-demo",
  "client_version": "1.0.0"
}

Note

The order of the events in the events array is not important.

5. Bundle more visitors

A second visitor, has been exposed to a different variation of the same campaign and experiment as the first visitor. The second visitor performs one of the same tracked actions as the first visitor.

{
  "account_id": "1887578053",
  "project_id": "7205579439",
  "visitors": [
    {
      "session_id": "",
      "visitor_id": "java-lover@example.com",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "6630810318"
            },
            {
              "campaign_id": "7586343465",
              "experiment_id": "8104989762",
              "variation_id": "4439927877"
            }
          ],
          "events": [
            {
              "entity_id": "9560823711",
              "type": "campaign_activated",
              "timestamp": 1491519130343,
              "uuid": "3a427b02-7ae0-4b20-8f02-32cc8a067be4"
            },
            {
              "key": "4841578001_view_optimizely_dev_docs",
              "revenue": 100,
              "timestamp": 1491519130344,
              "uuid": "145a44a2-6320-48d6-80d6-bff20b32cd65"
            },
            {
              "entity_id": "7586343465",
              "type": "campaign_activated",
              "timestamp": 1491519130351,
              "uuid": "bea80b99-22d9-4a7c-b421-3056b34d2070"
            },
            {
              "key": "8766076075_click_view_docs",
              "revenue": 400,
              "timestamp": 1491519130352,
              "uuid": "3bb9371d-c245-4bf8-8086-5fef9f60cd06"
            }
          ]
        }
      ]
    },
    {
      "session_id": "",
      "visitor_id": "python-ftw@foo.co.uk",
      "snapshots": [
        {
          "decisions": [
            {
              "campaign_id": "9560823711",
              "experiment_id": "5733750339",
              "variation_id": "7701725780"
            }
          ],
          "events": [
            {
              "entity_id": "9560823711",
              "type": "campaign_activated",
              "timestamp": 1491519130361,
              "uuid": "16da0db4-eae5-41a0-a349-7d7403b4d923"
            },
            {
              "key": "4841578001_view_optimizely_dev_docs",
              "revenue": 400,
              "timestamp": 1491519130362,
              "uuid": "899de30f-fa1b-440c-b8a8-75a18da104a2"
            }
          ]
        }
      ]
    }
  ],
  "anonymize_ip": true,
  "client_name": "Optimizely/event-api-demo",
  "client_version": "1.0.0"
}

Troubleshooting

I sent events via the API, but they are not showing up in the results page.

  • Experiment was/is not running
    Make sure the experiment is running and the events have timestamps within the bounds of the running experiment.

  • Event payload was malformed
    Inspect the payload to verify that all required identifiers are properly set to conform with the API's Swagger Specification. If the API returns with a 204 Response code, it means that the Optimizely Logging Service has received and persisted the payload. This response code is not an indication that the event payload has been validated.

  • Event had one or more incorrect or missing identifiers
    Inspect the payload and verify that all required identifiers are properly set.

  • Event was missing a decision
    Verify that you sent a decision event and that the decision event had an earlier timestamp than the conversion events. Read How Optimizely counts conversions for more information.

  • Decision was sent but not attributed to the correct campaign_id
    Make sure the entity_id matches the campaign_id for the variation the user was assigned to.

  • Event had an incorrect or out of bounds timestamp
    Make sure timestamps have the correct format (time since epoch in milliseconds, i.e., a 13-digit integer) and are within bounds of the running experiment.

I sent events with revenue values via the API, but the revenue is not calculated correctly in the results page.

  • Revenue is missing from event payload
    Make sure revenue is present under the correct conversion event.

  • Revenue has incorrect value
    Make sure revenue has an integer value and represents the revenue in cents.

I sent events via the API, I see some results but I don't get expected values.

  • Duplicate events are sent
    Optimizely detects events that have the same entity_id, uuid and timestamp and saves only one of them. Make sure each event is using a unique uuid or timestamp before sending.

  • Events have out-of-bounds timestamps
    Make sure timestamps have the correct format (time since epoch in milliseconds, i.e., a 13-digit integer) and are within bounds of the running experiment.

  • Conversion events have timestamps lower than the decision event's timestamp
    Make sure the conversion events have higher timestamp values than the related decision event's timestamps.