Handling Paging in Ranking

in Delivery API for multiple pages of continued listing results with consistent backwards navigation

Paging is when a previous search or ads ranking result is returned without modifications, typically by navigating backward in a multi-page or infinite scroll design. When paging is missing or broken, then when navigating backward, you see new search or feed results, not the results that you saw before. This is typically annoying to end users. Paging implements that preservation of past results on back navigation that most users expect in most search and feed products.

Implementing Paging


  1. Clients do their own retrieval. They narrow many candidates down to the top N (e.g. 300-500) to send into Promoted's SDK. These few hundred candidates are called Request Insertions.
  2. Delivery SDK (either in the SDK or Delivery API) will narrow down to a smaller page of items. These are Response Insertions. They are specified using Request.paging.offset and Request.paging.size.

For this case:

  • paging.offset = 0- Indicates which position to return as the first insertion in the Response.insertion list.
  • paging.size = 50- The size of the response page size. Similar to limit in select statements.
  • retrievalInsertionOffset = 0 - This is described down below if you want to send a different subset of insertions to Promoted's SDK.

Caching recently served response items

When Delivery API receives a Request, the API looks in our page cache by a paging key. This allows Promoted to return already paged items back to the user if they request the same pages again.

Promoted creates the paging key from Request properties such as:

  • anonUserId
  • clientInfo
  • useCase
  • searchQuery
  • blenderConfig
  • properties.

Promoted also has a setting for how long to keep recent pages. This setting defaults to around 30 minutes.


If you have Request.properties that will change across pages, contact Promoted to exclude them from the paging key

The default behavior is to include all Request.properties in the paging key. If a Request.property changes across pages (e.g. request timestamp), it'll change the paging key and break paging. If you want exclude certain request properties from the paging key, please contact a Promoted engineer.


When a new page is requested from Delivery API, Promoted will try to serve the next best recommendations to that page, regardless of the page number


  • User starts their request on page 10. Promoted will serve the top results on page 10.
  • Then the user hops back to page 0. Promoted will serve the next best items on page 0.

The results for each page are temporarily cached inside Promoted's servers.

If users try to share links to result lists, the items will be different for each user that tries to load the list. Each user gets their own personalized results.

Promoted can customize paging behavior for your use case. E.g. how long to keep the paged results in the paging DB?

Missing Request.insertion.content_ids on subsequent Requests

When a user makes a repeated request and certain contentIds previously allocated are missing in the new Request.insertion list, the Delivery API's behavior depends on its configuration. This situation arises due to common issues like inconsistent retrieval results or changes in item details.

Configurations and Behaviors

  1. Default Setting (limitToRequestInsertions=false):

The Delivery API continues to return the previously allocated contentId in its original position, even if it's no longer in the current Request.insertion. This allows for expanding the list of contentIds across multiple requests.


  • First Request: contentIds [A, B, C] for positions 0-2. Response: [B, C, A].
  • Second Request: contentIds [C, D, E] for positions 0-2. Response: [B, C, A].
  1. Alternative Setting (limitToRequestInsertions=true):

Any missing Request.insertion.contentIds are omitted from the response. This limits the content to only those items currently listed in Request.insertion.


  • First Request: contentIds [A, B, C] for positions 0-2. Response: [B, C, A].
  • Second Request: contentIds [C, D, E] for positions 0-2. Response: [D, C, E]. Here, A and B are excluded as they are not in the current insertion list, while C retains its position and D and E fill the available slots.

Sending more than the top few hundred insertions


Contact Promoted engineers if you want to send additional Request Insertions to Delivery API

Different windows of retrieval candidates can be sent to Promoted's SDK. The window is specified using the retrieval_insertion_offset parameter. The union config option needs to be enabled.

For this case:

  • Request.paging.offset = 550- The starting index.
  • Request.paging.size = 50- The response page size
  • retrievalInsertionOffset = 500 - The starting index of the window of retrieval insertions being passed into the SDK.

Delivery API will cache bot the earlier range of[0, 500) insertions and the additional [500, 999)insertions.

Linking Pages Together with Paging Keys

Promoted supports two methods of connecting Delivery Response pages into a paging sequence:

  • Use an implicit paging key (default). Promoted infers the paging key for the same user, query, search filters, and within a limited time. This is easier to integrate initially, but you have less control and can require maintenance to support new search filters and support different types of A/B experimentation.
  • Set an explicit paging key. You are responsible for all paging key preservation, passing, and logic. This option is the most reliable and has the most control, but it requires some overhead to handle the paging key. Contact Promoted about use of this feature for integration support.

Paging and Blender

Internally, Promoted implements paging like an additional retrieval system, plus a Blender allocation rule. If a position represented by (pagingKey, positionEnumeration) has an active paging cache entry, then when allocating that position in Blender, allocate the item as specified in the paging cache. (more details) If that item cannot be allocated for any reason, then allocate another available item. Blender is otherwise bypassed for Response Insertions allocated using Paging. Any rules that create attributes to be returned in the Response Insertion Properties like "isBoosted" are not re-created.

Paging and Response Insertion Properties

Response Insertion Properties from the original Response Insertion are returned on future paging cache copies. For example, if "isBoosted" was set in the original Response Insertion, then it will also be set on all future paging cache copies of that Response Insertion. Additionally, the "previouslyAllocated" = true is set on all paging cache Response Insertion Properties.

Paging cache Response Insertion are assigned new Insertion IDs. They do not reuse the original Response Insertion ID.

For example, say contentID = ABC was delivered on page 1 with the "isBoosted" attribute set and a pass-through of the L2 pCTR model inference as "pCTR." The user navigates to page 2 and then back to page 1.

The resulting new paging cache Response Insertion Properties may look like:

Response.Insertion.Properties = {
  "previouslyAllocated": true,
  "isBoosted": true,
  "pCTR": 0.32

Paging and Ads

Ads can be a special case of paged delivery. Sometimes, ads have user and allocation level frequency limits which can have edge cases when considering paging. Contact Promoted if you need special behavior for ads on paged results.