Setting the Context

Before proceeding, it would be good to acquaint yourself with Choosing Variations and Pageviews and where it fits in your workflow. Alternatively, you’re welcome to go with the flow and postpone the deep dive.

One thing that’s important to understand about the choose API endpoint: to minimize the number of calls to our API, by default this endpoint, is used both for choosing variations and implicitly reporting a new pageview, in one request. This lets you perform these two critical tasks in one round trip.

Creating a Context Object

Any API call to the choose endpoint requires passing in a detailed context in the POST body. The full context is of course specific to the page you're now rendering in the server, but it makes sense to define a skeleton context that will be available to any server-side route in the Petshop application.

Since we're using Express.js, let's have a bit of fun and create this skeleton context as a middleware, so it gets added to any request from the client. Add the following code to app.js before any routes are hooked ('/', '/product', etc.).

/* add dyContext */
app.use((req, _res, next) => {
  req.dyContext = {
    page: {
      location: `${req.protocol}://${req.hostname}${req.originalUrl}`,
      referrer: req.headers.referer || '',
      data: [],
    device: {
      userAgent: req.headers['user-agent'] || '',
      ip: req.ip,
    pageAttributes: req.query,

// existing rest of file
app.use('/', homepageRouter);
app.use('/product', productsRouter);

This object is indeed incomplete: in order to call choose we'll need to specify the page type, add relevant page data in the data array, and of course name the campaigns we want to choose variations for.

You can ignore the pageAttributes property for now - we'll get back to that later.

Integrating with Dynamic Yield in the homepage

Let's go back to our newly created file DYAPI.js, and add our first helper function for calling choose. We're also adding one required package for easy asynchronous HTTPS requests.

const request = require('request-promise-native');

const APIKEY = '12be1328c8d25cc072e9...'; // replace with your key
const DYHOST = '';      // or .eu

async function choose(userId, sessionId, dyContext, selectors = []) {
  const options = {
    method: 'POST',
    uri: `${DYHOST}/v2/serve/user/choose`,
    headers: {
      'DY-API-Key': APIKEY,
    body: {
      selector: {
        names: selectors,
      user: {
        id: userId,
      session: {
        custom: sessionId,
      context: dyContext,
    json: true,

  let variations = {};
  try {
    const response = await request(options);
    variations = response.choices;
    console.log(`Choose response: ${JSON.stringify(response, null, 2)}`);
  } catch (e) {
    console.error(`ERROR IN CHOOSE: ${e.message}`);
  return variations;

module.exports = {

Using the DYAPI Module in the homepage

Let's move now to the server-side handler for the homepage. Open routes/homepage.js and add the needed code for:

  1. Requiring the DYAPI module.
  2. Modifying the getPageContent function to call the choose API. For now we're not modifying the default homepage contents just yet, but the call will correctly report a pageview.
// Add this to existing require statements at the top
const DYAPI = require('./../DYAPI');

// ...later in the file:

async function getPageContent(req) {
  // Complete the context with the appropriate page type, and call the API = 'HOMEPAGE';
  const apiResponse = await DYAPI.choose(req.userId, req.sessionId, req.dyContext, []);

  // Rest of function remains as is, for now
  const content = {
    heroBanner: defaultHeroBanner,
    recommendations: defaultRecommendations,
  if (req.originalUrl.includes('SALE')) {
    content.overlay = defaultOverlay;
  return content;

Our little Node server is configured to auto-restart after any change to source file, so we can go back the browser and refresh the Petshop homepage (at http://localhost:3000).

Our new helper function is now called and emit its log output to the server console. You should see the following at the command line window:


Assuming your API key is valid, the call goes though and you'll get an empty array of choices, as we did not yet request variations for any campaign. As the next step, we'll do just that: create your first Dynamic Yield API-powered campaign.