Analytics
/

Snowplow Analytics

Using the snowplow plugin


Integration with Snowplow Analytics for analytics package.

Click to expand

Installation

Install analytics and @analytics/snowplow packages

npm install analytics
npm install @analytics/snowplow

How to use

The @analytics/snowplow package works in the browser and server-side in Node.js. To use, install the package, include in your project and initialize the plugin with analytics.

Below is an example of how to use the browser plugin.

import Analytics from 'analytics'
import snowplowPlugin from '@analytics/snowplow'

const analytics = Analytics({
  app: 'awesome-app',
  plugins: [
    // Minimal recommended configuration
    snowplowPlugin({
      name: 'snowplow',
      scriptSrc: '//*.cloudfront.net/2.15.0/sp.js',
      collectorUrl: 'collector.mysite.com',
      trackerSettings: {
        appId: 'myApp',
        contexts: {
          webPage: true
        }
      }
    })
  ]
})

/* Track a page view */
// Enable some automatic tracking before page event
analytics.on('initialize:snowplow', ({ instance }) => {
  instance.plugins.snowplow.enableActivityTracking(10, 10)
  instance.plugins.snowplow.enableLinkClickTracking()
})

// Track page
analytics.page()

// or Track page view with additional entities
analytics.page({
  contexts: [
    {
      schema: 'iglu:com.acme/blog_post/jsonschema/1-0-0',
      data: {
        title: 'Re-thinking the structure of event data',
        category: 'Data Insights',
        author: 'Cara Baestlein',
        datePublished: '2020-01-24'
      }
    }
  ]
})

/* Track a custom event */
// Track structured event
analytics.track('playedVideo', {
  category: 'Videos',
  label: 'Fall Campaign',
  value: 42
})

// or Track Self Describing event
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign'
  }
})

// or Track Self Describing event with additional entities
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign',
    videoTimestampInMs: 1104
  },
  contexts: [
    {
      schema: 'iglu:com.acme/product/jsonschema/1-0-0',
      data: {
        id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
        category: 'clothing',
        subCategory: 'socks',
        price: 3.99
      }
    }
  ]
})

// or Track Enchanced Ecommerce event with product context
analytics.track('EnhancedEcommerceProductContext', {
  id: 'P12345',
  name: 'Android Warhol T-Shirt',
  list: 'Search Results',
  brand: 'Google',
  category: 'Apparel/T-Shirts',
  variant: 'Black',
  quantity: 1
})
analytics.track('EnhancedEcommerceAction', {
  action: 'add'
})

/* Identify a visitor */
analytics.identify('user-id-xyz')

After initializing analytics with the snowplowPlugin plugin, data will be sent into Snowplow Analytics whenever analytics.page, analytics.track, or analytics.identify are called.

See additional implementation examples for more details on using in your project.

Platforms Supported

The @analytics/snowplow package works in the browser and server-side in Node.js

Browser usage

The Snowplow Analytics client side browser plugin works with these analytic api methods:

Browser API

import Analytics from 'analytics'
import snowplowPlugin from '@analytics/snowplow'

const analytics = Analytics({
  app: 'awesome-app',
  plugins: [
    // Minimal recommended configuration
    snowplowPlugin({
      name: 'snowplow',
      scriptSrc: '//*.cloudfront.net/2.15.0/sp.js',
      collectorUrl: 'collector.mysite.com',
      trackerSettings: {
        appId: 'myApp',
        contexts: {
          webPage: true
        }
      }
    })
  ]
})

Configuration options for browser

