Integrations / Shopify

Click and conversion events

From December 31, 2023, Algolia’s Search and Discovery application can’t modify the coding of Shopify themes. For more information, refer to Shopify’s Asset API documentation. As an alternative, Algolia offers Shopify’s App Embed and App Blocks features for Autocomplete and InstantSearch interfaces. For more information, refer to the Quick start and Shopify Algolia configuration documentation.

The Algolia Search and Discovery app lets you track click and conversion events from your Shopify store.

Sending events enables you to use these features:

Before you begin

Algolia Search and Discovery supports the default widgets provided by the app. If you’re using custom widgets, see Sending events for more information.

Algolia Search must be enabled on your theme, to get started, see Enable Algolia on your theme.

User token strategy

Events represent an interaction of a user with your store. Algolia relates a user profile to an event through a user token.

You can choose how you want to set the user token:

  • With a random alphanumeric string at every page refresh
  • Using cookies.

userToken is set with a random alphanumeric string at every page refresh

This option doesn’t use cookies. Because every page refresh generates a new user token, you can’t identify user profiles across sessions.

userToken is set using cookies depending on the user’s approval

This option stores the user token in a cookie on the user’s device. You must use Shopify’s Customer Privacy API. If the user hasn’t consented or you don’t use the Customer Privacy API, a random alphanumeric string is used as user token. Algolia uses Shopify’s loadFeatures method to check if the user has consented.

User token for Personalization

To personalize your search experience, you need to provide a way to identify user profiles across sessions with a stable user token. For example, you can use the user’s account ID after they signed in to your shop.

To add a stable user token, use custom hooks.

Send events

To track user interactions in your Shopify store and send them to Algolia, you can choose between:

  • Use Essentials Analytics: automatically send “click”, “view”, and “search” events to Algolia.
  • Use Conversion Analytics: using Shopify web pixels, send “addToCart” and “purchase” conversion events to Algolia.

Send click events section in the Shopify admin

Shopify web pixels

Shopify web pixels are JavaScript snippets that you can install in your Shopify store to track user interactions and improve your search results. The web pixels collect data about your users’ interactions with your store, such as add-to-cart and purchase events. You can use the data to improve the relevance of your search results and gain insights into your users’ behavior.

