Static and dynamic audience conditions

  • Updated
  • Optimizely Feature Experimentation
  • Optimizely Full Stack (Legacy)
  • Optimizely Web Experimentation
  • Optimizely Performance Edge

There are several ways to build an audience condition in Optimizely Web Experimentation, and approaches to evaluate and troubleshoot each one.  

Visitor attributes may change over time. For many of these—like cookies, custom attributes, and custom JavaScript—Optimizely Web Experimentation uses the freshest information to decide if a visitor qualifies for an experiment. However, when an attribute relies on network calls (such as geo-targeting or third-party integration), that information may take longer to arrive. This article describes the audience conditions, when they are available, and how to troubleshoot them. 

Static audience conditions 

Audience conditions that are not expected to change (are static) are evaluated at the beginning of the visitor's session and are not requested again for the entire session. Instead, the value is held in local storage and referenced as needed.

This section describes several examples of static audience conditions. 

Device Type

The device type condition uses last-touch attribution for a visitor session, meaning Optimizely Web Experimentation looks at the visitor's user agent to determine the user's device type and store that value in local storage.

Most visitors will not change the device they use during a session. However, when you test your experiments, checking different device types is common. 

For example, if a user emulates a mobile device in their browser and gets bucketed into an experiment, and then switches out of that emulated view back to the desktop, Optimizely Web Experimentation identifies that user as being on a mobile device. To check, look at the visitor object optimizely.get('visitor').device: the value returned is the device Optimizely Web Experimentation associates with the visitor. 

To change the device, clear cookies and local storage, or use a new incognito window. 


Optimizely Web Experimentation evaluates the referrer value as soon as the visitor first touches the snippet, potentially before an experiment even begins. This value is sticky and will not be revaluated until the visitor starts a new session. A visitor can have a different referring values for different sessions. 

  • This value is not the same as document.referrer. Optimizely Web Experimentation's referrer is the last URL a visitor saw on a domain that did not have the current snippet on it.  
  • To use document.referrer as an audience condition, use the Custom JavaScript audience condition to set your own logic.

Traffic source

Like referrertraffic source is evaluated as soon as the visitor begins their session. This value is sticky and will not be revaluated until the visitor starts a new session. A visitor can have a different traffic source values for different sessions.


This is a special query parameter that is stored in the visitor object optimizely.get('visitor').campaign. Optimizely Web Experimentation references the stored value as the visitor navigates around the site, and persists the audience condition even if the query parameter is gone.  The campaign query parameter lasts only for the session in which it was set. 

Custom attributes

Custom attributes are values stored on the visitor's browser using custom code. They will not change unless custom code is written to overwrite the value. A custom attribute will remain on the visitor's browser until the visitor clears local storage.

Custom attributes are generally not available on the first page load of the page where Optimizely Web Experimentation assigns the value to the visitor.

Dynamic audience conditions

Dynamic audience conditions are expected to change as the visitor navigates a site. Optimizely Web Experimentation evaluates them each time an experiment activates. This means a visitor can pass and fail the same audience condition in the same session. 

Query parameter

The Query parameter is evaluated immediately on pageload. Unlike the Campaign parameter (which is stored in the visitor object), a Query parameter persists only through pageloads that include the query within in the URL. 

If an experiment requires modification of the query parameters to match an audience condition, this change must occur before Optimizely Web Experimentation executes, or the page must be refreshed.

If the customer assigns to, some browsers do a full page reload using the just-assigned query parameters. Since the client reactive on this reload, query parameters are guaranteed fresh. 

Another way of changing query parameters is using the browser’s window.history.pushState/replaceState API to change the URL, but this will not trigger a page reload.  A manual reactivation of the client is required to apply to audience targeting conditions.

Custom JavaScript audience conditions

Custom JavaScript evaluates to true or false, and is evaluated every time the experiment activates. When using it, make sure that any values the custom JavaScript relies on are defined before Optimizely Web Experimentation begins evaluating. Audience conditions are evaluated very early in the snippet; if the values are not available in time, the visitor is not bucketed for the experiment as intended. 

If a required value is not available until after the snippet executes, you could use conditional activation to delay experiment activation until the variable is available. However, this approach can cause flashing.

To minimize flashing, consider also using a cookie audience to persist the audience condition.

If a visitor changes an audience condition, that change only applies to events triggered for experiments that activate after the change is made.  

Network-sourced attributes

Attributes like Dynamic Customer Profiles (DCP), list attributes, IP Address, and Location all involve sending network requests. This involves a tradeoff: 

  • Optimizely Web Experimentation can use potentially stale data to make an immediate decision about which experience the visitor will have.
  • Optimizely Web Experimentation can defer that decision to ensure it is made with fresh data, but risk prolonged flashing in the process.

In either case, the snippet still sends a request to refresh the data, so subsequent snippet activations are likely to have valid cached data to work with.

With these targeting conditions, Optimizely Web Experimentation sends requests to fetch the latest data from these services whenever the snippet activates. The responses to those requests may not arrive by the time the snippet decides on a visitor's experience. But even if that does happen, it is not always a problem: previous snippet activations may have left values for list attributes, IP address, and location cached in localStorage. The persisted values are refreshed when Optimizely Web Experimentation receives the responses to the snippet's original requests. If your experiment's activation mode is anything other than immediate, Optimizely Web Experimentation will almost certainly use the fresh values anyway.


