From a787b02549d3df6184fe90ea46237fb0e48f6e7e Mon Sep 17 00:00:00 2001 From: Patryk Zdunowski Date: Thu, 15 May 2025 23:54:52 +0200 Subject: [PATCH] feat(plugin-livesession): initial commit --- .../analytics-plugin-livesession/.babelrc | 9 + .../analytics-plugin-livesession/.gitignore | 14 + .../analytics-plugin-livesession/README.md | 244 ++++++++++++++++++ .../analytics-plugin-livesession/package.json | 73 ++++++ .../src/browser.js | 118 +++++++++ .../analytics-plugin-livesession/src/index.js | 5 + .../analytics-plugin-livesession/src/node.js | 34 +++ .../tests/browser.test.js | 20 ++ 8 files changed, 517 insertions(+) create mode 100644 packages/analytics-plugin-livesession/.babelrc create mode 100644 packages/analytics-plugin-livesession/.gitignore create mode 100644 packages/analytics-plugin-livesession/README.md create mode 100644 packages/analytics-plugin-livesession/package.json create mode 100644 packages/analytics-plugin-livesession/src/browser.js create mode 100644 packages/analytics-plugin-livesession/src/index.js create mode 100644 packages/analytics-plugin-livesession/src/node.js create mode 100644 packages/analytics-plugin-livesession/tests/browser.test.js diff --git a/packages/analytics-plugin-livesession/.babelrc b/packages/analytics-plugin-livesession/.babelrc new file mode 100644 index 00000000..b5e3023e --- /dev/null +++ b/packages/analytics-plugin-livesession/.babelrc @@ -0,0 +1,9 @@ +{ + "presets": [ + [ + "@babel/env", { + "modules": false + } + ] + ] +} diff --git a/packages/analytics-plugin-livesession/.gitignore b/packages/analytics-plugin-livesession/.gitignore new file mode 100644 index 00000000..4c29c639 --- /dev/null +++ b/packages/analytics-plugin-livesession/.gitignore @@ -0,0 +1,14 @@ +node_modules + +dist +lib +.size-snapshot.json + +*.log + +# IDE stuff +**/.idea + +# OS stuff +.DS_Store +.tmp diff --git a/packages/analytics-plugin-livesession/README.md b/packages/analytics-plugin-livesession/README.md new file mode 100644 index 00000000..5a3b69e6 --- /dev/null +++ b/packages/analytics-plugin-livesession/README.md @@ -0,0 +1,244 @@ + + +# LiveSession plugin for `analytics` + +Seamlessly connect [LiveSession](https://www.livesession.io/) with your [analytics](https://www.npmjs.com/package/analytics) implementation + +LiveSession empowers you to capture and analyze user interactions within your application. By recording and replaying user sessions, it provides valuable insights that help developers and product teams enhance their software's user experience and functionality. + +This plugin seamlessly integrates the LiveSession JavaScript library into your application and enables custom event tracking within LiveSession's ecosystem. + +For detailed information about LiveSession's core functionality, explore [the official LiveSession Browser SDK on NPM](https://www.npmjs.com/package/@livesession/browser). + +[View the docs](https://getanalytics.io/plugins/livesession/) + + +
+Click to expand + +- [Installation](#installation) +- [How to use](#how-to-use) +- [Platforms Supported](#platforms-supported) +- [Browser usage](#browser-usage) + - [Browser API](#browser-api) + - [Configuration options for browser](#configuration-options-for-browser) +- [Additional examples](#additional-examples) +- [Formatting payloads](#formatting-payloads) + +
+ + +## Installation + +Install `analytics` and `@analytics/livesession` packages + +```bash +npm install analytics +npm install @analytics/livesession +``` + +You will need your `trackId` from [LiveSession settings](https://livesession.dev/docs/api/browser/introduction) to connect to your account and initialize analytics. + + + +## How to use + +The `@analytics/livesession` package works in [the browser](#browser-usage). To use, install the package, include in your project and initialize the plugin with [analytics](https://www.npmjs.com/package/analytics). + +Below is an example of how to use the browser plugin. + +```js +import Analytics from 'analytics' +import livesessionPlugin from '@analytics/livesession' + +const analytics = Analytics({ + app: 'awesome-app', + plugins: [ + livesessionPlugin("your-track-id") + ] +}) + +/* Track a custom event */ +analytics.track('cartCheckout', { + item: 'pink socks', + price: 20 +}) + +/* Identify a visitor */ +analytics.identify('user-id-xyz', { + firstName: 'bill', + lastName: 'murray' +}) + +``` + +After initializing `analytics` with the `livesessionPlugin` plugin, data will be sent into LiveSession whenever [analytics.identify](https://getanalytics.io/api/#analyticsidentify), or [analytics.track](https://getanalytics.io/api/#analyticstrack) are called. + +See [additional implementation examples](#additional-examples) for more details on using in your project. + +## Platforms Supported + +The `@analytics/livesession` package works in [the browser](#browser-usage) + +## Browser usage + +The LiveSession client side browser plugin works with these analytic api methods: + +- **[analytics.identify](https://getanalytics.io/api/#analyticsidentify)** - Identify visitors and send details to LiveSession +- **[analytics.track](https://getanalytics.io/api/#analyticstrack)** - Track custom events and send to LiveSession + +### Browser API + +```js +import Analytics from 'analytics' +import livesessionPlugin from '@analytics/livesession' + +const analytics = Analytics({ + app: 'awesome-app', + plugins: [ + livesessionPlugin("your-track-id") + ] +}) + +``` + +### Configuration options for browser + +| Option | description | +|:---------------------------|:-----------| +| `trackId`
**required** - string| LiveSession website's `trackId` ID. | + + +## Additional examples + +Below are additional implementation examples. + +
+ 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. + + ```html + + + + Using @analytics/livesession in HTML + + + + + + .... + + + + ``` + +
+ +
+ Using in HTML via ES Modules + + Using `@analytics/livesession` in ESM modules. + + ```html + + + + Using @analytics/livesession in HTML via ESModules + + + + + .... + + + + ``` + +
+ + + + +## Formatting payloads + +LiveSession requires [specific naming conventions](https://help.livesession.io/en/articles/8496404-custom-events) for tracking. + +We have taken the liberty of making this easier to use with this plugin. 🎉 + +Values sent to LiveSession will be automatically converted into a values their API will understand. + +**Example** + +```js +analytics.track('itemPurchased', { + price: 11.11, + is_user: true, + first_name: 'steve' +}) +``` + +This tracking payload will be automatically converted to the [livesession naming conventions](https://help.livesession.io/en/articles/8496404-custom-events) and will be sent like: + +```js +__ls.event('itemPurchased', { + price_float: 11.11, + isUser_bool: true, + firstName_str: 'steve' +}) +``` + +This will ensure data flows into LiveSession correctly. diff --git a/packages/analytics-plugin-livesession/package.json b/packages/analytics-plugin-livesession/package.json new file mode 100644 index 00000000..756ead02 --- /dev/null +++ b/packages/analytics-plugin-livesession/package.json @@ -0,0 +1,73 @@ +{ + "name": "@analytics/livesession", + "version": "0.0.0", + "description": "LiveSession plugin for 'analytics' module", + "projectMeta": { + "provider": { + "name": "LiveSession", + "url": "https://www.livesession.io/" + }, + "platforms": { + "browser": "./src/browser.js" + } + }, + "keywords": [ + "analytics", + "analytics-project", + "analytics-plugin", + "livesession" + ], + "author": "Patryk Zdunowski", + "license": "MIT", + "scripts": { + "test": "ava -v", + "test:watch": "ava -v --watch", + "docs": "node ../analytics-cli/bin/run docs", + "build": "node ../../scripts/build/index.js", + "watch": "node ../../scripts/build/_watch.js", + "release:patch": "npm version patch && npm publish", + "release:minor": "npm version minor && npm publish", + "release:major": "npm version major && npm publish", + "es": "../../node_modules/.bin/babel-node ./testBabel.js" + }, + "main": "lib/analytics-plugin-livesession.cjs.js", + "globalName": "analyticsLiveSession", + "jsnext:main": "lib/analytics-plugin-livesession.es.js", + "module": "lib/analytics-plugin-livesession.es.js", + "browser": { + "./lib/analytics-plugin-livesession.cjs.js": "./lib/analytics-plugin-livesession.browser.cjs.js", + "./lib/analytics-plugin-livesession.es.js": "./lib/analytics-plugin-livesession.browser.es.js" + }, + "ava": { + "files": [ + "**/**/*.test.js" + ], + "require": [ + "esm", + "@babel/register" + ], + "verbose": true, + "failFast": true, + "sources": [ + "**/*.{js,jsx}" + ] + }, + "files": [ + "dist", + "lib", + "README.md" + ], + "homepage": "https://github.com/DavidWells/analytics#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/DavidWells/analytics.git" + }, + "devDependencies": { + "@babel/core": "7.5.5", + "@babel/preset-env": "7.5.5", + "@babel/register": "^7.5.5", + "@babel/runtime": "7.5.5" + }, + "dependencies": { + } +} diff --git a/packages/analytics-plugin-livesession/src/browser.js b/packages/analytics-plugin-livesession/src/browser.js new file mode 100644 index 00000000..0ac18548 --- /dev/null +++ b/packages/analytics-plugin-livesession/src/browser.js @@ -0,0 +1,118 @@ +/* global __ls */ + +/** + * https://livesession.dev/docs/api/browser/methods#options-signature + */ +const defaultConfig = { + keystrokes: "", + rootHostname: false, +} + +/** + * LiveSession Analytics plugin + * @link https://getanalytics.io/plugins/livesession + * @link https://livesession.dev/docs/api/browser/methods + * + * @param {string} trackId - LiveSession Track ID + * @param {string} pluginConfig.keystrokes - Enable global keystroke tracking + * @param {string} pluginConfig.rootHostname - Set this to the highest-level hostname to record session across different subdomains on your site + * + * @return {object} Analytics plugin + * + * @example: + * 1. livesessionPlugin("your-track-id", {}) + * 2. livesessionPlugin("your-track-id", { keystrokes: true }) + */ +export default function livesessionPlugin(trackId = "", pluginConfig = {}) { + return { + name: 'livesession', + config: { + ...defaultConfig, + ...pluginConfig, + trackId: trackId, + }, + + initialize: ({ config }) => { + if (!config.trackId) { + throw new Error('No trackId supplied for LiveSession') + } + + appendSnippet() + + if (typeof __ls === 'undefined') { + throw new Error('LiveSession script not loaded') + } + + const { + trackId, + ...restConfig + } = config + + __ls("init", trackId, restConfig || {}) + __ls("newPageView") + }, + + /** + * https://livesession.dev/docs/api/browser/methods#identify + */ + identify: ({ payload, config }) => { + if (typeof __ls === 'undefined') { + return false + } + + const { userId, anonymousId, traits } = payload + + __ls("identify", { + userId: userId || anonymousId, + ...traits || {} + }) + }, + + /** + * https://livesession.dev/docs/api/browser/methods#track + */ + track: ({ payload, options, config }) => { + if (typeof __ls === 'undefined') { + return false + } + + __ls.track(payload.event, payload.properties) + }, + + loaded: () => { + return !!window.__ls + }, + } +} + +/** + * https://github.com/livesession/livesession-browser/blob/master/src/snippet.ts + */ +export const defaultScriptURL = "https://cdn.livesession.io/track.js" + +const appendSnippet = ( + wnd = window, + doc = document, + type = "script", + scriptURL = defaultScriptURL, +) => { + return ((w, d, t, u) => { + if (w.__ls) { + throw new Error("LiveSession script already added"); + } + const f = (w.__ls = function () { + f.push ? f.push.apply(f, arguments) : f.store.push(arguments); + }); + if (!w.__ls) w.__ls = f; + f.store = []; + f.v = "1.1"; + + const ls = d.createElement(t); + ls.async = true; + ls.src = u; + ls.charset = "utf-8"; + ls.crossOrigin = "anonymous"; + const h = d.getElementsByTagName("head")[0]; + h.appendChild(ls); + })(wnd, doc, type, scriptURL); +}; diff --git a/packages/analytics-plugin-livesession/src/index.js b/packages/analytics-plugin-livesession/src/index.js new file mode 100644 index 00000000..d6561494 --- /dev/null +++ b/packages/analytics-plugin-livesession/src/index.js @@ -0,0 +1,5 @@ +import nodeCode from './node' +import browser from './browser' + +/* This module will shake out unused code and work in browser & node 🎉 */ +export default process.browser ? browser : nodeCode diff --git a/packages/analytics-plugin-livesession/src/node.js b/packages/analytics-plugin-livesession/src/node.js new file mode 100644 index 00000000..26c98b0a --- /dev/null +++ b/packages/analytics-plugin-livesession/src/node.js @@ -0,0 +1,34 @@ +/** + * Node side + */ + +const config = {} + +const name = 'livesession' + +const logMessage = () => { + console.log(`${name} not available in node.js yet. Todo implement https://github.com/livesession/livesession-node`) +} + +/* Export the integration */ +export default function livesessionPlugin(userConfig = {}) { + // Allow for userland overides of base methods + return { + name: name, + config: { + ...config, + ...userConfig + }, + initialize: ({ config }) => { + logMessage() + }, + // track event + track: ({ payload, config }) => { + logMessage() + }, + // identify user + identify: ({ payload }) => { + logMessage() + } + } +} diff --git a/packages/analytics-plugin-livesession/tests/browser.test.js b/packages/analytics-plugin-livesession/tests/browser.test.js new file mode 100644 index 00000000..33a22911 --- /dev/null +++ b/packages/analytics-plugin-livesession/tests/browser.test.js @@ -0,0 +1,20 @@ +import test from 'ava' + +import ls from '../src/browser' + +test('should create livesession client', (t) => { + const pluginConfig = { + keystrokes: true, + } + + const plugin = ls("test", pluginConfig) + + t.is(plugin.name, 'livesession') + t.deepEqual(plugin.config.trackId, "test") + t.deepEqual(plugin.config.keystrokes, true) + + t.is(typeof plugin.initialize, 'function') + t.is(typeof plugin.track, 'function') + t.is(typeof plugin.identify, 'function') + t.is(typeof plugin.loaded, 'function') +})