Ranking Requests

Goal: Promoted wants to rank content at the end of your getContent() API call.

Delivery API Overview

In order to rank Content , your API server needs to call Promoted's Delivery API. A similar integration works both for (1) initial logging to Promoted, (2) running experiments and (3) fully launched with Promoted's rankings.

You send the user information and retrieval results to Promoted's Delivery API. Promoted ranks the items and sends the results back to your server.

You send the user information and retrieval results to Promoted's Delivery API. Promoted ranks the items and sends the results back to your server.


Integration

The Promoted server-side SDK is called in your API server after retrieval and any internal ranking steps. Click here for reasons about why we have a server-side SDK.

The main inputs to the SDKs are a list of Request and a list of Insertion candidates.

  • Request: A list of content. This includes search, feed, and related items. Protocol Buffer definition
  • Insertion: A content candidate when processing a Request. We start with many potential Request Insertions, generated by the client's retrieval, and narrow down to a subset of Response Insertions to return to the UI. Insertions are different from Impressions because Insertions might not get viewed.

We have Delivery client libraries in multiple languages and can add support for additional languages if needed. Detailed integration instructions are found in each SDK doc on Github.

Here is an example code block for Typescript.

static async promotedDeliver(req: any, products: Product[], res: Response) {
  const responsePromise = promotedClient.deliver({
    // onlyLog: true - if you want to only log to Promoted.
    request: {
      userInfo: {
        anonUserId: req.anonUserId,
      },
      useCase: 'SEARCH', // Supports other enum values like 'FEED' and 'DISCOVER'.
      device: {
        browser: {
          userAgent: "Mozilla/5.0 ..."
        }
      },
      searchQuery: 'cars'
      properties: {
        struct: {
          // TODO - Add user, request and context features.
          // TODO - Add request filters.  The properties are used to generate a paging key that is used for caching.
        }
      },
      insertion: products.map((product, retrievalRank) => ({
        contentId: product.id,
        retrievalRank,
        properties: {
          struct: {
            // TODO - add user-item features here.
            // Example: "numReviews": product.numReviews,
          },
        },
      })),
    },
  });
  // Construct the map while the RPC is happening.
  const productIdToProduct = products.reduce<Record<string,Product>>((map, product) => {
      map[product.id] = product;
      return map;
  }, {});
  const clientResponse = await responsePromise;
  const responseProducts = toContents<Product>(clientResponse.insertion, productIdToProduct);

  // Change the response Product list to use the values in the returned Insertions.
  sendSuccessToClient(res, { products: responseProducts) });
  // Do not block.  Log asynchronously.
  clientResponse.log().catch(handleError);
}

Passing data on request

For Promoted to use data for ranking, the data needs to either be sent into the Delivery API call or it needs to be in Promoted already (e.g. previously sent content data through Content Service). This is where interaction features (combinations of content, user and context) should be passed in.

Example fields to pass in:

  • Your own retrieval scores.
  • Dynamic price.
  • Dynamic UI badges.

See the Metrics and Content sections for explanations on how to send data to Promoted.

Data that impacts ranking either needs to be passed in using:

  1. The Delivery API call.
  2. The Content Service (offline). This can be used for passing stable item or user data. It will

It’s possible to pass stable item or user features on this call but it’s better to pass those through the Content Service to improve scale and speed.

Select UserInfo fields

We've provided some extra information on certain UserInfo fields for clarification.

FieldTypeDescriptionDefault
is_internal_userboolIndicates that the user is from the marketplace or Promoted team. Internal users get depersonalized traffic and doesn't impact modelsfalse
ignore_usageboolCan be used to suppress traffic, and doesn't impact models. For usage that Promoted should ignore downstreamfalse
various user ID valuesstring