Dynamic Yield Developer Documentation

Browse Dynamic Yield's latest developer documentation including API references, articles, and sample code for optimizing, personalizing, and creating consistent digital customer experiences across touchpoints.

TRY FOR FREE

Choosing Variations and Pageviews

In the US:
https://dy-api.com/v2/serve/user/choose
https://dy-api.com/v2/collect/user/pageview
In the EU:
https://dy-api.eu/v2/serve/user/choose
https://dy-api.eu/v2/collect/user/pageview

Note: when using client-side keys from a browser use the sub-domain direct which supports CORS headers (e.g. https://direct.dy-api.com/v2/serve/user/choose; in the EU use direct.dy-api.eu). This also applies to using browser-based REST clients. For collection endpoints (pageviews, user engagement or events) from within a browser, use https://direct-collect.dy-api.com/v2/collect/...

:notebook-with-decorative-cover+: API Reference: Choosing Variations, Reporting Pageviews

The choose endpoint activates one or more Dynamic Yield campaigns by their name. The activation resolves targeting rules and test group allocations automatically and returns the correct variation for the user. Typically, you would make this call as part of your larger page and content rendering pipeline. Here is a detailed guide on where and how to use this endpoint.

👍

A page is a page by any other name

The term "pageview" in this document refers both to new web pages rendered by a web server, location changes in a Single Page Application, or a new screen rendered in a mobile app.

The common thread binding these is that from an end user's perspective, they have now moved to a new context, rather than acting on or navigating within the current view.

Choosing Variations and the Page Rendering Flow

At the heart of Dynamic Yield's platform is the ability to choose the right variation for each campaign, for each user. The rules by which this selection is made, be it manual or automatic, the duration in which this selection remains in effect for that user, and all other campaign settings, are all controlled and dynamically modified via the Admin UI.

There is no need to change the implementation as long as the schema of the variation's payload stays the same, whether it's the standard schema of Recommendations Campaigns or any custom payload you use in your Custom Campaigns.

Calling choose in the rendering flow

Although reporting a pageview and choosing variations for a campaign are functionally different actions, there is a lot connecting the two. When a page is rendered, whether the server is responsible for crafting the full HTML or only returns a data-only payload for an SPA or mobile app, there are typically similar steps to integrating Dynamic Yield:

  1. Determine all campaigns that are an inherent part of the page content, such as in-line elements, variable values, and configuration settings. Each campaign has its unique API Selector Name defined in the Admin UI.

  2. Call choose to get the chosen variations for all these campaigns. Since we also need to report this new pageview, and since the new page context has to be passed now anyway for proper campaign targeting to be performed, the choose call by default also implicitly reports a new pageview.

  3. Now that we have the chosen variations' payloads in hand, we can construct the full page and render it.

  4. Some content need not be rendered immediately as part of the synchronous process of displaying the page but can be deferred to a separate asynchronous call. Typically, these can be overlays or notifications that are shown over the page, recommendation widgets which are below the fold, or additional content that is lazy-loaded only when scrolling or expanding the view.

For these content types, you can make extra calls to choose to fetch the needed campaign variations, while making sure to turn off the implicit pageview in the arguments (see arguments in the code sample below).

The pageview Endpoint

If you only wish to report a pageview, with no relevant campaigns, you may also use the pageview endpoint. This is simply an alias for choose, but without any campaign name, which is valid use.

Recommended Use

Even before you have a full view of which campaigns should be integrated in your application, it's best to integrate a choose call in all page types in your application with the proper page context (more below), without referring to any campaign yet.

Now, here's the fun part: along with the person or people responsible for creating and managing campaigns (be it Marketers, Product Managers, Merchandisers, or other stakeholders in your organization), identify the places in your application where Dynamic Yield-managed campaigns should run. Any campaign you run has an API Selector Name that you'll use to get the chosen variation.

Now, adapt your call to choose in each page type so that you also pass the relevant campaign names in the selector parameter. It is perfectly valid to call campaigns which have only a single variation at that time, containing a default payload, in preparation for allowing testing and targeting multiple variations in that component later - without further code changes.

Request

Let's take a look at a sample request. The context is a Product Details Page (aka PDP) in an imaginary eCommerce website, "sugoi-ne.com":

curl --request POST \
  --url https://dy-api.com/v2/serve/user/choose \
  --header 'content-type: application/json' \
  --header 'DY-API-Key: baadc6ba740a352c9106dc7857a7eb9c' \
  --data '{
      "user": { "id": "yaexono4ohphania" },
      "session": { "custom": "iquahngaishe2koh" },
      "selector": { "names": ["PDP Top Banner", "PDP Recs"] },
      "context": {
        "page": {
          "type": "PRODUCT",
          "data": ["7383723-010"],
          "location": "https://sugoi-ne.com/men-pants/p7383723-010",
          "referrer": "https://sugoi-ne.com/men-pants",
          "locale": "en_US"
        },
        "device": {
          "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
          "ip": "54.100.200.255"
        },
        "pageAttributes": { "customPageAttribute": "someValue" },
        "options": { "isImplicitPageview": true }
      }
}'
curl --request POST \
  --url https://dy-api.com/v2/serve/user/choose \
  --header 'content-type: application/json' \
  --header 'DY-API-Key: baadc6ba740a352c9106dc7857a7eb9c' \
  --data '{
      "user": {
        "dyid": "-4350463893986789401",
        "dyid_server": "-4350463893986789401"
      },
      "session": { "dy": "ohyr6v42l9zd4bpinnvp7urjjx9lrssw" },
      "selector": { "names": ["PDP Top Banner", "PDP Recs"] },
      "context": {
        "page": {
          "type": "PRODUCT",
          "data": ["7383723-010"],
          "location": "https://sugoi-ne.com/men-pants/p7383723-010",
          "referrer": "https://sugoi-ne.com/men-pants",
          "locale": "en_US"
        },
        "device": {
          "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
          "ip": "54.100.200.255"
        },
        "pageAttributes": { "customPageAttribute": "someValue" },
        "options": { "isImplicitPageview": true }
      }
}'