Optiondescription
scriptSrc
required - string
Self-hosted Snowplow sp.js file location
collectorUrl
required - string
The URL to a Snowplow collector
name
optional - string
The name to identify this instance of the tracker, use if using multiple tracker instances ('snowplow' default)
trackerSettings
optional - Object
The arg map to pass to the Snowplow Tracker
trackerSettings.appId
optional - string
The appId to identify this application
trackerSettings.platform
optional - string
Platform of tracking ("web" default)
trackerSettings.cookieDomain
optional - string
Domain to set cookie against
trackerSettings.discoverRootDomain
optional - string
Automatically discover root domain
trackerSettings.cookieName
optional - string
Prefix for cookies ("sp" default)
trackerSettings.cookieSameSite
optional - string
SameSite cookie setting ("None" default)
trackerSettings.cookieSecure
optional - boolean
Secure cookie setting (true default)
trackerSettings.encodeBase64
optional - boolean
Encode JSON objects as Base64 (true default)
trackerSettings.respectDoNotTrack
optional - bolean
Respect do not track (consider analytics-plugin-do-not-track) (false default)
trackerSettings.pageUnloadTimer
optional - number
Timeout in ms to block page navigation until buffer is empty (500 default)
trackerSettings.forceSecureTracker
optional - boolean
Forces requests to be sent https (false default)
trackerSettings.eventMethod
optional - string
Method to send events, GET, POST, Beacon (POST default)
trackerSettings.bufferSize
optional - number
Amount of events to buffer before sending (1 default)
trackerSettings.maxPostBytes
optional - number
Maximum size of POST or Beacon before sending (40000 default)
trackerSettings.crossDomainLinker
optional - string
function to configure which links to add cross domain linking
trackerSettings.cookieLifetime
optional - number
Cookie lifetime (63072000 default)
trackerSettings.stateStorageStrategy
optional - string
Use cookies and/or localstorage ("cookieAndLocalStorage" default)
trackerSettings.maxLocalStorageQueueSize
optional - number
Maximum numbers of events to buffer in localstorage to prevent filling local storage (1000 default)
trackerSettings.resetActivityTrackingOnPageView
optional - boolean
Flag to decide whether to reset page ping timers on virtual page view (true default)
trackerSettings.connectionTimeout
optional - boolean
The timeout, in milliseconds, before GET and POST requests will timeout (5000 default) (Snowplow JS 2.15.0+)
trackerSettings.skippedBrowserFeatures
optional - Array.
Array to skip browser feature collection ([] default) (Snowplow JS 2.15.0+)
trackerSettings.anonymousTracking
optional - Object
Flag to enable anonymous tracking functionality (false default)
trackerSettings.anonymousTracking.withSessionTracking
optional - boolean
Flag to enable whether to continue tracking sessions in anonymous tracking mode (false default)
trackerSettings.contexts
optional - Object
The auto contexts for each event
trackerSettings.contexts.webPage
optional - boolean
The webpage context, containing the page view id. (true default)
trackerSettings.contexts.performanceTiming
optional - boolean
Add performance timing information
trackerSettings.contexts.clientHints
optional - Object
Add Client Hint information (Snowplow JS 2.15.0+)
trackerSettings.contexts.clientHints.includeHighEntropy
optional - boolean
Capture High Entropy Client Hints (Snowplow JS 2.15.0+)
trackerSettings.contexts.gaCookies
optional - boolean
Add gaCookie information
trackerSettings.contexts.geolocation
optional - boolean
Add browser geolocation information
trackerSettings.contexts.optimizelyXSummary
optional - boolean
Add browser geolocation information

Server-side usage

The Snowplow Analytics server-side node.js plugin works with these analytic api methods:

Server-side API

import Analytics from 'analytics'
import snowplowPlugin from '@analytics/snowplow'

const analytics = Analytics({
  app: 'awesome-app',
  plugins: [
    snowplowPlugin({
      name: 'snowplow',
      collectorUrl: 'collector.mysite.com',
      appId: 'myApp'
    })
  ]
})

Configuration options for server-side

Optiondescription
collectorUrl
required - string
The URL to a Snowplow collector
appId
required - string
The appId to identify this application
name
optional - string
The name to identify this instance of the tracker ('snowplow' default)
protocol
optional - string
http or https (https default)
port
optional - string
collector port (80 default)
method
optional - string
The method to send events to collector, POST or GET (POST default)
bufferSize
optional - string
Only send events once n are buffered. Defaults to 1 for GET requests and 10 for POST requests.
maxSockets
optional - string
Node.js agentOptions object to tune performance (6 default)
platform
optional - string
Sets the platform https://bit.ly/302dSQy ('srv' default)
screenResolution
optional - object
Sets device screen resolution if available
screenResolution.width
optional - number
Positive Integer for screen width
screenResolution.height
optional - number
Positive Integer for screen height
viewport
optional - object
Sets device viewport if available
viewport.width
optional - number
Positive Integer for viewport width
viewport.height
optional - number
Positive Integer for viewprt height
colorDepth
optional - number
Positive Integer, in bits per pixel
timezone
optional - string
Set user’s timezone e.g. 'Europe/London'
lang
optional - string
Ser user's lang e.globalThis. 'en'

Additional examples

Below are additional implementation examples.

Server-side ES6
import Analytics from 'analytics'
import snowplowPlugin from '@analytics/snowplow'

const analytics = Analytics({
  app: 'awesome-app',
  plugins: [
    snowplowPlugin({
      name: 'snowplow',
      collectorUrl: 'collector.mysite.com',
      appId: 'myApp'
    })
    // ...other plugins
  ]
})

/* Track a page view */
// Track page
analytics.page()

// or Track page view with additional entities
analytics.page({
  context: [
    {
      schema: 'iglu:com.acme/blog_post/jsonschema/1-0-0',
      data: {
        title: 'Re-thinking the structure of event data',
        url:
          'https://snowplowanalytics.com/blog/2020/01/24/re-thinking-the-structure-of-event-data/',
        category: 'Data Insights',
        author: 'Cara Baestlein',
        datePublished: '2020-01-24'
      }
    }
  ]
})

