Was this page helpful?

Experience SDK

Important: This Experience SDK is for Contentful Analytics use. If you are looking for the Experiences SDK for Studio, see the Studio documentation.

Table of contents

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 @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:

Server-side SDK

The Node.js SDK (@ninetailed/experience.js-node) is provided for integrating Contentful Analytics in server or edge runtimes.

Install the SDK

Dependency installation

npm install @ninetailed/experience.js-react
# OR
yarn add @ninetailed/experience.js-react
npm install @ninetailed/experience.js-next
# OR
yarn add @ninetailed/experience.js-next
npm install @ninetailed/experience.js-gatsby
# OR
yarn add @ninetailed/experience.js-gatsby
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.

Important: Your API Key can be found in the Ninetailed Dashboard. The API key is the same as the organization ID.

Ninetailed Content Sources page

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

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>
  );   
}

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.

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>
  );   
}

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.

... // 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
    }
  }
]
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 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.

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

page events

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:

page({'category': 'YOUR_BLOG_CATEGORY'})
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 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

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".

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 for track events for this purpose.

identify events

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.

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.

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.

NOTE: 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. 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.
  • 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.

Access event methods

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>.

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>
  );
}

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

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.

The <EntryAnalytics /> component

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

NOTE: 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

// 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}
    />);
};