en un clic
sdk-analytics-installer
// Use this skill when the user asks to install, configure, or set up @dotcms/analytics, sdk-analytics, analytics SDK, add analytics tracking, or mentions installing analytics in Next.js or React projects
// Use this skill when the user asks to install, configure, or set up @dotcms/analytics, sdk-analytics, analytics SDK, add analytics tracking, or mentions installing analytics in Next.js or React projects
| name | SDK Analytics Installer |
| description | Use this skill when the user asks to install, configure, or set up @dotcms/analytics, sdk-analytics, analytics SDK, add analytics tracking, or mentions installing analytics in Next.js or React projects |
| allowed-tools | Read, Write, Edit, Bash, Grep, Glob |
| version | 1.0.0 |
This skill provides step-by-step instructions for installing and configuring the @dotcms/analytics SDK in the Next.js example project at /core/examples/nextjs.
The @dotcms/analytics SDK is dotCMS's official JavaScript library for tracking content-aware events and analytics. It provides:
CRITICAL: useContentAnalytics() ALWAYS requires config as a parameter. The hook does NOT use React Context.
<DotContentAnalytics /> - Auto Page View Tracker
useContentAnalytics(config) - Manual Tracking Hook
// 1. Create centralized config file (once)
// /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",
};
// 2. Add DotContentAnalytics to layout for auto pageview tracking (optional)
// /src/app/layout.js
import { DotContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
<DotContentAnalytics config={analyticsConfig} />;
// 3. Import config in every component that uses the hook
// /src/components/MyComponent.js
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
const { track } = useContentAnalytics(analyticsConfig); // ✅ Config required!
Why centralize config? While you must import it in each component, centralizing prevents duplication and makes updates easier.
Here's the complete setup flow:
1. Install package
└─> npm install @dotcms/analytics
2. Create centralized config file
└─> /src/config/analytics.config.js
└─> export const analyticsConfig = { siteAuth, server, debug, ... }
3. (Optional) Add DotContentAnalytics for auto pageview tracking
└─> /src/app/layout.js
└─> import { analyticsConfig } from "@/config/analytics.config"
└─> <DotContentAnalytics config={analyticsConfig} />
4. Import config in EVERY component that uses the hook
└─> /src/components/MyComponent.js
└─> import { analyticsConfig } from "@/config/analytics.config"
└─> const { track } = useContentAnalytics(analyticsConfig) // ✅ Config required!
Key Benefits of Centralized Config:
Navigate to the Next.js example directory and install the package:
cd /core/examples/nextjs
npm install @dotcms/analytics
Check that the package was added to package.json:
grep "@dotcms/analytics" package.json
Expected output: "@dotcms/analytics": "latest" or similar version.
Create a dedicated configuration file to centralize your analytics settings. This makes it easier to maintain and reuse across your application.
File: /core/examples/nextjs/src/config/analytics.config.js
/**
* Centralized analytics configuration for dotCMS Content Analytics
*
* This configuration is used by:
* - DotContentAnalytics provider in layout.js
* - useContentAnalytics() hook when used standalone (optional)
*
* Environment variables required:
* - NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY
* - NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST
* - NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUG (optional)
*/
export const analyticsConfig = {
siteAuth: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY,
server: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST,
autoPageView: true, // Automatically track page views on route changes
debug: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUG === "true",
queue: {
eventBatchSize: 15, // Send when 15 events are queued
flushInterval: 5000, // Or send every 5 seconds (ms)
},
};
Benefits of this approach:
Update the root layout file to include the analytics provider using the centralized config.
File: /core/examples/nextjs/src/app/layout.js
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
Updated with Analytics (using centralized config):
import { Inter } from "next/font/google";
import { DotContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<DotContentAnalytics config={analyticsConfig} />
{children}
</body>
</html>
);
}
Create or update .env.local file in the Next.js project root:
File: /core/examples/nextjs/.env.local
# dotCMS Analytics Configuration
NEXT_PUBLIC_DOTCMS_AUTH_TOKEN={GENERATE TOKEN FROM USER PORTLET API ACCESS TOKEN}
NEXT_PUBLIC_DOTCMS_HOST={URL WHERE DOTCMS IS RUNNING}
NEXT_PUBLIC_DOTCMS_SITE_ID={SITE IDENTIFIER}
NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY={GENERATE KEY FROM CONTENT ANALYTICS APP}
NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST={SITE IDENTIFIER}
NEXT_PUBLIC_EXPERIMENTS_API_KEY={GENERATED KEY FROM THE EXPERIMENTS APP}
NEXT_PUBLIC_DOTCMS_MODE='production'
NODE_TLS_REJECT_UNAUTHORIZED=0
Important: Replace your_site_auth_key_here with your actual dotCMS Analytics site auth key. This can be obtained from the Analytics app in your dotCMS instance.
.env.local to .gitignoreEnsure the environment file is not committed to version control:
# Check if already ignored
grep ".env.local" /core/examples/nextjs/.gitignore
# If not present, add it
echo ".env.local" >> /core/examples/nextjs/.gitignore
With the configuration above, page views are automatically tracked on every route change. No additional code needed!
Track page views with additional context:
"use client";
import { useEffect } from "react";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function MyComponent() {
// ✅ ALWAYS pass config - import from centralized config file
const { pageView } = useContentAnalytics(analyticsConfig);
useEffect(() => {
// Track page view with custom data
pageView({
contentType: "blog",
category: "technology",
author: "john-doe",
wordCount: 1500,
});
}, []);
return <div>Content here</div>;
}
Track specific user interactions:
"use client";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function CallToActionButton() {
// ✅ ALWAYS pass config - import from centralized config file
const { track } = useContentAnalytics(analyticsConfig);
const handleClick = () => {
// Track custom event
track("cta-click", {
button: "Buy Now",
location: "hero-section",
price: 299.99,
});
};
return <button onClick={handleClick}>Buy Now</button>;
}
"use client";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function ContactForm() {
const { track } = useContentAnalytics(analyticsConfig);
const handleSubmit = async (e) => {
e.preventDefault();
// Track form submission
track("form-submit", {
formName: "contact-form",
formType: "lead-gen",
source: "homepage",
});
// Submit form...
};
return <form onSubmit={handleSubmit}>{/* Form fields */}</form>;
}
"use client";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function VideoPlayer({ videoId }) {
const { track } = useContentAnalytics(analyticsConfig);
const handlePlay = () => {
track("video-play", {
videoId,
duration: 120,
autoplay: false,
});
};
const handleComplete = () => {
track("video-complete", {
videoId,
watchPercentage: 100,
});
};
return (
<video onPlay={handlePlay} onEnded={handleComplete}>
{/* Video sources */}
</video>
);
}
"use client";
import { useEffect } from "react";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function ProductPage({ product }) {
const { track } = useContentAnalytics(analyticsConfig);
useEffect(() => {
// Track product view
track("product-view", {
productId: product.sku,
productName: product.title,
category: product.category,
price: product.price,
inStock: product.inventory > 0,
});
}, [product]);
return <div>{/* Product details */}</div>;
}
"use client";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function CheckoutButton({ product, quantity }) {
const { conversion } = useContentAnalytics(analyticsConfig);
const handlePurchase = () => {
// Process checkout logic here...
// After successful payment confirmation:
// Track conversion ONLY after successful purchase
conversion("purchase", {
value: product.price * quantity,
currency: "USD",
productId: product.sku,
productName: product.title,
quantity: quantity,
category: product.category,
});
};
return <button onClick={handlePurchase}>Complete Purchase</button>;
}
"use client";
import { useContentAnalytics } from "@dotcms/analytics/react";
import { analyticsConfig } from "@/config/analytics.config";
function DownloadWhitepaper() {
const { conversion } = useContentAnalytics(analyticsConfig);
const handleDownload = () => {
// Trigger download logic here...
// After download is successfully completed:
// Track conversion ONLY after successful download
conversion("download", {
fileType: "pdf",
fileName: "whitepaper-2024.pdf",
category: "lead-magnet",
});
};
return (
<button id="download-btn" onClick={handleDownload}>
Download Whitepaper
</button>
);
}
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
siteAuth | string | Yes | - | Site authentication key from dotCMS Analytics |
server | string | Yes | - | Your dotCMS server URL |
debug | boolean | No | false | Enable verbose logging for debugging |
autoPageView | boolean | No | true (React) | Automatically track page views on route changes |
queue | QueueConfig | false | No | Default queue settings | Event batching configuration |
impressions | ImpressionConfig | boolean | No | false | Content impression tracking (disabled by default) |
clicks | boolean | No | false | Content click tracking with 300ms throttle (disabled by default) |
Controls how events are batched and sent:
| Option | Type | Default | Description |
|---|---|---|---|
eventBatchSize | number | 15 | Max events per batch - auto-sends when reached |
flushInterval | number | 5000 | Time in ms between flushes |
Disable Queuing (send immediately):
const analyticsConfig = {
siteAuth: "your_key",
server: "https://your-server.com",
queue: false, // Send events immediately
};
Controls automatic tracking of content visibility:
| 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) |
Enable with defaults:
const analyticsConfig = {
siteAuth: "your_key",
server: "https://your-server.com",
impressions: true, // 50% visible, 750ms dwell, 1000 max nodes
};
Custom thresholds:
const analyticsConfig = {
siteAuth: "your_key",
server: "https://your-server.com",
impressions: {
visibilityThreshold: 0.7, // Require 70% visible
dwellMs: 1000, // Must be visible for 1 second
maxNodes: 500, // Track max 500 elements
},
};
How it works:
dotcms-analytics-contentlet class and data-dot-analytics-* attributesControls automatic tracking of user interactions with content elements.
Enable click tracking:
const analyticsConfig = {
siteAuth: "your_key",
server: "https://your-server.com",
clicks: true, // Enable with 300ms throttle (fixed)
};
How it works:
<a> and <button> elements within contentletsdotcms-analytics-contentlet class and data-dot-analytics-* attributeshref, aria-label, data-*) and excludes CSS classesCaptured Data:
For each click, the SDK captures:
identifier, inode, title, content_typetext - Button/link text (truncated to 100 chars)type - Element type (a or button)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., /signup not http://..., only for <a>, empty string for buttons)attributes - Additional useful attributes (see below)viewport_offset_pct - Position relative to viewport (0-100%)dom_index - Element position in DOMAttributes Object:
The attributes object captures additional semantic data:
✅ Included (semantic/analytics value):
data-* - Custom data attributes (e.g., data-category="primary-cta")aria-* - Accessibility attributestitle, target - 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 attributesAdding Custom Analytics Metadata:
Use data-* attributes to enrich click tracking:
// In your Next.js component
<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>
Complete Configuration Example:
// /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",
queue: {
eventBatchSize: 15,
flushInterval: 5000,
},
impressions: {
visibilityThreshold: 0.5, // 50% visible
dwellMs: 750, // 750ms dwell time
maxNodes: 1000, // Track up to 1000 elements
},
clicks: true, // Enable click tracking (300ms throttle, fixed)
};
The SDK automatically enriches events with:
track()dot_analytics_session_id in localStoragedot_analytics_user_idSet debug: true in config to see verbose logging:
const analyticsConfig = {
siteAuth: "your_key",
server: "https://your-server.com",
debug: true, // Enable debug logging
};
/api/v1/analytics/content/eventOpen browser DevTools � Application � Local Storage:
dot_analytics_user_id - Anonymous user identifierdot_analytics_session_id - Current session IDdot_analytics_session_utm - UTM campaign datadot_analytics_session_start - Session start timestampVerify Configuration:
siteAuth and server are correctdebug: true to see console logsCheck Network Requests:
/api/v1/analytics/content/eventEditor Mode Detection:
Environment Variables:
.env.local is loaded (restart dev server if needed)NEXT_PUBLIC_eventBatchSize - might not be reaching thresholdflushInterval is appropriate for your use casevisibilitychangeImport Path Not Found:
// ❌ Error: Cannot find module '@/config/analytics.config'
/src/config/analytics.config.jsjsconfig.json or tsconfig.json has the @ alias configured:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
Undefined Config Values:
// Config shows undefined for siteAuth or server
.env.local.env.localNEXT_PUBLIC_Config Not Updated:
rm -rf .nextnpm run devThe Next.js example at /core/examples/nextjs already uses other dotCMS SDK packages:
@dotcms/client - Core API client@dotcms/experiments - A/B testing@dotcms/react - React components@dotcms/types - TypeScript types@dotcms/uve - Universal Visual EditorAdding analytics complements these by providing:
DotContentAnalyticsinterface AnalyticsConfig {
siteAuth: string;
server: string;
debug?: boolean;
autoPageView?: boolean;
queue?: QueueConfig | false;
}
interface QueueConfig {
eventBatchSize?: number;
flushInterval?: number;
}
<DotContentAnalytics config={analyticsConfig} />;
useContentAnalyticsinterface ContentAnalyticsHook {
pageView: (customData?: Record<string, unknown>) => void;
track: (eventName: string, properties?: Record<string, unknown>) => void;
conversion: (name: string, options?: Record<string, unknown>) => void;
}
// ✅ CORRECT: Always pass config - import from centralized config file
import { analyticsConfig } from "@/config/analytics.config";
const { pageView, track, conversion } = useContentAnalytics(analyticsConfig);
CRITICAL: The hook ALWAYS requires config as a parameter. There is no provider pattern for the hook - <DotContentAnalytics /> is only for auto pageview tracking and does NOT provide context to child components.
Always import and pass the centralized config from /config/analytics.config.js to ensure consistency.
pageView(customData?)Track a page view with optional custom data. Automatically captures page, device, UTM, and context data.
Parameters:
customData (optional): Object with custom properties to attachExample:
pageView({
contentType: "product",
category: "electronics",
});
track(eventName, properties?)Track a custom event with optional properties.
Parameters:
eventName (required): String identifier for the event (cannot be "pageview" or "conversion")properties (optional): Object with event-specific dataExample:
track("button-click", {
label: "Subscribe",
location: "sidebar",
});
conversion(name, options?)Track a conversion event (purchase, download, sign-up, etc.) with optional metadata.
⚠️ 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:
Parameters:
name (required): String identifier for the conversion (e.g., "purchase", "download", "signup")options (optional): Object with conversion metadata (all properties go into custom object)Examples:
// Basic conversion (after successful download)
conversion("download");
// Conversion with custom metadata (after successful purchase)
conversion("purchase", {
value: 99.99,
currency: "USD",
productId: "SKU-12345",
});
// Conversion with additional context (after successful signup)
conversion("signup", {
source: "homepage",
plan: "premium",
});
Centralize Configuration: Create a dedicated config file (/config/analytics.config.js) for all analytics settings
// ✅ GOOD: Centralized config file
// /config/analytics.config.js
export const analyticsConfig = {
siteAuth: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_SITE_KEY,
server: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_HOST,
debug: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_DEBUG === "true",
autoPageView: true,
};
// ❌ BAD: Inline config in multiple files
// component1.js
const config = { siteAuth: "...", server: "..." };
// component2.js
const config = { siteAuth: "...", server: "..." }; // Duplicate!
Always Import and Pass Config: The hook requires config as a parameter
// ✅ CORRECT: Import centralized config in every component
// MyComponent.js
import { analyticsConfig } from "@/config/analytics.config";
const { track } = useContentAnalytics(analyticsConfig);
// ❌ WRONG: Inline config duplication
// MyComponent.js
const { track } = useContentAnalytics({
siteAuth: "...", // Duplicated!
server: "...", // Duplicated!
});
Use DotContentAnalytics for Auto PageViews: Add to layout for automatic tracking
// layout.js - For automatic pageview tracking only
import { analyticsConfig } from "@/config/analytics.config";
<DotContentAnalytics config={analyticsConfig} />;
Environment Variables: Always use environment variables for sensitive config (siteAuth)
Event Naming: Use consistent, descriptive event names (e.g., cta-click, not just click)
Custom Data: Include relevant context in event properties
Queue Configuration: Use default queue settings unless you have specific performance needs
Debug Mode: Enable only in development, disable in production
Auto Page Views: Keep enabled for SPAs (Next.js) to track route changes
/core/core-web/libs/sdk/analytics/README.md/core/core-web/libs/sdk/analytics//core/examples/nextjs/# Install package
cd /core/examples/nextjs
npm install @dotcms/analytics
# Start Next.js dev server
npm run dev
# Build for production
npm run build
# Start production server
npm run start
# Verify installation
npm list @dotcms/analytics
Migrates VTL (Velocity Template Language) custom field templates from the legacy DotCMS Dojo/Dijit API to the modern DotCustomFieldApi. Use this skill whenever a user asks to migrate, update, or convert a VTL file, custom field template, or dotCMS field that uses any of: DotCustomFieldApi.get(), DotCustomFieldApi.set(), DotCustomFieldApi.onChangeField(), dojo.ready(), dojo.byId(), dijit.byId(), dijit.form.*, dojoType attributes, or any Dojo/Dijit pattern. Also trigger when the user pastes a VTL snippet and asks "what needs to change" or "can you update this". If in doubt, use this skill.
Use when a GitHub Actions workflow fails, PR build breaks, merge queue rejects, nightly reports failures, or user mentions CI/CD test failures in dotCMS/core. Also use for "check build", "diagnose run", "why did CI fail", "flaky test", "merge queue blocked".
Create GitHub issues using repository templates. Use when the user asks to create an issue, bug report, feature request, task, spike, epic, or UX requirement. Also use when the user describes a problem, bug, enhancement, or work item that should be tracked. Also use when the user asks to update, query, or view an existing GitHub issue. Also use when the user wants to find, search, list, or discover issues — assigned to them, open for their team, recently active, or matching a keyword. Supports both English and Spanish input.
Use when a repo skill fails, produces errors, gives wrong instructions, or references stale information. Also use when a command from a skill returns "not found" or "unknown flag", when a skill references a file path that doesn't exist, when a skill's behavior doesn't match the codebase, or to list available skills, manage local overrides, check staleness, or optimize token usage and quality.
Triage GitHub issues using the AI triage pipeline. Fetches the next issue from the "Needs Triage" project column (or a specific issue), creates an agent team to validate completeness, detect duplicates, and research the codebase in parallel, then presents a triage proposal for human approval before posting anything to GitHub.