https://github.com/stacksjs/ts-analytics
A privacy-first analytics toolkit for web applications, powered by DynamoDB. Includes error-tracking.
https://github.com/stacksjs/ts-analytics
analytics dynamodb fathom heatmaps privacy-friendly typescript
Last synced: 21 days ago
JSON representation
A privacy-first analytics toolkit for web applications, powered by DynamoDB. Includes error-tracking.
- Host: GitHub
- URL: https://github.com/stacksjs/ts-analytics
- Owner: stacksjs
- License: mit
- Created: 2025-11-30T02:53:01.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-06-10T03:22:07.000Z (27 days ago)
- Last Synced: 2026-06-10T05:09:42.095Z (27 days ago)
- Topics: analytics, dynamodb, fathom, heatmaps, privacy-friendly, typescript
- Language: TypeScript
- Homepage: https://ts-analytics.stacksjs.com
- Size: 1.77 MB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 38
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE.md
- Code of conduct: .github/CODE_OF_CONDUCT.md
- Security: .github/SECURITY.md
Awesome Lists containing this project
README

[![npm version][npm-version-src]][npm-version-href]
[![GitHub Actions][github-actions-src]][github-actions-href]
[](http://commitizen.github.io/cz-cli/)
[![npm downloads][npm-downloads-src]][npm-downloads-href]
# @stacksjs/analytics
A privacy-first analytics toolkit for web applications, powered by DynamoDB single-table design.
## Features
- **Privacy-First**: No cookies, no personal data collection, GDPR-compliant by design
- **DynamoDB Single-Table Design**: Efficient, scalable, and cost-effective storage
- **Real-time Analytics**: Live visitor tracking and dashboard updates
- **Goal Tracking**: Define and track conversion goals
- **Vue Dashboard Components**: Ready-to-use dashboard UI components
- **Framework Agnostic**: Works with Bun, Express, Hono, AWS Lambda, and more
- **Stacks Integration**: First-class support for the Stacks framework
## Installation
```bash
bun add @stacksjs/analytics
```
## Integrate on Your Site (the 3-step recipe)
The validated pattern for adding ts-analytics to any site (docs sites included):
1. **Create a project** in the dashboard (or let the first event auto-create it), then copy the one-liner from **Settings → Installation**:
```html
```
It captures page views, SPA route changes, link & outbound clicks, engagement time, web vitals, and JS errors — no cookies, no consent banner needed.
2. **Verify** with the *Verify installation* button in Settings (fires a real event through `/collect` and confirms the round trip), or just visit your site and watch the dashboard.
3. **Optional hardening**: append `?stealth=true` for the unlisted beacon path, or serve it first-party from your own domain — see the [ad-blocker resilience guide](docs/guide/tracking-script.md#ad-blocker-resilience-first-party-proxy). Error tracking without analytics: grab the DSN + SDK snippet from the same Settings page.
## Quick Start
### 1. Set Up the Analytics Store
```typescript
import { AnalyticsStore, createAnalyticsTable } from '@stacksjs/analytics'
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
import { CreateTableCommand, DescribeTableCommand } from '@aws-sdk/client-dynamodb'
const client = new DynamoDBClient({ region: 'us-east-1' })
// Create the analytics table (one-time setup)
await createAnalyticsTable(client, {
tableName: 'my-analytics',
billingMode: 'PAY_PER_REQUEST',
}, { CreateTableCommand, DescribeTableCommand })
// Initialize the store
const store = new AnalyticsStore({
tableName: 'my-analytics',
})
```
### 2. Add the Tracking Script
```typescript
import { generateTrackingScript } from '@stacksjs/analytics'
const script = generateTrackingScript({
siteId: 'my-site-id',
endpoint: 'https://api.example.com/collect',
// Optional settings
trackPageviews: true,
trackOutboundLinks: true,
respectDoNotTrack: true,
})
// Inject into your HTML
const html = `${script}...`
```
### 3. Create API Handlers
```typescript
import { AnalyticsAPI, createBunRouter } from '@stacksjs/analytics'
const api = new AnalyticsAPI({
tableName: 'my-analytics',
siteId: 'my-site-id',
})
// For Bun
const router = createBunRouter(api, executeCommand)
// For AWS Lambda
import { createLambdaHandler } from '@stacksjs/analytics'
export const handler = createLambdaHandler(api, executeCommand)
```
## Architecture: Source of Truth
The repository has two API layers — only one is live:
| Layer | Status | Where |
|---|---|---|
| **Live server** | ✅ source of truth | `src/router.ts` + `src/handlers/*` (DynamoDB-backed), served by `server/index.ts`; jobs in `src/jobs/`, pre-aggregation in `src/lib/rollups.ts` |
| Legacy library | ⚠️ compatibility only | `src/api.ts`, `src/stacks-integration.ts`, and the in-memory `AnalyticsStore`/`AnalyticsQueryAPI`/`AggregationPipeline` classes in `src/Analytics.ts` |
New endpoints and features belong in `src/router.ts` + `src/handlers/`. The legacy layer is kept so existing imports of the published package keep compiling; it does not serve the bundled server or dashboard. (`generateTrackingScript` in `src/Analytics.ts` **is** live — it builds the served `/script.js`.)
## Core Concepts
### Analytics Store
The `AnalyticsStore` provides DynamoDB operations for all analytics entities:
```typescript
const store = new AnalyticsStore({
tableName: 'analytics',
useTtl: true,
rawEventTtl: 30 _ 24 _ 60 * 60, // 30 days
})
// Create a site
const siteCommand = store.createSiteCommand({
id: 'site-123',
name: 'My Website',
domains: ['example.com'],
ownerId: 'user-456',
})
// Record a page view
const pvCommand = store.recordPageViewCommand({
id: 'pv-789',
siteId: 'site-123',
path: '/blog/hello-world',
visitorId: 'visitor-hash',
sessionId: 'session-abc',
timestamp: new Date(),
})
```
### Aggregation Pipeline
Pre-compute statistics for fast dashboard queries:
```typescript
import { AggregationPipeline, AnalyticsAggregator } from '@stacksjs/analytics'
const pipeline = new AggregationPipeline({
tableName: 'analytics',
})
// Run hourly aggregation
const aggregator = new AnalyticsAggregator({
tableName: 'analytics',
})
await aggregator.aggregateHourly('site-123', new Date())
```
### Query API
Fetch analytics data for dashboards:
```typescript
import { AnalyticsQueryAPI } from '@stacksjs/analytics'
const queryApi = new AnalyticsQueryAPI({
tableName: 'analytics',
})
// Generate dashboard queries
const queries = queryApi.generateDashboardQueries({
siteId: 'site-123',
dateRange: { start: new Date('2024-01-01'), end: new Date() },
})
```
### Goal Tracking
Define and track conversion goals:
```typescript
import { GoalMatcher } from '@stacksjs/analytics'
const goals = [
{ id: 'signup', type: 'pageview', pattern: '/signup/complete', matchType: 'exact' },
{ id: 'purchase', type: 'event', pattern: 'purchase', matchType: 'exact' },
]
const matcher = new GoalMatcher(goals)
// Check if a page view matches any goals
const matches = matcher.matchPageView('/signup/complete')
// => [{ goalId: 'signup', value: undefined }]
```
## Dashboard Components
Vue 3 components for building analytics dashboards:
```vue
import {
AnalyticsDashboard,
StatCard,
TimeSeriesChart,
TopList,
DeviceBreakdown,
RealtimeCounter,
DateRangePicker,
} from '@stacksjs/analytics'
```
### Composables
```typescript
import { createAnalyticsComposable, fetchDashboardData } from '@stacksjs/analytics'
// Create a composable for Vue
const analytics = createAnalyticsComposable({
baseUrl: '/api/analytics',
siteId: 'my-site',
})
// Or fetch data directly
const data = await fetchDashboardData(
{ baseUrl: '/api/analytics', siteId: 'my-site' },
{ startDate: new Date('2024-01-01'), endDate: new Date() }
)
```
## Stacks Framework Integration
First-class integration with the Stacks framework:
```typescript
import { createAnalyticsDriver, createAnalyticsMiddleware } from '@stacksjs/analytics'
// Create the driver
const driver = await createAnalyticsDriver({
tableName: 'analytics',
siteId: 'my-site',
region: 'us-east-1',
})
// Add tracking middleware
app.use(createAnalyticsMiddleware(driver))
// Server-side tracking
app.use(createServerTrackingMiddleware(driver, {
excludedPaths: [/^\/api/, /^\/admin/],
}))
// Dashboard actions
const actions = createDashboardActions(driver)
const stats = await actions.getDashboardStats({ startDate: '2024-01-01' })
```
## Infrastructure
Generate infrastructure code for deployment:
```typescript
import {
generateCloudFormationTemplate,
generateCdkCode,
generateSamTemplate,
generateAwsCliCommands,
} from '@stacksjs/analytics'
// CloudFormation
const cfn = generateCloudFormationTemplate({ tableName: 'analytics' })
// AWS CDK
const cdk = generateCdkCode({ tableName: 'analytics' })
// SAM
const sam = generateSamTemplate({ tableName: 'analytics' })
// AWS CLI commands
const cli = generateAwsCliCommands({ tableName: 'analytics' })
```
## Models
Stacks-compatible model definitions for all analytics entities:
```typescript
import {
SiteModel,
PageViewModel,
SessionModel,
CustomEventModel,
GoalModel,
AggregatedStatsModel,
// ... and more
} from '@stacksjs/analytics'
```
## Testing
```bash
bun test
```
## Changelog
Please see our [releases](https://github.com/stacksjs/analytics/releases) page for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.
## Community
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
[Discussions on GitHub](https://github.com/stacksjs/stacks/discussions)
For casual chit-chat with others using this package:
[Join the Stacks Discord Server](https://discord.gg/stacksjs)
## Postcardware
Stacks OSS will always stay open-sourced, and we will always love to receive postcards from wherever Stacks is used! _And we also determine the OSS dependencies we utilize._
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, USA
## Sponsors
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
- [JetBrains](https://www.jetbrains.com/)
- [The Solana Foundation](https://solana.com/)
## License
The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.
Made with love by [Chris Breuer](https://github.com/chrisbbreuer) and [contributors](https://github.com/stacksjs/analytics/graphs/contributors).
[npm-version-src]: https://img.shields.io/npm/v/@stacksjs/analytics?style=flat-square
[npm-version-href]: https://npmjs.com/package/@stacksjs/analytics
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/analytics/ci.yml?style=flat-square&branch=main
[github-actions-href]: https://github.com/stacksjs/analytics/actions?query=workflow%3Aci
[npm-downloads-src]: https://img.shields.io/npm/dm/@stacksjs/analytics?style=flat-square
[npm-downloads-href]: https://npmjs.com/package/@stacksjs/analytics