Skip to content

Commit 4d04e24

Browse files
committed
fix(tracker): reject unsafe URLs and align docs
1 parent 8868360 commit 4d04e24

8 files changed

Lines changed: 61 additions & 11 deletions

File tree

apps/docs/content/docs/Integrations/gtm.mdx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,7 @@ Send GTM data layer events to Databuddy:
166166

167167
## Triggers Configuration
168168

169-
### Page View Tracking
170-
171-
Create a trigger for enhanced page views:
172-
173-
1. **Trigger Type**: Page View - DOM Ready
174-
2. **Trigger Name**: "Databuddy - Enhanced Page View"
175-
3. **Conditions**: Page Path contains your domain
169+
The analytics script records pageviews automatically, including SPA navigation. Use the **All Pages** trigger only to load the script; do not add a second pageview tag.
176170

177171
### Scroll Tracking
178172

apps/docs/content/docs/sdk/configuration.mdx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This page documents all configuration options across the Databuddy SDK platforms
2121
scriptUrl="https://cdn.databuddy.cc/databuddy.js"
2222
2323
// Core tracking
24-
trackWebVitals // default: false
24+
trackWebVitals={true} // opt in; default: false
2525
trackErrors // default: false
2626
trackOutgoingLinks // default: false
2727
trackInteractions // default: false
@@ -65,13 +65,17 @@ This page documents all configuration options across the Databuddy SDK platforms
6565

6666
| Prop | Type | Default | Description |
6767
|------|------|---------|-------------|
68-
| `trackWebVitals` | `boolean` | `false` | Core Web Vitals (LCP, INP, CLS, TTFB) |
68+
| `trackWebVitals` | `boolean` | `false` | FCP, LCP, INP, CLS, TTFB, and FPS |
6969
| `trackErrors` | `boolean` | `false` | JavaScript errors |
7070
| `trackOutgoingLinks` | `boolean` | `false` | External link clicks |
7171
| `trackInteractions` | `boolean` | `false` | Button clicks and form submissions |
7272
| `trackAttributes` | `boolean` | `false` | Elements with `data-track` attributes |
7373
| `trackHashChanges` | `boolean` | `false` | URL hash changes |
7474

75+
<Callout type="info">
76+
Use `trackWebVitals` in React, Vue, and Nuxt, or `data-track-web-vitals` with the CDN script. The older `trackPerformance` option remains a deprecated compatibility alias; `trackWebVitals` takes precedence when both are set.
77+
</Callout>
78+
7579
#### Batching & Performance
7680

7781
| Prop | Type | Default | Description |
@@ -139,7 +143,7 @@ Vue uses the same props as React but with kebab-case naming:
139143
| Attribute | Type | Default | Description |
140144
|-----------|------|---------|-------------|
141145
| `data-client-id` | `string` | Required | Your client ID |
142-
| `data-track-web-vitals` | flag | `false` | Track page performance and Core Web Vitals |
146+
| `data-track-web-vitals` | flag | `false` | FCP, LCP, INP, CLS, TTFB, and FPS |
143147
| `data-track-errors` | flag | `false` | Track JavaScript errors |
144148
| `data-track-outgoing-links` | flag | `false` | Track external links |
145149
| `data-track-interactions` | flag | `false` | Track interactions |

apps/docs/content/docs/sdk/nuxt.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ All options are passed under the `databuddy` key in `nuxt.config.ts`:
148148
| `clientId` | `string` || Your Databuddy client ID |
149149
| `disabled` | `boolean` | `false` | Disable all tracking |
150150
| `debug` | `boolean` | `false` | Enable verbose logging |
151-
| `trackWebVitals` | `boolean` | `false` | Core Web Vitals (LCP, CLS, TTFB) |
151+
| `trackWebVitals` | `boolean` | `false` | Core Web Vitals (LCP, INP, CLS, TTFB) |
152152
| `trackErrors` | `boolean` | `false` | JS errors + Vue component errors |
153153
| `trackOutgoingLinks` | `boolean` | `false` | Clicks on external links |
154154
| `trackInteractions` | `boolean` | `false` | Button clicks and form submissions |
@@ -158,6 +158,10 @@ All options are passed under the `databuddy` key in `nuxt.config.ts`:
158158
| `samplingRate` | `number` | `1.0` | Event sampling rate (0.0–1.0) |
159159
| `flags` | `FlagsConfig` || Feature flag configuration |
160160

161+
<Callout type="info" title="Renamed from trackPerformance">
162+
`trackPerformance` still works as a deprecated compatibility alias. Rename it to `trackWebVitals`; if both are set, `trackWebVitals` takes precedence.
163+
</Callout>
164+
161165
## Privacy
162166

163167
<CodeBlock language="ts" filename="nuxt.config.ts">

apps/docs/lib/public-copy-contract.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,40 @@ describe("public copy contracts", () => {
2323
expect(publicDocs).not.toContain("trackSessions=");
2424
});
2525

26+
it("lists every performance metric collected by trackWebVitals", async () => {
27+
const configuration = await readFile(
28+
join(
29+
import.meta.dir,
30+
"..",
31+
"content",
32+
"docs",
33+
"sdk",
34+
"configuration.mdx"
35+
),
36+
"utf8"
37+
);
38+
const vitalsPlugin = await readFile(
39+
join(
40+
import.meta.dir,
41+
"..",
42+
"..",
43+
"..",
44+
"packages",
45+
"tracker",
46+
"src",
47+
"plugins",
48+
"vitals.ts"
49+
),
50+
"utf8"
51+
);
52+
const description = "FCP, LCP, INP, CLS, TTFB, and FPS";
53+
54+
expect(configuration.split(description)).toHaveLength(3);
55+
for (const metric of ["FCP", "LCP", "INP", "CLS", "TTFB", "FPS"]) {
56+
expect(vitalsPlugin).toContain(`on${metric}(handleMetric)`);
57+
}
58+
});
59+
2660
it("keeps the tracker-size claim aligned with the checked-in bundle", async () => {
2761
const bundle = await readFile(
2862
join(

apps/docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
},
9292
"devDependencies": {
9393
"@biomejs/biome": "2.5.1",
94+
"@databuddy/tracker": "workspace:*",
9495
"@tailwindcss/postcss": "^4.2.2",
9596
"@types/d3": "^7.4.3",
9697
"@types/d3-geo": "^3.1.0",

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/tracker/src/core/utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ export function sanitizePageUrl(value: string): string {
7575
}
7676
try {
7777
const url = new URL(value);
78+
if (!(url.protocol === "http:" || url.protocol === "https:")) {
79+
return "";
80+
}
7881
return `${url.origin}${url.pathname}`;
7982
} catch {
8083
return "";

packages/tracker/tests/unit/utils.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ describe("privacy-safe page context", () => {
123123
).toBe("https://referrer.example/path");
124124
});
125125

126+
test("only accepts HTTP page and referrer URLs", () => {
127+
expect(sanitizePageUrl("http://example.com/path?secret=value")).toBe(
128+
"http://example.com/path"
129+
);
130+
expect(sanitizePageUrl("javascript:alert(1)")).toBe("");
131+
expect(sanitizePageUrl("data:text/plain,private")).toBe("");
132+
expect(sanitizePageUrl("file:///tmp/private.txt")).toBe("");
133+
});
134+
126135
test("honors Global Privacy Control", () => {
127136
Object.defineProperty(globalThis, "window", {
128137
configurable: true,

0 commit comments

Comments
 (0)