Skip to content
Back to skills

Stacks Analytics

ASecurity

Use when adding analytics to a Stacks application - configuring Fathom, Plausible, Google Analytics or self-hosted analytics, generating tracking scripts, privacy-friendly analytics setup, or the analytics configuration. Covers @stacksjs/analytics and config/analytics.ts.

  • 631 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 5, 2026
developmenttypescriptgobashapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add stacksjs/stacks --skill stacks-analytics --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Stacks Analytics?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Stacks Analytics
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/stacksjs-stacks-analytics/badge)](https://www.skillsdirectory.com/skills/stacksjs-stacks-analytics)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: stacks-analytics
description: Use when adding analytics to a Stacks application - configuring Fathom, Plausible, Google Analytics or self-hosted analytics, generating tracking scripts, privacy-friendly analytics setup, or the analytics configuration. Covers @stacksjs/analytics and config/analytics.ts.
license: MIT
compatibility: Bun >= 1.3.0, TypeScript
allowed-tools: Read Edit Write Bash Grep Glob
---

# Stacks Analytics

Privacy-friendly analytics with four drivers: Fathom, Plausible, Google Analytics
and self-hosted.

## Key Paths
- Core package: `storage/framework/core/analytics/src/`
- Drivers: `storage/framework/core/analytics/src/drivers/`
- Registry (dispatch on the configured driver): `storage/framework/core/analytics/src/registry.ts`
- Configuration: `config/analytics.ts`

## Driver registry

Read `config/analytics.ts` and render the driver it names. This is the entry
point; reach for an individual driver only when you need one specific script
regardless of config.

```typescript
import { generateAnalyticsScript, getAnalyticsHead } from '@stacksjs/analytics'
import { analytics } from '@stacksjs/config'

// HTML you can drop into a layout <head>
const script = generateAnalyticsScript(analytics)

// Or the [tag, attributes] pairs a docs `head` array takes
const head = getAnalyticsHead(analytics)
```

The registry is loud on purpose. A `driver` value with no implementation throws,
and so does a selected third-party driver missing its config (the message names
the exact key to set). An app with no `driver` defaults to AnalyticsHQ. It emits
nothing until `drivers.analyticshq.siteId` is set.

Nothing injects the script for you - a framework that silently posted pageviews
to a third party would be the wrong default. Render it yourself in the layout
that should carry it.

## Drivers

### Fathom
Hosted, cookie-free, GDPR-compliant. Requires a Fathom account.
`scriptUrl` points the tag at your own origin so a content blocker does not drop it.

```typescript
import { generateFathomScript } from '@stacksjs/analytics'

generateFathomScript({
  siteId: 'ABCDEFGH',
  honorDnt: true,      // -> data-honor-dnt="true"
  spa: true,           // -> data-spa="auto"
  scriptUrl: undefined, // defaults to Fathom's CDN
})
```

### Plausible
Cookie-free, hosted or self-hosted. `hashMode` and `trackLocalhost` pick the
script variant (`script.hash.js`, `script.local.js`); `scriptUrl` overrides the
computed URL entirely, which is how you point at a self-hosted install.

```typescript
import { generatePlausibleScript } from '@stacksjs/analytics'

generatePlausibleScript({ domain: 'example.com', hashMode: true })
```

### Google Analytics
GA4 via gtag.js. Emits the loader plus the inline `js` / `config` bootstrap;
`debug: true` sets `debug_mode` so the property shows up in DebugView.

```typescript
import { generateGoogleAnalyticsScript } from '@stacksjs/analytics'

generateGoogleAnalyticsScript({ trackingId: 'G-XXXXXXXXXX', debug: false })
```

### Self-Hosted
A small first-party tracker that POSTs to your own endpoint.

```typescript
import { generateSelfHostedScript, getSelfHostedAnalyticsHead } from '@stacksjs/analytics'

const script = generateSelfHostedScript({
  siteId: 'ABCDEF',
  apiEndpoint: 'https://analytics.myapp.com/api/event',
  honorDnt: true,                // respect Do Not Track
  trackHashChanges: false,       // track hash URL changes
  trackOutboundLinks: true       // track external link clicks
})

const headConfig = getSelfHostedAnalyticsHead({
  siteId: 'ABCDEF',
  apiEndpoint: 'https://analytics.myapp.com/api/event'
})
```

## Driver config interfaces

```typescript
interface FathomConfig {
  siteId: string                  // Fathom site ID
  scriptUrl?: string              // serve the script first-party
  honorDnt?: boolean              // respect Do Not Track
  spa?: boolean                   // re-record pageviews on client routing
}

interface PlausibleConfig {
  domain: string                  // the site's domain
  scriptUrl?: string              // self-hosted Plausible or a proxy
  trackLocalhost?: boolean        // keep localhost pageviews
  hashMode?: boolean              // count hash routes
}

interface GoogleAnalyticsConfig {
  trackingId: string              // GA4 measurement ID
  debug?: boolean                 // debug_mode -> DebugView
}

interface AnalyticsHqConfig {
  siteId: string                  // the data-site id AnalyticsHQ minted
  scriptUrl?: string              // self-hosted instance or verified custom domain
  respectDnt?: boolean            // false counts DNT/GPC visitors (skipped by default)
  vitals?: boolean                // false stops Core Web Vitals beacons
}

interface SelfHostedConfig {
  siteId: string                  // unique site identifier
  apiEndpoint: string             // analytics API URL
  honorDnt?: boolean              // respect Do Not Track header
  trackHashChanges?: boolean      // track SPA hash navigation
  trackOutboundLinks?: boolean    // track clicks to external sites
}
```

## config/analytics.ts

```typescript
{
  driver: 'analyticshq',         // 'analyticshq' | 'fathom' | 'plausible' | 'google-analytics' | 'self-hosted'
  drivers: {
    analyticshq: { siteId: '' }, // empty means no tracking tags
    googleAnalytics: { trackingId: '' },
    fathom: { siteId: '' },
    plausible: { domain: '' },
    selfHosted: { siteId: '', apiEndpoint: '' },
  }
}
```

## First-party pageview capture

Separate from the drivers, and no script at all: `capturePageviews: true` has the
stx servers record page GETs into `analytics_events`, which is what feeds the
native `/analytics/pages`, `/referrers` and `/devices` dashboards.

## Dashboard Integration

Analytics dashboard at `/dashboard/analytics` displays:
- Page views and visitor counts
- Traffic sources
- Popular pages
- Engagement metrics

## Gotchas
- Selecting a driver does not inject anything - call `generateAnalyticsScript()` in your layout
- A misconfigured third-party driver throws rather than emitting nothing; the message names the config key
- AnalyticsHQ is the first-party default and emits nothing until its site id is set
- `honorDnt: true` respects browser Do Not Track settings
- Attribute values are escaped, and inline script values are JS-escaped, to prevent XSS
- Fathom is a paid service - self-hosted is free but requires infrastructure
- `trackOutboundLinks` adds click handlers to external `<a>` tags
- `capturePageviews` is server-side and independent of `driver`
- AnalyticsHQ custom events need no script: `data-analyticshq-event="Ticket click"` on any element, with other `data-analyticshq-*` attributes as properties

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.