dotCMS logodotCMS logo
OverviewAuthorBuildManageReference
dotCMS Github RepodotCMS Github RepodotCMS Discourse CommunityChat With Us
Headless and SDKs
Build
Getting StartedContent ModelingHeadless and SDKsTemplates and ThemesServer Side ScriptingAPIsExtending dotCMSIntegrationsSearch

SDK Libraries

  • Headless SDK
  • SDK Example Projects
  • SDK: @dotcms/analytics Library
  • SDK: @dotcms/angular Library
  • SDK: @dotcms/client Library
  • SDK: @dotcms/experiments Library
  • SDK: @dotcms/react Library
  • SDK: @dotcms/types Library
  • SDK: @dotcms/uve Library
  • SDK: dotcms/php-sdk Library (alpha)

Example Projects

  • SDK: .NET Example
  • SDK: Angular Example
  • SDK: Astro Example
  • SDK: Laravel Example
  • SDK: Next.js Example
  • SDK: Symfony Example

dotCMS

Universal content management, made simple.

GitHubTwitterLinkedIndotCMS Discourse Community
dotDev HomeBlogChangelogsCurrent releasesAboutContactPrivacy PolicyTrust Center

© 2026 dotCMS. All rights reserved.

    Assistant

    Responses are generated using AI and may contain mistakes.

    Hi, I'm an AI assistant with access to documentation and other content.

    Tip: You can toggle this pane with ⌘/ or ⌘K.

    Try asking

    Enter to send · Shift+Enter for newline

    @dotcms/analytics

    Content Analytics SDK for tracking content-aware events in dotCMS-powered React applications.

    Quick Start#


    1. Install#

    npm install @dotcms/analytics

    2. Create a centralized config file#

    // src/config/analytics.config.js
    export const analyticsConfig = {
        siteAuth: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY,
        server: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST,
        autoPageView: true,
        debug: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUG === 'true',
        impressions: true,
        clicks: true
    };

    3. Add automatic page view tracking to your layout#

    // src/app/layout.js
    import { DotContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    export default function RootLayout({ children }) {
        return (
            <html lang="en">
                <body>
                    <DotContentAnalytics config={analyticsConfig} />
                    {children}
                </body>
            </html>
        );
    }

    4. Track events in your components#

    'use client';
    
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    function ContactForm() {
        const { conversion } = useContentAnalytics(analyticsConfig);
    
        const handleSubmit = (e) => {
            e.preventDefault();
            // ... submit form logic ...
    
            // Track conversion ONLY after successful submission
            conversion('form-submit', {
                formName: 'contact-us',
                formType: 'lead-gen'
            });
        };
    
        return <form onSubmit={handleSubmit}>{/* form fields */}</form>;
    }

    Understanding the Components#


    The SDK exports two React primitives. Understanding their roles is critical for correct usage.

    <DotContentAnalytics /> -- Automatic Page View Tracker#

    • Its only purpose is to automatically track page views on route changes
    • It is NOT a React Context Provider
    • It does NOT share config with child components
    • Place it once in your root layout

    useContentAnalytics(config) -- Manual Tracking Hook#

    • Used for custom events, conversions, and manual page views
    • ALWAYS requires config as a parameter -- it does not read from context
    • Import the centralized config in every component that uses the hook
    // Every component that tracks events must import config explicitly
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    const { track, pageView, conversion } = useContentAnalytics(analyticsConfig);

    Why centralize config? You must import it in each component, but having a single file prevents duplication and makes updates easier.

    Configuration#


    Environment Variables#

    Add these to your .env.local file:

    NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY=YOUR_ANALYTICS_SITE_KEY
    NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST=http://localhost:8080
    NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUG=true
    VariableDescription
    NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEYSite auth key from the Content Analytics app in dotCMS
    NEXT_PUBLIC_DOTCMS_ANALYTICS_HOSTURL where your dotCMS instance is running
    NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUGSet to "true" to enable verbose console logging

    Config Options#

    OptionTypeRequiredDefaultDescription
    siteAuthstringYes--Site auth from dotCMS Analytics app
    serverstringYes--Your dotCMS server URL
    debugbooleanNofalseEnable verbose logging
    autoPageViewbooleanNotrueAuto track page views on route changes
    queueQueueConfig | falseNoSee belowEvent batching configuration
    impressionsImpressionConfig | booleanNofalseContent impression tracking
    clicksbooleanNofalseContent click tracking (300ms throttle)

    Queue Configuration#

    Controls how events are batched before being sent to the server:

    • false: Disable queuing, send events immediately
    • undefined (default): Enable queuing with default settings
    • QueueConfig object: Custom settings
    OptionTypeDefaultDescription
    eventBatchSizenumber15Max events per batch -- auto-sends when reached
    flushIntervalnumber5000Time between flushes in milliseconds

    How it works:

    • Sends immediately when eventBatchSize is reached
    • Sends pending events every flushInterval milliseconds
    • Auto-flushes on page navigation/close using visibilitychange + pagehide
    • Uses navigator.sendBeacon() for reliable delivery on page unload
    // Disable queuing (send immediately)
    export const analyticsConfig = {
        siteAuth: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY,
        server: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST,
        queue: false
    };
    
    // Custom queue settings
    export const analyticsConfig = {
        siteAuth: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY,
        server: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST,
        queue: {
            eventBatchSize: 10,
            flushInterval: 3000
        }
    };

    Impression Tracking#

    Controls automatic tracking of content visibility in the viewport:

    • false or undefined (default): Disabled
    • true: Enabled with default settings
    • ImpressionConfig object: Custom settings
    OptionTypeDefaultDescription
    visibilityThresholdnumber0.5Min percentage visible (0.0 to 1.0)
    dwellMsnumber750Min time visible in milliseconds
    maxNodesnumber1000Max elements to track (performance limit)

    How it works:

    • Tracks contentlets marked with dotcms-contentlet class and data-dot-* attributes
    • Uses Intersection Observer API for performance
    • Only fires when an element is visible for the configured threshold and dwell time
    • One impression per contentlet per session (no duplicates)
    • Automatically disabled in dotCMS editor mode
    // Enable with defaults (50% visible, 750ms dwell)
    export const analyticsConfig = {
        // ...required fields
        impressions: true
    };
    
    // Custom thresholds
    export const analyticsConfig = {
        // ...required fields
        impressions: {
            visibilityThreshold: 0.7,
            dwellMs: 1000,
            maxNodes: 500
        }
    };

    Click Tracking#

    Controls automatic tracking of user clicks on content elements:

    • false or undefined (default): Disabled
    • true: Enabled with 300ms throttle

    How it works:

    • Tracks clicks on <a> and <button> elements within contentlets
    • Contentlets must be marked with dotcms-contentlet class and data-dot-* attributes
    • Captures semantic attributes (href, aria-label, data-*) and excludes CSS classes
    • Throttles rapid clicks to prevent duplicates (300ms)
    • Automatically disabled in dotCMS editor mode

    Captured data per click:

    • Content Info: identifier, inode, title, content_type
    • Element Info: text, type (a/button), id, class, href, attributes
    • Position Info: viewport_offset_pct, dom_index

    You can enrich click data using data-* attributes in your HTML:

    <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>
    
    <button data-action="download" data-file-type="pdf" data-category="lead-magnet">
        Download Whitepaper
    </button>

    Core Concepts#


    Event Types#

    The SDK sends four types of events, identified by event_type:

    Event TypeTriggerRequires
    pageviewAutomatically on route change, or manually via pageView()autoPageView: true or manual call
    content_impressionWhen a contentlet becomes visible in the viewportimpressions config enabled
    content_clickWhen a user clicks a link/button inside a contentletclicks config enabled
    conversionExplicitly via conversion() after a successful business actionManual call

    Page Views#

    The pageView() method tracks page navigation events. It automatically enriches the event with:

    • Page data: URL, title, referrer, path, protocol, search params
    • Device data: Screen resolution, viewport size, language, user agent
    • UTM parameters: Campaign tracking data (source, medium, campaign, term, content)
    • Context: Site key, session ID, user ID, timestamp

    You can optionally pass custom data that will be sent in addition to all the automatic enrichment.

    Conversion Tracking#

    The conversion() method tracks user conversions (purchases, downloads, sign-ups, etc.).

    Only track conversions after a successful action or completed goal. Tracking on clicks or attempts (before success) diminishes their value as conversion metrics. Track when:

    • Purchase is completed and payment is confirmed
    • Download is successfully completed
    • Sign-up form is submitted and account is created
    • Any business goal is actually achieved

    Custom Events#

    The track() method tracks any custom user action with a unique event name and optional properties.

    • eventName cannot be "pageview" or "conversion" (reserved)
    • Use descriptive names: "button-click", "form-submit", "video-play", etc.

    Sessions#

    • 30-minute inactivity timeout
    • Resets at midnight UTC
    • New session if UTM campaign changes

    Identity#

    • Anonymous user ID persisted across sessions
    • Stored in dot_analytics_user_id

    Usage Examples#


    Automatic Page View Tracking#

    Add DotContentAnalytics to your root layout. No additional code is needed -- page views are tracked on every route change.

    // src/app/layout.js
    import { DotContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    export default function RootLayout({ children }) {
        return (
            <html lang="en">
                <body>
                    <DotContentAnalytics config={analyticsConfig} />
                    {children}
                </body>
            </html>
        );
    }

    Manual Page View with Custom Data#

    'use client';
    
    import { useEffect } from 'react';
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    function BlogPost({ post }) {
        const { pageView } = useContentAnalytics(analyticsConfig);
    
        useEffect(() => {
            pageView({
                contentType: 'blog',
                category: post.category,
                author: post.author,
                wordCount: post.wordCount
            });
        }, []);
    
        return <article>{/* post content */}</article>;
    }

    Custom Event Tracking#

    'use client';
    
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    function CallToAction() {
        const { track } = useContentAnalytics(analyticsConfig);
    
        const handleClick = () => {
            track('cta-click', {
                button: 'Buy Now',
                location: 'hero-section',
                price: 299.99
            });
        };
    
        return <button onClick={handleClick}>Buy Now</button>;
    }

    Conversion Tracking (Real-World Example)#

    This example is based on the Contact Us form in the Next.js example app:

    'use client';
    
    import { useState } from 'react';
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    export default function ContactUs({ description }) {
        const [isSubmitting, setIsSubmitting] = useState(false);
        const [isSuccess, setIsSuccess] = useState(false);
        const { conversion } = useContentAnalytics(analyticsConfig);
    
        const handleSubmit = (e) => {
            e.preventDefault();
            setIsSubmitting(true);
    
            // Simulate form submission
            setTimeout(() => {
                setIsSuccess(true);
    
                // Track conversion ONLY after successful submission
                conversion('form-submit', {
                    formName: 'contact-us',
                    formType: 'lead-gen'
                });
            }, 3000);
        };
    
        return (
            <form onSubmit={handleSubmit}>
                {/* form fields */}
                <button type="submit" disabled={isSubmitting}>
                    {isSubmitting ? 'Submitting...' : 'Submit'}
                </button>
            </form>
        );
    }

    E-commerce Purchase Conversion#

    'use client';
    
    import { useContentAnalytics } from '@dotcms/analytics/react';
    import { analyticsConfig } from '@/config/analytics.config';
    
    function CheckoutButton({ product, quantity }) {
        const { conversion } = useContentAnalytics(analyticsConfig);
    
        const handlePurchase = async () => {
            // Process payment...
            const result = await processPayment(product, quantity);
    
            if (result.success) {
                // Track conversion ONLY after confirmed payment
                conversion('purchase', {
                    value: product.price * quantity,
                    currency: 'USD',
                    productId: product.sku,
                    category: product.category
                });
            }
        };
    
        return <button onClick={handlePurchase}>Complete Purchase</button>;
    }

    API Reference#


    <DotContentAnalytics />#

    React component for automatic page view tracking on route changes.

    interface DotContentAnalyticsProps {
        config: DotCMSAnalyticsConfig;
    }

    Place once in your root layout. Wraps the internal tracker in <Suspense> for Next.js App Router compatibility.

    useContentAnalytics(config)#

    React hook that returns tracking methods. Always requires config as a parameter.

    function useContentAnalytics(config: DotCMSAnalyticsConfig): DotCMSAnalytics;
    
    interface DotCMSAnalytics {
        /** Track a page view with optional custom data */
        pageView: (customData?: Record<string, unknown>) => void;
    
        /** Track a custom event (eventName cannot be "pageview" or "conversion") */
        track: (eventName: string, properties?: Record<string, unknown>) => void;
    
        /** Track a conversion after a successful business action */
        conversion: (name: string, options?: Record<string, unknown>) => void;
    }

    DotCMSAnalyticsConfig#

    interface DotCMSAnalyticsConfig {
        server: string;
        siteAuth: string;
        debug?: boolean;
        autoPageView?: boolean;
        queue?: QueueConfig | false;
        impressions?: ImpressionConfig | boolean;
        clicks?: boolean;
    }
    
    interface QueueConfig {
        eventBatchSize?: number;
        flushInterval?: number;
    }
    
    interface ImpressionConfig {
        visibilityThreshold?: number;
        dwellMs?: number;
        maxNodes?: number;
    }

    Event Payload Structures#

    Page View Event#

    When you call pageView(customData?), the SDK sends:

    {
        context: {
            site_key: string;          // Your site key
            session_id: string;        // Current session ID
            user_id: string;           // Anonymous user ID
            device: {
                screen_resolution: string;
                language: string;
                viewport_width: string;
                viewport_height: string;
            }
        },
        events: [{
            event_type: "pageview",
            local_time: string,        // ISO 8601 timestamp with timezone
            data: {
                page: {                // Captured automatically
                    url: string;
                    title: string;
                    referrer: string;
                    path: string;
                    doc_host: string;
                    doc_protocol: string;
                    doc_search: string;
                    doc_hash: string;
                    doc_encoding: string;
                },
                utm?: {                // Captured automatically (if present in URL)
                    source: string;
                    medium: string;
                    campaign: string;
                    term: string;
                    content: string;
                },
                custom?: {             // Your optional data from pageView(customData)
                    // Any properties you pass
                }
            }
        }]
    }

    Custom Event#

    When you call track(eventName, properties):

    {
        context: { /* same as above */ },
        events: [{
            event_type: string,        // Your custom event name
            local_time: string,
            data: {
                custom: {
                    // Your properties object
                }
            }
        }]
    }

    Conversion Event#

    When you call conversion(name, options):

    {
        context: { /* same as above */ },
        events: [{
            event_type: "conversion",
            local_time: string,
            data: {
                conversion: {
                    name: string;      // Your conversion name
                },
                page: {
                    url: string;
                    title: string;
                },
                custom?: {             // Your optional data from options parameter
                    // All properties from options
                }
            }
        }]
    }

    Click Event#

    When click tracking is enabled and a user clicks on a contentlet element:

    {
        "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",
            "href": "/signup",
            "attributes": [
                "data-category:primary-cta",
                "data-campaign:summer-sale",
                "aria-label:Sign up for free trial"
            ]
        },
        "position": {
            "viewport_offset_pct": 45.2,
            "dom_index": 2
        }
    }

    Under the Hood#


    Storage Keys#

    KeyPurpose
    dot_analytics_user_idAnonymous user identifier (persisted across sessions)
    dot_analytics_session_idCurrent session ID
    dot_analytics_session_utmUTM campaign data for the session
    dot_analytics_session_startSession start timestamp

    Editor Detection#

    Analytics are automatically disabled when inside the dotCMS Universal Visual Editor (UVE). No events are sent in editor mode.

    Endpoint#

    All events are sent via POST to:

    {server}/api/v1/analytics/content/event

    Where {server} is the server value from your config.

    Debugging & Troubleshooting#


    Enable Debug Mode#

    Set debug: true in your config to see verbose logging in the browser console.

    Verify Events in the Network Tab#

    1. Open browser DevTools > Network tab
    2. Filter by /api/v1/analytics/content/event
    3. Perform actions in your app
    4. Inspect request payloads to see captured data

    Check Storage#

    Open browser DevTools > Application > Local Storage and look for:

    • dot_analytics_user_id
    • dot_analytics_session_id
    • dot_analytics_session_utm
    • dot_analytics_session_start

    Common Issues#

    Events not appearing?

    • Verify siteAuth and server are correct in your config
    • Enable debug: true to see console logs
    • Ensure environment variables are set in .env.local (restart dev server after changes)
    • Check that variable names start with NEXT_PUBLIC_
    • Analytics are auto-disabled in dotCMS editor mode -- test in preview or published mode

    Queue not flushing?

    • Check eventBatchSize -- the threshold might not be reached yet
    • Verify flushInterval is appropriate for your use case
    • Events auto-flush on page navigation/close via visibilitychange

    Session not persisting?

    • Check that localStorage is enabled in the browser
    • Verify no browser extensions are blocking storage

    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-analytics when 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:

    1. Fork the repository dotCMS/core
    2. Create a feature branch (git checkout -b feature/amazing-feature)
    3. Commit your changes (git commit -m 'Add some amazing feature')
    4. Push to the branch (git push origin feature/amazing-feature)
    5. Open a Pull Request

    Please ensure your code follows the existing style and includes appropriate tests.

    Licensing#


    dotCMS is available under either the Business Source License 1.1 (BSL) or a commercial license.

    Under the BSL, dotCMS can be used at no cost by individual developers, small businesses or agencies under $5M in total finances, and by larger organizations in non-production environments. Every BSL release automatically converts to GPL v3 four years after its release date. For full terms and FAQs, visit dotcms.com/bsl and dotcms.com/bsl-faq.

    Production use in larger organizations, along with access to managed cloud, SLAs, support, and enterprise capabilities, is available under a commercial license from dotCMS. For details on commercial plans, features, and support options, see dotcms.com/pricing.

    Package: @dotcms/analytics
    Tag: latest

    Found an issue with this documentation? View the source