/* Track a custom event */
// Track structured event
analytics.track('playedVideo', {
  category: 'Videos',
  label: 'Fall Campaign',
  value: 42
})

// or Track Self Describing event
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign'
  }
})

// or Track Self Describing event with additional entities
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign',
    videoTimestampInMs: 1104
  },
  context: [
    {
      schema: 'iglu:com.acme/product/jsonschema/1-0-0',
      data: {
        id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
        category: 'clothing',
        subCategory: 'socks',
        price: 3.99
      }
    }
  ]
})

// or Track Enchanced Ecommerce event with product context
analytics.track('ScreenView', {
  name: 'Product Page',
  id: 'p-123',
  context: [
    {
      schema: 'iglu:com.acme/product/jsonschema/1-0-0',
      data: {
        id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
        category: 'clothing',
        subCategory: 'socks',
        price: 3.99
      }
    }
  ]
})

/* Identify a visitor */
analytics.identify('user-id-xyz', {
  firstName: 'bill',
  lastName: 'murray'
})
Server-side Node.js with common JS

If using node, you will want to import the .default

const analyticsLib = require('analytics').default
const snowplowPlugin = require('@analytics/snowplow').default

const analytics = analyticsLib({
  app: 'my-app-name',
  plugins: [
    snowplowPlugin({
      name: 'snowplow',
      collectorUrl: 'collector.mysite.com',
      appId: 'myApp'
    })
  ]
})

/* Track a page view */
// Track page
analytics.page()

// or Track page view with additional entities
analytics.page({
  context: [
    {
      schema: 'iglu:com.acme/blog_post/jsonschema/1-0-0',
      data: {
        title: 'Re-thinking the structure of event data',
        url:
          'https://snowplowanalytics.com/blog/2020/01/24/re-thinking-the-structure-of-event-data/',
        category: 'Data Insights',
        author: 'Cara Baestlein',
        datePublished: '2020-01-24'
      }
    }
  ]
})

/* Track a custom event */
// Track structured event
analytics.track('playedVideo', {
  category: 'Videos',
  label: 'Fall Campaign',
  value: 42
})

// or Track Self Describing event
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign'
  }
})

// or Track Self Describing event with additional entities
analytics.track('selfDescribingEvent', {
  schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
  data: {
    id: 42,
    title: 'Fall Campaign',
    videoTimestampInMs: 1104
  },
  context: [
    {
      schema: 'iglu:com.acme/product/jsonschema/1-0-0',
      data: {
        id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
        category: 'clothing',
        subCategory: 'socks',
        price: 3.99
      }
    }
  ]
})

// or Track Enchanced Ecommerce event with product context
analytics.track('ScreenView', {
  name: 'Product Page',
  id: 'p-123',
  context: [
    {
      schema: 'iglu:com.acme/product/jsonschema/1-0-0',
      data: {
        id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
        category: 'clothing',
        subCategory: 'socks',
        price: 3.99
      }
    }
  ]
})

/* Identify a visitor */
analytics.identify('user-id-xyz', {
  firstName: 'bill',
  lastName: 'murray'
})
Using in HTML

Below is an example of importing via the unpkg CDN. Please note this will pull in the latest version of the package.

<!DOCTYPE html>
<html>
  <head>
    <title>Using @analytics/snowplow in HTML</title>
    <script src="https://unpkg.com/analytics/dist/analytics.min.js"></script>
    <script src="https://unpkg.com/@analytics/snowplow/dist/@analytics/snowplow.min.js"></script>
    <script type="text/javascript">
      /* Initialize analytics */
      var Analytics = _analytics.init({
        app: 'my-app-name',
        plugins: [
          // Minimal recommended configuration
          analyticsSnowplow({
            name: 'snowplow',
            scriptSrc: '//*.cloudfront.net/2.15.0/sp.js',
            collectorUrl: 'collector.mysite.com',
            trackerSettings: {
              appId: 'myApp',
              contexts: {
                webPage: true
              }
            }
          })
        ]
      })

      /* Track a page view */
      // Enable some automatic tracking before page event
      analytics.on('initialize:snowplow', ({ instance }) => {
        instance.plugins.snowplow.enableActivityTracking(10, 10)
        instance.plugins.snowplow.enableLinkClickTracking()
      })

      // Track page
      analytics.page()

      // or Track page view with additional entities
      analytics.page({
        contexts: [
          {
            schema: 'iglu:com.acme/blog_post/jsonschema/1-0-0',
            data: {
              title: 'Re-thinking the structure of event data',
              category: 'Data Insights',
              author: 'Cara Baestlein',
              datePublished: '2020-01-24'
            }
          }
        ]
      })

      /* Track a custom event */
      // Track structured event
      analytics.track('playedVideo', {
        category: 'Videos',
        label: 'Fall Campaign',
        value: 42
      })

      // or Track Self Describing event
      analytics.track('selfDescribingEvent', {
        schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
        data: {
          id: 42,
          title: 'Fall Campaign'
        }
      })

      // or Track Self Describing event with additional entities
      analytics.track('selfDescribingEvent', {
        schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
        data: {
          id: 42,
          title: 'Fall Campaign',
          videoTimestampInMs: 1104
        },
        contexts: [
          {
            schema: 'iglu:com.acme/product/jsonschema/1-0-0',
            data: {
              id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
              category: 'clothing',
              subCategory: 'socks',
              price: 3.99
            }
          }
        ]
      })

      // or Track Enchanced Ecommerce event with product context
      analytics.track('EnhancedEcommerceProductContext', {
        id: 'P12345',
        name: 'Android Warhol T-Shirt',
        list: 'Search Results',
        brand: 'Google',
        category: 'Apparel/T-Shirts',
        variant: 'Black',
        quantity: 1
      })
      analytics.track('EnhancedEcommerceAction', {
        action: 'add'
      })

      /* Identify a visitor */
      analytics.identify('user-id-xyz')
    </script>
  </head>
  <body>
    ....
  </body>
