Event tracking with Headless (Shopify Hydrogen)

This is for:

Developer
In this article

It’s crucial that you track touchpoints to analyze storefront performance, create reports, and power Coveo Machine Learning (Coveo ML) models. You can do this by sending events to the Coveo Usage Analytics (Coveo UA) service.

If you use Coveo Headless to build your product discovery solutions, track events using dedicated Headless controllers. These controllers automatically log specific commerce events, such as when a user makes a purchase or adds a product to a cart.

Headless commerce controllers rely on the Event Protocol to log events.

The following table shows the types of events to track and the corresponding controllers.

Event Tracking controller

Click

Use the InteractiveProduct controller to track clicks in product lists

Product view

Use the ProductView controller to log view events when a user navigates to a PDP

Cart

Use the Cart controller to update cart state when products are added or removed

Purchase events

Purchase events can be tracked automatically by leveraging the Coveo app, which logs purchase events when the required cart attributes are set:

  • coveoClientId

  • coveoTrackingId

  • coveoOrganizationId

  • coveoAccessToken

Add the attributes to your cart by performing the following series of modifications to your underlying Shopify cart logic.

Note

If you’re not using the app, see implement your own web pixel for instructions on how to log purchase events.

Prerequisites

Be familiar with the concepts discussed in Getting started (Shopify Hydrogen) and Core concepts (Shopify Hydrogen).

Implementation

Note

Samples in this section are simplified for clarity. For a complete implementation, see ($locale).cart.tsx in the Barca Sports demo repository.

The example implementation consists of two main parts, a helper function to update cart attributes and the usage of this helper in both the Remix action and Remix loader.

Create a helper function to update the cart

Check if the attributes are present on the cart, and if not, add them using the updateAttributes method from the Cart handler. You’ll call this after any operation that retrieves or modifies the cart to configure the attributes as required for proper purchase event tracking.

// ...

import { engineConfig, engineDefinition  } from '~/lib/coveo.engine';

// ...

async function setCoveoConfigAttributes(
  context: any,
  request: Request,
  cartResult: CartQueryDataReturn,
) {
  const {cart: cartHandler} = context;
  const cart = cartResult.cart;

  if (!cart) return cartResult;

  const attributes = cart.attributes ?? [];
  const attributesToUpdate = [];

  const navigatorProvider = new ServerSideNavigatorContextProvider(request); 1

  const {clientId} = navigatorProvider;
  const {
    configuration: {
      analytics: {trackingId},
      organizationId,
      accessToken,
    },
  } = engineConfig;

  const attributesToFind = [
    'coveoClientId',
    'coveoTrackingId',
    'coveoOrganizationId',
    'coveoAccessToken',
  ];

  const foundAttributes = (cart.attributes ?? []).reduce((acc, item) => {
  if (attributesToFind.includes(item.key)) {
    acc[item.key] = {key: item.key, value: item.value};
  }
    return acc;
  }, {} as Record<string, {key: string; value: string}>);

  if (!foundAttributes.coveoClientId) {
    attributesToUpdate.push({key: 'coveoClientId', value: clientId}); 2
  }
  if (!foundAttributes.coveoTrackingId) {
    attributesToUpdate.push({key: 'coveoTrackingId', value: trackingId}); 2
  }
  if (!foundAttributes.coveoOrganizationId) {
    attributesToUpdate.push({ 2
      key: 'coveoOrganizationId',
      value: organizationId,
    });
  }
  if (!foundAttributes.coveoAccessToken) {
    attributesToUpdate.push({key: 'coveoAccessToken', value: accessToken}); 2
  }

  let updatedResult = cartResult;
  if (attributesToUpdate.length > 0) {
    try {
      updatedResult = await cartHandler.updateAttributes(attributesToUpdate); 3
    } catch (error) {
      console.warn('Failed to set Coveo attributes:', error);
    }
  }

  return updatedResult;
}
1 Use the ServerSideNavigatorContextProvider to obtain the clientId for the current session or visitor. For more details on how the ServerSideNavigatorContextProvider works and its implementation, see Server-side and client navigation context providers.
2 Add the attributes to the list of attributes to update if they’re not already present.
3 Update the cart attributes using the updateAttributes method from the Cart handler.

Update the cart attributes

Use your helper function when the cart is retrieved and modified.

  • Loader: on page load to ensure attributes are set when the cart is retrieved.

    export async function loader({request, context}: LoaderFunctionArgs) {
      const {cart} = context;
    
      // ...
    
      const cartData  = await cart.get(); 1
      if (cartData) {
        await setCoveoConfigAttributes(context, request, {cart: cartData}); 2
      }
    
      // ...
    }
    1 Fetches the current cart data from Shopify when the page loads or is refreshed.
    2 Add the required Coveo cart attributes if they’re missing, so purchase events can be tracked correctly.
  • Action: after any calls that would modify the cart. (for example, adding or removing items)

    export async function action({request, context}: ActionFunctionArgs) {
      const {cart} = context;
    
      // ...
    
      result = await setCoveoConfigAttributes(context, request, result); 1
    
      const {cart: cartResult, errors, warnings} = result;
    
        return json(
        {
          cart: cartResult,
          errors,
          warnings,
          analytics: {
            cartId,
          },
        },
        {status, headers},
      );
    }
    1 Add the required Coveo cart attributes after any cart mutation. This is essential for accurate purchase event tracking by the Coveo app web pixel.

By setting the, coveoCoveoClientId, coveoTrackingId, coveoOrganizationId and coveoAccessToken attributes on the cart, the Coveo app web pixel can automatically log purchase events when a transaction is completed. This integration streamlines event tracking and analytics for your Shopify with Headless and Hydrogen commerce solution.