> This page is for Analytics.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://contentful-staging.ferndocs.com/developers/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful-staging.ferndocs.com/developers/docs/_mcp/server.

# Experience SDK

> Integrate Contentful Analytics within your Javascript SDKs.

> **Info**
>
> This Experience SDK is for Contentful Analytics use. If you are looking for the **Experiences SDK for Studio**, see the [Studio documentation](/experiences/overview).

## Overview

We provide SDKs and plugins for modern web frameworks to use Contentful Analytics. Our SDKs include first-class TypeScript support with exported type definitions for a smooth development experience in TypeScript projects.

The SDKs provide abstractions that communicate with the APIs that power Contentful Analytics by:

* Creating `page`, `track`, and `identify` events and sending them to the Experience API
* Providing built-in capabilities to handle errors, retries and queuing
* Enabling caching of the profile client-side via `localStorage`.

## Composed JavaScript SDKs

Our SDKs have three levels of abstraction. At the lowest-level, the Shared SDK `@ninetailed/experience.js-shared` creates an API Client that communicates with the Experience API's endpoints. The data objects, types, and methods it provides are applicable across all SDKs.
The [JavaScript SDK](https://www.npmjs.com/package/@ninetailed/experience.js) `@ninetailed/experience.js` is based on the Shared SDK. It creates an instance that stores and updates a profile in response to events.

### Front-end SDKs

The Shared and JavaScript SDKs can be used to integrate Contentful Analytics with arbitrary front-ends that run JavaScript. For fast integration with popular front-end frameworks, we provide SDKs for:

* [React (@ninetailed/experience.js-react)](https://www.npmjs.com/package/@ninetailed/experience.js-react)
* [Next.js (@ninetailed/experience.js-next)](https://www.npmjs.com/package/@ninetailed/experience.js-next)
* [Gatsby (experience.js-gatsby)](https://www.npmjs.com/package/@ninetailed/experience.js-gatsby).

### Server-side SDK

The [Node.js SDK (@ninetailed/experience.js-node)](https://www.npmjs.com/package/@ninetailed/experience.js-node) is provided for integrating Contentful Analytics in server or edge runtimes.

## Install the SDK

### Dependency installation

#### React

```sh
npm install @ninetailed/experience.js-react
# OR
yarn add @ninetailed/experience.js-react
```

#### Next.js

```sh
npm install @ninetailed/experience.js-next
# OR
yarn add @ninetailed/experience.js-next
```

#### Gatsby

```bash
npm install @ninetailed/experience.js-gatsby
# OR
yarn add @ninetailed/experience.js-gatsby
```

#### JavaScript

```bash
npm install @ninetailed/experience.js
# OR
yarn add @ninetailed/experience.js
```

### Create an instance

At its core, the Experience SDK defines a `Ninetailed` class instance based on your input configuration. That instance then:

* Keeps track of the current profile and provides a hook into profile changes.
* Exposes declarative methods to interact with the Experience API.
* Provides extensibility through plugins.

When working with the React, Next.js or Gatsby SDK, an instance will be created and made available to your application globally through a React context provider.

> **Info**
>
> Your API key is the **Client ID** field value displayed under the "SDK Keys" section on the **Optimization** tab.
>
> ![Client ID](/developers/docs/_fern-img/d9c1e92409fed1e1c97c28fd1fc9f7c5e1fcfcdc19c22cc05eba86b166a94a5f.webp)

#### React

Add the `<NinetailedProvider>` component to the top level of the application, so that the profile can be consumed from any child component.

```jsx
import React from 'react';
import MyAppCode from '../MyAppCode.jsx';
import { NinetailedProvider } from '@ninetailed/experience.js-react';

export const App = () => {
  return (
    <div id="my-app">
      <NinetailedProvider 
        // REQUIRED. An API key uniquely identifying your Ninetailed account.
        clientId="NINETAILED_API_KEY"
        
        // === ALL OF THE FOLLOWING PROPS ARE OPTIONAL ===
        // === DEFAULT VALUES ARE SHOWN ===
        
        // Your Ninetailed environment, typically "main" or "development"
        environment="main"
        
        // Add any plugin instances
        plugins=[]
        
        // Specify an amount of time (ms) that an component must
        // be present in the viewport to register a component view
        componentViewTrackingThreshold={2000}
        
        // Specify a maximum amount of time (ms) to wait for an Experience API response before falling back to baseline content
        requestTimeout={5000}
        
        // Specify a locale to localize profile location information
        locale="en-US"
        
        // Specify an alternative Experience API base URL
        url="https://experience.ninetailed.co"
        
        // Set to true ONLY if using an unindexed CMS
        useSDKEvaluation=true
      >
        <MyAppCode />
      </NinetailedProvider>
    </div>
  );   
}
```

#### Next.js

We recommend adding the `<NinetailedProvider>` component to the top level of the application. This way, the profile can be consumed from any child component.

The Next.js `<NinetailedProvider>` additionally hooks into the Next page router and automatically calls `ninetailed.page()` on every route change. Calling this method again will lead to duplicated events.

```jsx
import { NinetailedProvider } from '@ninetailed/experience.js-next';

export const App = ({component, pageProps}) => {
  return (
    <div id="my-app">
      <NinetailedProvider 
        // REQUIRED. An API key uniquely identifying your Ninetailed account.
        clientId="NINETAILED_API_KEY"
        
        // === ALL OF THE FOLLOWING PROPS ARE OPTIONAL ===
        // === DEFAULT VALUES ARE SHOWN ===
        
        // Your Ninetailed environment, "main" or "development"
        environment="main"
        
        // Add any plugin instances
        plugins=[]
        
        // Specify an amount of time (ms) that an <Experience /> component must
        // be present in the viewport to register a component view
        componentViewTrackingThreshold={2000}
        
        // Specify a maximum amount of time (ms) to wait for an Experience API response before falling back to baseline content
        requestTimeout={5000}
        
        // Specify a locale to localize profile location information
        locale="en-US"
        
        // Specify an alternative Experience API base URL
        url="https://experience.ninetailed.co"
        
        // Set to true ONLY if using an unindexed CMS
        useSDKEvaluation=true
      >
        <Component {...pageProps} />
      </NinetailedProvider>
    </div>
  );   
}
```

#### Gatsby

Add the plugin to your plugins array in your `gatsby-config.js|ts` file. When using the Gatsby JS plugin you don't have to configure the `NinetailedProvider` as described for the React and Next.js SDKs.

The plugin automatically calls `ninetailed.page()` on every route change. Calling this method again will lead to duplicated events.

```javascript
... // Your Other Gatsby configuration
plugins: [
  ... // Your existing Gatsby plugins
  {
    resolve: `@ninetailed/experience.js-gatsby`,
    options: {
      // REQUIRED. An API key uniquely identifying your Ninetailed account.
      clientId: "NINETAILED_API_KEY", 
        
      // === ALL OF FOLLOWING PROPERTIES ARE OPTIONAL ===
      // === DEFAULT VALUES ARE SHOWN ===
        
      // Your Ninetailed environment, "main" or "development"
      environment: "main",

      // Add any plugin instances
      ninetailedPlugins: [],
      
      // Specify an amount of time (ms) that a component must
      // be present in the viewport to register a component view
      componentViewTrackingThreshold: 2000,
      
      // Specify a maximum amount of time (ms) to wait for an
      // Experience API response before falling back to baseline content
      requestTimeout: 5000,
      
      // Specify a locale to localize profile location information
      locale: "en-US",
        
      // Specify an alternative Experience API base URL
      url: "https://experience.ninetailed.co",
      
      // Set to true ONLY if using an unindexed CMS
      useSDKEvaluation: true
    }
  }
]
```

#### JavaScript

```javascript
import { Ninetailed } from '@ninetailed/experience.js';

export const ninetailed = new Ninetailed(
   { 
        // REQUIRED. An API key uniquely identifying your Ninetailed account.
        clientId: "NINETAILED_API_KEY", 
        // OPTIONAL. Your Ninetailed environment, "main" or "development"
        environment: "main" // Default
    }, 
    // === THE FOLLOWING ARGUMENT AND ALL OF ITS PROPERTIES ARE OPTIONAL ===
    // === DEFAULT VALUES ARE SHOWN ===
    { 
        // Add any plugin instances
        plugins: [],
        
        // Specify an amount of time (ms) that a component must
        // be present in the viewport to register a component view
        componentViewTrackingThreshold: 2000,
        
        // Specify a maximum amount of time (ms) to wait for an Experience API response before falling back to baseline content
        requestTimeout: 5000,
        
        // Specify a locale to localize profile location information
        locale: "en-US",
        
        // Specify an alternative Experience API base URL
        url: "https://experience.ninetailed.co"
        
        // Set to true ONLY if using an unindexed CMS
        useSDKEvaluation: true
    }
);
```

### Browser instance access

Installing the Experience SDK exposes several properties and methods on a `window.ninetailed` instance for testing and debugging.

| Properties and methods                | Description                                                                  |
| ------------------------------------- | ---------------------------------------------------------------------------- |
| `page()`, `track()`, and `identify()` | The core tracking methods.                                                   |
| `debug(arg: boolean)`                 | Turn on debug mode, which will output additional information to the console. |
| `plugins`                             | Access the methods of any plugins attached to the instance.                  |
| `profile`                             | Output the current profile state.                                            |
| `reset()`                             | Discard the current profile.                                                 |

For a full list of instance properties and methods, see the [JavaScript SDK](/personalization/the-ninetailed-instance) documentation.

## Send events

Contentful Analytics uses profiles to identify users. A profile is created and updated by sending three types of events about that profile to the Experience API: `page`, `track`, and `identify`. We recommend using the methods provided by any of the Experience SDKs for sending events.

> **Info**
>
> Interacting with the Experience API endpoints directly is possible and necessary for integration with applications that do not support JavaScript.

### page events

```typescript
type Page = (properties?: Object) => Promise<void>;
```

A `page` event represents a user viewing a page. The SDKs provide a context object that captures important parameters of the page, including the `referrer`, `url`, `path`, and `user-agent`, which are sent to the Experience API.

Typical usecases will call the `page` method without arguments. However, you may optionally specify any properties you want to send alongside the page view event. This can be useful for creating Audiences - for example, if the category of blog posts is not contained in the URL, yet you'd like to create an Audience that has viewed blog posts of a certain category a certain number of times. In this case, you can pass the category along in the argument:

```javascript
page({'category': 'YOUR_BLOG_CATEGORY'})
```

> **Info**
>
> **NOTES**:
>
> * The Gatsby SDK automatically sends a `page` event on every route change.
> * The Next.js SDK also sends `page` events automatically on page changes, but only if you're using Page Router. If you're using App Router, you have to set up the logic for sending the event. [Here is an example](https://github.com/ninetailed-inc/ninetailed-examples/blob/main/marketing-contentful-next-app/app/layout.tsx#L43) where the event is sent in the `TrackPages` component for App Router.
> * If your application uses the React, JavaScript or Node SDK, you have to manually implement a `page` call on every route change.

### track events

```typescript
type Track = (event: string, properties?: Object) => Promise<void>;
```

A `track` event logs user actions, like `signup` or `registered_for_newsletter`.
It can be arbitrarily named and accepts a `properties` argument that enriches the event with additional information.
For example, you might include the SKU and quantity of items on a `track` event called `"add_to_cart"`.

```javascript
track('add_to_cart', {sku: '9T41L', quantity: 1})
```

Contentful Analytics uses `track` events to calculate conversions and the importance measure.
You have to configure a [metric](https://www.contentful.com/help/personalization/metrics/set-up-metrics/) for `track` events for this purpose.

### identify events

```typescript
type Identify = (uid: string, traits?: Traits) => Promise<void>;
```

An `identify` event allows adding custom information, called traits, to a profile.
Traits are arbitrary attributes in JSON form. They allow you to customize the data that segments profiles into audiences.
For example, a user's responses from a sign up form, a list of recently viewed products, or data from any upstream source, like a CRM or CDP, may be traits.

```javascript
identify('', { favoriteColor: "red" })
```

`identify` events allow setting a custom alias for a profile. That way, IDs stored within, for example, an analytics system, customer data platform, or e-commerce platform can be used to identify that profile.

```javascript
identify('customer12345')
```

An aliasing profile is reinstating on a different device or browser by calling `identify` again, which merges the latest activity of the current profile with the profile at that alias.
To reidentify users across sessions, we recommend calling `identify` after each successful authentication.

> **Info**
>
> The flexibility of `identify` is powerful but should be used with caution. In particular, you should consider what privacy legislation your application needs to abide by, and whether that affects what data should not be stored as traits. For example, you probably would not want to store contact information, such as email addresses or phone numbers as traits, or use them as aliases.

### component events

A `component` event records every time a user views a Contentful content entry on a website, as well as how long they viewed it for. It includes contextual details such as the entry ID, timestamp, device type and environment. `component` events are automatically sent by the SDK.

Component events:

* Track the total number of views for each component.
* Track the amount of time that each component was viewed for.
* Attribute conversions to specific components.
* Analyze the impact of content at the component level.
* Support Contentful Personalization by linking views to specific experiences or variants.

### component click events

A `component_click` event records every time a user clicks an interactive element inside of a Contentful content entry on a website. It includes contextual details such as the entry ID, timestamp, device type and environment. `component_click` events are enabled by adding the `trackClicks` prop to an `<Experience />` component.

Component click events:

* Track the total number of times each component was clicked.
* Analyze the impact of content at the component level.

### component hover events

A `component_hover` event records every time a desktop user hovers an element inside of a Contentful content entry on a website, as well as how long they hovered it for. It includes contextual details such as the entry ID, timestamp, device type and environment. `component_hover` events are enabled by adding the `trackHovers` prop to an `<Experience />` component.

Component hover events:

* Track the total number of times each component was hovered.
* Analyze the impact of content at the component level.

### Access event methods

#### React, Next.js, Gatsby

The `useNinetailed` hook provides the tracking methods `page`, `track`, and `identify`. These will call the Experience API using the configuration parameters supplied to a `<NinetailedProvider>`.

```jsx
import React from 'react';

import { useNinetailed } from '@ninetailed/experience.js-react';
// or import { useNinetailed } from '@ninetailed/experience.js-next';
// or import { useNinetailed } from '@ninetailed/experience.js-gatsby';

export const myComponent = () => {
  const { page, track, identify } = useNinetailed();
  
  page();
  identify('anAlias', {someTrait: "value"});
    
  return (
    <button 
      type="button" 
      onClick={() => { track('add_to_cart'); }}
    >
      Add to Cart
    </button>
  );
}
```

#### Javascript

The `page`, `track`, and `identify` methods are available directly on a Ninetailed class instance.

```javascript
import { Ninetailed } from '@ninetailed/experience.js';

const ninetailed = new Ninetailed({ clientId: "NINETAILED_API_KEY"})

ninetailed.page();
ninetailed.track('myEvent')
ninetailed.identify('alias', {traitName: "traitValue"})
```

## Render Analytics Entries

When using one of the React SDKs, Contentful entries must be rendered as children of an `<EntryAnalytics />` component, or an `<Experience />` component for Contentful Analytics to work correctly.

* Render entries as children of an `<EntryAnalytics />` component if you use Contentful Analytics as a standalone product.
* Render entries as children of an `<Experience />` component if you use Contentful Analytics **and** Contentful Personalization. This will require additional setup work as described in the [Personalization Experience SDK documentation](/personalization/experience-sdk#render-experiences).

### The `<EntryAnalytics />` component

The React-based SDKs provide an `<EntryAnalytics />` component for rendering Contentful Analytics entries.

> **Info**
>
> This component is a part of the Experience React SDK, introduced in version `7.17.6`.

The `<EntryAnalytics>` component functions wraps your existing React component. It automatically detects the properties needed from the wrapped component.

| Prop         | Required | Description                                                                                                                                          |
| :----------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{...props}` | Yes      | All props the `component` prop requires to render the entry.                                                                                         |
| `id`         | Yes      | The Contentful entry ID of the entry.                                                                                                                |
| `component`  | Yes      | The React component that your entry will use to render. This can either be a regular React component, or a component that uses React's `forwardRef`. |

#### Example use

```tsx
// or '@ninetailed/experience.js-next', '@ninetailed/experience.js-gatsby'
import { EntryAnalytics } from '@ninetailed/experience.js-react';

// This function is assumed to return a single entry and all its supporting data.
import { getCmsEntry } from '../api/yourEntryGetter'
import { YourComponent } from './YourComponent'

export const YourAnalytics = (contentfulEntry) => {
  const entry = getCmsEntry(contentfulEntry);

  return (
    <EntryAnalytics
      {...entry}
      id={entry.sys.id}
      component={YourComponent}
    />);
};
```