Install Shopify web pixels

  1. Go to your Shopify admin and click Settings.

  2. Open the Customer events tab.

    Shopify settings customer events

  3. Click Add custom pixel.

    Shopify add custom pixel

  4. Name your pixel and click Add pixel.

    Shopify add pixel name

  5. Copy the pixel code and paste it into the Algolia web pixels area in the Code section provided by Shopify.

    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
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    
     // Add Algolia Insights cdn
     const ALGOLIA_INSIGHTS_SRC =
       'https://cdn.jsdelivr.net/npm/search-insights@2.13.0/dist/search-insights.min.js';
     !function(e,a,t,n,s,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){
     (e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(/@([^\/]+)\/?/) || [])[1],i=a.createElement(t),c=a.getElementsByTagName(t)[0],
     i.async=1,i.src=n,c.parentNode.insertBefore(i,c)
     }(window,document,"script",ALGOLIA_INSIGHTS_SRC,"aa");
    
     // Enrich line items with queryID
     const enrichLineItemsWithQueryID = (items, purchases) =>
       items.map(item => {
         const purchaseItem = purchases.find(purchase =>
           purchase.objectIDs.includes(item.variant.id)
         );
         if (purchaseItem) {
           return {
             ...item,
             variant: {
               ...item.variant,
               queryID: purchaseItem.queryID,
             },
           };
         }
         return item;
       });
    
     // Filter items with and without queryID
     const filterItemsWithQueryID = enrichedItems =>
       enrichedItems.filter(item => !!item.variant.queryID);
     const filterItemsWithoutQueryID = enrichedItems =>
       enrichedItems.filter(item => !item.variant.queryID);
    
     // Function to create random user token if one isn't found
     function createRandomUserToken() {
       return Array.from(Array(20), () =>
         Math.floor(Math.random() * 36).toString(36)
       ).join('');
     }
    
     // Constant Storage keys
     const CONFIG_STORAGE_KEY = 'algolia_config';
     const ANALYTICS_STORAGE_KEY = 'algolia_analytics_options';
     const CLICK_STORAGE_KEY = 'algolia_analytics_clicked_objects';
     const PURCHASE_STORAGE_KEY = 'algolia_analytics_purchase_objects';
    
     analytics.subscribe('product_added_to_cart', async event => {
       try {
         // Get all stored data from the Shopping session
         const analyticsData = await browser.localStorage.getItem(
           ANALYTICS_STORAGE_KEY
         );
         const analyticsOptions = analyticsData ? JSON.parse(analyticsData) : {};
    
         const config = await browser.localStorage.getItem(CONFIG_STORAGE_KEY);
         const algoliaConfig = JSON.parse(config);
         const { app_id, search_api_key, index_name, user_token } = algoliaConfig;
    
         const clickedObjects = await browser.localStorage.getItem(
           CLICK_STORAGE_KEY
         );
         const previousClickItems = clickedObjects ? JSON.parse(clickedObjects) : [];
    
         const cartLine = event.data.cartLine;
         const variant = cartLine.merchandise;
         const product = variant.product;
         const cartLineCostCurrency = cartLine.cost.totalAmount.currencyCode;
    
         let selectedRecord = previousClickItems.find(record =>
           record.objectIDs.includes(variant.id)
         );
         let algoliaInsightMethod = 'addedToCartObjectIDsAfterSearch';
    
         // Look for the parent (product) if the variant is not found.
         if (!selectedRecord) {
           const productIdClicked = previousClickItems.find(
             record => record.productId == product.id
           );
    
           // Reassign the objectIDs to the variant id if the parent is found.
           if (productIdClicked) {
             productIdClicked.objectIDs = [variant.id];
             selectedRecord = productIdClicked;
           }
         }
    
         // If the variant is not found we send what we have
         if (!selectedRecord) {
           algoliaInsightMethod = 'addedToCartObjectIDs';
           selectedRecord = {
             index: index_name,
             objectIDs: [variant.id],
           };
         }
    
         selectedRecord.currency = cartLineCostCurrency;
         selectedRecord.eventName = 'Add To Cart';
    
         aa('init', {
           appId: app_id,
           apiKey: search_api_key,
           partial: true,
           userToken: user_token || createRandomUserToken(),
           ...analyticsOptions,
         });
         aa('addAlgoliaAgent', 'Shopify Web Pixels');
    
         delete selectedRecord.positions;
         aa(algoliaInsightMethod, selectedRecord);
    
         // Remove the item from local storage
         const updatedClickItems = previousClickItems.filter(
           item => !item.objectIDs.includes(variant.id)
         );
    
         await browser.localStorage.setItem(
           CLICK_STORAGE_KEY,
           JSON.stringify(updatedClickItems)
         );
    
         // Add clicked event to the purchase cookie
         const purchaseStorage = await browser.localStorage.getItem(
           PURCHASE_STORAGE_KEY
         );
         const purchaseObjects = purchaseStorage ? JSON.parse(purchaseStorage) : [];
         purchaseObjects.push(selectedRecord);
         await browser.localStorage.setItem(
           PURCHASE_STORAGE_KEY,
           JSON.stringify(purchaseObjects)
         );
       } catch (error) {
         console.error(error);
       }
     });
    
     analytics.subscribe('checkout_completed', async event => {
       try {
         // Get all stored data from the Shopping session
         const analyticsData = await browser.localStorage.getItem(
           ANALYTICS_STORAGE_KEY
         );
         const analyticsOptions = analyticsData ? JSON.parse(analyticsData) : {};
    
         const config = await browser.localStorage.getItem(CONFIG_STORAGE_KEY);
         const algoliaConfig = JSON.parse(config);
         const { app_id, search_api_key, index_name, user_token } = algoliaConfig;
    
         const purchaseDataStorage = await browser.localStorage.getItem(
           PURCHASE_STORAGE_KEY
         );
         const purchaseData = purchaseDataStorage ? JSON.parse(purchaseDataStorage) : [];
    
         const lineItems = event.data.checkout.lineItems;
    
         // Combine the purchase data with the line items
         // Filter out the line items that don't have a queryID and the ones that do
         const allEnrichedPurchaseObjects = enrichLineItemsWithQueryID(
           lineItems,
           purchaseData
         );
         const purchaseObjectWithQueryID = filterItemsWithQueryID(
           allEnrichedPurchaseObjects
         );
         const purchaseObjectsWithOutQueryID = filterItemsWithoutQueryID(
           allEnrichedPurchaseObjects
         );
    
         aa('init', {
           appId: app_id,
           apiKey: search_api_key,
           partial: true,
           userToken: user_token || createRandomUserToken(),
           ...analyticsOptions,
         });
         aa('addAlgoliaAgent', 'Shopify Web Pixels');
    
         // Add all the items purchased objects with query IDs
         if (purchaseObjectWithQueryID.length > 0) {
           const purchasedObjectIDsAfterSearch = {
             eventName: 'Checkout Completed',
             index: index_name,
             objectIDs: purchaseObjectWithQueryID.map(item => item.variant.id),
             objectData: purchaseObjectWithQueryID.map(item => ({
               queryID: item.variant.queryID,
               price: item.variant.price.amount,
               discount: item.discountAllocations[0] ? item.discountAllocations[0].amount.amount : 0,
               quantity: item.quantity,
             })),
             value: event.data.checkout.subtotalPrice.amount,
             currency: event.data.checkout.subtotalPrice.currencyCode,
           };
    
           aa('purchasedObjectIDsAfterSearch', {
             ...purchasedObjectIDsAfterSearch,
           });
         }
    
         if (purchaseObjectsWithOutQueryID.length > 0) {
           const purchasedObjectIDs = {
             eventName: 'Checkout Completed',
             index: index_name,
             objectIDs: purchaseObjectsWithOutQueryID.map(item => item.variant.id),
             objectData: purchaseObjectsWithOutQueryID.map(item => ({
               price: item.variant.price.amount,
               discount: item.discountAllocations[0] ? item.discountAllocations[0].amount.amount : 0,
               quantity: item.quantity,
             })),
             value: event.data.checkout.subtotalPrice.amount,
             currency: event.data.checkout.subtotalPrice.currencyCode,
           };
    
           aa('purchasedObjectIDs', {
             ...purchasedObjectIDs,
           });
         }
    
         // Clear the purchase data from the storage
         const updatePurchaseItems = purchaseData.filter(
           purchase =>
             !lineItems.some(item => item.variant.id === purchase.objectIDs[0])
         );
    
         await browser.localStorage.setItem(
           PURCHASE_STORAGE_KEY,
           JSON.stringify(updatePurchaseItems)
         );
       } catch (error) {
         console.error(error);
       }
     });
    
  6. Click Save, then Connect.

    Your Shopify web pixels are now installed and can start tracking user interactions on your store. Make sure that your web pixels show Connected in their status.

    Shopify connected status

  7. Go back to your Shopify admin dashboard and complete the setup by clicking on Activate & Continue.

    Final web pixel step

Did you find this page helpful?