Ranking Requests

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

Goal

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.

Integration

The Promoted server-side SDK is called in your API server after ranked your own list of content. 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 request for a list of content. E.g. search, feed, related items. Protocol Buffer definition
  • Insertion = A content candidate when processing a Request. We start with more potential Request Insertions 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. More detailed integration instructions can be found in each SDK docs.

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 How to send features to Promoted? 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.