> For the complete documentation index, see [llms.txt](https://fredhopper.gitbook.io/product-discovery/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fredhopper.gitbook.io/product-discovery/tracking-and-sending-events/implementation-guide/sdk.md).

# SDK

Guide to using the SDK for FHR and XO tracking: install via CDN or npm, track client-side interactions, and customize event handling and data integration.

The SDK is a JavaScript library. It can be used on both the client-side and on the server-side. The SDK supports tracking features for FHR and XO systems, enabling a wide range of use cases.

We recommend SDK to implement detailed, real-time tracking that integrates smoothly with your website's flow and infrastructure, while offering customization for user behavior, event handling, and data integration.

The SDK is especially suited for:

* Client-side tracking
* Tracking specific user interactions with a high level of control and flexibility

## Installation

{% hint style="info" %}
The `xo` library is used for both FHR and XO.
{% endhint %}

You can install the tracker using either **CDN** or **npm** methods:

* For browser-based implementations, use the client from our [CDN](#cdn-installation).
* For more advanced use cases involving a bundler and server-side tracking, use the[ npm package](#npm-installation).

### CDN installation

To make SDK available, inject the following script via your TMS[^1] or simply embedd it on your platform:

```html
<script type="text/javascript">
!function(att,raq,t){
    var version = "2";
    var supportOldBrowsers = false;
    att[raq]=att[raq]||[];var n=["init","send","setUser","addUserIdentity","setUserIdentities","addUserSegment","setUserSegments","addUserTrait","setUserTraits","clearUser","getUserClusters"];if(!att.xo){att.xo={activity:{},init:function(e){att[raq].push(["init",e.activity])}};for(var r=0;r<n.length;r++)att.xo.activity[n[r]]=function(e){return function(r,s,a){att[raq].push([n[e],r,s,a])}}(r)}var s=document.createElement("script");s.type="text/javascript",s.async=!0,s.src=t+version+".min.js",(att.document.documentMode||supportOldBrowsers)&&(s.src=t+version+".compat.min.js");var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(s,a);
}(window,"_attraqt","https://cdn.attraqt.io/xo.all-");
</script>
```

Inject this snippet as early as possible - preferably in the **header**. We have purposely kept the client lightweight to ensure it does not slow down your page.

{% hint style="info" %}
To avoid missing any events, start sending events even before the client is fully loaded. This is enabled by the built-in queuing system.
{% endhint %}

#### CDN advanced options

The client is designed to work on all recent browsers. If you require support for legacy browsers, set the `supportOldBrowsers` option to `true`.

```html
<script type="text/javascript">
!function(att,raq,t){
    var version = "2";
    var supportOldBrowsers = true;
    att[raq]=att[raq]||[];var n=["init","send","setUser","addUserIdentity","setUserIdentities","addUserSegment","setUserSegments","addUserTrait","setUserTraits","clearUser","getUserClusters"];if(!att.xo){att.xo={activity:{},init:function(e){att[raq].push(["init",e.activity])}};for(var r=0;r<n.length;r++)att.xo.activity[n[r]]=function(e){return function(r,s,a){att[raq].push([n[e],r,s,a])}}(r)}var s=document.createElement("script");s.type="text/javascript",s.async=!0,s.src=t+version+".min.js",(att.document.documentMode||supportOldBrowsers)&&(s.src=t+version+".compat.min.js");var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(s,a);
}(window,"_attraqt","https://cdn.attraqt.io/xo.all-");
</script>
```

This option loads a polyfilled version of our library, which increases its weight.

The version can either be a major version, which will allow you to benefit from all the backward compatible updates automatically, or an exact one (x.x.x). You can find a list of all available version [here](https://www.npmjs.com/package/@attraqt/xo-js).

### NPM installation

To install the SDK via npm, add the `xo-js` client to your npm dependencies:

```
npm install --save @attraqt/xo-js
```

Our package is written in TypeScript and natively supports it.

{% tabs %}
{% tab title="Typescript" %}

```typescript
import * as xo from '@attraqt/xo-js';
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const xo = require('@attraqt/xo-js');
```

{% endtab %}
{% endtabs %}

## Initialization

Once the SDK is installed, initialize it to start tracking user activities:

1. Call the `init` function to set up the tracker with your unique `trackerKey`.
2. Include other configurations such as `region` and `storage`.

{% hint style="info" %}
To obtain your tracker key(s), reach out to your Customer Support Manager.
{% endhint %}

{% hint style="warning" %}
The `init` function must be called **before** you interact with the SDK to ensure that all necessary configurations are set up, and the SDK is ready to track data. This prevents issues such as missed events, improper data collection, and user identification problems. It is a critical first step in the integration of the SDK, and it should be executed early in your application's lifecycle to ensure accurate and consistent tracking. This can be done in the `<head>` section of your website or at the start of your JavaScript code, ensuring that the SDK is available for tracking from the very beginning.
{% endhint %}

The `init` function is available under the `xo` , `xo.activity` and `xo.search` namespace:

* `xo.init({activity: {activityOptions}, search: {searchOptions}})`
* `xo.activity.init({activityOptions})`
* `xo.search.init({searchOptions})`

{% hint style="warning" %}
`xo.init` and `xo.activity` are both for FHR & XO, `xo.search` is for XO Search customers only
{% endhint %}

The `activityOptions` parameters are:

* `trackerKey` : Your unique trackerKey to enable the tracking functions
* `region` (optional): The region where the activity pipeline is running; currently only **EU** is available, and is enabled by default
* `storage` (optional): Used to define [<mark style="color:blue;">**custom storage**</mark>](#using-custom-storage)

The `searchOptions` parameters are:

* `token`: your unique Search token, available in your Console at [this address](https://console.early-birds.io/#/search/token). The right token that corresponds to the XO tenant needs to be used.
* `region`: the region in which your data is stored. Available regions are listed below, and the default is **EU**.

<table><thead><tr><th width="325">Supported regions</th><th>Code</th></tr></thead><tbody><tr><td><strong>Europe (default)</strong></td><td><strong>EU</strong></td></tr><tr><td>United States</td><td>US</td></tr><tr><td>Australia</td><td>AP2</td></tr></tbody></table>

{% tabs %}
{% tab title="Inline HTML" %}

```html
<script type="text/javascript">
    xo.init({
        activity: {
            trackerKey: 'YOUR TRACKER KEY',
            region: 'YOUR REGION'
        }
    });
</script>
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
xo.init({
    activity: {
        trackerKey: 'YOUR TRACKER KEY',
        region: 'YOUR REGION'
    }
});
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
To prevent possible loss of data, you should always **initialize the client** and **identify the user** before sending activities.
{% endhint %}

## Handling

Once the SDK is initialized, you can interact with it to send and manage tracking events. Below you can find a simple example of how to register a [view action](/product-discovery/tracking-and-sending-events/activities/view.md#views-on-products-pdps-powered-by-fhr) for a product with the ID 123.

Execute the following JavaScript snippet using the SDK, or make the following API call:

```javascript
// First, import the library
const xo = require('@attraqt/xo-js');

// Next, initialize the SDK with your tracker key
xo.init({activity: {trackerKey: '30cbb5fc-375f-4cf2-8efd-ed86d909718e'}});

const myActivity = {
  "action": "view",
  "target": {
    "product": "123"
  },
  "user": {
    "identities": {
      "sessionId": "2ee80450-28ed-11eb-adc1-0242ac120002"
    }
  }
};

// Then, use the send() method of the SDK
xo.activity.send(myActivity);
```

### Activity object <a href="#the-activity" id="the-activity"></a>

* `action` **field**: Represents the action the user performed\
  Example: `"view"` represents a [**view** on a **product**](/product-discovery/tracking-and-sending-events/activities/view.md#views-on-products-pdps-powered-by-fhr)
* `target` **object**: Covers the details of the target of the action (**view**)\
  Example: `{ product: "123" }` specifies a **product** with ID **123**
* `user` **object**: Contains the [**identities**](/product-discovery/tracking-and-sending-events/identities.md);\
  Example: `{ identities: { sessionId: "2ee80450-28ed-11eb-adc1-0242ac120002" } }` specifies the **session** **ID**

{% hint style="info" %}
The above example provides only minimal information. Include additional details in the activity object to enhance the quality of analytics.
{% endhint %}

You can read more on the activity object [here](/product-discovery/tracking-and-sending-events/activities/activity-object.md).

### Identities <a href="#identities" id="identities"></a>

In order to be able to perform analytics on the actions of shoppers, you need to be able to distinguish users of all the events you send. This allows you to link different actions a shopper makes, such as clicks, purchases etc., to better understand their behaviour, and improve their shopping experience. This is where **identities management** comes in.

At least one identity, the **session ID**, is required to send events to the tracking system. You can find more information on managing identities [here](/product-discovery/tracking-and-sending-events/identities/working-with-identities.md#sdk).

### **Response**

If your integration is correctly configured, you will receive a successful **201** response. Any issues with the tracker key, SDK, or endpoint trigger an error message. Should you experience any problems, contact Rezolve AI Professional Services for further assistance.

## Using custom storage

By default, when the SDK library is initialized, it uses default storage mechanisms that depend on the environment in which it is running.

### **Browser environments**

In browser environments, `localStorage` is used to store tracking data by default. This ensures that data persists across browser sessions for the same user. This way tracking data remains accessible even after a page reload or session restart.

### **Node.js environments**

For server-side implementations using Node.js, a **variable** is used instead of `localStorage`. Since Node.js does not have access to `localStorage` (a browser-specific feature), the SDK uses a variable to temporarily hold the tracking data during the session.

However, you may need to use **custom storage** if you need to integrate with an external storage system, or require specific data storage behavior.

To use custom storage, **initialize the SDK** with custom storage. Use the `storage` option as described below:

{% tabs %}
{% tab title="HTML" %}

```html
<script type="text/javascript">
    xo.init({
        activity: {
            trackerKey: 'YOUR TRACKER KEY',
            region: 'YOUR REGION',
            storage: myCustomStorage
        }
    });
</script>
```

{% endtab %}

{% tab title="NodeJS" %}

```javascript
xo.init({
    activity: {
        trackerKey: 'YOUR TRACKER KEY',
        region: 'YOUR REGION',
        storage: myCustomStorage
    }
});
```

{% endtab %}
{% endtabs %}

The `storage`parameter takes a custom storage object with the same methods as the `localStorage` API. See [localStorage documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) for the four methods:

| Method                | description                                     |
| --------------------- | ----------------------------------------------- |
| `setItem(key, value)` | The `value` to be stored and its `key`          |
| `getItem(key)`        | Return the `value` for given `key` from storage |
| `removeItem(key)`     | Remove key and value from storage               |
| `clear()`             | Clear storage                                   |

{% hint style="warning" %}
All `key` and `value` parameters must be strings.
{% endhint %}

Once you have succesfully set up the use of custom storage:

* **Store data:** Any data sent through the SDK will be stored using the `setItem()` method.
* **Retrieve data**: When fetching data, the SDK uses the `getItem()` method to retrieve the data.
* **Clear data**: You can use `clear()` to reset all stored data, which might be necessary when a user logs out or a session expires.

[^1]: Tag Management System
