Skip to content

Commit cdc2b98

Browse files
authored
feat: add databuddy analytics (#495)
1 parent 61ff7cf commit cdc2b98

File tree

3 files changed

+338
-0
lines changed

3 files changed

+338
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
title: Databuddy Analytics
3+
description: Use Databuddy Analytics in your Nuxt app.
4+
links:
5+
- label: Source
6+
icon: i-simple-icons-github
7+
to: https://github.com/nuxt/scripts/blob/main/src/runtime/registry/databuddy-analytics.ts
8+
size: xs
9+
---
10+
11+
[Databuddy](https://www.databuddy.cc/) is a privacy-first analytics platform focused on performance and minimal data collection.
12+
13+
Use the registry to easily inject the Databuddy CDN script with sensible defaults, or call the composable for fine-grain control.
14+
15+
## Loading Globally
16+
17+
The simplest way to enable Databuddy globally is via `nuxt.config` (or module config). You can use environment overrides to only enable in production.
18+
19+
::code-group
20+
21+
```ts [Always enabled]
22+
export default defineNuxtConfig({
23+
scripts: {
24+
registry: {
25+
databuddyAnalytics: {
26+
clientId: 'YOUR_CLIENT_ID'
27+
}
28+
}
29+
}
30+
})
31+
```
32+
33+
```ts [Production only]
34+
export default defineNuxtConfig({
35+
$production: {
36+
scripts: {
37+
registry: {
38+
databuddyAnalytics: {
39+
clientId: 'YOUR_CLIENT_ID'
40+
}
41+
}
42+
}
43+
}
44+
})
45+
```
46+
47+
```ts [Environment Variables]
48+
export default defineNuxtConfig({
49+
scripts: {
50+
registry: {
51+
databuddyAnalytics: true,
52+
}
53+
},
54+
runtimeConfig: {
55+
public: {
56+
scripts: {
57+
databuddyAnalytics: {
58+
// .env
59+
// NUXT_PUBLIC_SCRIPTS_DATABUDDY_ANALYTICS_CLIENT_ID=<your-client-id>
60+
clientId: ''
61+
},
62+
},
63+
},
64+
},
65+
})
66+
```
67+
68+
::
69+
70+
## useScriptDatabuddyAnalytics
71+
72+
The `useScriptDatabuddyAnalytics` composable gives you control over when and how Databuddy is loaded.
73+
74+
```ts
75+
const db = useScriptDatabuddyAnalytics({
76+
clientId: 'YOUR_CLIENT_ID',
77+
trackWebVitals: true,
78+
trackErrors: true,
79+
enableBatching: true,
80+
})
81+
```
82+
83+
The composable returns the script proxy (when available). You can interact with the global API via `db` or `window.db` / `window.databuddy`.
84+
85+
### CDN / Self-hosted
86+
87+
By default the registry injects `https://cdn.databuddy.cc/databuddy.js`. If you host the script yourself, pass `scriptUrl` in options to override the `src`.
88+
89+
```ts
90+
useScriptDatabuddyAnalytics({
91+
scriptInput: { src: 'https://my-host/databuddy.js' },
92+
clientId: 'YOUR_CLIENT_ID'
93+
})
94+
```
95+
96+
### DatabuddyAnalyticsApi
97+
98+
```ts
99+
export interface DatabuddyAnalyticsApi {
100+
track: (eventName: string, properties?: Record<string, any>) => Promise<any> | any | void
101+
screenView: (path?: string, properties?: Record<string, any>) => void
102+
setGlobalProperties: (properties: Record<string, any>) => void
103+
trackCustomEvent: (eventName: string, properties?: Record<string, any>) => void
104+
clear: () => void
105+
flush: () => void
106+
}
107+
```
108+
109+
### Config Schema
110+
111+
You must provide a `clientId` when configuring the registry for the first time. The registry supports a large set of Databuddy options which are passed to the script via `data-` attributes.
112+
113+
```ts
114+
export const DatabuddyAnalyticsOptions = object({
115+
clientId: string(),
116+
scriptUrl: optional(string()),
117+
apiUrl: optional(string()),
118+
disabled: optional(boolean()),
119+
trackScreenViews: optional(boolean()),
120+
trackPerformance: optional(boolean()),
121+
trackSessions: optional(boolean()),
122+
trackWebVitals: optional(boolean()),
123+
trackErrors: optional(boolean()),
124+
trackOutgoingLinks: optional(boolean()),
125+
trackScrollDepth: optional(boolean()),
126+
trackEngagement: optional(boolean()),
127+
trackInteractions: optional(boolean()),
128+
trackAttributes: optional(boolean()),
129+
trackHashChanges: optional(boolean()),
130+
trackExitIntent: optional(boolean()),
131+
trackBounceRate: optional(boolean()),
132+
enableBatching: optional(boolean()),
133+
batchSize: optional(number()),
134+
batchTimeout: optional(number()),
135+
enableRetries: optional(boolean()),
136+
maxRetries: optional(number()),
137+
initialRetryDelay: optional(number()),
138+
samplingRate: optional(number()),
139+
sdk: optional(string()),
140+
sdkVersion: optional(string()),
141+
enableObservability: optional(boolean()),
142+
observabilityService: optional(string()),
143+
observabilityEnvironment: optional(string()),
144+
observabilityVersion: optional(string()),
145+
enableLogging: optional(boolean()),
146+
enableTracing: optional(boolean()),
147+
enableErrorTracking: optional(boolean()),
148+
})
149+
```
150+
151+
## Example
152+
153+
Track a custom event using the composable proxy (noop in SSR/development):
154+
155+
::code-group
156+
157+
```vue [EventButton.vue]
158+
<script setup lang="ts">
159+
const { proxy } = useScriptDatabuddyAnalytics({ clientId: 'YOUR_CLIENT_ID' })
160+
161+
function sendEvent() {
162+
proxy?.track('signup_completed', { plan: 'pro' })
163+
}
164+
</script>
165+
166+
<template>
167+
<button @click="sendEvent">Send Event</button>
168+
</template>
169+
```

src/registry.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ export async function registry(resolve?: (path: string, opts?: ResolvePathOption
6767
from: await resolve('./runtime/registry/rybbit-analytics'),
6868
},
6969
},
70+
{
71+
label: 'Databuddy Analytics',
72+
category: 'analytics',
73+
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="56.5" height="32" viewBox="0 0 8 8" shape-rendering="crispEdges"><path d="M0 0h8v8H0z"/><path fill="#fff" d="M1 1h1v6H1zm1 0h4v1H2zm4 1h1v1H6zm0 1h1v1H6zm0 1h1v1H6zm0 1h1v1H6zM2 6h4v1H2zm1-3h1v1H3zm1 1h1v1H4z"/></svg>`,
74+
import: {
75+
name: 'useScriptDatabuddyAnalytics',
76+
from: await resolve('./runtime/registry/databuddy-analytics'),
77+
},
78+
},
7079
{
7180
label: 'Segment',
7281
scriptBundling: (options?: SegmentInput) => {
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { useRegistryScript } from '../utils'
2+
import { object, optional, string, boolean, number } from '#nuxt-scripts-validator'
3+
import type { RegistryScriptInput } from '#nuxt-scripts/types'
4+
5+
// Options schema based on https://www.databuddy.cc/docs/sdk
6+
export const DatabuddyAnalyticsOptions = object({
7+
// Required
8+
clientId: string(),
9+
10+
// Advanced
11+
scriptUrl: optional(string()), // defaults to https://cdn.databuddy.cc/databuddy.js
12+
apiUrl: optional(string()), // defaults to https://basket.databuddy.cc
13+
disabled: optional(boolean()),
14+
15+
// Core tracking (enabled by default by SDK)
16+
trackScreenViews: optional(boolean()),
17+
trackPerformance: optional(boolean()),
18+
trackSessions: optional(boolean()),
19+
20+
// Optional tracking
21+
trackWebVitals: optional(boolean()),
22+
trackErrors: optional(boolean()),
23+
trackOutgoingLinks: optional(boolean()),
24+
trackScrollDepth: optional(boolean()),
25+
trackEngagement: optional(boolean()),
26+
trackInteractions: optional(boolean()),
27+
trackAttributes: optional(boolean()),
28+
trackHashChanges: optional(boolean()),
29+
trackExitIntent: optional(boolean()),
30+
trackBounceRate: optional(boolean()),
31+
32+
// Performance options
33+
enableBatching: optional(boolean()),
34+
batchSize: optional(number()),
35+
batchTimeout: optional(number()),
36+
enableRetries: optional(boolean()),
37+
maxRetries: optional(number()),
38+
initialRetryDelay: optional(number()),
39+
samplingRate: optional(number()),
40+
41+
// SDK metadata
42+
sdk: optional(string()),
43+
sdkVersion: optional(string()),
44+
45+
// Observability & logging (accepted by SDK config)
46+
enableObservability: optional(boolean()),
47+
observabilityService: optional(string()),
48+
observabilityEnvironment: optional(string()),
49+
observabilityVersion: optional(string()),
50+
enableLogging: optional(boolean()),
51+
enableTracing: optional(boolean()),
52+
enableErrorTracking: optional(boolean()),
53+
})
54+
55+
export type DatabuddyAnalyticsInput = RegistryScriptInput<typeof DatabuddyAnalyticsOptions, false>
56+
57+
export interface DatabuddyAnalyticsApi {
58+
/**
59+
* Track a custom event.
60+
* @param eventName Name of the event (use snake_case)
61+
* @param properties Optional event properties
62+
*/
63+
track: (eventName: string, properties?: Record<string, any>) => Promise<any> | any | void
64+
65+
/**
66+
* Manually record a page / screen view. Useful for SPA route changes.
67+
* @param path Optional path to record (defaults to current location)
68+
* @param properties Optional additional properties for the screen view
69+
*/
70+
screenView: (path?: string, properties?: Record<string, any>) => void
71+
72+
/**
73+
* Set properties that will be attached to all future events (e.g. user_id).
74+
* @param properties Key/value map of properties to attach globally
75+
*/
76+
setGlobalProperties: (properties: Record<string, any>) => void
77+
78+
/**
79+
* Track a custom event alias (compatibility helper present on the global)
80+
* @param eventName Name of the event
81+
* @param properties Optional event properties
82+
*/
83+
trackCustomEvent: (eventName: string, properties?: Record<string, any>) => void
84+
85+
/**
86+
* Clears session and anonymous identifiers (useful on logout).
87+
*/
88+
clear: () => void
89+
90+
/**
91+
* Force immediate sending of any queued/batched events.
92+
*/
93+
flush: () => void
94+
}
95+
96+
declare global {
97+
interface Window {
98+
databuddy?: DatabuddyAnalyticsApi
99+
db?: DatabuddyAnalyticsApi
100+
}
101+
}
102+
103+
export function useScriptDatabuddyAnalytics<T extends DatabuddyAnalyticsApi>(_options?: DatabuddyAnalyticsInput) {
104+
return useRegistryScript<T, typeof DatabuddyAnalyticsOptions>('databuddyAnalytics', (options) => {
105+
return {
106+
scriptInput: {
107+
// Default CDN script, can be overridden via scriptUrl
108+
'src': options?.scriptUrl || 'https://cdn.databuddy.cc/databuddy.js',
109+
'data-client-id': options.clientId,
110+
// Advanced
111+
'data-api-url': options?.apiUrl,
112+
'data-disabled': options?.disabled,
113+
// Core
114+
'data-track-screen-views': options?.trackScreenViews,
115+
'data-track-performance': options?.trackPerformance,
116+
'data-track-sessions': options?.trackSessions,
117+
// Optional
118+
'data-track-web-vitals': options?.trackWebVitals,
119+
'data-track-errors': options?.trackErrors,
120+
'data-track-outgoing-links': options?.trackOutgoingLinks,
121+
'data-track-scroll-depth': options?.trackScrollDepth,
122+
'data-track-engagement': options?.trackEngagement,
123+
'data-track-interactions': options?.trackInteractions,
124+
'data-track-attributes': options?.trackAttributes,
125+
'data-track-hash-changes': options?.trackHashChanges,
126+
'data-track-exit-intent': options?.trackExitIntent,
127+
'data-track-bounce-rate': options?.trackBounceRate,
128+
// Performance tuning
129+
'data-enable-batching': options?.enableBatching,
130+
'data-batch-size': options?.batchSize,
131+
'data-batch-timeout': options?.batchTimeout,
132+
'data-enable-retries': options?.enableRetries,
133+
'data-max-retries': options?.maxRetries,
134+
'data-initial-retry-delay': options?.initialRetryDelay,
135+
'data-sampling-rate': options?.samplingRate,
136+
// SDK meta
137+
'data-sdk': options?.sdk,
138+
'data-sdk-version': options?.sdkVersion,
139+
// Observability & logging
140+
'data-enable-observability': options?.enableObservability,
141+
'data-observability-service': options?.observabilityService,
142+
'data-observability-environment': options?.observabilityEnvironment,
143+
'data-observability-version': options?.observabilityVersion,
144+
'data-enable-logging': options?.enableLogging,
145+
'data-enable-tracing': options?.enableTracing,
146+
'data-enable-error-tracking': options?.enableErrorTracking,
147+
},
148+
schema: import.meta.dev ? DatabuddyAnalyticsOptions : undefined,
149+
scriptOptions: {
150+
use() {
151+
if (typeof window === 'undefined') {
152+
return null as unknown as T
153+
}
154+
// Prefer the lightweight proxy (db) if available, else raw tracker instance
155+
return (window.db || window.databuddy || null) as unknown as T
156+
},
157+
},
158+
}
159+
}, _options)
160+
}

0 commit comments

Comments
 (0)