Quickstart: Implementing 'Top Items' suggestions with the API

Introduction

A powerful way to enhance product discovery is to provide suggestions 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 suggestions and tracking all related analytics events.

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 suggestions.
  • The critical importance of manually tracking analytics for these "on focus" suggestions.

Who is this guide for

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 GET requests 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

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

In your JavaScript configuration section, add a new constant for the Top Items API URL.

Example

// --- CONFIGURATION ---
const TRACKER_ID = "YOUR_TRACKER_ID";
const TOP_ITEMS_API_URL = "https://live.luigisbox.com/v1/top_items"; // <-- ADD THIS
const AUTOCOMPLETE_API_URL = "https://live.luigisbox.com/autocomplete/v2";
// ... rest of your config

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

GET https://live.luigisbox.com/v1/top_items

Required parameters

  • tracker_id: Your unique site identifier.
  • type: A comma-separated list of the content type you want suggestions for, along with the quantity for each (e.g, product:6,category:3).
  • 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

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 suggestion groups.

Step 3: Update Analytics for different suggestion types

To distinguish between regular query-based suggestions and these new "on-focus" suggestions, we need to modify our analytics tracking. We will update the sendAutocompleteViewAnalytics function to accept a custom filter.

Example: Replace your existing sendAutocompleteViewAnalytics function with this enhanced version

// This function replaces your previous analytics function
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);
}

Example: Update the two fetcher functions

In getTopItemSuggestions, add this line after renderResults(hits):

// Send analytics with a filter to identify this as an "on-focus" event
if (hits && hits.length > 0) {
    sendAutocompleteViewAnalytics(null, hits, { source: 'top_items_on_focus' });
}

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

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

// --- EVENT LISTENERS ---
searchInput.addEventListener('input', debounce(e => getQuerySuggestions(e.target.value), 300));

// ADD THIS NEW LISTENER
searchInput.addEventListener('focus', () => {
    // Only fetch top items if the search box is empty
    if (searchInput.value === '') {
        getTopItemsSuggestions();
    }
});

Advanced: Adding personalized Top items

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

const PERSONALIZED_TOP_ITEMS_API_URL = "https://live.luigisbox.com/v1/personalized_top_items";

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

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

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

// 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

  • 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 optional hit_fields parameter 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_id you send in the API request must match the customer_id you send in your analytics events for that same user.

Next Steps

Now that your on-focus suggestions are working, you can continue to enhance your autocomplete experience.