Algolia first strategy
Use the Algolia first strategy if the other strategies aren’t an option and if your retail media platform (RMP), such as Criteo, lets you filter out already-found products. This guide explains how the strategy works, its requirements, and how to implement it.
How the Algolia first strategy works
- User performs a search (for example, “running shoes”).
- Your app queries Algolia to retrieve the regular product results.
- Your app sends a request to the RMP, including the list of products from Algolia. This allows the RMP to avoid recommending products that are also in the regular results.
- The combined list of regular and sponsored results is sent to the frontend for display.
Requirements
To effectively implement the Algolia first strategy, your RMP must support exclusions. It should accept a list of product IDs and exclude them from its sponsored recommendations to prevent duplicate results.
Pros
- The RMP handles deduplication.
Cons
- Results may be less relevant. The most relevant Algolia searches may be excluded from RMP selection.
- Slower than the parallel requests strategy. Because the RMP call must wait until the Algolia request finishes, the response time is slower than the parallel request strategy.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import algoliasearch from 'algoliasearch';
// Constants
const RETAIL_MEDIA_TIMEOUT_MS = 500;
const RETAIL_MEDIA_API_ENDPOINT = 'https://api.retailmediaplaform.com/search/v1/products/';
const SPONSORED_PRODUCT_POSITIONS = [0, 1, 8, 12];
const ALGOLIA_INDEX_NAME = 'prod_products';
const ALGOLIA_APP_ID = '';
const ALGOLIA_API_KEY = '';
// Algolia setup
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY);
const index = client.initIndex(ALGOLIA_INDEX_NAME);
/* -------------------------------------------------------------------------- */
/**
* Fetches sponsored products from the RMP with a timeout mechanism.
* If the request takes longer than RETAIL_MEDIA_TIMEOUT_MS, it will be stopped.
* @param {string} searchQuery - The search term to find sponsored products
* @param {string} filters - Filtering criteria in Algolia format (e.g. 'size:10 AND color:"blue"')
* @param {Array} organicObjectIds - Array of objectIDs from Algolia's regular hits
* @returns {Promise} Returns the JSON response from RMP if successful, null if the request times out or fails
*/
async function fetchRetailMediaWithTimeout(searchQuery, filters, organicObjectIds) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), RETAIL_MEDIA_TIMEOUT_MS);
try {
const { statusCode, body } = await request(RETAIL_MEDIA_API_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
signal: controller.signal,
body: JSON.stringify({
keyword: searchQuery,
filters: filters,
organicResults: organicObjectIds || [] // Pass organic results to RMP
})
});
clearTimeout(timeout);
if (statusCode === 200) {
return await body.json();
}
throw new Error(`Request failed with status ${statusCode}`);
} catch (error) {
if (error.name === 'AbortError') {
console.error('Retail Media Platform request timeout');
} else {
console.error('Retail Media Platform request failed:', error);
}
return null;
}
}
/**
* Injects sponsored products into regular hits at specific positions defined by SPONSORED_PRODUCT_POSITIONS.
* Removes any duplicate products that exist in both regular and sponsored hits.
* @param {Array} regularHits - The array of regular product hits from Algolia
* @param {Array} sponsoredHits - The array of sponsored product hits from RMP
* @returns {Array} Combined array of regular and sponsored hits with sponsored products at specified positions
*/
function injectSponsoredProducts(regularHits, sponsoredHits) {
if (!sponsoredHits?.length) return regularHits;
// Remove duplicates
const sponsoredIds = new Set(sponsoredHits.map(hit => hit.objectID));
const finalHits = regularHits.filter(hit => !sponsoredIds.has(hit.objectID));
// Insert sponsored products
SPONSORED_PRODUCT_POSITIONS.forEach((position, index) => {
if (index < sponsoredHits.length) {
const sponsoredHit = { ...sponsoredHits[index], sponsored: true };
const insertPosition = Math.min(position, finalHits.length);
finalHits.splice(insertPosition, 0, sponsoredHit);
}
});
return finalHits;
}
/**
* Performs sequential search requests, first to Algolia, then to RMP
* Passes Algolia regular results to RMP to inform sponsored product selection,
* then combines both results maintaining the specified positioning.
* @param {string} searchQuery - The search term to find products
* @param {Object|string} filters - Filtering criteria for both searches
* @returns {Promise<Array>} Combined array of regular and sponsored hits, empty if the search fails
*/
async function searchProducts(searchQuery, filters) {
try {
// Get regular results from Algolia
const { hits: organicHits } = await index.search(searchQuery, {
filters: filters,
hitsPerPage: 48
});
// Extract objectIDs from regular results
const organicObjectIds = organicHits.map(hit => hit.objectID);
// Get sponsored products from RMP, passing regular results
const retailMediaResult = await fetchRetailMediaWithTimeout(
searchQuery,
filters,
organicObjectIds
);
// Merge results by removing hits duplicates
return injectSponsoredProducts(
organicHits,
retailMediaResult?.hits || []
);
} catch (error) {
console.error('Search failed:', error);
return [];
}
}
// Usage
const searchQuery = 'running shoes';
const filters = 'size:10 AND color:"blue"';
const results = await searchProducts(searchQuery, filters);
render(results);
How the code works
- Call Algolia. Queries Algolia to retrieve regular results and extract the product IDs.
- Call RMP. Calls the RMP with the list of product IDs. The RMP uses the product IDs to exclude already-found products.
- Merge and inject sponsored products. Inserts the returned sponsored items at the predefined positions.
- Return merged results. The frontend receives the merged list, where sponsored products are appropriately labeled.
Before your strategy goes live, ensure you’ve considered the regulatory requirements and the influence of sponsored results on your analytics, ranking, and UI.