Dev guideAPI Reference
Dev guideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket

Advanced Audience Targeting for Agent

Information on implementing Advanced Audience Targeting with your Optimizely Feature Experimentation Agent instance.

After creating a new audience with Advanced Audience Targeting and assigning it to a flag rule, you can integrate the audience segments in your Agent instance.

👍

Beta

The Advanced Audience Targeting integration and fetching qualified segments and sending events is in beta. Apply on the Optimizely beta signup page or contact your Customer Success Manager.

Fetch qualified segments

You can fetch all qualified segments for the user ID by calling the decide endpoint:

POST /v1/decide?keys={flagKey}

with fetchSegments set to True:

For example:

#============================
# Fetch qualified segments
#============================

params = {"keys": "my-feature-flag"}
payload = {
    "userId": "test-user",
    "decideOptions": [
        "ENABLED_FLAGS_ONLY",
        "INCLUDE_REASONS"
    ],
    "userAttributes": {},
    "fetchSegments": True,
}

response = s.post(url = 'http://localhost:8080/v1/decide', params=params, json=payload)

print(response.json())

Example response:

{
    "variationKey": "variation_b",
    "enabled": true,
    "ruleKey": "ab_experiment",
    "flagKey": "my-feature-flag",
    "userContext": {
        "userId": "test-user",
        "attributes": {}
    },
    "reasons": ["Audiences for experiment ab_experiment collectively evaluated to true."]
}

ODP GraphQL API

  • <https://api.zaius.com/v3/graphql>
  • ODP public API key = "<odp_api_key>"

Example GraphQL Request: fetch information with fs_user_id for ["has_email", "has_email_opted_in", "push_on_sale"] segments.

Headers

  • Content-Type: application/json
  • x-api-key: <odp_api_key>
query MyQuery {
    customer(vuid: "d66a9d81923d4d2f99d8f64338976322") {
     audiences(subset:["has_email", "has_email_opted_in", "push_on_sale"]) {
       edges {
         node {
           name
           state
         }
       }
     }
    }
    }

Example GraphQL Responses

  {
    "data": {
     "customer": {
       "audiences": {
         "edges": [
           {
             "node": {
               "name": "has_email",
               "state": "qualified",
             }
           },
           {
             "node": {
               "name": "has_email_opted_in",
               "state": "qualified",
             }
           },
            ...
         ]
       }
     }
    }
    }
{
    "errors": [
    {
       "message": "Exception while fetching data (/customer) : java.lang.RuntimeException:
       could not resolve _fs_user_id = asdsdaddddd",
       "locations": [
        {
           "line": 2,
           "column": 3
        }
       ],
       "path": [
         "customer"
       ],
       "extensions": {
         "classification": "InvalidIdentifierException"
        }
    }
    ],
    "data": {
     "customer": null
    }
}

The network calls between your application, Agent, and the ODP server when fetching all qualified segments is demonstrated below:

Network request diagram between Agent and ODP

Click to enlarge image

  1. POST request is made to /v1/decide endpoint with fetchQualifiedSegments=true.
  2. Agent makes GraphQL call to ODP to fetch segments.
  3. ODP responds with segments.
  4. Fetched segments mapping user IDs to segments are cached.
  5. Appropriate variations are returned for user.

OdpSegmentManager

Agent has an OdpSegmentManager module which manages a segments cache that is shared for all user contexts. The cache is in memory (not persistent), so it will be reset when the application is terminated/device is rebooted.

Some more specifics about the cache:

  • Cache stores mapping of user IDs to segments.
  • Agent calls the ODP server on cache miss/expiration.
  • Cache is least recently used (LRU).
  • Caches is expired on timeout.
  • Both cache size and timeout are configurable (default values provided).
  • Caching is enabled by default and can be disabled by setting the size to zero.
  • Can use custom cache such as redis instead of default implementation (see segmentsCache section of Agent config.yaml).

If you would like to bypass caching, you can add the following options to the payload JSON object:

  • "fetchSegmentsOptions": ["IGNORE_CACHE"] – Bypass segments cache for lookup and save.
  • "fetchSegmentsOptions": ["RESET_CACHE"] – Reset all segments cache.

For example:

params = {"keys": "my-feature-flag"}
payload = {
    "userId": "test-user",
    "decideOptions": [
        "ENABLED_FLAGS_ONLY",
        "INCLUDE_REASONS"
    ],
    "userAttributes": {},
    "fetchSegments": True,
    "fetchSegmentsOptions":["RESET_CACHE"]
}

response = s.post(url = 'http://localhost:8080/v1/decide', params=params, json=payload)

print(response.json())

Send ODP Events

Send data to the ODP server by calling the send-odp-eventendpoint:

POST /v1/send-odp-event

You can then use this data to analyze user behavior and optimize experiences across different channels and touchpoints.

Use the send-odp-event endpoint to

  • merge or stitch users together and determine which event is associated with which customer.
  • send various types of events and actions, such as pageviews, clicks, form submissions, and others. You can include additional data to provide more context and information about the event being tracked.

For example, by connecting an email address identifier with a fs_user_id identifier, you can use the send-odp-event endpoint to send events that are associated with both identifiers. This enables you to track and analyze the behavior of a specific user across different touchpoints and devices.

You cannot create or update user profile data like name or address with the send-odp-event endpoint. Instead, you can use the ODP Create and update customers API endpoint or ODP UI to manage customer profiles.

ParameterTypeDescription
action
required
stringSpecifies the subcategory of the event type, used to track the app and user lifecycle. The call fails with the following error: ODP action is not valid (cannot be empty) if null or empty.
typestringThe type of event to be sent. Set to "fullstack" if not specified.
identifiersDictionary<string, string>A key-value map of user identifiers. At least one key-value pair is required.
dataDictionary<string, object>The event data in a key-value map. The value can be any type (string, number, or boolean.) You can use null values, but they become empty strings.

The Python SDK adds default event data to the given data dictionary. Sending the same key when creating your Dictionary overwrites the default data values.

  • "idempotence_id":<UUID created by the Python SDK>

  • "data_source_type":"sdk"

  • "data_source":"python-sdk"

  • "data_source_version":<Python SDK version implemented>

#============================
# Send ODP event
#============================
payload = {
    "type": "test_type",
    "data": {
        "idempotence_id": "abc-1234",
        "data_source_type": "agent",
    },
    "identifiers": {"user_id": "test_user_1"},
    "action": "test_action",
}

response = s.post(url = 'http://localhost:8080/v1/send-odp-event', params={}, json=payload)

print(response.json())

Example of successful response:

{
    "success": true
}

This response only indicates that the event was successfully queued in the event queue. It is not a guarantee that event was successfully delivered.

If the event was sent successfully, meaning it has left the event queue, then there should be no errors logged. If unsuccessful, then error should be visible in Agent logs, for example 400 BadRequest.

The network calls between your application, Agent, and the ODP server when sending ODP events is demonstrated below:

Network diagram of calls between Agent and ODP

Click to enlarge image

  1. POST request is made to /v1/send-odp-event.
  2. Agent makes a POST request to ODP.
  3. ODP responds with acknowledgement or relevant error.
  4. Agent responds to application with success acknowledgement or relevant error.