Step 7 - Usage Analytics

Coveo Usage Analytics (Coveo UA) is a very important part of any Coveo implementation. Without it, a large portion of the Coveo technology stack cannot function properly.

For instance, the Coveo™ Machine Learning (Coveo ML) service will not be able to work correctly if it cannot access the usage analytics data about your search page (see Coveo Machine Learning).

In this step of the tutorial, you will learn more about the Analytics component and its options. You will also learn how to log analytics events programmatically and modify standard analytics event.

  • For more detailed information on Coveo UA, see Coveo Cloud Usage Analytics and Usage Analytics Concepts.

  • If you significantly modified the ./bin/index.html page in previous steps of this tutorial, you can undo these changes by rebuilding the project. To do so, run the following command line from the top of the tutorial project folder:

npm run build

The Analytics Component

In order to allow your search page to log usage analytics events, you need to insert an Analytics component in your search interface as shown in the following code excerpt:

<body id="search" class="CoveoSearchInterface">
  <!-- ... -->
  <div class="CoveoAnalytics"></div>
  <!-- ... -->
</body>

If your Coveo Cloud organization is in the HIPAA environment, set the endpoint option of your Analytics component to https://usageanalyticshipaa.cloud.coveo.com.

<div class="CoveoAnalytics" data-endpoint="https://usageanalyticshipaa.cloud.coveo.com"></div>

The Analytics component can be inserted anywhere inside the search interface. It does not provide any visual aspect to your search page. Thus, moving it around will have no impact on the rendering of your search interface.

After it has been added, the Analytics component will take care of logging all search and click events triggered by basic components.

It is important to note that the Analytics component does not decide which event data or metadata needs to be logged. Each component will individually do an explicit call to the Analytics component to signal its need to log an event.

About the searchHub Option

The searchHub option is a very important parameter which is used to determine from what page the analytics events originated.

This parameter is essential to many concepts, such as the query pipeline (see What Is a Query Pipeline?).

There are two ways to specify the searchHub:

  • Client side, by setting the data-search-hub option on the CoveoAnalytics component in the markup.

    This means the property is not “enforced”, but rather set client side with JavaScript code. You can still use the property to create conditions in query pipelines, but you should not use it for features that require the searchHub to be set securely (such as providing query suggestions based on the searchHub).

  • Enforced by the search token (see Search Token Authentication). This is more complicated to setup, but is much more secure. You would implement it the same way you would implement authentication (see Step 5 - Create Your Own Search Endpoint With Authentication - API Key and Search Tokens).

Whenever possible, you should use a searchHub enforced by the search token.

In some scenarios, for example when inside the Coveo for Salesforce application, the Analytics component is properly configured out of the box with a valid searchHub enforced in the token.

You should refer to your specific Coveo product documentation for more specific information.

Troubleshooting Analytics Requests

The following steps detail the requests and responses of a very basic search event when the Analytics component present in a search page.

You can actively follow these steps by inspecting the requests and responses from your web browser.

  1. Make sure there is an Analytics component in your page. It can be placed anywhere inside the search interface.

  2. Type something in the search box, then send the request.

  3. You should see that your browser sends an OPTIONS request to https://usageanalytics.coveo.com.

    This is called a CORS preflight request (see HTTP access control (CORS)).

    Very simply speaking, the browser is making sure that the backend service supports CORS correctly.

  4. You should then see that your browser sends a POST request to https://usageanalytics.coveo.com.

    Here is the important information you should look for in that request:

    1. Authorization header

      This will normally use the same search token or API key that you used to perform the query, unless you specified a different one in the Analytics component.

    2. Visitor query string parameter

      This is an ID that the UI retrieves from your cookies to track a single visit.

      The first time someone visits a Coveo search page in which the Analytics component is enabled, the ID of this visitor will be sent from Coveo UA and stored in your cookie.

      Each event belonging to the same visit will send the same visitor ID.

    3. The request payload

      This is the body of the request. It is different for each event type. Feel free to investigate the data that the framework sends to Coveo UA.

      The actionType and actionCauseparameters specify which component triggered the event.

      The customData parameter is a simple key-value pair which can be used to create customized dashboards and reports in Coveo UA.

      The originLevel1, originLevel2, and originLevel3 parameters should specify where the event was triggered from.

      originLevel1should be a general name for your search interface (e.g., the location of the search page or a string that describes the purpose of the page). If not set, it will fallback to "default".

      originLevel2 will try to match the current Tab component, if available. If not set, it will fallback to an empty string.

      originLevel3 is set to the document.referrer value.

  5. You should then see a response from https://usageanalytics.coveo.com.

    1. If the request was successful, you should see a 200 OK response with the content being a JSON containing the visitor ID and query ID.

    2. If the request was not successful, you should inspect the response content. It will normally be a detailed response describing what the problem is. In most cases, this will be a privilege related error. Concretely, this means that if you used an API key to log a search event, you need to make sure that this API key has the privilege to push analytics data (i.e., the Push access level on the Analytics data domain) (see Privilege Management and Analytics Data Domain).

Logging Search Events Programmatically

All out of the box components take care of logging their own events in Coveo UA. However, it is important that your implementation takes care of logging search events correctly, since you can create your own components and execute queries using JavaScript code (see Step 2 - Interacting With the Search Interface and Component Instances). Logging search events programmatically can be done with the logSearchEvent function.

Consider the following code:

<head>
  <script class="coveo-script" src="https://static.cloud.coveo.com/searchui/v2.5395/js/CoveoJsSearch.Lazy.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", () => {
      Coveo.SearchEndpoint.configureSampleEndpointV2();
      let root = Coveo.$$(document).find("#search");
      Coveo.init(root);
      Coveo.executeQuery(root);
  })
  </script>
