@pageviews/tracker 0.1.0 → 0.2.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/README.md +145 -0
- package/dist/module/index.cjs +37 -8
- package/dist/module/index.mjs +37 -8
- package/package.json +2 -2
- package/dist/tracker.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @pageviews/tracker
|
|
2
|
+
|
|
3
|
+
The official JavaScript SDK for [Pageviews.ai](https://pageviews.ai) — a lightweight, cookie-free analytics platform built for privacy.
|
|
4
|
+
|
|
5
|
+
Use this package to add analytics to React, Vue, Next.js, or any other JavaScript framework with full programmatic control over pageview and event tracking.
|
|
6
|
+
|
|
7
|
+
> For simple script tag installation (no build step), see the [Script Tag guide](https://pageviews.ai/docs) instead.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Cookie-free and GDPR-compliant — no consent banner required
|
|
12
|
+
- Automatic pageview tracking for SPAs (React Router, Vue Router, Next.js App Router)
|
|
13
|
+
- Custom event tracking with properties and revenue data
|
|
14
|
+
- Engagement tracking — active time and scroll depth per page
|
|
15
|
+
- Auto-tracking for outbound links, file downloads, and form submissions
|
|
16
|
+
- Realtime User Explorer via `identify()`
|
|
17
|
+
- Full TypeScript support
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @pageviews/tracker
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { init, track, identify } from '@pageviews/tracker'
|
|
29
|
+
|
|
30
|
+
// Initialize once at your app's entry point
|
|
31
|
+
await init({ siteId: 'your-site-id' })
|
|
32
|
+
|
|
33
|
+
// Track custom events
|
|
34
|
+
track('signup', { props: { plan: 'pro' } })
|
|
35
|
+
|
|
36
|
+
// Identify a logged-in user for the Realtime User Explorer
|
|
37
|
+
identify({ userId: 'user-123' })
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Your site ID is available in the Pageviews dashboard under **Settings → Tracking**.
|
|
41
|
+
|
|
42
|
+
## Framework Examples
|
|
43
|
+
|
|
44
|
+
### Next.js (App Router)
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// app/providers.tsx
|
|
48
|
+
'use client'
|
|
49
|
+
|
|
50
|
+
import { useEffect } from 'react'
|
|
51
|
+
import { init, destroy } from '@pageviews/tracker'
|
|
52
|
+
|
|
53
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
init({ siteId: 'your-site-id' })
|
|
56
|
+
return () => destroy()
|
|
57
|
+
}, [])
|
|
58
|
+
|
|
59
|
+
return <>{children}</>
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### React
|
|
64
|
+
|
|
65
|
+
```jsx
|
|
66
|
+
// Entry point or layout component
|
|
67
|
+
import { useEffect } from 'react'
|
|
68
|
+
import { init, destroy } from '@pageviews/tracker'
|
|
69
|
+
|
|
70
|
+
export function AnalyticsProvider({ children, siteId }) {
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
init({ siteId })
|
|
73
|
+
return () => destroy()
|
|
74
|
+
}, [siteId])
|
|
75
|
+
|
|
76
|
+
return children
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Vue
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
// main.js
|
|
84
|
+
import { init } from '@pageviews/tracker'
|
|
85
|
+
|
|
86
|
+
init({ siteId: 'your-site-id' })
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
### `init(options): Promise<void>`
|
|
92
|
+
|
|
93
|
+
Initializes the tracker. Call once at your app's entry point.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
await init({
|
|
97
|
+
siteId: 'your-site-id', // required — from your Pageviews dashboard
|
|
98
|
+
endpoint?: string, // optional — custom ingest URL (self-hosted / proxy)
|
|
99
|
+
configEndpoint?: string, // optional — custom config URL
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
On init, site configuration (routing mode, auto-tracking rules, scroll goals) is fetched from the Pageviews API and cached in `localStorage` for 1 hour.
|
|
104
|
+
|
|
105
|
+
### `track(eventName, options?): void`
|
|
106
|
+
|
|
107
|
+
Sends a custom event.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
track('purchase', {
|
|
111
|
+
props: { plan: 'pro', annual: true },
|
|
112
|
+
revenue: { amount: 49, currency: 'USD' },
|
|
113
|
+
callback: (result) => console.log(result),
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `identify(data): void`
|
|
118
|
+
|
|
119
|
+
Associates a user identifier with the current session. Appears in the Realtime User Explorer in the dashboard. **Not persisted to the database** — stored in memory only for the duration of the session.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
identify({ userId: 'user-123' })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `destroy(): void`
|
|
126
|
+
|
|
127
|
+
Stops all tracking and resets state. Useful for SPA cleanup or testing. `init()` can be called again after `destroy()`.
|
|
128
|
+
|
|
129
|
+
## Privacy
|
|
130
|
+
|
|
131
|
+
- No cookies or persistent browser identifiers set
|
|
132
|
+
- Query parameters containing potential PII are stripped from URLs before sending — only UTM parameters and `ref` are kept
|
|
133
|
+
- Referrer query strings are stripped entirely — only the domain and path are sent
|
|
134
|
+
- IP addresses are hashed server-side with a daily-rotating salt and never stored in raw form
|
|
135
|
+
- No cross-site tracking
|
|
136
|
+
|
|
137
|
+
## Full Documentation
|
|
138
|
+
|
|
139
|
+
For configuration options, advanced usage, and the script tag installation method, see the full docs:
|
|
140
|
+
|
|
141
|
+
**[pageviews.ai/docs/npm-module-at-pageviewstracker](https://pageviews.ai/docs/npm-module-at-pageviewstracker)**
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
MIT
|
package/dist/module/index.cjs
CHANGED
|
@@ -35,6 +35,35 @@ function sendBeaconEvent(endpoint, payload, siteId) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// src/core/utils.ts
|
|
38
|
+
const ALLOWED_QUERY_PARAMS = new Set([
|
|
39
|
+
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref',
|
|
40
|
+
]);
|
|
41
|
+
function sanitizeUrl(url) {
|
|
42
|
+
try {
|
|
43
|
+
const u = new URL(url);
|
|
44
|
+
const toDelete = [];
|
|
45
|
+
u.searchParams.forEach((_, key) => {
|
|
46
|
+
if (!ALLOWED_QUERY_PARAMS.has(key))
|
|
47
|
+
toDelete.push(key);
|
|
48
|
+
});
|
|
49
|
+
toDelete.forEach(key => u.searchParams.delete(key));
|
|
50
|
+
return u.toString();
|
|
51
|
+
}
|
|
52
|
+
catch (_a) {
|
|
53
|
+
return url;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function sanitizeReferrer(referrer) {
|
|
57
|
+
if (!referrer)
|
|
58
|
+
return referrer;
|
|
59
|
+
try {
|
|
60
|
+
const u = new URL(referrer);
|
|
61
|
+
return u.origin + u.pathname;
|
|
62
|
+
}
|
|
63
|
+
catch (_a) {
|
|
64
|
+
return referrer;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
38
67
|
function getScreenSize() {
|
|
39
68
|
return `${window.innerWidth}x${window.innerHeight}`;
|
|
40
69
|
}
|
|
@@ -75,8 +104,8 @@ function createTracker(config) {
|
|
|
75
104
|
const payload = {
|
|
76
105
|
n: 'pageview',
|
|
77
106
|
d: config.site,
|
|
78
|
-
u: url || location.href,
|
|
79
|
-
r: document.referrer || null,
|
|
107
|
+
u: sanitizeUrl(url || location.href),
|
|
108
|
+
r: sanitizeReferrer(document.referrer) || null,
|
|
80
109
|
s: getScreenSize(),
|
|
81
110
|
};
|
|
82
111
|
if (config.hashRouting)
|
|
@@ -87,8 +116,8 @@ function createTracker(config) {
|
|
|
87
116
|
const payload = {
|
|
88
117
|
n: eventName,
|
|
89
118
|
d: config.site,
|
|
90
|
-
u: (options === null || options === void 0 ? void 0 : options.url) || location.href,
|
|
91
|
-
r: document.referrer || null,
|
|
119
|
+
u: sanitizeUrl((options === null || options === void 0 ? void 0 : options.url) || location.href),
|
|
120
|
+
r: sanitizeReferrer(document.referrer) || null,
|
|
92
121
|
s: getScreenSize(),
|
|
93
122
|
};
|
|
94
123
|
if (options === null || options === void 0 ? void 0 : options.props) {
|
|
@@ -113,7 +142,7 @@ function createTracker(config) {
|
|
|
113
142
|
const payload = {
|
|
114
143
|
n: 'identify',
|
|
115
144
|
d: config.site,
|
|
116
|
-
u: location.href,
|
|
145
|
+
u: sanitizeUrl(location.href),
|
|
117
146
|
r: null,
|
|
118
147
|
s: getScreenSize(),
|
|
119
148
|
uid: data.userId,
|
|
@@ -284,7 +313,7 @@ function startEventTracking(trackFn, config) {
|
|
|
284
313
|
return;
|
|
285
314
|
}
|
|
286
315
|
if (config.outboundLinks && isOutbound(link)) {
|
|
287
|
-
trackFn('Outbound Link: Click', { props: { url:
|
|
316
|
+
trackFn('Outbound Link: Click', { props: { url: cleanUrl } });
|
|
288
317
|
}
|
|
289
318
|
};
|
|
290
319
|
document.addEventListener('click', clickHandler);
|
|
@@ -352,7 +381,7 @@ function setupTracking(config, tracker) {
|
|
|
352
381
|
stopEngagement();
|
|
353
382
|
startEngagement();
|
|
354
383
|
let isFirstPageview = true;
|
|
355
|
-
let currentUrl = location.href;
|
|
384
|
+
let currentUrl = sanitizeUrl(location.href);
|
|
356
385
|
startNavTracking(() => {
|
|
357
386
|
// Send engagement for previous page (skip on first pageview)
|
|
358
387
|
if (!isFirstPageview) {
|
|
@@ -371,7 +400,7 @@ function setupTracking(config, tracker) {
|
|
|
371
400
|
resetEngagement();
|
|
372
401
|
}
|
|
373
402
|
isFirstPageview = false;
|
|
374
|
-
currentUrl = location.href;
|
|
403
|
+
currentUrl = sanitizeUrl(location.href);
|
|
375
404
|
tracker.trackPageview();
|
|
376
405
|
stopScrollGoals();
|
|
377
406
|
if (config.scrollTargets.length > 0) {
|
package/dist/module/index.mjs
CHANGED
|
@@ -33,6 +33,35 @@ function sendBeaconEvent(endpoint, payload, siteId) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// src/core/utils.ts
|
|
36
|
+
const ALLOWED_QUERY_PARAMS = new Set([
|
|
37
|
+
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref',
|
|
38
|
+
]);
|
|
39
|
+
function sanitizeUrl(url) {
|
|
40
|
+
try {
|
|
41
|
+
const u = new URL(url);
|
|
42
|
+
const toDelete = [];
|
|
43
|
+
u.searchParams.forEach((_, key) => {
|
|
44
|
+
if (!ALLOWED_QUERY_PARAMS.has(key))
|
|
45
|
+
toDelete.push(key);
|
|
46
|
+
});
|
|
47
|
+
toDelete.forEach(key => u.searchParams.delete(key));
|
|
48
|
+
return u.toString();
|
|
49
|
+
}
|
|
50
|
+
catch (_a) {
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function sanitizeReferrer(referrer) {
|
|
55
|
+
if (!referrer)
|
|
56
|
+
return referrer;
|
|
57
|
+
try {
|
|
58
|
+
const u = new URL(referrer);
|
|
59
|
+
return u.origin + u.pathname;
|
|
60
|
+
}
|
|
61
|
+
catch (_a) {
|
|
62
|
+
return referrer;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
36
65
|
function getScreenSize() {
|
|
37
66
|
return `${window.innerWidth}x${window.innerHeight}`;
|
|
38
67
|
}
|
|
@@ -73,8 +102,8 @@ function createTracker(config) {
|
|
|
73
102
|
const payload = {
|
|
74
103
|
n: 'pageview',
|
|
75
104
|
d: config.site,
|
|
76
|
-
u: url || location.href,
|
|
77
|
-
r: document.referrer || null,
|
|
105
|
+
u: sanitizeUrl(url || location.href),
|
|
106
|
+
r: sanitizeReferrer(document.referrer) || null,
|
|
78
107
|
s: getScreenSize(),
|
|
79
108
|
};
|
|
80
109
|
if (config.hashRouting)
|
|
@@ -85,8 +114,8 @@ function createTracker(config) {
|
|
|
85
114
|
const payload = {
|
|
86
115
|
n: eventName,
|
|
87
116
|
d: config.site,
|
|
88
|
-
u: (options === null || options === void 0 ? void 0 : options.url) || location.href,
|
|
89
|
-
r: document.referrer || null,
|
|
117
|
+
u: sanitizeUrl((options === null || options === void 0 ? void 0 : options.url) || location.href),
|
|
118
|
+
r: sanitizeReferrer(document.referrer) || null,
|
|
90
119
|
s: getScreenSize(),
|
|
91
120
|
};
|
|
92
121
|
if (options === null || options === void 0 ? void 0 : options.props) {
|
|
@@ -111,7 +140,7 @@ function createTracker(config) {
|
|
|
111
140
|
const payload = {
|
|
112
141
|
n: 'identify',
|
|
113
142
|
d: config.site,
|
|
114
|
-
u: location.href,
|
|
143
|
+
u: sanitizeUrl(location.href),
|
|
115
144
|
r: null,
|
|
116
145
|
s: getScreenSize(),
|
|
117
146
|
uid: data.userId,
|
|
@@ -282,7 +311,7 @@ function startEventTracking(trackFn, config) {
|
|
|
282
311
|
return;
|
|
283
312
|
}
|
|
284
313
|
if (config.outboundLinks && isOutbound(link)) {
|
|
285
|
-
trackFn('Outbound Link: Click', { props: { url:
|
|
314
|
+
trackFn('Outbound Link: Click', { props: { url: cleanUrl } });
|
|
286
315
|
}
|
|
287
316
|
};
|
|
288
317
|
document.addEventListener('click', clickHandler);
|
|
@@ -350,7 +379,7 @@ function setupTracking(config, tracker) {
|
|
|
350
379
|
stopEngagement();
|
|
351
380
|
startEngagement();
|
|
352
381
|
let isFirstPageview = true;
|
|
353
|
-
let currentUrl = location.href;
|
|
382
|
+
let currentUrl = sanitizeUrl(location.href);
|
|
354
383
|
startNavTracking(() => {
|
|
355
384
|
// Send engagement for previous page (skip on first pageview)
|
|
356
385
|
if (!isFirstPageview) {
|
|
@@ -369,7 +398,7 @@ function setupTracking(config, tracker) {
|
|
|
369
398
|
resetEngagement();
|
|
370
399
|
}
|
|
371
400
|
isFirstPageview = false;
|
|
372
|
-
currentUrl = location.href;
|
|
401
|
+
currentUrl = sanitizeUrl(location.href);
|
|
373
402
|
tracker.trackPageview();
|
|
374
403
|
stopScrollGoals();
|
|
375
404
|
if (config.scrollTargets.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pageviews/tracker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Lightweight, cookie-free analytics tracker for PageViews.ai",
|
|
5
5
|
"author": "Pageviews <hello@pageviews.ai>",
|
|
6
6
|
"homepage": "https://pageviews.ai",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
|
-
"dist"
|
|
31
|
+
"dist/module"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "rollup -c",
|
package/dist/tracker.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
!function(){"use strict";function t(t,e,n,i){if("undefined"==typeof fetch)return;const o={"Content-Type":"text/plain"};i&&(o["X-Site-ID"]=i),fetch(t,{method:"POST",headers:o,keepalive:!0,body:JSON.stringify(e)}).then(t=>{n&&n({status:t.status})}).catch(t=>{n&&n({error:t})})}function e(){return`${window.innerWidth}x${window.innerHeight}`}let n=null,i=0,o=0,r=!1,s=0,c=!1,a=0;function l(){const t=document.body||{},e=document.documentElement||{};return Math.max(t.scrollHeight||0,t.offsetHeight||0,e.scrollHeight||0,e.offsetHeight||0)}function u(){a=l()}function d(){"hidden"===document.visibilityState?r&&(o+=Date.now()-i,r=!1):"visible"===document.visibilityState&&(i=Date.now(),r=!0)}function v(){c||(c=!0,requestAnimationFrame(()=>{const t=function(){if(0===a)return 0;const t=window.innerHeight||0;if(a<=t)return 100;const e=window.scrollY||document.documentElement.scrollTop||0;return Math.round((e+t)/a*100)}();t>s&&(s=t),c=!1}))}function m(){document.removeEventListener("visibilitychange",d),document.removeEventListener("scroll",v),window.removeEventListener("resize",u)}function f(){const t=r?Date.now()-i:0;return{activeTime:o+t,maxScrollDepth:s}}const h=["pdf","xlsx","docx","txt","rtf","csv","exe","key","pps","ppt","pptx","7z","pkg","rar","gz","zip","avi","mov","mp4","mpeg","wmv","midi","mp3","wav","wma","dmg"];let p=null,g=null;function w(){p&&(document.removeEventListener("click",p),p=null),g&&(document.removeEventListener("submit",g,!0),g=null)}let y=null;function b(){y&&(document.removeEventListener("scroll",y),y=null)}function E(c,E){m(),m(),i=Date.now(),o=0,s=0,r=!0,a=l(),document.addEventListener("visibilitychange",d),document.addEventListener("scroll",v,{passive:!0}),window.addEventListener("resize",u,{passive:!0});let L=!0,S=location.href;!function(t,e){let i=location.pathname;const o=()=>{(e||location.pathname!==i)&&(i=location.pathname,t())};if(t(),e)window.addEventListener("hashchange",o),n=()=>window.removeEventListener("hashchange",o);else{const e=history.pushState;history.pushState=function(...t){e.apply(this,t),o()};const r=()=>{i=location.pathname,t()};window.addEventListener("popstate",r),n=()=>{history.pushState=e,window.removeEventListener("popstate",r)}}const r=e=>{e.persisted&&t()};window.addEventListener("pageshow",r);const s=n;n=()=>{null==s||s(),window.removeEventListener("pageshow",r)}}(()=>{if(!L){const n=f();n.activeTime>=1e3&&t(c.endpoint,{n:"engagement",d:c.site,u:S,r:null,s:e(),sd:n.maxScrollDepth,e:n.activeTime},void 0,c.siteId),i=Date.now(),o=0,s=0,r=!0}L=!1,S=location.href,E.trackPageview(),b(),c.scrollTargets.length>0&&function(t,e,n){const i=e.filter(t=>t.path===n);if(0===i.length)return;const o=new Set;let r=!1;y=()=>{r||(r=!0,requestAnimationFrame(()=>{var e;const n=Math.max(document.documentElement.scrollHeight||0,(null===(e=document.body)||void 0===e?void 0:e.scrollHeight)||0),s=window.innerHeight||0,c=window.scrollY||0,a=n<=s?100:Math.round((c+s)/n*100);for(const e of i)!o.has(e.goalName)&&a>=e.threshold&&(o.add(e.goalName),t(e.goalName));r=!1}))},document.addEventListener("scroll",y,{passive:!0})}(t=>E.track(t),c.scrollTargets,location.pathname)},c.hashRouting),function(t,e){w(),p=n=>{const i=function(t){let e=t;for(;e&&"A"!==e.tagName;)e=e.parentElement;return e}(n.target);if(!i||!i.href)return;const o=i.href,r=o.split("?")[0];e.fileDownloads&&function(t){var e;const n=null===(e=t.split("?")[0].split(".").pop())||void 0===e?void 0:e.toLowerCase();return!!n&&h.includes(n)}(o)?t("File Download",{props:{url:r}}):e.outboundLinks&&function(t){return""!==t.host&&t.host!==location.host}(i)&&t("Outbound Link: Click",{props:{url:o}})},document.addEventListener("click",p),e.formSubmissions&&(g=e=>{const n=e.target;(n.hasAttribute("novalidate")||n.checkValidity())&&t("Form Submission")},document.addEventListener("submit",g,!0))}((t,e)=>E.track(t,e),{outboundLinks:c.outboundLinks,fileDownloads:c.fileDownloads,formSubmissions:c.formSubmissions});const k=()=>{if("hidden"===document.visibilityState){const n=f();n.activeTime>=1e3&&function(e,n,i){const o=JSON.stringify(n);if("undefined"!=typeof navigator&&navigator.sendBeacon){const t=new Blob([o],{type:"text/plain"});if(navigator.sendBeacon(e,t))return}t(e,n,void 0,i)}(c.endpoint,{n:"engagement",d:c.site,u:S,r:null,s:e(),sd:n.maxScrollDepth,e:n.activeTime},c.siteId)}};return document.addEventListener("visibilitychange",k),()=>{null==n||n(),n=null,m(),w(),b(),document.removeEventListener("visibilitychange",k)}}!function(){var n;const i=document.currentScript;if(!i)return;const o="undefined"!=typeof __PAGEVIEWS_CONFIG__?__PAGEVIEWS_CONFIG__:null;if(!o)return;const r=i.getAttribute("data-api")||void 0,s=function(t,e){return e||"https://data.pageviews.ai/api/event"}(i.src,r),c=Object.assign(Object.assign({},o),{endpoint:s}),{tracker:a}=function(n){const i=function(n){const i="localhost"===(o=location.hostname)||/^127(\.[0-9]+){0,2}\.[0-9]+$/.test(o)||"[::1]"===o||function(){try{return"true"===window.localStorage.getItem("pageviews_ignore")}catch(t){return!1}}()||function(){const t=window,e=navigator;return!!(t._phantom||t.__nightmare||e.webdriver||t.Cypress||t.__puppeteer_evaluation_script__||t.__playwright)}();var o;function r(e,o){i?null==o||o():t(n.endpoint,e,o,n.siteId)}return{trackPageview:function(t){const i={n:"pageview",d:n.site,u:t||location.href,r:document.referrer||null,s:e()};n.hashRouting&&(i.h=!0),r(i)},track:function(t,i){const o={n:t,d:n.site,u:(null==i?void 0:i.url)||location.href,r:document.referrer||null,s:e()};if(null==i?void 0:i.props){const t={};for(const[e,n]of Object.entries(i.props))t[e]=String(n);o.p=t}if(null==i?void 0:i.revenue){const{amount:t,currency:e}=i.revenue;t>0&&t<=1e9&&e&&(o.rv={a:t,c:e})}n.hashRouting&&(o.h=!0),r(o,null==i?void 0:i.callback)},identify:function(t){r({n:"identify",d:n.site,u:location.href,r:null,s:e(),uid:t.userId})}}}(n);let o=null;if("prerender"===document.visibilityState){const t=()=>{"visible"===document.visibilityState&&(document.removeEventListener("visibilitychange",t),o=E(n,i))};return document.addEventListener("visibilitychange",t),{tracker:i,destroy:()=>{document.removeEventListener("visibilitychange",t),null==o||o()}}}return o=E(n,i),{tracker:i,destroy:()=>{null==o||o()}}}(c),l=i.getAttribute("data-user-id");l&&a.identify({userId:l});const u=(t,...e)=>{"track"===t?a.track(e[0],e[1]):"identify"===t&&a.identify(e[0])},d=null===(n=window.pageviews)||void 0===n?void 0:n.q;Array.isArray(d)&&d.forEach(t=>u(t[0],...t.slice(1))),window.pageviews=u}()}();
|