Optimizely Web Experimentation's geo-targeting is based on IP address information from Akamai EdgeScape. Optimizely Web Experimentation makes an API call to define the visitor's location when the snippet evaluates. This happens only if an audience using geo-targeting is being evaluated for an experiment activated on that page. The IP address is then used in an API call that checks the address against the EdgeScape database and returns information about the visitor's location. Next, Optimizely Web Experimentation uses that information to evaluate the audience condition and stores it in the visitor object, where it can be referenced for the duration of the session.

To troubleshoot geo-targeting, type the following URL in an adjacent tab of your website:

You see the information Optimizely Web Experimentation uses to build the audience condition at the beginning of the session.


Because Optimizely Web Experimentation evaluates this information at the start of the visitor's session, mobile device users can move during the session. If they do, the information Optimizely Web Experimentation needs for geo-targeting will be stale. To check the freshness of Optimizely Web Experimentation's location data, use the visitor object optimizely.get('visitor').location to get the values Optimizely Web Experimentation is actively using.

Screen Shot 2018-10-30 at 2.55.50 PM.png

List attribute and DCP

List attributes and DCP are audiences that are based off uploaded content provided by the Optimizely Web Experimentation user. They are different in that list attributes are made up of a single column of data, such as a set of zip-codes, while DCP is more than one column of data, like plan type and country that can be accessed by a predefined customer ID. Each works a little differently:

  • List attributes – When the snippet activates, it looks for cached list attributes. If they exist but are based on a set of list attribute values which differ from the visitor’s current values, the snippet ignores them.
  • DCP – When the snippet activates, it looks for cached data. If that cached data exists but is for a set of aliases which differ from the visitor’s current aliases, the snippet ignores the data because it is out of date.

In either of these cases, or when there is no cached data at all, the snippet delays making a decision by two seconds to allow fresh data to arrive. If that happens, the fresh data is incorporated into the visitor’s profile and used for evaluating audience membership. Otherwise, the decision proceeds without the new data. In that case, Optimizely Web Experimentation assumes the visitor does not satisfy any conditions relating to that data.

Even in these situations, a visitor may still qualify for an audience. As an example, consider an audience like DCP “or” Cookie, where DCP information is not absolutely necessary to be included in the audience. For this audience, determining experiment eligibility would be delayed only if the cookie condition failed and there was no cached and valid DCP data.

To refresh the data that comes from these sources long after the page has loaded (for example, in a single-page app), reactivate the snippet via the activate API call.

Troubleshoot list attributes

For list attributes, troubleshoot using the visitor object API call (optimizely.get('visitor').lists) to determine if you meet the conditions of an audience constructed with an uploaded list; Optimizely Web Experimentation returns a value of true or false. The following example shows an uploaded list of California zip codes used as an audience condition:


To identify the value Optimizely Web Experimentation used to evaluate uploaded audience conditions, use the following URL in an adjacent tab to get the object from Optimizely Web Experimentation's audience evaluating service, Tapi.<project id>

This object will include more details than the geo-targeting URL above.


Optimizely Web Experimentation uses the visitor's IP to find the zip code. The value is then passed to the list attributes targeting service, where it is matched against the lists that have uploaded through Optimizely Web Experimentation. The service returns a value of true or false, which is what Optimizely Web Experimentation uses to determine audience eligibility. This evaluation usually takes longer than a pageload, so the zip code audience is not specifically defined until the second pageload.

Tapi services uses Maxmind for geolocation evaluation. Unlike the geo-targeting audience above where Optimizely Web Experimentation makes a direct request to the endpoint and receives an object back, in list attributes Optimizely Web Experimentation makes a request to the Tapi service. The Tapi service, in turn, makes the request to Maxmind, which returns a location based on IP address that includes additional information like zip codes. This object is then used by Tapi to compare the returned information against the uploaded list on file and returns true or false evaluation for the audience condition in the response in addition to the location object.

Troubleshoot DCP

For Dynamic Customer Profiles, troubleshoot using the visitor object API call (optimizely.get('visitor').dcpData) to determine if you meet the conditions of an audience constructed with an uploaded list. If no object returns, confirm that an experiment using a DCP audience is active on the page. Optimizely Web Experimentation will return an object that returns information based on the uploaded list ID and the customer ID that Optimizely Web Experimentation identified for the visitor. Below is an example of the returned object:targeting-9.png

The aliases object contains a set of keys and values, where the key represents the ID for the uploaded DCP table and the value is the value of the customer ID. The ID of the uploaded table can be found under the title for the uploaded table under the Attributes section of Optimizely Web Experimentation. 

Screen Shot 2019-07-24 at 4.48.03 PM.png

Like list attributes, DCPs rely on the Optimizely Web Experimentation Tapi service to make decisions about if a visitor passes an audience condition or not.  When the snippet executes, and an experiment with a DCP audience activates, Optimizely Web Experimentation looks for the customer ID.  If the customer ID is found, the value is sent to Tapi.  The audience condition is specific to a DCP table, so when Tapi checks for the customerId value, it will only look at the DCP table associated with the audience condition it is evaluating for. 

When Tapi completes its check of the visitor's customerId value it sends a response that can be found in the network by filtering for the word tapi.  The Optimizely Web Experimentation userId is used as the name, click the Preview tab for an easy-to-read response.  This is the same information that gets stored in the visitor object.

Screen Shot 2019-07-24 at 5.32.12 PM.png

This evaluation usually takes longer than a pageload, so the DCP audience is not defined until the second pageload.

Audience integration waiting policy

The waiting policy for audience integration is the same for DCP and list attributes. The main difference is that, instead of the snippet initiating and waiting on HTTP requests, some other condition (for example, a property on the global object being defined) is awaited.

Each audience integration has its own implementation requirements. For a specific integration, see Integrate other platforms.