mytart 0.2.4 → 0.3.0
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 +34 -2
- package/dist/index.d.mts +28 -18
- package/dist/index.d.ts +28 -18
- package/dist/index.js +68 -48
- package/dist/index.mjs +68 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,10 +50,42 @@ await analytics.page({ url: 'https://example.com/pricing', name: 'Pricing' });
|
|
|
50
50
|
|
|
51
51
|
### Google Analytics 4
|
|
52
52
|
|
|
53
|
+
GA4 supports two modes via the `appType` option:
|
|
54
|
+
|
|
55
|
+
#### Server mode (default)
|
|
56
|
+
|
|
57
|
+
Uses the [GA4 Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/ga4) — direct HTTP calls, no browser APIs. Use this for Node.js, API routes, serverless functions, etc.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
{
|
|
61
|
+
provider: 'google-analytics',
|
|
62
|
+
measurementId: 'G-XXXXXXXXXX',
|
|
63
|
+
apiSecret: 'YOUR_SECRET',
|
|
64
|
+
enabled: true,
|
|
65
|
+
// appType defaults to 'server'
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Browser mode
|
|
70
|
+
|
|
71
|
+
Injects Google's official [gtag.js snippet](https://developers.google.com/tag-platform/gtagjs) into the page. Use this for client-side tracking in any framework (React, Vue, Svelte, plain HTML, etc.). No `apiSecret` needed.
|
|
72
|
+
|
|
53
73
|
```typescript
|
|
54
|
-
{
|
|
74
|
+
{
|
|
75
|
+
provider: 'google-analytics',
|
|
76
|
+
measurementId: 'G-XXXXXXXXXX',
|
|
77
|
+
appType: 'browser',
|
|
78
|
+
enabled: true,
|
|
79
|
+
}
|
|
55
80
|
```
|
|
56
81
|
|
|
82
|
+
When `appType: 'browser'` is set:
|
|
83
|
+
|
|
84
|
+
- The gtag.js script is loaded once on the first `track()`, `identify()`, or `page()` call
|
|
85
|
+
- All calls use the standard `gtag()` API — compatible with Google Tag Tester and Tag Assistant
|
|
86
|
+
- SSR-safe: silently succeeds when `window` is undefined (e.g. during server-side rendering)
|
|
87
|
+
- `apiSecret` is not required (and not used)
|
|
88
|
+
|
|
57
89
|
### Mixpanel
|
|
58
90
|
|
|
59
91
|
```typescript
|
|
@@ -187,7 +219,7 @@ All types are exported:
|
|
|
187
219
|
```typescript
|
|
188
220
|
import type {
|
|
189
221
|
MytartConfig, BaseProviderConfig, ProviderConfig, TrackOptions, IdentifyOptions, PageOptions,
|
|
190
|
-
TrackResult, MytartError, EventContext, ProviderName,
|
|
222
|
+
TrackResult, MytartError, EventContext, ProviderName, GoogleAnalyticsAppType,
|
|
191
223
|
GoogleAnalyticsConfig, MixpanelConfig, SegmentConfig,
|
|
192
224
|
AmplitudeConfig, PlausibleConfig, PostHogConfig,
|
|
193
225
|
} from 'mytart';
|
package/dist/index.d.mts
CHANGED
|
@@ -126,34 +126,44 @@ declare global {
|
|
|
126
126
|
dataLayer: unknown[];
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
(command: 'config', measurementId: string, config?: GtagConfig): void;
|
|
131
|
-
(command: 'event', eventName: string, params?: Record<string, unknown>): void;
|
|
132
|
-
(command: 'set', config: Record<string, unknown>): void;
|
|
133
|
-
(command: string, ...args: unknown[]): void;
|
|
134
|
-
}
|
|
135
|
-
interface GtagConfig {
|
|
136
|
-
send_page_view?: boolean;
|
|
137
|
-
page_title?: string;
|
|
138
|
-
page_location?: string;
|
|
139
|
-
page_referrer?: string;
|
|
140
|
-
user_id?: string;
|
|
141
|
-
[key: string]: unknown;
|
|
142
|
-
}
|
|
129
|
+
type GtagFn = (...args: unknown[]) => void;
|
|
143
130
|
declare class GoogleAnalyticsProvider extends BaseProvider {
|
|
144
131
|
readonly name = "google-analytics";
|
|
145
132
|
private readonly config;
|
|
146
133
|
private readonly http;
|
|
147
134
|
private readonly endpoint;
|
|
148
135
|
private readonly isBrowser;
|
|
149
|
-
private
|
|
136
|
+
private gtagReady;
|
|
150
137
|
constructor(config: GoogleAnalyticsConfig);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Initializes the gtag.js snippet exactly as Google's official documentation
|
|
140
|
+
* specifies. This mirrors the standard snippet:
|
|
141
|
+
*
|
|
142
|
+
* <script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
|
|
143
|
+
* <script>
|
|
144
|
+
* window.dataLayer = window.dataLayer || [];
|
|
145
|
+
* function gtag(){dataLayer.push(arguments);}
|
|
146
|
+
* gtag('js', new Date());
|
|
147
|
+
* gtag('config', 'TAG_ID');
|
|
148
|
+
* </script>
|
|
149
|
+
*
|
|
150
|
+
* Key details:
|
|
151
|
+
* - The script URL MUST include ?id=TAG_ID for Google Tag Tester detection
|
|
152
|
+
* - dataLayer and the gtag shim are set up BEFORE the script loads
|
|
153
|
+
* - gtag('js') and gtag('config') are called synchronously — they queue
|
|
154
|
+
* into dataLayer and are processed once the real script loads
|
|
155
|
+
* - The returned promise resolves when the script finishes loading
|
|
156
|
+
*/
|
|
157
|
+
private initGtag;
|
|
158
|
+
/**
|
|
159
|
+
* Ensures gtag is initialized exactly once. Subsequent calls return the
|
|
160
|
+
* same promise so the script is never injected twice.
|
|
161
|
+
*/
|
|
162
|
+
private ensureGtag;
|
|
154
163
|
private trackBrowser;
|
|
155
164
|
private identifyBrowser;
|
|
156
165
|
private pageBrowser;
|
|
166
|
+
private buildGtagResult;
|
|
157
167
|
track({ event, properties, userId, anonymousId, timestamp }: TrackOptions): Promise<TrackResult>;
|
|
158
168
|
identify({ userId, traits }: IdentifyOptions): Promise<TrackResult>;
|
|
159
169
|
page({ name, url, referrer, userId, anonymousId }: PageOptions): Promise<TrackResult>;
|
package/dist/index.d.ts
CHANGED
|
@@ -126,34 +126,44 @@ declare global {
|
|
|
126
126
|
dataLayer: unknown[];
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
(command: 'config', measurementId: string, config?: GtagConfig): void;
|
|
131
|
-
(command: 'event', eventName: string, params?: Record<string, unknown>): void;
|
|
132
|
-
(command: 'set', config: Record<string, unknown>): void;
|
|
133
|
-
(command: string, ...args: unknown[]): void;
|
|
134
|
-
}
|
|
135
|
-
interface GtagConfig {
|
|
136
|
-
send_page_view?: boolean;
|
|
137
|
-
page_title?: string;
|
|
138
|
-
page_location?: string;
|
|
139
|
-
page_referrer?: string;
|
|
140
|
-
user_id?: string;
|
|
141
|
-
[key: string]: unknown;
|
|
142
|
-
}
|
|
129
|
+
type GtagFn = (...args: unknown[]) => void;
|
|
143
130
|
declare class GoogleAnalyticsProvider extends BaseProvider {
|
|
144
131
|
readonly name = "google-analytics";
|
|
145
132
|
private readonly config;
|
|
146
133
|
private readonly http;
|
|
147
134
|
private readonly endpoint;
|
|
148
135
|
private readonly isBrowser;
|
|
149
|
-
private
|
|
136
|
+
private gtagReady;
|
|
150
137
|
constructor(config: GoogleAnalyticsConfig);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Initializes the gtag.js snippet exactly as Google's official documentation
|
|
140
|
+
* specifies. This mirrors the standard snippet:
|
|
141
|
+
*
|
|
142
|
+
* <script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
|
|
143
|
+
* <script>
|
|
144
|
+
* window.dataLayer = window.dataLayer || [];
|
|
145
|
+
* function gtag(){dataLayer.push(arguments);}
|
|
146
|
+
* gtag('js', new Date());
|
|
147
|
+
* gtag('config', 'TAG_ID');
|
|
148
|
+
* </script>
|
|
149
|
+
*
|
|
150
|
+
* Key details:
|
|
151
|
+
* - The script URL MUST include ?id=TAG_ID for Google Tag Tester detection
|
|
152
|
+
* - dataLayer and the gtag shim are set up BEFORE the script loads
|
|
153
|
+
* - gtag('js') and gtag('config') are called synchronously — they queue
|
|
154
|
+
* into dataLayer and are processed once the real script loads
|
|
155
|
+
* - The returned promise resolves when the script finishes loading
|
|
156
|
+
*/
|
|
157
|
+
private initGtag;
|
|
158
|
+
/**
|
|
159
|
+
* Ensures gtag is initialized exactly once. Subsequent calls return the
|
|
160
|
+
* same promise so the script is never injected twice.
|
|
161
|
+
*/
|
|
162
|
+
private ensureGtag;
|
|
154
163
|
private trackBrowser;
|
|
155
164
|
private identifyBrowser;
|
|
156
165
|
private pageBrowser;
|
|
166
|
+
private buildGtagResult;
|
|
157
167
|
track({ event, properties, userId, anonymousId, timestamp }: TrackOptions): Promise<TrackResult>;
|
|
158
168
|
identify({ userId, traits }: IdentifyOptions): Promise<TrackResult>;
|
|
159
169
|
page({ name, url, referrer, userId, anonymousId }: PageOptions): Promise<TrackResult>;
|
package/dist/index.js
CHANGED
|
@@ -82,75 +82,87 @@ function isAxiosError(error) {
|
|
|
82
82
|
// src/providers/google-analytics.ts
|
|
83
83
|
var GA4_ENDPOINT = "https://www.google-analytics.com/mp/collect";
|
|
84
84
|
var GA4_DEBUG_ENDPOINT = "https://www.google-analytics.com/debug/mp/collect";
|
|
85
|
-
var
|
|
85
|
+
var GTAG_SCRIPT_URL = "https://www.googletagmanager.com/gtag/js";
|
|
86
86
|
var GoogleAnalyticsProvider = class extends BaseProvider {
|
|
87
87
|
constructor(config) {
|
|
88
88
|
super();
|
|
89
89
|
this.name = "google-analytics";
|
|
90
|
-
this.
|
|
90
|
+
this.gtagReady = null;
|
|
91
91
|
this.config = config;
|
|
92
92
|
this.http = createHttpClient();
|
|
93
93
|
this.endpoint = config.debug ? GA4_DEBUG_ENDPOINT : GA4_ENDPOINT;
|
|
94
94
|
this.isBrowser = config.appType === "browser";
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Initializes the gtag.js snippet exactly as Google's official documentation
|
|
98
|
+
* specifies. This mirrors the standard snippet:
|
|
99
|
+
*
|
|
100
|
+
* <script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
|
|
101
|
+
* <script>
|
|
102
|
+
* window.dataLayer = window.dataLayer || [];
|
|
103
|
+
* function gtag(){dataLayer.push(arguments);}
|
|
104
|
+
* gtag('js', new Date());
|
|
105
|
+
* gtag('config', 'TAG_ID');
|
|
106
|
+
* </script>
|
|
107
|
+
*
|
|
108
|
+
* Key details:
|
|
109
|
+
* - The script URL MUST include ?id=TAG_ID for Google Tag Tester detection
|
|
110
|
+
* - dataLayer and the gtag shim are set up BEFORE the script loads
|
|
111
|
+
* - gtag('js') and gtag('config') are called synchronously — they queue
|
|
112
|
+
* into dataLayer and are processed once the real script loads
|
|
113
|
+
* - The returned promise resolves when the script finishes loading
|
|
114
|
+
*/
|
|
115
|
+
initGtag() {
|
|
116
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
117
|
+
return Promise.resolve();
|
|
102
118
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
window.dataLayer = window.dataLayer || [];
|
|
120
|
+
window.gtag = function gtag() {
|
|
121
|
+
window.dataLayer.push(arguments);
|
|
122
|
+
};
|
|
123
|
+
window.gtag("js", /* @__PURE__ */ new Date());
|
|
124
|
+
window.gtag("config", this.config.measurementId);
|
|
106
125
|
return new Promise((resolve) => {
|
|
107
|
-
window.dataLayer = window.dataLayer || [];
|
|
108
|
-
window.gtag = window.gtag || function gtag(...args) {
|
|
109
|
-
window.dataLayer.push(args);
|
|
110
|
-
};
|
|
111
126
|
const script = document.createElement("script");
|
|
112
127
|
script.async = true;
|
|
113
|
-
script.src =
|
|
114
|
-
script.onload = () =>
|
|
115
|
-
window.gtag("js", /* @__PURE__ */ new Date());
|
|
116
|
-
window.gtag("config", this.config.measurementId, {
|
|
117
|
-
send_page_view: false
|
|
118
|
-
});
|
|
119
|
-
resolve();
|
|
120
|
-
};
|
|
128
|
+
script.src = `${GTAG_SCRIPT_URL}?id=${this.config.measurementId}`;
|
|
129
|
+
script.onload = () => resolve();
|
|
121
130
|
script.onerror = () => resolve();
|
|
122
|
-
|
|
123
|
-
firstScript.parentNode?.insertBefore(script, firstScript);
|
|
131
|
+
document.head.appendChild(script);
|
|
124
132
|
});
|
|
125
133
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Ensures gtag is initialized exactly once. Subsequent calls return the
|
|
136
|
+
* same promise so the script is never injected twice.
|
|
137
|
+
*/
|
|
138
|
+
ensureGtag() {
|
|
139
|
+
if (!this.gtagReady) {
|
|
140
|
+
this.gtagReady = this.initGtag();
|
|
141
|
+
}
|
|
142
|
+
return this.gtagReady;
|
|
132
143
|
}
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// Browser mode methods — delegate to gtag()
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
133
147
|
async trackBrowser({ event, properties, userId }) {
|
|
134
148
|
if (typeof window === "undefined") {
|
|
135
149
|
return this.buildGtagResult();
|
|
136
150
|
}
|
|
137
|
-
await this.
|
|
151
|
+
await this.ensureGtag();
|
|
138
152
|
if (userId) {
|
|
139
153
|
window.gtag("set", { user_id: userId });
|
|
140
154
|
}
|
|
141
|
-
window.gtag("event", event, properties
|
|
155
|
+
window.gtag("event", event, properties ?? {});
|
|
142
156
|
return this.buildGtagResult();
|
|
143
157
|
}
|
|
144
158
|
async identifyBrowser({ userId, traits }) {
|
|
145
159
|
if (typeof window === "undefined") {
|
|
146
160
|
return this.buildGtagResult();
|
|
147
161
|
}
|
|
148
|
-
await this.
|
|
162
|
+
await this.ensureGtag();
|
|
149
163
|
window.gtag("set", { user_id: userId });
|
|
150
164
|
if (traits) {
|
|
151
|
-
|
|
152
|
-
window.gtag("set", { [key]: value });
|
|
153
|
-
});
|
|
165
|
+
window.gtag("set", "user_properties", traits);
|
|
154
166
|
}
|
|
155
167
|
return this.buildGtagResult();
|
|
156
168
|
}
|
|
@@ -158,31 +170,39 @@ var GoogleAnalyticsProvider = class extends BaseProvider {
|
|
|
158
170
|
if (typeof window === "undefined") {
|
|
159
171
|
return this.buildGtagResult();
|
|
160
172
|
}
|
|
161
|
-
await this.
|
|
162
|
-
const config = {
|
|
163
|
-
page_title: name,
|
|
164
|
-
page_location: url,
|
|
165
|
-
page_referrer: referrer,
|
|
166
|
-
send_page_view: true
|
|
167
|
-
};
|
|
173
|
+
await this.ensureGtag();
|
|
168
174
|
if (userId) {
|
|
169
|
-
|
|
175
|
+
window.gtag("set", { user_id: userId });
|
|
170
176
|
}
|
|
171
|
-
window.gtag("
|
|
177
|
+
window.gtag("event", "page_view", {
|
|
178
|
+
page_title: name,
|
|
179
|
+
page_location: url,
|
|
180
|
+
page_referrer: referrer
|
|
181
|
+
});
|
|
172
182
|
return this.buildGtagResult();
|
|
173
183
|
}
|
|
184
|
+
buildGtagResult() {
|
|
185
|
+
return {
|
|
186
|
+
provider: this.name,
|
|
187
|
+
success: true,
|
|
188
|
+
statusCode: 200
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Public API — routes to browser or server mode
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
174
194
|
async track({ event, properties, userId, anonymousId, timestamp }) {
|
|
175
195
|
if (this.isBrowser) {
|
|
176
196
|
return this.trackBrowser({ event, properties, userId, anonymousId, timestamp });
|
|
177
197
|
}
|
|
178
198
|
try {
|
|
179
|
-
const
|
|
199
|
+
const clientId = anonymousId ?? this.config.clientId ?? "anonymous";
|
|
180
200
|
const params = { ...properties };
|
|
181
201
|
if (timestamp) {
|
|
182
202
|
params["timestamp_micros"] = timestamp.getTime() * 1e3;
|
|
183
203
|
}
|
|
184
204
|
const body = {
|
|
185
|
-
client_id,
|
|
205
|
+
client_id: clientId,
|
|
186
206
|
events: [{ name: event, params }]
|
|
187
207
|
};
|
|
188
208
|
if (userId) {
|
package/dist/index.mjs
CHANGED
|
@@ -39,75 +39,87 @@ function isAxiosError(error) {
|
|
|
39
39
|
// src/providers/google-analytics.ts
|
|
40
40
|
var GA4_ENDPOINT = "https://www.google-analytics.com/mp/collect";
|
|
41
41
|
var GA4_DEBUG_ENDPOINT = "https://www.google-analytics.com/debug/mp/collect";
|
|
42
|
-
var
|
|
42
|
+
var GTAG_SCRIPT_URL = "https://www.googletagmanager.com/gtag/js";
|
|
43
43
|
var GoogleAnalyticsProvider = class extends BaseProvider {
|
|
44
44
|
constructor(config) {
|
|
45
45
|
super();
|
|
46
46
|
this.name = "google-analytics";
|
|
47
|
-
this.
|
|
47
|
+
this.gtagReady = null;
|
|
48
48
|
this.config = config;
|
|
49
49
|
this.http = createHttpClient();
|
|
50
50
|
this.endpoint = config.debug ? GA4_DEBUG_ENDPOINT : GA4_ENDPOINT;
|
|
51
51
|
this.isBrowser = config.appType === "browser";
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Initializes the gtag.js snippet exactly as Google's official documentation
|
|
55
|
+
* specifies. This mirrors the standard snippet:
|
|
56
|
+
*
|
|
57
|
+
* <script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
|
|
58
|
+
* <script>
|
|
59
|
+
* window.dataLayer = window.dataLayer || [];
|
|
60
|
+
* function gtag(){dataLayer.push(arguments);}
|
|
61
|
+
* gtag('js', new Date());
|
|
62
|
+
* gtag('config', 'TAG_ID');
|
|
63
|
+
* </script>
|
|
64
|
+
*
|
|
65
|
+
* Key details:
|
|
66
|
+
* - The script URL MUST include ?id=TAG_ID for Google Tag Tester detection
|
|
67
|
+
* - dataLayer and the gtag shim are set up BEFORE the script loads
|
|
68
|
+
* - gtag('js') and gtag('config') are called synchronously — they queue
|
|
69
|
+
* into dataLayer and are processed once the real script loads
|
|
70
|
+
* - The returned promise resolves when the script finishes loading
|
|
71
|
+
*/
|
|
72
|
+
initGtag() {
|
|
73
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
74
|
+
return Promise.resolve();
|
|
59
75
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
window.dataLayer = window.dataLayer || [];
|
|
77
|
+
window.gtag = function gtag() {
|
|
78
|
+
window.dataLayer.push(arguments);
|
|
79
|
+
};
|
|
80
|
+
window.gtag("js", /* @__PURE__ */ new Date());
|
|
81
|
+
window.gtag("config", this.config.measurementId);
|
|
63
82
|
return new Promise((resolve) => {
|
|
64
|
-
window.dataLayer = window.dataLayer || [];
|
|
65
|
-
window.gtag = window.gtag || function gtag(...args) {
|
|
66
|
-
window.dataLayer.push(args);
|
|
67
|
-
};
|
|
68
83
|
const script = document.createElement("script");
|
|
69
84
|
script.async = true;
|
|
70
|
-
script.src =
|
|
71
|
-
script.onload = () =>
|
|
72
|
-
window.gtag("js", /* @__PURE__ */ new Date());
|
|
73
|
-
window.gtag("config", this.config.measurementId, {
|
|
74
|
-
send_page_view: false
|
|
75
|
-
});
|
|
76
|
-
resolve();
|
|
77
|
-
};
|
|
85
|
+
script.src = `${GTAG_SCRIPT_URL}?id=${this.config.measurementId}`;
|
|
86
|
+
script.onload = () => resolve();
|
|
78
87
|
script.onerror = () => resolve();
|
|
79
|
-
|
|
80
|
-
firstScript.parentNode?.insertBefore(script, firstScript);
|
|
88
|
+
document.head.appendChild(script);
|
|
81
89
|
});
|
|
82
90
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Ensures gtag is initialized exactly once. Subsequent calls return the
|
|
93
|
+
* same promise so the script is never injected twice.
|
|
94
|
+
*/
|
|
95
|
+
ensureGtag() {
|
|
96
|
+
if (!this.gtagReady) {
|
|
97
|
+
this.gtagReady = this.initGtag();
|
|
98
|
+
}
|
|
99
|
+
return this.gtagReady;
|
|
89
100
|
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Browser mode methods — delegate to gtag()
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
90
104
|
async trackBrowser({ event, properties, userId }) {
|
|
91
105
|
if (typeof window === "undefined") {
|
|
92
106
|
return this.buildGtagResult();
|
|
93
107
|
}
|
|
94
|
-
await this.
|
|
108
|
+
await this.ensureGtag();
|
|
95
109
|
if (userId) {
|
|
96
110
|
window.gtag("set", { user_id: userId });
|
|
97
111
|
}
|
|
98
|
-
window.gtag("event", event, properties
|
|
112
|
+
window.gtag("event", event, properties ?? {});
|
|
99
113
|
return this.buildGtagResult();
|
|
100
114
|
}
|
|
101
115
|
async identifyBrowser({ userId, traits }) {
|
|
102
116
|
if (typeof window === "undefined") {
|
|
103
117
|
return this.buildGtagResult();
|
|
104
118
|
}
|
|
105
|
-
await this.
|
|
119
|
+
await this.ensureGtag();
|
|
106
120
|
window.gtag("set", { user_id: userId });
|
|
107
121
|
if (traits) {
|
|
108
|
-
|
|
109
|
-
window.gtag("set", { [key]: value });
|
|
110
|
-
});
|
|
122
|
+
window.gtag("set", "user_properties", traits);
|
|
111
123
|
}
|
|
112
124
|
return this.buildGtagResult();
|
|
113
125
|
}
|
|
@@ -115,31 +127,39 @@ var GoogleAnalyticsProvider = class extends BaseProvider {
|
|
|
115
127
|
if (typeof window === "undefined") {
|
|
116
128
|
return this.buildGtagResult();
|
|
117
129
|
}
|
|
118
|
-
await this.
|
|
119
|
-
const config = {
|
|
120
|
-
page_title: name,
|
|
121
|
-
page_location: url,
|
|
122
|
-
page_referrer: referrer,
|
|
123
|
-
send_page_view: true
|
|
124
|
-
};
|
|
130
|
+
await this.ensureGtag();
|
|
125
131
|
if (userId) {
|
|
126
|
-
|
|
132
|
+
window.gtag("set", { user_id: userId });
|
|
127
133
|
}
|
|
128
|
-
window.gtag("
|
|
134
|
+
window.gtag("event", "page_view", {
|
|
135
|
+
page_title: name,
|
|
136
|
+
page_location: url,
|
|
137
|
+
page_referrer: referrer
|
|
138
|
+
});
|
|
129
139
|
return this.buildGtagResult();
|
|
130
140
|
}
|
|
141
|
+
buildGtagResult() {
|
|
142
|
+
return {
|
|
143
|
+
provider: this.name,
|
|
144
|
+
success: true,
|
|
145
|
+
statusCode: 200
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Public API — routes to browser or server mode
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
131
151
|
async track({ event, properties, userId, anonymousId, timestamp }) {
|
|
132
152
|
if (this.isBrowser) {
|
|
133
153
|
return this.trackBrowser({ event, properties, userId, anonymousId, timestamp });
|
|
134
154
|
}
|
|
135
155
|
try {
|
|
136
|
-
const
|
|
156
|
+
const clientId = anonymousId ?? this.config.clientId ?? "anonymous";
|
|
137
157
|
const params = { ...properties };
|
|
138
158
|
if (timestamp) {
|
|
139
159
|
params["timestamp_micros"] = timestamp.getTime() * 1e3;
|
|
140
160
|
}
|
|
141
161
|
const body = {
|
|
142
|
-
client_id,
|
|
162
|
+
client_id: clientId,
|
|
143
163
|
events: [{ name: event, params }]
|
|
144
164
|
};
|
|
145
165
|
if (userId) {
|