Using Experience APIs and Script together

The use case

Consider the following scenario.

Assume that you have a website with an existing script-based implementation of Dynamic Yield. You now want to migrate some of your campaigns to API. Say, a Hero Banner at the top of your homepage, where you really want to ensure no flicker or delay. So, you set up an API campaign for this banner with some variations to test, with the selector name "homepage hero banner".

When a user navigates to your homepage, their browser makes a request for this page from your backend server. As part of page rendering, a call is made to our [choose](doc:choose) endpoint to get the right banner variation for this user.

Returning users

Cookies for returning users

If this isn't the first time this user has interacted with your website, they'll already have some first-party cookies that were previously set by our client-side script that's already embedded on your site. These cookies are:

  • _dyid: A unique user identifier generated by Dynamic Yield. Usually referred to as the DYID.
  • _dyjsession: The current session identifier generated by Dynamic Yield. Because this cookie has a short time-to-live, it probably won't exist anymore when this returning user begins this current visit.
  • _dyid_server: This cookie is set by your backend server as part of the standard web implementation. This is required due to browser restrictions on third-party cookies. This cookie simply holds a copy of the value of the _dyid cookie. By having this cookie set from your first-party server, it has a longer expiration period. For more details, see the article Implementing First-Party Cookies to Resolve Third-party Cookie Browser Restrictions on our user support site.

The API call (code)

This is what the choose call looks like for returning users, to get the correct variation the hero banner campaign:

/choose request body for a returning user

{
  "user": {
    "dyid": "1679843083476146043",
    "dyid_server": "1679843083476146043"
  },
  "session": {
    "dy": "a2719b4d6c4709128bf5f57a3bf3"
  },
  "selector": {
    "names": ["homepage hero banner"]
  },
  "context": {
    "page": {
      "type": "HOMEPAGE",
      "location": "https://shop.biz/",
      "locale": "en_US"
    },
    "device": {
      "userAgent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/56.0.29",
      "ip": "54.100.200.255"
    }
  }
}

Note the following in the request:

  • The user attribute object contains the values of both dyid and dyid_server, which you can get straight from the respective cookies as passed by the returning user's browser. If you only get one of these values, that's OK, pass the one you have. Now that you've let us know this is a returning user, our servers can apply targeting based on all we know of that user (audiences, affinity profile, and so on).
  • Similarly, the session attribute is an object containing the dy attribute, which you should fill with the value of the _dyjsession cookie, if available. If it isn't, don't pass anything within session. A new session ID is returned in the response.

New users

If the visitor is new to your site and interacting with it for the very first time, none of the listed cookies are available to your backend code. In this case, we request the campaign with the user and session arguments empty:

/choose request body for a new user

{
  "user": {
    "dyid": "",
    "dyid_server": ""
  },
"session": {
    "dy": ""
  },
"selector": {
    "names": ["homepage hero banner"]
  },
  "context": {
    "page": {
      "type":"HOMEPAGE",
      "location":"https://shop.biz/",
      "locale":"en_US"
  },
  "device": {
    "userAgent":"Mozilla/5.0 (X11; Linux x86_64) Chrome/56.0.29",
    "ip":"54.100.200.255"
  }
}

Getting the response and setting cookies

Whether the user is new or returning, this is what the response looks like:

/Choose response

{
  "cookies": [
      {"name": "_dyid_server", "value": "16798430146043", "maxAge": "63072000"},
      {"name": "_dyjsession", "value": "a2719b4d6c470383f1bf3", "maxAge": "1800"}
  ],
  "choices": [
      "id": 5,
      "name": "homepage hero banner",
      "type": "DECISION",
      "decisionId": "aGVsbG8K",
      "variations": [
        {
          "id": 52,
          "payload": {
            "type": "CUSTOM_JSON",
            "data": {
              "key1": "value1",
              "key2": "value2"
          }
        }
      ]
 ...
}

Note the cookies array in the response: Each entry has the exact name of a cookie you need to set as part of the response to the browser, along with its value and time to live (known as maxAge in the HTTP specification, in seconds).

Here are a few things to know:

  • Whether the user is new or returning, you always get these cookies in the response, to set in your next call. If you've passed these values in the request, you get the same values back, but with an updated maxAge. If you haven't passed them, new ones are generated and returned.
  • The expiry for the user ID is set for one year, and the session is set for 30 minutes. Because you get a fresh value in each choose call, this effectively sets the time of user inactivity after which the browser deletes the cookies. This means that user IDs are "forgotten" after a year of inactivity, and sessions end after 30 minutes of inactivity. For this to work correctly, always set the cookies you get back from the choose call.

Going back to the use case scenario:

After the user's browser receives the homepage along with the cookies, the Dynamic Yield client-side script embedded in the page knows to "respect" these cookies, so that the same identifiers are used for both API campaigns and web-based campaigns.

If the first-ever page that the user lands on does not use any API campaigns, these cookies are not available to the client script when the page loads. In this case, the script creates these cookies on its end. This means that a user making a second pageview (or third, or...), even during their first-ever visit, already has all the right cookies set, so for our purposes, they're already considered returning users.