SDK: @dotcms/analytics Library
Lightweight JavaScript SDK for tracking content-aware events in dotCMS. Works in vanilla JS and React apps. Angular & Vue support coming soon.
š Quick Start#
Standalone (Script Tag)#
<script src="ca.min.js" data-analytics-server="https://demo.dotcms.com" data-analytics-auth="SITE_AUTH" data-analytics-auto-page-view="true" data-analytics-debug="false"></script>
npm (ES Module)
npm install @dotcms/analytics
import { initializeContentAnalytics } from '@dotcms/analytics'; const analytics = initializeContentAnalytics({ siteAuth: 'SITE_AUTH', server: 'https://demo.dotcms.com' }); analytics.track('page-loaded');
React (In Development)#
npm install @dotcms/analytics
import { DotContentAnalytics } from '@dotcms/analytics/react'; const config = { siteAuth: 'SITE_AUTH', server: 'https://demo.dotcms.com', autoPageView: true // Optional, default is true in React }; export function AppRoot() { return <DotContentAnalytics config={config} />; }
Note: React API is subject to change during development.
š Core Concepts#
Page Views#
The pageView() method tracks page navigation events. It automatically enriches the event with comprehensive data, including:
- Page data: URL, title, referrer, path, protocol, search params, etc.
- Device data: Screen resolution, viewport size, language, user agent
- UTM parameters: Campaign tracking data (source, medium, campaign, etc.)
- Context: Site key, session ID, user ID, timestamp
You can optionally include custom data that will be sent in addition to all the automatic enrichment.
Method signature:
pageView(customData?: Record<string, unknown>): void
Behavior:
- Standalone (IIFE): Auto-tracked only if
data-analytics-auto-page-view="true"; otherwise callwindow.dotAnalytics.pageView()manually. - React: In development (API may change)
- Custom data is optional and gets attached to the pageview event under the
customproperty alongside all automatically captured data.
Conversion Tracking#
The conversion() method tracks user conversions (purchases, downloads, sign-ups, etc.) from your application.
ā ļø IMPORTANT: Conversion events are business events that should only be tracked after a successful action or completed goal. Tracking conversions on clicks or attempts (before success) diminishes their value as conversion metrics. Only track conversions when:
- ā Purchase is completed and payment is confirmed
- ā Download is successfully completed
- ā Sign-up form is submitted and account is created
- ā Form submission is successful and data is saved
- ā Any business goal is actually achieved
Method signature:
conversion(name: string): void conversion(name: string, options?: Record<string, unknown>): void
Usage examples:
// Basic conversion tracking (after successful download) analytics.conversion('download'); // Conversion with custom metadata (after successful purchase) analytics.conversion('purchase', { value: 99.99, currency: 'USD', category: 'ecommerce', productId: 'SKU-12345' }); // Conversion with additional context (after successful signup) analytics.conversion('signup', { source: 'homepage', plan: 'premium' });
Event payload structure:
{ "event_type": "conversion", "local_time": "2025-10-01T16:08:33-04:00", "data": { "conversion": { "name": "download" }, "page": { "url": "...", "title": "..." }, "custom": { "value": 99.99, "currency": "USD", "source": "homepage" } } }
Important:
nameis required and identifies the conversion type- All properties in
optionsgo into thecustomobject - Page data (url, title) is automatically added by the SDK
- Only track conversions after successful completion of business goals
Custom Events#
The track() method allows you to track any custom user action with a unique event name and optional properties.
Method signature:
track(eventName: string, properties?: Record<string, unknown>): void
Important:
eventNamecannot be"pageview"or"conversion"(reserved for specific tracking methods)eventNameshould be a descriptive string like"button-click","form-submit","video-play", etc.propertiesis optional and can contain any custom data relevant to the event
Sessions#
- 30-minute timeout
- Resets at midnight UTC
- New session if UTM campaign changes
Identity#
- Anonymous user ID persisted across sessions
- Stored in
dot_analytics_user_id
āļø Configuration Options#
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
siteAuth | string | ā | - | Site auth from dotCMS Analytics app |
server | string | ā | - | Your dotCMS server URL |
debug | boolean | ā | false | Enable verbose logging |
autoPageView | boolean | ā | React: true / Standalone: false | Auto track page views on route changes |
queueConfig | QueueConfig | ā | See below | Event batching configuration |
impressions | ImpressionConfig|boolean | ā | false | Content impression tracking (disabled by default) |
clicks | boolean | ā | false | Content click tracking with 300ms throttle (disabled by default) |
Queue Configuration#
The queueConfig option controls event batching:
false: Disable queuing, send events immediatelyundefined(default): Enable queuing with default settingsQueueConfigobject: Enable queuing with custom settings
| Option | Type | Default | Description |
|---|---|---|---|
eventBatchSize | number | 15 | Max events per batch - auto-sends when reached |
flushInterval | number | 5000 | Time between flushes - sends pending events (ms) |
How it works:
- ā
Send immediately when
eventBatchSizereached (e.g., 15 events) - ā
Send pending events every
flushInterval(e.g., 5 seconds) - ā
Auto-flush on page navigation/close using
visibilitychange+pagehideevents - Example: If you have 10 events and 5 seconds pass ā sends those 10
About page unload handling:
The SDK uses modern APIs (visibilitychange + pagehide) instead of beforeunload/unload to ensure:
- ā Better reliability on mobile devices
- ā Compatible with browser back/forward cache (bfcache)
- ā
Events are sent via
navigator.sendBeacon()for guaranteed delivery - ā No negative impact on page performance
Example: Disable queuing for immediate sends
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', queue: false // Send events immediately without batching });
Example: Custom queue config
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', queue: { eventBatchSize: 10, // Auto-send when 10 events queued flushInterval: 3000 // Or send every 3 seconds } });
Impression Tracking Configuration#
The impressions option controls automatic tracking of content visibility:
falseorundefined(default): Impression tracking disabledtrue: Enable tracking with default settingsImpressionConfigobject: Enable tracking with custom settings
| Option | Type | Default | Description |
|---|---|---|---|
visibilityThreshold | number | 0.5 | Min percentage visible (0.0 to 1.0) |
dwellMs | number | 750 | Min time visible in milliseconds |
maxNodes | number | 1000 | Max elements to track (performance limit) |
How it works:
- ā
Tracks contentlets marked with
dotcms-analytics-contentletclass anddata-dot-analytics-*attributes - ā Uses Intersection Observer API for high performance and battery efficiency
- ā Only fires when element is ā„50% visible for ā„750ms (configurable)
- ā Only tracks during active tab (respects page visibility)
- ā One impression per contentlet per session (no duplicates)
- ā Respects user consent settings
- ā Automatically disabled in dotCMS editor mode
Example: Enable with defaults
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', impressions: true // 50% visible, 750ms dwell, 1000 max nodes });
Example: Custom thresholds
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', impressions: { visibilityThreshold: 0.7, // Require 70% visible dwellMs: 1000, // Must be visible for 1 second maxNodes: 500 // Track max 500 elements } });
Example: Disable tracking
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', impressions: false // Explicitly disabled (also default if omitted) });
Click Tracking Configuration#
The clicks option controls automatic tracking of user interactions with content elements:
falseorundefined(default): Click tracking disabledtrue: Enable tracking with default settings (300ms throttle)
How it works:
- ā
Tracks clicks on
<a>and<button>elements within contentlets - ā
Contentlets must be marked with
dotcms-analytics-contentletclass anddata-dot-analytics-*attributes - ā
Captures semantic attributes (
href,aria-label,data-*) and excludes CSS classes - ā Throttles rapid clicks to prevent duplicate tracking (300ms fixed)
- ā One click event per interaction
- ā Respects user consent settings
- ā Automatically disabled in dotCMS editor mode
Captured Data:
For each click, the SDK captures:
- Content Info:
identifier,inode,title,content_type - Element Info:
text- Button/link text (truncated to 100 chars)type- Element type (aorbutton)id- Element ID (required by backend, empty string if not present)class- Element CSS classes (required by backend, empty string if not present)href- Link destination as written in HTML (e.g.,/signupnothttp://..., only for<a>, empty string for buttons)attributes- Additional useful attributes (see below)
- Position Info:
viewport_offset_pct- Position relative to viewport (0-100%)dom_index- Element position in DOM
Attributes Array:
Note: The
attributesfield is formatted as an array of'key:value'strings (e.g.,['data-category:primary-cta', 'aria-label:Sign up']) for efficient serialization and backend parsing.
The attributes array captures additional semantic data in 'key:value' string format:
ā Included (semantic/analytics value):
data-*- Custom data attributes (e.g.,'data-category:primary-cta')aria-*- Accessibility attributes (e.g.,'aria-label:Sign up now')title- Element titletarget- Link target (e.g.,'target:_blank')- Any other standard HTML attributes
ā Excluded (to avoid duplication):
class- Already captured as top-level propertyid- Already captured as top-level propertyhref- Already captured as top-level propertydata-dot-analytics-*- Internal SDK attributes
Example: Enable click tracking
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', clicks: true // Enable with 300ms throttle (fixed) });
Example: Adding Custom Analytics Metadata
Use data-* attributes to enrich click tracking with custom metadata:
<!-- Primary CTA with category --> <a href="/signup" id="cta-signup" data-category="primary-cta" data-campaign="summer-sale" aria-label="Sign up for free trial"> Start Free Trial ā </a> <!-- Product link with metadata --> <a href="/products/123" data-product-id="123" data-product-name="Premium Plan" data-price="29.99"> View Product </a> <!-- Button with custom tracking --> <button data-action="download" data-file-type="pdf" data-category="lead-magnet"> Download Whitepaper </button>
Resulting Click Event:
{ "content": { "identifier": "abc123", "inode": "xyz789", "title": "Product Page", "content_type": "Page" }, "element": { "text": "Start Free Trial ā", "type": "a", "id": "cta-signup", "class": "btn btn-primary text-white", "href": "/signup", "attributes": [ "data-category:primary-cta", "data-campaign:summer-sale", "aria-label:Sign up for free trial", "target:_blank" ] }, "position": { "viewport_offset_pct": 45.2, "dom_index": 2 } }
Example: Disable tracking
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', clicks: false // Explicitly disabled (also default if omitted) });
š ļø Usage Examples#
Vanilla JavaScript#
Basic Page View
// After init with the <script> tag, dotAnalytics is added to the window // Automatically captures: page, device, UTM, context (session, user, site) window.dotAnalytics.pageView();
Page View with Additional Custom Data
// All automatic data (page, device, UTM, context) is STILL captured // Plus your custom properties are added under 'custom' window.dotAnalytics.pageView({ contentType: 'blog', category: 'technology', author: 'john-doe', wordCount: 1500 }); // The server receives: page + device + utm + context + custom (your data)
Track Custom Events
// Basic event tracking window.dotAnalytics.track('cta-click', { button: 'Buy Now', location: 'hero-section' }); // Track form submission window.dotAnalytics.track('form-submit', { formName: 'contact-form', formType: 'lead-gen' }); // Track video interaction window.dotAnalytics.track('video-play', { videoId: 'intro-video', duration: 120, autoplay: false });
Advanced: Manual Init with Custom Properties
const analytics = initializeContentAnalytics({ siteAuth: 'abc123', server: 'https://your-dotcms.com', debug: true, autoPageView: false }); // Track custom events with properties analytics.track('product-view', { productId: 'SKU-12345', category: 'Electronics', price: 299.99, inStock: true }); // Manual page view with custom data // Automatic enrichment (page, device, UTM, context) + your custom data analytics.pageView({ section: 'checkout', step: 'payment', cartValue: 299.99 });
React#
Note: React integration is currently in development. The API may change.
Basic Setup
import { DotContentAnalytics } from '@dotcms/analytics/react'; const config = { siteAuth: 'SITE_KEY', server: 'https://demo.dotcms.com', autoPageView: true }; export function AppRoot() { return <DotContentAnalytics config={config} />; }
Using the Hook
import { useContentAnalytics } from '@dotcms/analytics/react'; function MyComponent() { const { track, pageView } = useContentAnalytics({ siteAuth: 'SITE_AUTH', server: 'https://demo.dotcms.com' }); // Track custom events (same API as vanilla JS) const handleClick = () => { track('button-click', { label: 'CTA Button' }); }; return <button onClick={handleClick}>Click Me</button>; }
API Reference#
interface DotCMSAnalytics { /** * Track a page view event with optional custom data * @param customData - Optional object with custom properties to attach to the pageview */ pageView: (customData?: Record<string, unknown>) => void; /** * Track a custom event * @param eventName - Name of the custom event (cannot be "pageview" or "conversion") * @param properties - Optional object with event-specific properties */ track: (eventName: string, properties?: Record<string, unknown>) => void; /** * Track a conversion event (purchase, download, sign-up, etc.) * ā ļø IMPORTANT: Only track conversions after successful completion of business goals * @param name - Name of the conversion (e.g., "purchase", "download", "signup") * @param options - Optional object with conversion metadata (all properties go into custom object) */ conversion: (name: string, options?: Record<string, unknown>) => void; }
Page View Event Structure#
When you call pageView(customData?), the SDK automatically enriches the event with comprehensive data and sends:
{ context: { // š¤ AUTOMATIC - Identity & Session site_key: string; // Your site key session_id: string; // Current session ID user_id: string; // Anonymous user ID device: { // š¤ AUTOMATIC - Device & Browser Info screen_resolution: string; // Screen size language: string; // Browser language viewport_width: string; // Viewport width viewport_height: string; // Viewport height } }, events: [{ event_type: "pageview", local_time: string, // š¤ AUTOMATIC - ISO 8601 timestamp with timezone data: { page: { // š¤ AUTOMATIC - Page Information url: string; // Full URL title: string; // Page title referrer: string; // Referrer URL path: string; // Path doc_host: string; // Hostname doc_protocol: string; // Protocol (http/https) doc_search: string; // Query string doc_hash: string; // URL hash doc_encoding: string; // Character encoding }, utm?: { // š¤ AUTOMATIC - Campaign Tracking (if present in URL) source: string; // utm_source medium: string; // utm_medium campaign: string; // utm_campaign term: string; // utm_term content: string; // utm_content }, custom?: { // š¤ YOUR DATA (optional) // Any custom properties you pass to pageView(customData) contentType?: string; category?: string; author?: string; // ... any other properties } } }] }
Key Points:
- š¤ Most data is captured automatically - you don't need to provide it
- š¤
customis where your optional data goes - All automatic data is always captured, even if you don't pass
customData
Custom Event Structure#
When you call track(eventName, properties), the following structure is sent:
{ context: { site_key: string; // Your site key session_id: string; // Current session ID user_id: string; // Anonymous user ID device: { // š¤ AUTOMATIC - Device & Browser Info screen_resolution: string; // Screen size language: string; // Browser language viewport_width: string; // Viewport width viewport_height: string; // Viewport height } }, events: [{ event_type: string, // Your custom event name local_time: string, // ISO 8601 timestamp data: { custom: { // Your properties object } } }] }
Conversion Event Structure#
When you call conversion(name, options), the following structure is sent:
{ context: { site_key: string; // Your site key session_id: string; // Current session ID user_id: string; // Anonymous user ID device: { // š¤ AUTOMATIC - Device & Browser Info screen_resolution: string; // Screen size language: string; // Browser language viewport_width: string; // Viewport width viewport_height: string; // Viewport height } }, events: [{ event_type: "conversion", local_time: string, // ISO 8601 timestamp data: { conversion: { // š¤ AUTOMATIC - Conversion Info name: string; // Your conversion name }, page: { // š¤ AUTOMATIC - Page Information url: string; // Full URL title: string; // Page title }, custom?: { // š¤ YOUR DATA (optional) // All properties from options parameter value?: number; currency?: string; category?: string; // ... any other custom properties } } }] }
Key Points:
- š¤ Conversion name and page data are captured automatically
- š¤ All properties in
optionsgo into thecustomobject - ā ļø Only track conversions after successful completion of business goals
Under the Hood#
Storage Keys#
dot_analytics_user_iddot_analytics_session_iddot_analytics_session_utmdot_analytics_session_start
Editor Detection#
Analytics are disabled when inside the dotCMS editor.
Debugging & Troubleshooting#
Not seeing events?
- Ensure
siteKey&serverare correct - Enable debug mode
- Check network requests to:
https://your-server/api/v1/analytics/content/event - Avoid using inside dotCMS editor (auto-disabled)
Standalone attributes to verify:
data-analytics-auth(required)data-analytics-server(optional, defaults to current origin)data-analytics-auto-page-view(trueto enable)data-analytics-debug(trueto enable)
Roadmap#
- Scroll depth & file download tracking
- Form interaction analytics
- Angular & Vue support
- Realtime dashboard
Support#
We offer multiple channels to get help with the dotCMS Analytics SDK:
- GitHub Issues: For bug reports and feature requests, please open an issue in the GitHub repository
- Community Forum: Join our community discussions to ask questions and share solutions
- Stack Overflow: Use the tag
dotcms-analyticswhen posting questions - Enterprise Support: Enterprise customers can access premium support through the dotCMS Support Portal
When reporting issues, please include:
- SDK version you're using
- Framework/library version (if applicable)
- Minimal reproduction steps
- Expected vs. actual behavior
Contributing#
GitHub pull requests are the preferred method to contribute code to dotCMS. We welcome contributions to the dotCMS Analytics SDK! If you'd like to contribute, please follow these steps:
- Fork the repository dotCMS/core
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please ensure your code follows the existing style and includes appropriate tests.
Licensing#
dotCMS comes in multiple editions and as such is dual-licensed. The dotCMS Community Edition is licensed under the GPL 3.0 and is freely available for download, customization, and deployment for use within organizations of all stripes. dotCMS Enterprise Editions (EE) adds several enterprise features and is available via a supported, indemnified commercial license from dotCMS. For the differences between the editions, see the feature page.
This SDK is part of dotCMS's dual-licensed platform (GPL 3.0 for Community, commercial license for Enterprise).
Learn more at dotcms.com.
mainFound an issue with this documentation? Report it on GitHub