Concepts / Building Search UI / Plug analytics
Feb. 20, 2019

Plug analytics

Using Algolia Insights with InstantSearch.js

Loading and initializing the library

The search-insights library can either be bundled with your application or loaded via the jsDelivr CDN. The snippet below should be added to all pages for which you wish to track search analytics.

1
2
3
4
5
6
7
8
9
<script>
  !function(e,a,t,n,s,i,c){e.AlgoliaAnalyticsObject=s,e.aa=e.aa||function(){(e.aa.queue=e.aa.queue||[]).push(arguments)},i=a.createElement(t),c=a.getElementsByTagName(t)[0],i.async=1,i.src="https://cdn.jsdelivr.net/npm/search-insights@1.0.1",c.parentNode.insertBefore(i,c)}(window,document,"script",0,"aa");

  // Initialize library
  aa('init', {
    appId: 'APPLICATION_ID',
    apiKey: 'SEARCH_API_KEY'
  });
</script>

We recommend using jsDelivr only for prototyping, not for production applications. Whenever possible, you should host your assets yourself or use a premium CDN service. jsDelivr is a free service and isn’t operated by Algolia, so we won’t be able to provide support if it fails.

Enabling the queryID response

To enable the queryID response from the search API, InstantSearch.js lets you set custom search parameters when you instantiate the search. The clickAnalytics parameter must be set to true.

1
2
3
4
5
6
7
const search = instantsearch({
  searchClient,
  indexName: 'INDEX_NAME',
  searchParameters: {
    clickAnalytics: true,
  },
});

Reporting click and conversion events

The time you want to trigger a click event depends on your implementation and business logic. A good framework would be to send a click event once a user clicks on something that indicates an action inside the hit. For example:

  • Click: when a user clicks on a result
  • Conversion: when a user adds an item to a cart

This example covers how to obtain the objectID and position for reporting. We advise that you add the data-object-id and data-position data attributes in your hit template to simplify the implementation.

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
search.addWidget(
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      item(hit) {
        return `
          <article>
            <h3>
              ${instantsearch.highlight({
                attribute: 'name',
                hit,
              })}
            </h3>

            <button
              class="button-click"
              data-query-id="${hit._queryID}"
              data-object-id="${hit.objectID}"
              data-position="${hit._hitPosition}"
            >
              Click event
            </button>

            <button
              class="button-conversion"
              data-query-id="${hit._queryID}"
              data-object-id="${hit.objectID}"
            >
              Conversion event
            </button>
          <article>
        `;
      },
    },
    transformItems(items) {
      const result = search.helper.lastResults;
      const offset = result.hitsPerPage * result.page;

      return items.map((item, position) => ({
        ...item,
        _queryID: result.queryID,
        _hitPosition: offset + position + 1,
      }));
    },
  })
);

After you’ve specified the DOM to generate, you need to create the handlers to trigger the action. This can be done by specifying a global click event handler and checking if the clicked element matches the action item.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
document.addEventListener('click', event => {
  if (event.target.matches('.button-click')) {
    window.aa('clickedObjectIDsAfterSearch', {
      eventName: 'CLICK_HIT',
      index: 'INDEX_NAME',
      queryID: event.target.getAttribute('data-query-id'),
      objectIDs: [event.target.getAttribute('data-object-id')],
      // We call `parseInt()` because `getAttribute()` returns a string
      positions: [parseInt(event.target.getAttribute('data-position'), 10)],
    });
  } else if (event.target.matches('.button-convert')) {
    window.aa('convertedObjectIDsAfterSearch', {
      eventName: 'CONVERT_HIT',
      index: 'INDEX_NAME',
      queryID: event.target.getAttribute('data-query-id'),
      objectIDs: [event.target.getAttribute('data-object-id')],
    });
  }
});

Advanced: sending click events on right click

Sometimes - and it is often the case in e-commerce - users right-click and open the product in a new tab. To be able to report that event as a click event, you have to bind a global contextmenu event listener similar to the click event.

1
2
3
4
5
6
7
8
9
10
11
12
document.addEventListener('contextmenu', event => {
  if (event.target.matches('.button-click')) {
    window.aa('clickedObjectIDsAfterSearch', {
      eventName: 'ADD_TO_CART',
      index: 'INDEX_NAME',
      queryID: event.target.getAttribute('data-query-id'),
      objectIDs: [event.target.getAttribute('data-object-id')],
      // We call `parseInt()` because `getAttribute()` returns a string
      positions: [parseInt(event.target.getAttribute('data-position'), 10)],
    });
  }
});

Google Analytics with InstantSearch.js

Even though Algolia provides analytics that are tailored to your search implementation, you might want to integrate your search into your existing analytics tools. InstantSearch.js provides a widget called analytics to do that.

This widget is platform agnostic and can be used either with Google Analytics or any solution that provides a REST endpoint. The example below uses Google Analytics.

Integrating with Google Analytics requires 2 steps:

Once the Google Analytics library is installed on your website, you can use the analytics widget. The logic is defined in the pushFunction option.

1
2
3
4
5
6
7
8
search.addWidget(
  instantsearch.widgets.analytics({
    pushFunction(formattedParameters, state, results) {
      window.ga('set', 'page', window.location.pathname + window.location.search);
      window.ga('send', 'pageView');
    },
  })
);

Did you find this page helpful?