@m13v/seo-components 0.31.2 → 0.31.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/track.ts +35 -0
package/package.json
CHANGED
package/src/lib/track.ts
CHANGED
|
@@ -8,6 +8,38 @@
|
|
|
8
8
|
|
|
9
9
|
import { captureFromWindow } from "./analytics-context";
|
|
10
10
|
|
|
11
|
+
// Rage-click dedup window. A real visitor revisiting the page later still
|
|
12
|
+
// records; only same-event+same-destination+same-page firings within this
|
|
13
|
+
// window collapse to one. 2026-05-03: claude-meter.com had 11 reported
|
|
14
|
+
// `get_started_click` events in 24h that were actually 2 unique users
|
|
15
|
+
// rage-mashing the install button (5-6 clicks within 4-14s each). Dedup
|
|
16
|
+
// at the helper layer catches every callsite (GetStartedCTA, InlineCta,
|
|
17
|
+
// StickyBottomCta, InstallEmailGate, ClaudeMeterCta, BookCallCTA,
|
|
18
|
+
// SiteNavbar, and any custom caller in consumer sites).
|
|
19
|
+
const _DEDUP_WINDOW_MS = 1500;
|
|
20
|
+
const _lastFire = new Map<string, number>();
|
|
21
|
+
|
|
22
|
+
function _shouldSuppressRecent(key: string, windowMs = _DEDUP_WINDOW_MS): boolean {
|
|
23
|
+
if (typeof window === "undefined") return false;
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
const last = _lastFire.get(key);
|
|
26
|
+
if (last != null && now - last < windowMs) return true;
|
|
27
|
+
_lastFire.set(key, now);
|
|
28
|
+
// Keep the map from growing unbounded on long-lived SPAs.
|
|
29
|
+
if (_lastFire.size > 256) {
|
|
30
|
+
const cutoff = now - 60_000;
|
|
31
|
+
for (const [k, t] of _lastFire) {
|
|
32
|
+
if (t < cutoff) _lastFire.delete(k);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _dedupKey(event: string, destination: string | undefined): string {
|
|
39
|
+
const page = typeof window !== "undefined" ? window.location.pathname : "";
|
|
40
|
+
return event + "::" + (destination || "") + "::" + page;
|
|
41
|
+
}
|
|
42
|
+
|
|
11
43
|
/**
|
|
12
44
|
* Rewrite a booking URL (Cal.com, Calendly, etc.) so the booking webhook can
|
|
13
45
|
* attribute the booking back to the specific landing page it came from.
|
|
@@ -81,6 +113,7 @@ export interface ScheduleClickProps {
|
|
|
81
113
|
*/
|
|
82
114
|
export function trackScheduleClick(props: ScheduleClickProps): void {
|
|
83
115
|
const { destination, site, section, text, component, extra } = props;
|
|
116
|
+
if (_shouldSuppressRecent(_dedupKey("schedule_click", destination))) return;
|
|
84
117
|
captureFromWindow("schedule_click", {
|
|
85
118
|
...(extra || {}),
|
|
86
119
|
destination,
|
|
@@ -119,6 +152,7 @@ export interface GetStartedClickProps {
|
|
|
119
152
|
*/
|
|
120
153
|
export function trackGetStartedClick(props: GetStartedClickProps): void {
|
|
121
154
|
const { destination, site, section, text, component, extra } = props;
|
|
155
|
+
if (_shouldSuppressRecent(_dedupKey("get_started_click", destination))) return;
|
|
122
156
|
captureFromWindow("get_started_click", {
|
|
123
157
|
...(extra || {}),
|
|
124
158
|
destination,
|
|
@@ -176,6 +210,7 @@ export interface CrossProductClickProps {
|
|
|
176
210
|
*/
|
|
177
211
|
export function trackCrossProductClick(props: CrossProductClickProps): void {
|
|
178
212
|
const { destination, site, targetProduct, section, text, component, extra } = props;
|
|
213
|
+
if (_shouldSuppressRecent(_dedupKey("cross_product_click", destination))) return;
|
|
179
214
|
captureFromWindow("cross_product_click", {
|
|
180
215
|
...(extra || {}),
|
|
181
216
|
destination,
|