Let's break this down:

  • Contents of the user and session attributes differ by implementation mode - this is the only difference between the two snippets above. For more information see Basic Concepts

  • The selector argument contains the API selector name of two campaigns which are part of every product page in that website: one for the content of the top banner, and the second for the recommendations widget. (In future versions, additional selector types for fetching a subset of campaigns will be available)

  • The context argument is comprised of three parts

    1. page

      1.1. The type of the page, such as HOMEPAGE or PRODUCT. Some types also mandate passing additional identifiers in the data property. In the case of a product page, it's the product SKU. For some page types, multiple identifiers may be passed, and so this property is always in array notation. See below for the list of context types and appropriate data parameters.

      1.2. The location of the page, and optionally the referrer from which the user got to this page, if known. For the web, this should be a canonical URL. For apps, this is the logical name of the location or screen.

      1.3. The locale is optional and allows recommendations objects to support multi-locale product feeds. See the Knowledge Base for more.

    2. device: this is optional and applies to requests made from client devices, or on their behalf. It is useful for both targeting and data collection based on device attributes:

      2.1 userAgent is applicable for web browser-based clients, whether they call this API directly or through your server-side. The user agent string usually contains not only the browser name and version but also the operating system and brand of the mobile device - all of which can be used for targeting. If this argument is not passed, the gateway checks whether the API call was made with an User-Agent HTTP header, which is the case when a request is done directly from the browser.

      2.2 ip is the IPv4 address of the client device, if available. This allows for targeting based on geo-location and weather. Note: the IP address is never stored on our end, but rather translated immediately to geo-location. (support for IPv6 is planned for future versions)

    3. Additional attributes:

      3.1. pageAttributes is an optional object allowing you to pass any key-value pair you'd like to use for targeting in this campaign. It is an ad-hoc method for quickly targeting based on any attribute known to the caller of the API. All you need to do is pass these attributes and set targeting rules over them in the Admin UI. Note that this data is not stored, and thus cannot be used for creating audience groups.

      3.2 options is used to control the behavior of this endpoint. Currently, only the isImplicitPageview boolean parameter is supported, and it is true by default. Meaning, a pageview is to be reported as part of this call. If you call the endpoint outside the rendering of a new page, set this to false.

👍

Using Ad-hoc Page Attributes vs. User Data Onboarding

While pageAttributes is great as a quick way to enable targeting over custom data, this capability has inherent limitations:

These attributes are usable only for the specific campaign(s) for which you passed these attributes. If you choose the same campaign name in multiple places but do not pass the same attributes anywhere, targeting may not work the way you expected it to.

However, Dynamic Yield also supports the onboarding of first- and third-party data into our backend, which can then be used for audience building and targeting. The latter option is based on a strong schema and usually requires more work to set up.
Learn more.

The additional benefit you get is separation of concerns: the calls you make to choose in various places in your code base do not need to know nor pass any attributes. New attributes can always be added and be used through the Admin UI with no changes to your code calling choose.

Page Context Types

Here are your options for context.page.type and the appropriate data argument for each.

Type

Data

Example

Homepage

Empty

"type": "HOMEPAGE", "data": []

Category Page (PLP)

Full hierarchy of category names

"type": "CATEGORY", "data": ["Men", "Shoes", "Sneakers"]

Product Page (PDP)

The product SKU - always a single string.

"type": "PRODUCT", "data": ["p61239"]

Article Page (aka Post)

The article ID

"type": "POST", "data": ["17562"]

Cart Page

The list of SKUs currently in cart, which may be empty - a list of strings

