Implementing top items with the API
Introduction
Section titled “Introduction”A powerful way to enhance product discovery is to show Top Items the moment a user shows intent by clicking into your search bar, even before they start typing. This guide will show you how to use the Top Items API to implement this feature for a custom UI.
This approach is for developers who need full control over the user experience and are responsible for rendering the results and tracking all related analytics events.
What you’ll learn
Section titled “What you’ll learn”- How to call the Top Items API to fetch popular items.
- How to call the Personalized Top Items API to fetch user-specific top items.
- The critical importance of manually tracking analytics when top items are shown on focus.
Who is this guide for
Section titled “Who is this guide for”- Developers who have understood the “Getting query suggestions via the Autocomplete API” and now want to add top items shown on focus.
- Mobile developers (iOS, Android) who are integrating search suggestions.
- Any developer needing to fetch top or personalized item data directly.
Prerequisites
Section titled “Prerequisites”Before you start, please ensure you have the following in place:
- A working search input field in your application.
- The ability to make HTTP
GETrequests from your application and render the results. - Your Luigi’s Box
trackerId. - A setup for manually sending analytics events, as detailed in the Events API guides.
Step-by-step
Section titled “Step-by-step”We will now modify the code from the previous guide. The changes involve adding a new API endpoint, creating a function to fetch top items, updating your analytics tracking, and adding a focus event listener.
Step 1: Add the top items API endpoint
Section titled “Step 1: Add the top items API endpoint”In your JavaScript configuration section, add a new constant for the Top Items API URL.
Example
Section titled “Example”// --- CONFIGURATION ---const TRACKER_ID = "YOUR_TRACKER_ID";const TOP_ITEMS_API_URL = "https://live.luigisbox.com/v1/top_items"; // <-- ADD THISconst AUTOCOMPLETE_API_URL = "https://live.luigisbox.com/autocomplete/v2";// ... rest of your configStep 2: Create a function to fetch top items
Section titled “Step 2: Create a function to fetch top items”Next, add a new asynchronous function specifically for fetching top items. This function will call the TOP_ITEMS_API_URL and then use your existing renderResults function to display the data.
Endpoint
Section titled “Endpoint”GET https://live.luigisbox.com/v1/top_items
Required parameters
Section titled “Required parameters”tracker_id: Your unique site identifier.type: A comma-separated list of the content type you want top items for, along with the quantity for each (e.g,product:6,category:3).
Optional parameters (recommended)
Section titled “Optional parameters (recommended)”hit_fields: A comma-separated list of attributes you need (e.g., title,url,price,image_link). Using this parameter is highly recommended to keep the API response fast and small by only fetching the data you will display.
Example: Add this new function to your core logic
Section titled “Example: Add this new function to your core logic”const getTopItemsSuggestions = async () => { try { const response = await axios.get(TOP_ITEMS_API_URL, { params: { tracker_id: TRACKER_ID, type: "product:5,category:3", hit_fields: "title,url,price,image_link", }, }); const hits = response.data.hits;
// Override the default group titles for this specific view const customTitles = { item: "Popular Products", category: "Top Categories", }; renderResults(hits, customTitles);
// We will send analytics in the next step } catch (error) { console.error("Failed to fetch top items:", error); }};This function is very similar to your existing getQuerySuggestions function but calls a different endpoint and doesn’t require a q (query) parameter. It also prepares custom titles for the groups.
Step 3: Update analytics for different suggestion types
Section titled “Step 3: Update analytics for different suggestion types”To distinguish between regular query-based suggestions and top items shown on focus, we need to adjust our analytics tracking. You have two options for sending analytics: the DataLayer Collector (recommended for web integrations that already use a dataLayer) or the Events API (recommended for backend or mobile integrations). If you choose the DataLayer Collector, make sure the LBX script is included on your page.
- Query-driven suggestions (from the Autocomplete API) should be tracked as an Autocomplete event.
- Top items shown on focus (loaded from the Top Items endpoint) should be tracked as a Recommendation event.
Autocomplete (query-driven) view event
Section titled “Autocomplete (query-driven) view event”// Send VIEW event (Autocomplete list)function sendAutocompleteViewAnalytics(query, hits) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: "view_item_list", ecommerce: { item_list_name: "Autocomplete", search_term: query || "", items: hits.map((hit, index) => ({ item_id: hit.url || hit.attributes.title, item_name: hit.attributes.title, index: index + 1 })) } });}// Send VIEW event (Autocomplete list)function sendAutocompleteViewAnalytics(query, hits, customFilters = {}) { const analyticsPayload = { id: uuid.v4(), type: "event", tracker_id: TRACKER_ID, client_id: CLIENT_ID, lists: { "Autocomplete": { query: { string: query || "", // Add custom filters to distinguish the source filters: customFilters }, items: hits.map((hit, index) => ({ title: hit.attributes.title, url: hit.url || hit.attributes.title, position: index + 1 })) } } }; sendAnalyticsEvent(analyticsPayload);}Top items on focus (recommendation) view event
Section titled “Top items on focus (recommendation) view event”// Send VIEW event (Recommendation list for Top Items on focus)function sendTopItemsViewAnalytics(hits) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: "view_item_list", ecommerce: { item_list_name: "Recommendation", items: hits.map((hit, index) => ({ item_id: hit.url || hit.attributes.title, item_name: hit.attributes.title, index: index + 1, price: hit.attributes.price || null, type: hit.type, })), filters: { RecommenderClientId: "autocomplete_popup", Recommender: "autocomplete_popup", }, }, });}// Send VIEW event (Recommendation list)function sendTopItemsViewAnalytics(hits) { const analyticsPayload = { id: uuid.v4(), type: "event", tracker_id: TRACKER_ID, client_id: CLIENT_ID, lists: { Recommendation: { query: { filters: { // REQUIRED: stable identifier of this widget/list RecommenderClientId: "autocomplete_popup", // Optional but useful for debugging/segmentation Recommender: "autocomplete_popup", }, }, items: hits.map((hit, index) => ({ title: hit.attributes.title, type: hit.type, url: hit.url || hit.attributes.title, position: index + 1, price: hit.attributes.price || null, })), }, }, }; sendAnalyticsEvent(analyticsPayload);}Example: Update the two fetcher functions
Section titled “Example: Update the two fetcher functions”In getTopItemSuggestions, add this line after renderResults(hits):
if (hits && hits.length > 0) { sendTopItemsViewAnalytics(hits);}In your existing getQuerySuggestions, modify the analytics call:
// Change the original analytics call to this:if (hits && hits.length > 0) { sendAutocompleteViewAnalytics(query, hits); // No custom filter needed here}Step 4: Add the focus event listener
Section titled “Step 4: Add the focus event listener”Finally, add a focus event listener to your search input. This will trigger your new getTopItemsSuggestions function whenever a user clicks into an empty search box.
Example
Section titled “Example”// --- EVENT LISTENERS ---searchInput.addEventListener( "input", debounce((e) => getQuerySuggestions(e.target.value), 300),);
// ADD THIS NEW LISTENERsearchInput.addEventListener("focus", () => { // Only fetch top items if the search box is empty if (searchInput.value === "") { getTopItemsSuggestions(); }});Advanced: Adding personalized top items
Section titled “Advanced: Adding personalized top items”Step 1: Add the personalized API endpoint
Section titled “Step 1: Add the personalized API endpoint”First, add the URL for the personalized API to your configuration constants.
Example: Add the following line to your configuration
Section titled “Example: Add the following line to your configuration”const PERSONALIZED_TOP_ITEMS_API_URL = "https://live.luigisbox.com/v1/personalized_top_items";Step 2: Create a function for personalized suggestions
Section titled “Step 2: Create a function for personalized suggestions”Now, create a new function to handle fetching personalized data. This function calls the personalized endpoint and requires a user_id parameter.
Example: Add the following function to your core logic
Section titled “Example: Add the following function to your core logic”const getPersonalizedTopItemsSuggestions = async (userId) => { if (!userId) return; // Don't run if there's no user ID
try { const response = await axios.get(PERSONALIZED_TOP_ITEMS_API_URL, { params: { tracker_id: TRACKER_ID, user_id: userId, // The specific user's ID type: "items:5,query:3", // e.g., personalized items and last searched queries }, }); const hits = response.data.hits; const customTitles = { item: "Recommended For You", query: "Your Recent Searches", }; renderResults(hits, customTitles);
// Add the analytics call for this new function if (hits && hits.length > 0) { sendAutocompleteViewAnalytics(null, hits, { source: "personalized_top_items", }); } } catch (error) { console.error("Failed to fetch personalized top items:", error); }};Step 3: Update the focus event listener
Section titled “Step 3: Update the focus event listener”The final step is to update your focus event listener with logic to choose which function to call based on whether a user is logged in.
Example: Replace your existing focus listener with the following version
Section titled “Example: Replace your existing focus listener with the following version”// Replace the previous searchInput.addEventListener('focus', ...) with this:searchInput.addEventListener("focus", () => { if (searchInput.value === "") { // In a real application, you would check if the user is logged in // and get their actual ID from your session or auth system. const currentUserId = "user-123"; // Example: get this from your session
if (currentUserId) { getPersonalizedTopItemsSuggestions(currentUserId); } else { getTopItemsSuggestions(); } }});Best practices
Section titled “Best practices”- You are in control: Remember that when using the direct API, you are fully responsible for the implementation, including all analytics tracking. Failure to send analytics events will prevent the system from learning.
- Use
hit_fields: To minimize the response size and improve speed, use the optionalhit_fieldsparameter in your API call to request only the attributes you actually need to display (e.g.,&hit_fields=title,price,image_link). - Match user IDs for personalization: For the Personalized Top Items API to be effective, the
user_idyou send in the API request must match thecustomer_idyou send in your analytics events for that same user.
Next steps
Section titled “Next steps”- Implement trending queries: Learn how to fetch and display popular search terms by following our “Implementing trending queries suggestions” guide.
Was this page helpful?
Thanks.