</head>
<body id="search" class="CoveoSearchInterface" data-auto-trigger-query="false">
  <div class="CoveoAnalytics"></div>
</body>

The script would produce a warning such as:

This is because a search was triggered without any related search event while the Analytics component was active on the page.

To log a search event correctly, you would need to modify the script like this:

var eventCause = { name: "searchEventName", type: "searchEventType" };
var metadata = { key1: "value1", key2: "value2" };
Coveo.logSearchEvent(root, eventCause, metadata);
Coveo.executeQuery(root);

Q: Is it necessary to make the logSearchEvent call before the executeQuery call?

A: Yes, because it allows the Analytics component to queue the search event and wait for the query to successfully complete before sending the event.

If you were to only call logSearchEvent without any query, you would not see the search event being sent from the browser.

Q: What is the customEventCause parameter ?

A: This parameter accepts a JSON with the following two properties: name and type.

Both of these properties can be set to any arbitrary string value. However, you should respect the following guidelines:

  • The name property should uniquely identify the precise action that caused the search event to be triggered.

  • The type property should describe the general category of the event. This value can be used by more than one event or component.

The basic Searchbox component can log the following search events:

  • The user “submits” the query by pressing Enter: {name: "searchboxSubmit", type: "search box"}
  • The user “clears” the query by pressing the clear button in the Searchbox component: {name: "searchboxClear", type: "search box"}
  • The search-as-you-type feature is used to trigger queries: {name: "searchboxAsYouType", type: "search box"}

It is not useful to memorize the individual name and type values logged by each out of the box component. However, it is important to understand that the name value should uniquely identify the action itself whereas the type value should be a general concept for a given component.

If you were to implement a calendar component which would trigger queries, you could log search events with customEventCause parameters such as these:

  • The user clicks on a day in the calendar: {name: "selectDay", type: "calendar"}
  • The user clicks on the next month button: {name: "nextMonth", type: "calendar"}

Q: What is the metaData parameter?

A: This parameter can be used to send any arbitrary data to the Coveo Analytics service to create custom dimensions (see Adding and Managing Dimensions on Custom Data).

The metaData parameter needs to be a key-value pair, with the value being a string containing no more than 255 characters.

This parameter is optional. If you do not wish to log any metadata, you can simply pass an empty JSON: {}.

Logging Click Events Programmatically

Click events can be associated to any action resulting in the end user viewing an item, such as a ResultLink click or a Quickview click.

Logging click events can be done using the logClickEvent function as shown in the following code excerpt:

var eventCause = { name: "clickEventName", type: "clickEventType" };
var metadata = { key1: "value1", key2: "value2" };
var result = getTheResult();
Coveo.logClickEvent(root, eventCause, metadata, result)

Q: How can I get the result?

A: The result can be retrieved in many ways. One way is to use the querySuccess event (see Step 3 - Understanding the Event System).

Most of the time, a function that needs to log a click event will be executed inside the scope of a result template. The result object is always available inside a result template (see Step 6 - Result Templates).

Logging Search-As-You-Type Events Programmatically

Logging search-as-you-type events follows the exact same logic as logging normal search events, with the exception that those types of event are handled with a bit of extra logic.

Search-as-you-type events will wait until one of the following conditions is met before logging the actual event after it has been queued up:

  • Five seconds have passed since the search-as-you-type event was queued up.

    If a new search-as-you-type event is queued up, the countdown is reset. Only the last search-as-you-type event queued up in this manner will be logged.

  • Another search event which is not a search-as-you-type event is queued up.

    For instance, a facet value is selected. In that case, the search-as-you-type event is logged, followed by the standard search event.

This is done to avoid logging multiple partial queries. Only the last “valid” query will be logged.

Search-as-you-type events can be logged programmatically using the logSearchAsYouTypeEvent function as shown in the following code excerpt:

var eventCause = { name: "searchAsYouTypeEventName", type: "searchAsYouTypeEventType" };
var metadata = { key1: "value1", key2: "value2" };
Coveo.logSearchAsYouTypeEvent(root, eventCause, metadata);
Coveo.executeQuery(root);

Logging Custom Events Programmatically

A custom event can be any event that does not trigger a search and does not result in the end user viewing an item.

For example, a Case Deflection form powered by Coveo search could log a custom event when a Cancel or Submit button is pressed.

Custom events can be logged programmatically using the logCustomEvent function as shown in the following code excerpt:

var eventCause = { name: "customEventName", type: "customEventType" };
var metadata = { key1: "value1", key2: "value2" };
Coveo.logCustomEvent(root, eventCause, metadata);

Modifying Standard Analytics Events

Sometimes, it can be useful to tweak and modify the standard usage analytics events logged by the Coveo JavaScript Search Framework.

For example, you could want to add the end-user profile name to all usage analytics events for a given implementation.

You can do so by using adding a changeAnalyticsCustomData event handler as shown in the following code excerpt:

var root = document.body;
Coveo.$$(root).on("changeAnalyticsCustomData", function(e, args) {
// args will be an object containing the following information:
//   type: which can be SearchEvent, CustomEvent, or ClickEvent.
//   metaObject: which will be the metadata object. You can override a value or add a new key-value pair.
//   originLevel1, originLevel2, originLevel3.
// You can set a new value on any of those properties. This will allow you to modify the analytics event data.
  args.originLevel1 = "myOriginLevel1";
  args.metaObject["foo"] = "bar";
})

Binding event handlers was explained in the third step of this tutorial (see Step 3 - Understanding the Event System).

Other Useful Reference Documentation

What’s Next?

You should now proceed to Step 8 - State and QueryStateModel - Interacting With Component State and With the URL.