This document is designed to be consumed by AI coding assistants. It provides complete technical specifications for integrating CAnalytics into web projects.
CAnalytics is a privacy-first web analytics service. It tracks pageviews, custom events, and JavaScript errors without cookies, personal data collection, or GDPR consent requirements.
https://analytics.cloudlineconsulting.com/ctag.js
Add the following script tag inside the <head> element. The user must replace C-YOUR_API_KEY with their actual API key obtained from the CAnalytics dashboard.
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
></script>
All configuration is done via data attributes on the script tag.
| Attribute | Required | Default | Description |
|---|---|---|---|
data-key |
Yes | — | CTag API key. Format: C- followed by 20 lowercase alphanumeric characters (total 22 characters). |
data-auto |
No | "true" |
When "true": tracks initial pageview on load + all SPA navigation (pushState, replaceState, popstate). Set to "false" to disable all automatic tracking. |
data-errors |
No | "true" |
When "true": captures uncaught JavaScript errors and unhandled promise rejections. Set to "false" to disable. |
data-userid |
No | — | Custom user ID to associate with events. When set, replaces the auto-generated anonymous ID (anon-*). Use for logged-in users. |
pageview event immediately when script initializes.history.pushState and history.replaceState to track pageviews on each call.popstate event to track browser back/forward navigation.This covers all single-page application (SPA) frameworks without additional configuration.
No automatic pageview tracking occurs. Use window.ctag.pageview() and window.ctag.track() manually.
window.error event for uncaught exceptions.unhandledrejection event for promise rejections."error" containing message, filename, line number, column number, and stack trace (truncated to 1000 characters).The script exposes a global window.ctag object with two methods:
Manually track a pageview. Use when data-auto="false" or for custom navigation scenarios.
window.ctag.pageview();
Associate events with a known user. Call after user login. Replaces the anonymous ID with the provided user ID for all subsequent events. Also persists to localStorage.
// After user authenticates
window.ctag.identify('user_12345');
// All subsequent events will use 'user_12345' as userId instead of 'anon-*'
Alternative: Set data-userid="user_12345" on the script tag if the user ID is known at page load.
Track a custom event with optional properties object.
// Event without properties
window.ctag.track('signup');
// Event with properties
window.ctag.track('purchase', {
orderId: 'ORD-12345',
total: 99.99,
currency: 'USD'
});
// Button click tracking
window.ctag.track('click', { button: 'cta_header', location: 'homepage' });
// Form submission
window.ctag.track('form_submit', { form: 'contact', success: true });
For TypeScript projects, add this declaration:
declare global {
interface Window {
ctag: {
track: (eventType: string, props?: Record<string, unknown>) => void;
pageview: () => void;
identify: (userId: string) => void;
};
}
}
Every event (pageview, custom, error) automatically includes:
| Field | Type | Description |
|---|---|---|
type |
string | Event type: "pageview", "error", or custom event name |
url |
string | Full URL including protocol, domain, path, and query string |
path |
string | URL pathname only (e.g., /products/123) |
domain |
string | Hostname extracted from URL |
referrer |
string | Document referrer (previous page URL) |
sessionId |
string | 16-character session identifier. Stored in localStorage. Expires after 30 minutes of inactivity. |
userId |
string | Anonymous visitor ID prefixed with anon-. Stored in localStorage. Persists for 1 year. |
timestamp |
string | ISO 8601 format (e.g., 2026-02-02T15:30:00.000Z) |
isLocal |
boolean | true if hostname is localhost, 127.0.0.1, *.localhost, *.local, or file:// protocol |
queryParams |
object | All URL query parameters as key-value pairs. Includes UTM tags. |
custom |
object | Custom properties passed to track(). Omitted if empty. |
<!DOCTYPE html>
<html>
<head>
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
></script>
</head>
<body>
<button onclick="ctag.track('click', { button: 'demo' })">Track Click</button>
</body>
</html>
File: app/layout.tsx
import Script from 'next/script';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
<Script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
strategy="afterInteractive"
/>
</head>
<body>{children}</body>
</html>
);
}
File: pages/_app.tsx
import Script from 'next/script';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
strategy="afterInteractive"
/>
<Component {...pageProps} />
</>
);
}
File: index.html
<!DOCTYPE html>
<html>
<head>
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
File: index.html
<!DOCTYPE html>
<html>
<head>
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
In layout component:
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
is:inline
></script>
File: src/app.html
<!DOCTYPE html>
<html>
<head>
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
async
></script>
%sveltekit.head%
</head>
<body>
<div>%sveltekit.body%</div>
</body>
</html>
To disable all automatic tracking and use only manual track() calls:
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
data-auto="false"
async
></script>
Then call manually:
// Track pageview when ready
window.ctag.pageview();
// Track custom events
window.ctag.track('user_action', { action: 'specific' });
<script
src="https://analytics.cloudlineconsulting.com/ctag.js"
data-key="C-YOUR_API_KEY"
data-errors="false"
async
></script>
When an error is captured, the custom field contains:
| Field | Description |
|---|---|
message |
Error message string |
filename |
Source file URL where error occurred |
lineno |
Line number |
colno |
Column number |
stack |
Stack trace (max 1000 characters) |
type |
"unhandledrejection" for promise rejections, absent for regular errors |
POST{script_origin}/api/collect (derived from script src attribute)Content-Type: application/json, x-api-key: {data-key value}fetch() with keepalive: true to survive page unloadsctag_sid: Session ID in localStoragectag_sts: Session timestamp in localStorage (for 30-minute inactivity timeout)ctag_uid: Visitor ID in localStorage16-character alphanumeric string generated using crypto.getRandomValues().
All errors are silently caught. The script never throws exceptions or breaks page functionality.
The API key is bound to allowed domains configured in the CAnalytics dashboard. Requests from non-whitelisted domains receive HTTP 403 Forbidden. The user must add their domain(s) to the CTag configuration.
Common domains to add:
example.com and www.example.com for productionstaging.example.com for staginglocalhost for local developmentBefore integration, the user must:
C- followed by 20 lowercase alphanumeric characters)Dashboard URL: https://analytics.cloudlineconsulting.com/