Analytics
Analytics is especially important for the Coveo. The AI Model learns how to give more accurate results based on it. Components shipped by us, already leverage Interactive Results and Interactive Instant Results on click but there is much more.
A lot of events are already supported by the Coveo Headless library, for example, if you send a query request, or select facet, change the sort order and so on. Basically, every interaction with a headless controller will be automatically tracked. However, there are some events that are not supported out of the box, like view product details page, add to cart, remove from cart, etc.
Currently supported events:
- all native headless events
- click on the interactive result (search result)
- click on the interactive instant result (quick search result)
- view product details page
Table of contents
Our module doesn't support each kind of events supported by Coveo yet.
Including coveoua
library
To handle custom events, there is a coveoua library that can be used.
Our composable useCoveoua
bases on the coveoua
library that has to be added to the head
. You can do that by modifying nuxt.config.js
file, and adding inside app.head
object:
// `useCoveoua` hook loads the `coveoua` library automatically. You do not need to include it manually.
Capturing customer events
To reach better personalization you need to attach anonymous identifier to authenticated customer:
// layouts/DefaultLayout.tsx
// Import following
import { CoveoSearch, useCoveoCustomer } from '@sf-modules/coveo'; import { useEffect } from 'react';
export function DefaultLayout({ children, breadcrumbs = [] }: LayoutPropsType): JSX.Element {
// ...
// Add the following
const { buildIdentifier } = useCoveoCustomer(); useEffect(() => { buildIdentifier(customer.data); }, [customer]); // ...
}
You need to perform same operations in different layouts related to Customer's session. In base template, these will be following:
// layouts/CheckoutLayout.tsx
// Import following
import { useCoveoCustomer } from '@sf-modules/coveo'; import { useEffect } from 'react'; import { useCart, useCustomer } from '~/hooks';
export function CheckoutLayout({ children, breadcrumbs = [] }: LayoutPropsType): JSX.Element {
// ...
// Add the following
const customer = useCustomer(); const { buildIdentifier } = useCoveoCustomer(); useEffect(() => { buildIdentifier(customer.data); }, [customer]); // ...
}
// layouts/OrderLayout.tsx
// Import following
import { useEffect } from 'react'; import { useCoveoCustomer } from '@sf-modules/coveo'; import { useCustomer } from '~/hooks';
export function OrderLayout({ children, breadcrumbs = [] }: LayoutPropsType): JSX.Element {
// ...
// Add the following
const customer = useCustomer(); const { buildIdentifier } = useCoveoCustomer(); useEffect(() => { buildIdentifier(customer.data); }, [customer]); // ...
}
Analytics mappers
To facilitate working with Coveoua and our ecosystem, we provide mappers transforming data types to required by analytics CoveouaProduct
type. Thanks to that, you could easily send events using data from different sources like:
Using existing mappers
Using mapGetProductDetailsToCoveouaProduct
mapper that has the following signature:
(source: GetProductDetailsData): CoveouaProduct
import { mapGetProductDetailsToCoveouaProduct, useCoveoua } from '@sf-modules/coveo';
//...
const coveoua = useCoveoua();
const productDetail = useProductDetails({ id, sku });
useEffect(() => {
coveoua.sendViewPDP(productDetail.data!)); // TS Error: Invalid type!
coveoua.sendViewPDP(mapGetProductDetailsToCoveouaProduct(productDetail.data!)); // It works
}, []);
//...
Using mapNormalizedResultToCoveouaProduct
mapper that has the following signature:
(result: NormalizedResult): CoveouaProduct
import { mapNormalizedResultToCoveouaProduct, useCoveoua } from '@sf-modules/coveo';
//...
const coveoua = useCoveoua();
const productCatalog = useCoveoSearchProducts();
// inside some callback
const someProduct = productsCatalog.products[0].result;
coveoua.sendViewPDP(someProduct!)); // TS Error: Invalid type!
coveoua.sendViewPDP(mapNormalizedResultToCoveouaProduct(someProduct!)); // It works
//...
Creating own analytics mapper
What if your data type doens't match any aforementioned mappers? In that case, it is recommended to create own mapper.
It is as simple as creating function, all it has to do is return CoveouaProduct
type.
import { CoveouaProduct } from "@sf-modules/coveo";
interface MyType {
a: number;
b: string;
// ...
}
export function mapMyTypeToCoveouaProduct(result: MyType): CoveouaProduct {
return {
// ...
};
}
Usage:
import { useCoveoua } from "@sf-modules/coveo";
import { mapMyTypeToCoveouaProduct } from "...";
//...
const coveoua = useCoveoua();
// In some function/composable/hook:
const myData: MyType = // ...
coveoua.sendViewPDP(myData!); // TS Error: Invalid type!
coveoua.sendViewPDP(mapMyTypeToCoveouaProduct(myData!)); // It works
//...
Events
Below, we specify every supported custom events with a brief description of how to implement it in your application.
Available events:
View PDP event
This event should be sent when a user views a product details page. It is important for the Coveo AI Model to learn more about the user's behavior. To track this event, you can use the sendViewPDP
method from the useCoveoua
composable.
// pages/product/[slug]/[id].tsx
import { useCoveoua, mapGetProductDetailsToCoveouaProduct } from '@sf-modules/coveo';
import { useEffect } from 'react';
const productDetail = useProductDetails({ id, sku: getQueryParameter(sku) });
const coveoua = useCoveoua();
useEffect(() => {
coveoua.sendViewPDP(mapGetProductDetailsToCoveouaProduct(productDetail.data!));
}, []);
Cart events
This section assumes, you already implemented View PDP event.
There are 3 places where you can modify the cart in our application:
- PDP,
- PLP (Category/Search results),
- Cart view.
We need to trigger events in all of them.
PDP
// components/AddToCartButton/AddToCartButton.tsx
import { useCoveouaCart } from '@sf-modules/coveo';
// ...
const { sendAddToCartEvent } = useCoveouaCart();
// ...
return (
<SfButton
// onClick={() => addToCart.mutate({ quantity })}
onClick={() => {
addToCart.mutate({ quantity });
sendAddToCartEvent({ productId, quantity: quantity || 1, sku: sku as string | undefined });
}}
// ...
// ...
PLP
It's covered by us changes made in previous step.
Cart view
// components/ui/CartProductCardWrapper/CartProductCardWrapper.tsx
import { useCoveouaCart } from '@sf-modules/coveo';
// ...
// const { id } = props;
const { id, value, sku } = props;
const { sendUpdateCartEvent, sendRemoveFromCartEvent } = useCoveouaCart();
return (
<CartProductCard
{...props}
onUpdate={(quantity) => {
updateCartQuantity.mutate({ quantity });
sendUpdateCartEvent({ productId: id, oldQuantity: value, quantity, sku }); // +
removeWantedQuantities(id);
}}
onRemove={() => {
removeCartLineItem.mutate();
sendRemoveFromCartEvent({ productId: id, quantity: value, sku }); // +
removeWantedQuantities(id);
}}
// ...
Purchase event
The sendPurchase
method should be called just after user placed an order.
import { useCoveoua } from '@sf-modules/coveo';
const coveoua = useCoveoua();
const onPlacedOrderSuccesfully = (order: SfOrder) => {
coveoua.sendPurchase(order!);
};