</html>
Using in HTML via ES Modules

Using @analytics/snowplow in ESM modules.

<!DOCTYPE html>
<html>
  <head>
    <title>Using @analytics/snowplow in HTML via ESModules</title>
    <script>
      // Polyfill process.
      // **Note**: Because `import`s are hoisted, we need a separate, prior <script> block.
      window.process = window.process || { env: { NODE_ENV: 'production' } }
    </script>
    <script type="module">
      import analytics from 'https://unpkg.com/analytics/lib/analytics.browser.es.js?module'
      import analyticsSnowplow from 'https://unpkg.com/@analytics/snowplow/lib/analytics-plugin-snowplow.browser.es.js?module'
      /* Initialize analytics */
      const Analytics = analytics({
        app: 'analytics-html-demo',
        debug: true,
        plugins: [
          // Minimal recommended configuration
          analyticsSnowplow({
            name: 'snowplow',
            scriptSrc: '//*.cloudfront.net/2.15.0/sp.js',
            collectorUrl: 'collector.mysite.com',
            trackerSettings: {
              appId: 'myApp',
              contexts: {
                webPage: true
              }
            }
          })
          // ... add any other third party analytics plugins
        ]
      })

      /* Track a page view */
      // Enable some automatic tracking before page event
      analytics.on('initialize:snowplow', ({ instance }) => {
        instance.plugins.snowplow.enableActivityTracking(10, 10)
        instance.plugins.snowplow.enableLinkClickTracking()
      })

      // Track page
      analytics.page()

      // or Track page view with additional entities
      analytics.page({
        contexts: [
          {
            schema: 'iglu:com.acme/blog_post/jsonschema/1-0-0',
            data: {
              title: 'Re-thinking the structure of event data',
              category: 'Data Insights',
              author: 'Cara Baestlein',
              datePublished: '2020-01-24'
            }
          }
        ]
      })

      /* Track a custom event */
      // Track structured event
      analytics.track('playedVideo', {
        category: 'Videos',
        label: 'Fall Campaign',
        value: 42
      })

      // or Track Self Describing event
      analytics.track('selfDescribingEvent', {
        schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
        data: {
          id: 42,
          title: 'Fall Campaign'
        }
      })

      // or Track Self Describing event with additional entities
      analytics.track('selfDescribingEvent', {
        schema: 'iglu:com.acme/video_played/jsonschema/1-0-0',
        data: {
          id: 42,
          title: 'Fall Campaign',
          videoTimestampInMs: 1104
        },
        contexts: [
          {
            schema: 'iglu:com.acme/product/jsonschema/1-0-0',
            data: {
              id: 'f9cb6cb6-5ca8-47a6-9035-d9c6ac13029e',
              category: 'clothing',
              subCategory: 'socks',
              price: 3.99
            }
          }
        ]
      })

      // or Track Enchanced Ecommerce event with product context
      analytics.track('EnhancedEcommerceProductContext', {
        id: 'P12345',
        name: 'Android Warhol T-Shirt',
        list: 'Search Results',
        brand: 'Google',
        category: 'Apparel/T-Shirts',
        variant: 'Black',
        quantity: 1
      })
      analytics.track('EnhancedEcommerceAction', {
        action: 'add'
      })

      /* Identify a visitor */
      analytics.identify('user-id-xyz')
    </script>
  </head>
  <body>
    ....
  </body>
</html>

See the full list of analytics provider plugins in the main repo.