"type": "CART", "data": ["p61239", "p17834"]

Other Page Type

Empty

"type": "OTHER", "data": []

Response

{
  "choices": [
    {
      "id": 5,
      "name": "PDP Top Banner",
      "type": "DECISION",
      "decisionId": "aGVsbG8K",
      "variations": [
        {
          "id": 52,
          "payload": {
            "type": "CUSTOM_JSON",
            "data": {
              "key1": "value1",
              "key2": "value2"
            }
          }
        }
      ]
    },
    {
      "id": 24,
      "name": "PDP Recs",
      "type": "RECS_DECISION",
      "decisionId": "d29ybGQK",
      "variations": [
        {
          "id": 203,
          "payload": {
            "type": "RECS",
            "data": {
              "slots": [
                {
                  "slotId": "aGVsbG93b3JsZAo=",
                  "sku": "6323723",
                  "productData": {
                    "name": "Plaid shirt",
                    "price": 39.99,
                    "url": "https://website.com/men-pants/p6323723-020"
                  }
                },
                {
                  "slotId": "d2VsY29tZWR1ZAo=",
                  "sku": "5413764",
                  "productData": {
                    "name": "Khaki pants",
                    "price": 59.99,
                    "url": "https://website.com/men-pants/p5413764-010"
                  }
                }
              ]
            }
          }
        }
      ]
    }
  ]
}

The response is always formatted as JSON and encoded as UTF-8.

A successful response (HTTP 200) returns an array of choices, containing the chosen variations (one or more) for each campaign name passed in the request. With each variation comes its payload, whose contents vary by the returned type.

Note that campaigns can be set up in the Admin UI to choose more than one variation out of the total available (aka choosing k-of-n). Hence, variations is always returned as an array.

📘

Returning multiple variations for a campaign

This is useful when you wish to render a slider showing, for example, the best 3 out of 8 available banners. Another example is rendering a list of 3 special offers out of a longer list. Variations in such campaigns are usually updated through a Variation Feed, rather than manually created in the UI.

For each returned campaign, note first the type of decision, which also determines the payload type within. This can be either:

  • DECISION for Custom Campaigns: in this case, the only supported payload type is CUSTOM_JSON, meaning that defining the payload in the UI and parsing it in the caller is completely up to the customer. In this case, it is important to store the unique decisionId for reporting clicks over the rendered variation.
    To simplify the creation of variations in the UI and prevent typing errors, developers may create templates with multiple built-in variable types. As the saying goes, friends don't let non-dev friends compose JSON from scratch over and over again.

  • RECS_DECISION for Recommendations Campaigns. In this case, the payload type is always the built-in RECS, as in the example response above. In this case, you can ignore the returned decisionId, as the payload contains a slotId identifier per each recommended item.

  • NO_DECISION for any campaign type where no targeting rule was matched and there is no default experience in the campaign. You should always be ready to handle this type, as the contents of the campaign can change at any time via the UI, and it is perfectly valid in many cases not to return any variation at all, relying on hard-coded default behavior to kick-in, instead. For this type, there is no decisionId or payload.

The Payload Data

With the CUSTOM_JSON payload type, it's simple - this is totally up to you. Please check out the tutorial for examples.

For the RECS type, data contains an array of objects. Each is a single recommended item, or "slot." The number of slots returned is defined in the Admin UI.

For each slot you have its sku, plus a productData object containing all product attributes from the feed, and a slotId. This identifier represents the slot contents in this unique recommendations response, and you'd need to keep it for reporting clicks over that specific slot. Given this slotId, our backend knows all the details about that slot for reporting purposes, such as which recommendations strategy was used, whether there was a fallback to another strategy, and more.

HTTP Response Codes

Code

Meaning

200

Request succeeded

400

Error parsing request

401

Invalid or missing API key

403

Access denied for a valid API key

405

Wrong HTTP method (not POST, in this case)

422

Request body did not match schema

429

Too many requests received

451

Wrong key type was used (server-side key used from client-side or client-side key used from server-side)

500

Unspecified internal error

Updated 3 months ago



Choosing Variations and Pageviews


In the US:
https://dy-api.com/v2/serve/user/choose
https://dy-api.com/v2/collect/user/pageview
In the EU:
https://dy-api.eu/v2/serve/user/choose
https://dy-api.eu/v2/collect/user/pageview

Note: when using client-side keys from a browser use the sub-domain direct which supports CORS headers (e.g. https://direct.dy-api.com/v2/serve/user/choose; in the EU use direct.dy-api.eu). This also applies to using browser-based REST clients. For collection endpoints (pageviews, user engagement or events) from within a browser, use https://direct-collect.dy-api.com/v2/collect/...

:notebook-with-decorative-cover+: API Reference: Choosing Variations, Reporting Pageviews

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.