mytart 0.6.0 â 0.6.2
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 +123 -2
- package/dist/index.d.mts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +107 -3
- package/dist/index.mjs +107 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- ð **
|
|
9
|
+
- ð **8 providers out of the box**: Google Analytics 4, Mixpanel, Segment, Amplitude, Plausible, PostHog, Meta Pixel, Microsoft Clarity
|
|
10
10
|
- ð **Universal**: works in Node.js, browsers, and any JS framework (Next.js, Remix, Astro, SvelteKit, etc.)
|
|
11
11
|
- ð· **TypeScript-first**: precise typings, object-parameter style for great DX
|
|
12
12
|
- ðĶ **Dual ESM/CJS output**: works with `import` and `require`
|
|
13
13
|
- ðŠķ **Lightweight**: direct HTTP via axios, no SDK overhead
|
|
14
|
+
- ðĪ **Bot filtering**: optionally ignore bots and crawlers via [ua-parser-js](https://github.com/nicolevanderhoeven/ua-parser-js)
|
|
15
|
+
- ð **Cross-provider linking**: auto-captures click IDs (`gclid`, `fbclid`, `msclkid`, etc.) and cookies, then injects them into every provider call for unified attribution
|
|
14
16
|
- â
**Node.js âĨ 18**
|
|
15
17
|
|
|
16
18
|
## Installation
|
|
@@ -253,6 +255,123 @@ await provider.updatePixelConsent(true); // fbq('consent', 'grant')
|
|
|
253
255
|
await provider.updatePixelConsent(false); // fbq('consent', 'revoke')
|
|
254
256
|
```
|
|
255
257
|
|
|
258
|
+
### Microsoft Clarity
|
|
259
|
+
|
|
260
|
+
[Microsoft Clarity](https://clarity.microsoft.com/) is a free behavioral analytics tool that provides session recordings, heatmaps, and insights. Clarity is **browser-only** â there is no server mode.
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
{
|
|
264
|
+
provider: 'clarity',
|
|
265
|
+
projectId: 'YOUR_PROJECT_ID',
|
|
266
|
+
enabled: true,
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
When enabled:
|
|
271
|
+
|
|
272
|
+
- The official `https://www.clarity.ms/tag/{projectId}` script is loaded once on the first `track()`, `identify()`, or `page()` call
|
|
273
|
+
- `track()` fires `clarity('event', eventName)` and sets each property as a custom tag via `clarity('set', key, value)`
|
|
274
|
+
- `identify()` calls `clarity('identify', userId)` with an optional friendly name from `traits.name`, and sets remaining traits as custom tags
|
|
275
|
+
- `page()` fires a `PageView` event and sets `pageUrl`, `pageName`, and `referrer` as custom tags
|
|
276
|
+
- SSR-safe: silently succeeds when `window` is undefined
|
|
277
|
+
|
|
278
|
+
#### Cookie consent
|
|
279
|
+
|
|
280
|
+
By default Clarity operates in cookieless mode. To enable cookie-based tracking, set `cookie: true`:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
{
|
|
284
|
+
provider: 'clarity',
|
|
285
|
+
projectId: 'YOUR_PROJECT_ID',
|
|
286
|
+
cookie: true,
|
|
287
|
+
enabled: true,
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This calls `clarity('consent')` during initialisation so Clarity can set cookies for more accurate session tracking.
|
|
292
|
+
|
|
293
|
+
## Bot Filtering
|
|
294
|
+
|
|
295
|
+
Set `ignoreBots: true` at the top level to silently drop all `track()`, `identify()`, and `page()` calls when the visitor is a known bot or crawler. Detection is powered by [`ua-parser-js`](https://github.com/nicolevanderhoeven/ua-parser-js)'s `isBot()` function.
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
const analytics = new Mytart({
|
|
299
|
+
ignoreBots: true,
|
|
300
|
+
providers: [
|
|
301
|
+
{ provider: 'google-analytics', measurementId: 'G-XXXXXXXXXX', enabled: true },
|
|
302
|
+
{ provider: 'segment', writeKey: 'YOUR_KEY', enabled: true },
|
|
303
|
+
],
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
When a bot is detected, all methods return an empty `TrackResult[]` array â no events are dispatched to any provider.
|
|
308
|
+
|
|
309
|
+
The User-Agent is read from:
|
|
310
|
+
|
|
311
|
+
1. `context.userAgent` if supplied in the `track()` call
|
|
312
|
+
2. `navigator.userAgent` in browser environments
|
|
313
|
+
|
|
314
|
+
If no User-Agent is available (e.g. server-side without `context.userAgent`), the call proceeds normally.
|
|
315
|
+
|
|
316
|
+
## Cross-Provider Linking
|
|
317
|
+
|
|
318
|
+
Set `crossProviderLinking: true` to automatically capture click IDs and analytics cookies, then inject them as `xpl_`-prefixed properties into every `track()`, `page()`, and `identify()` call. This lets you correlate events across providers â e.g. trace a Meta ad click through to a Clarity session recording or a Mixpanel funnel.
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
const analytics = new Mytart({
|
|
322
|
+
crossProviderLinking: true,
|
|
323
|
+
providers: [
|
|
324
|
+
{ provider: 'google-analytics', measurementId: 'G-XXXXXXXXXX', appType: 'browser', enabled: true },
|
|
325
|
+
{ provider: 'meta-pixel', pixelId: '123456789', appType: 'browser', enabled: true },
|
|
326
|
+
{ provider: 'clarity', projectId: 'YOUR_PROJECT_ID', enabled: true },
|
|
327
|
+
{ provider: 'mixpanel', token: 'YOUR_TOKEN', enabled: true },
|
|
328
|
+
],
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### What gets captured
|
|
333
|
+
|
|
334
|
+
| Source | Captured ID | Property key |
|
|
335
|
+
|---|---|---|
|
|
336
|
+
| `?gclid=` URL param | Google click ID | `xpl_gclid` |
|
|
337
|
+
| `?fbclid=` URL param | Meta click ID | `xpl_fbclid` |
|
|
338
|
+
| `?ttclid=` URL param | TikTok click ID | `xpl_ttclid` |
|
|
339
|
+
| `?msclkid=` URL param | Microsoft Ads click ID | `xpl_msclkid` |
|
|
340
|
+
| `?li_fat_id=` URL param | LinkedIn click ID | `xpl_li_fat_id` |
|
|
341
|
+
| `_fbp` cookie | Meta browser ID | `xpl_fbp` |
|
|
342
|
+
| `_fbc` cookie | Meta click ID cookie | `xpl_fbc` |
|
|
343
|
+
| `_ga` cookie | GA client ID | `xpl_ga_client_id` |
|
|
344
|
+
|
|
345
|
+
If `fbclid` is present in the URL but the `_fbc` cookie has not yet been set, mytart synthesises an `fbc` value in Meta's standard format (`fb.1.{timestamp}.{fbclid}`).
|
|
346
|
+
|
|
347
|
+
### How it flows to each provider
|
|
348
|
+
|
|
349
|
+
All captured IDs are injected as event properties (`track`/`page`) or user traits (`identify`). No provider code changes are needed â each provider already forwards properties to its API:
|
|
350
|
+
|
|
351
|
+
- **GA4** â `xpl_*` fields appear as event parameters and user properties (queryable in BigQuery exports)
|
|
352
|
+
- **Meta Pixel** â `xpl_*` fields become custom data parameters (`fbclid`/`_fbp`/`_fbc` are also handled natively by Meta)
|
|
353
|
+
- **Clarity** â `xpl_*` fields are set as custom tags, letting you filter session recordings by ad click source
|
|
354
|
+
- **Mixpanel / Amplitude / PostHog** â `xpl_*` fields become event and user properties, fully queryable
|
|
355
|
+
- **Segment** â `xpl_*` fields flow through to all downstream destinations in your Segment pipeline
|
|
356
|
+
- **Plausible** â `xpl_*` fields are sent as custom props (must be [registered in your Plausible dashboard](https://plausible.io/docs/custom-props/introduction) to appear in reports)
|
|
357
|
+
|
|
358
|
+
### Inspecting captured IDs
|
|
359
|
+
|
|
360
|
+
Use `getCapturedIds()` to see what was captured at construction time:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
const ids = analytics.getCapturedIds();
|
|
364
|
+
// { fbclid: 'abc123', fbc: 'fb.1.1234567890.abc123', gaClientId: '1234567890.1234567890' }
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Returns `null` when `crossProviderLinking` is disabled.
|
|
368
|
+
|
|
369
|
+
### Notes
|
|
370
|
+
|
|
371
|
+
- **Browser-only.** SSR-safe â returns empty results when `window` is undefined.
|
|
372
|
+
- **User properties take precedence.** If you pass a property with the same `xpl_*` key, your value wins.
|
|
373
|
+
- **Consent.** This feature reads existing URL parameters and cookies â it does not set new cookies or tracking identifiers. Each provider's own consent mechanism remains authoritative.
|
|
374
|
+
|
|
256
375
|
## API Reference
|
|
257
376
|
|
|
258
377
|
### `new Mytart(config: MytartConfig)`
|
|
@@ -263,6 +382,8 @@ interface MytartConfig {
|
|
|
263
382
|
defaultUserId?: string; // applied to every track/page call if no userId given
|
|
264
383
|
defaultAnonymousId?: string; // applied to every track/page call if no anonymousId given
|
|
265
384
|
debug?: boolean;
|
|
385
|
+
ignoreBots?: boolean; // when true, silently drops all tracking calls from known bots/crawlers
|
|
386
|
+
crossProviderLinking?: boolean; // when true, auto-captures click IDs & cookies and injects them into every call
|
|
266
387
|
}
|
|
267
388
|
```
|
|
268
389
|
|
|
@@ -373,7 +494,7 @@ import type {
|
|
|
373
494
|
TrackResult, MytartError, EventContext, ProviderName, GoogleAnalyticsAppType,
|
|
374
495
|
GoogleAnalyticsConfig, ConsentSettings, ConsentState, MixpanelConfig, SegmentConfig,
|
|
375
496
|
AmplitudeConfig, PlausibleConfig, PostHogConfig, MetaPixelConfig, MetaPixelAppType,
|
|
376
|
-
MetaPixelAdvancedMatching,
|
|
497
|
+
MetaPixelAdvancedMatching, ClarityConfig,
|
|
377
498
|
} from 'mytart';
|
|
378
499
|
```
|
|
379
500
|
|
package/dist/index.d.mts
CHANGED
|
@@ -197,6 +197,32 @@ interface MytartConfig {
|
|
|
197
197
|
defaultUserId?: string;
|
|
198
198
|
defaultAnonymousId?: string;
|
|
199
199
|
debug?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* When `true`, silently drops all `track`, `identify`, and `page` calls
|
|
202
|
+
* if the visitor's User-Agent belongs to a known bot or crawler.
|
|
203
|
+
*
|
|
204
|
+
* Detection uses `isBot()` from `ua-parser-js`. The User-Agent is read
|
|
205
|
+
* from `context.userAgent` (if supplied) or `navigator.userAgent` in
|
|
206
|
+
* browser environments.
|
|
207
|
+
*
|
|
208
|
+
* Defaults to `false` (bots are tracked like any other visitor).
|
|
209
|
+
*/
|
|
210
|
+
ignoreBots?: boolean;
|
|
211
|
+
/**
|
|
212
|
+
* When `true`, automatically captures click IDs from URL parameters
|
|
213
|
+
* (`gclid`, `fbclid`, `ttclid`, `msclkid`, `li_fat_id`) and analytics
|
|
214
|
+
* cookies (`_fbp`, `_fbc`, `_ga`) at construction time, then injects
|
|
215
|
+
* them as `xpl_`-prefixed properties into every `track()`, `page()`,
|
|
216
|
+
* and `identify()` call.
|
|
217
|
+
*
|
|
218
|
+
* This enables cross-provider attribution â e.g. linking a Meta ad
|
|
219
|
+
* click to a Clarity session recording or a Mixpanel event â without
|
|
220
|
+
* any manual wiring.
|
|
221
|
+
*
|
|
222
|
+
* Browser-only. SSR-safe (no-op when `window` is undefined).
|
|
223
|
+
* Defaults to `false`.
|
|
224
|
+
*/
|
|
225
|
+
crossProviderLinking?: boolean;
|
|
200
226
|
}
|
|
201
227
|
interface EventContext {
|
|
202
228
|
ip?: string;
|
|
@@ -245,10 +271,46 @@ interface MytartError {
|
|
|
245
271
|
originalError?: unknown;
|
|
246
272
|
}
|
|
247
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Cross-provider identity linking.
|
|
276
|
+
*
|
|
277
|
+
* Captures click IDs from URL parameters and analytics cookies in the
|
|
278
|
+
* browser, then converts them into a flat property map that can be
|
|
279
|
+
* injected into every provider call.
|
|
280
|
+
*
|
|
281
|
+
* Browser-only â returns empty results when `window` is undefined.
|
|
282
|
+
*/
|
|
283
|
+
/** Identifiers captured from URL parameters and cookies. */
|
|
284
|
+
interface CapturedIds {
|
|
285
|
+
/** Google click ID (`gclid` URL param) */
|
|
286
|
+
gclid?: string;
|
|
287
|
+
/** Meta/Facebook click ID (`fbclid` URL param) */
|
|
288
|
+
fbclid?: string;
|
|
289
|
+
/** TikTok click ID (`ttclid` URL param) */
|
|
290
|
+
ttclid?: string;
|
|
291
|
+
/** Microsoft Ads click ID (`msclkid` URL param) */
|
|
292
|
+
msclkid?: string;
|
|
293
|
+
/** LinkedIn click ID (`li_fat_id` URL param) */
|
|
294
|
+
li_fat_id?: string;
|
|
295
|
+
/** Meta browser ID (from `_fbp` cookie) */
|
|
296
|
+
fbp?: string;
|
|
297
|
+
/** Meta click ID cookie (from `_fbc` cookie, or synthesised from `fbclid`) */
|
|
298
|
+
fbc?: string;
|
|
299
|
+
/** Google Analytics client ID (extracted from `_ga` cookie) */
|
|
300
|
+
gaClientId?: string;
|
|
301
|
+
}
|
|
302
|
+
|
|
248
303
|
declare class Mytart {
|
|
249
304
|
private readonly providers;
|
|
250
305
|
private readonly config;
|
|
306
|
+
private readonly capturedIds;
|
|
307
|
+
private readonly linkingProperties;
|
|
251
308
|
constructor(config: MytartConfig);
|
|
309
|
+
/**
|
|
310
|
+
* Returns `true` when `ignoreBots` is enabled and the given (or detected)
|
|
311
|
+
* User-Agent belongs to a known bot or crawler.
|
|
312
|
+
*/
|
|
313
|
+
private isBotRequest;
|
|
252
314
|
track(options: TrackOptions): Promise<TrackResult[]>;
|
|
253
315
|
identify(options: IdentifyOptions): Promise<TrackResult[]>;
|
|
254
316
|
page(options: PageOptions): Promise<TrackResult[]>;
|
|
@@ -265,6 +327,11 @@ declare class Mytart {
|
|
|
265
327
|
addProvider(config: ProviderConfig): void;
|
|
266
328
|
removeProvider(name: string): void;
|
|
267
329
|
getProviders(): string[];
|
|
330
|
+
/**
|
|
331
|
+
* Returns the click IDs and cookie values captured at construction
|
|
332
|
+
* time, or `null` when `crossProviderLinking` is disabled.
|
|
333
|
+
*/
|
|
334
|
+
getCapturedIds(): CapturedIds | null;
|
|
268
335
|
}
|
|
269
336
|
|
|
270
337
|
declare abstract class BaseProvider {
|
|
@@ -510,4 +577,4 @@ declare class ClarityProvider extends BaseProvider {
|
|
|
510
577
|
page(options: PageOptions): Promise<TrackResult>;
|
|
511
578
|
}
|
|
512
579
|
|
|
513
|
-
export { type AmplitudeConfig, AmplitudeProvider, BaseProvider, type BaseProviderConfig, type ClarityConfig, ClarityProvider, type ConsentSettings, type ConsentState, type EventContext, type GoogleAnalyticsAppType, type GoogleAnalyticsConfig, GoogleAnalyticsProvider, type IdentifyOptions, type MetaPixelAdvancedMatching, type MetaPixelAppType, type MetaPixelConfig, MetaPixelProvider, type MixpanelConfig, MixpanelProvider, Mytart, type MytartConfig, type MytartError, type PageOptions, type PlausibleConfig, PlausibleProvider, type PostHogConfig, PostHogProvider, type ProviderConfig, type ProviderName, type SegmentConfig, SegmentProvider, type TrackOptions, type TrackResult };
|
|
580
|
+
export { type AmplitudeConfig, AmplitudeProvider, BaseProvider, type BaseProviderConfig, type CapturedIds, type ClarityConfig, ClarityProvider, type ConsentSettings, type ConsentState, type EventContext, type GoogleAnalyticsAppType, type GoogleAnalyticsConfig, GoogleAnalyticsProvider, type IdentifyOptions, type MetaPixelAdvancedMatching, type MetaPixelAppType, type MetaPixelConfig, MetaPixelProvider, type MixpanelConfig, MixpanelProvider, Mytart, type MytartConfig, type MytartError, type PageOptions, type PlausibleConfig, PlausibleProvider, type PostHogConfig, PostHogProvider, type ProviderConfig, type ProviderName, type SegmentConfig, SegmentProvider, type TrackOptions, type TrackResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -197,6 +197,32 @@ interface MytartConfig {
|
|
|
197
197
|
defaultUserId?: string;
|
|
198
198
|
defaultAnonymousId?: string;
|
|
199
199
|
debug?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* When `true`, silently drops all `track`, `identify`, and `page` calls
|
|
202
|
+
* if the visitor's User-Agent belongs to a known bot or crawler.
|
|
203
|
+
*
|
|
204
|
+
* Detection uses `isBot()` from `ua-parser-js`. The User-Agent is read
|
|
205
|
+
* from `context.userAgent` (if supplied) or `navigator.userAgent` in
|
|
206
|
+
* browser environments.
|
|
207
|
+
*
|
|
208
|
+
* Defaults to `false` (bots are tracked like any other visitor).
|
|
209
|
+
*/
|
|
210
|
+
ignoreBots?: boolean;
|
|
211
|
+
/**
|
|
212
|
+
* When `true`, automatically captures click IDs from URL parameters
|
|
213
|
+
* (`gclid`, `fbclid`, `ttclid`, `msclkid`, `li_fat_id`) and analytics
|
|
214
|
+
* cookies (`_fbp`, `_fbc`, `_ga`) at construction time, then injects
|
|
215
|
+
* them as `xpl_`-prefixed properties into every `track()`, `page()`,
|
|
216
|
+
* and `identify()` call.
|
|
217
|
+
*
|
|
218
|
+
* This enables cross-provider attribution â e.g. linking a Meta ad
|
|
219
|
+
* click to a Clarity session recording or a Mixpanel event â without
|
|
220
|
+
* any manual wiring.
|
|
221
|
+
*
|
|
222
|
+
* Browser-only. SSR-safe (no-op when `window` is undefined).
|
|
223
|
+
* Defaults to `false`.
|
|
224
|
+
*/
|
|
225
|
+
crossProviderLinking?: boolean;
|
|
200
226
|
}
|
|
201
227
|
interface EventContext {
|
|
202
228
|
ip?: string;
|
|
@@ -245,10 +271,46 @@ interface MytartError {
|
|
|
245
271
|
originalError?: unknown;
|
|
246
272
|
}
|
|
247
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Cross-provider identity linking.
|
|
276
|
+
*
|
|
277
|
+
* Captures click IDs from URL parameters and analytics cookies in the
|
|
278
|
+
* browser, then converts them into a flat property map that can be
|
|
279
|
+
* injected into every provider call.
|
|
280
|
+
*
|
|
281
|
+
* Browser-only â returns empty results when `window` is undefined.
|
|
282
|
+
*/
|
|
283
|
+
/** Identifiers captured from URL parameters and cookies. */
|
|
284
|
+
interface CapturedIds {
|
|
285
|
+
/** Google click ID (`gclid` URL param) */
|
|
286
|
+
gclid?: string;
|
|
287
|
+
/** Meta/Facebook click ID (`fbclid` URL param) */
|
|
288
|
+
fbclid?: string;
|
|
289
|
+
/** TikTok click ID (`ttclid` URL param) */
|
|
290
|
+
ttclid?: string;
|
|
291
|
+
/** Microsoft Ads click ID (`msclkid` URL param) */
|
|
292
|
+
msclkid?: string;
|
|
293
|
+
/** LinkedIn click ID (`li_fat_id` URL param) */
|
|
294
|
+
li_fat_id?: string;
|
|
295
|
+
/** Meta browser ID (from `_fbp` cookie) */
|
|
296
|
+
fbp?: string;
|
|
297
|
+
/** Meta click ID cookie (from `_fbc` cookie, or synthesised from `fbclid`) */
|
|
298
|
+
fbc?: string;
|
|
299
|
+
/** Google Analytics client ID (extracted from `_ga` cookie) */
|
|
300
|
+
gaClientId?: string;
|
|
301
|
+
}
|
|
302
|
+
|
|
248
303
|
declare class Mytart {
|
|
249
304
|
private readonly providers;
|
|
250
305
|
private readonly config;
|
|
306
|
+
private readonly capturedIds;
|
|
307
|
+
private readonly linkingProperties;
|
|
251
308
|
constructor(config: MytartConfig);
|
|
309
|
+
/**
|
|
310
|
+
* Returns `true` when `ignoreBots` is enabled and the given (or detected)
|
|
311
|
+
* User-Agent belongs to a known bot or crawler.
|
|
312
|
+
*/
|
|
313
|
+
private isBotRequest;
|
|
252
314
|
track(options: TrackOptions): Promise<TrackResult[]>;
|
|
253
315
|
identify(options: IdentifyOptions): Promise<TrackResult[]>;
|
|
254
316
|
page(options: PageOptions): Promise<TrackResult[]>;
|
|
@@ -265,6 +327,11 @@ declare class Mytart {
|
|
|
265
327
|
addProvider(config: ProviderConfig): void;
|
|
266
328
|
removeProvider(name: string): void;
|
|
267
329
|
getProviders(): string[];
|
|
330
|
+
/**
|
|
331
|
+
* Returns the click IDs and cookie values captured at construction
|
|
332
|
+
* time, or `null` when `crossProviderLinking` is disabled.
|
|
333
|
+
*/
|
|
334
|
+
getCapturedIds(): CapturedIds | null;
|
|
268
335
|
}
|
|
269
336
|
|
|
270
337
|
declare abstract class BaseProvider {
|
|
@@ -510,4 +577,4 @@ declare class ClarityProvider extends BaseProvider {
|
|
|
510
577
|
page(options: PageOptions): Promise<TrackResult>;
|
|
511
578
|
}
|
|
512
579
|
|
|
513
|
-
export { type AmplitudeConfig, AmplitudeProvider, BaseProvider, type BaseProviderConfig, type ClarityConfig, ClarityProvider, type ConsentSettings, type ConsentState, type EventContext, type GoogleAnalyticsAppType, type GoogleAnalyticsConfig, GoogleAnalyticsProvider, type IdentifyOptions, type MetaPixelAdvancedMatching, type MetaPixelAppType, type MetaPixelConfig, MetaPixelProvider, type MixpanelConfig, MixpanelProvider, Mytart, type MytartConfig, type MytartError, type PageOptions, type PlausibleConfig, PlausibleProvider, type PostHogConfig, PostHogProvider, type ProviderConfig, type ProviderName, type SegmentConfig, SegmentProvider, type TrackOptions, type TrackResult };
|
|
580
|
+
export { type AmplitudeConfig, AmplitudeProvider, BaseProvider, type BaseProviderConfig, type CapturedIds, type ClarityConfig, ClarityProvider, type ConsentSettings, type ConsentState, type EventContext, type GoogleAnalyticsAppType, type GoogleAnalyticsConfig, GoogleAnalyticsProvider, type IdentifyOptions, type MetaPixelAdvancedMatching, type MetaPixelAppType, type MetaPixelConfig, MetaPixelProvider, type MixpanelConfig, MixpanelProvider, Mytart, type MytartConfig, type MytartError, type PageOptions, type PlausibleConfig, PlausibleProvider, type PostHogConfig, PostHogProvider, type ProviderConfig, type ProviderName, type SegmentConfig, SegmentProvider, type TrackOptions, type TrackResult };
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,68 @@ __export(index_exports, {
|
|
|
43
43
|
});
|
|
44
44
|
module.exports = __toCommonJS(index_exports);
|
|
45
45
|
|
|
46
|
+
// src/mytart.ts
|
|
47
|
+
var import_bot_detection = require("ua-parser-js/bot-detection");
|
|
48
|
+
|
|
49
|
+
// src/utils/cross-provider-ids.ts
|
|
50
|
+
var CLICK_ID_PARAMS = ["gclid", "fbclid", "ttclid", "msclkid", "li_fat_id"];
|
|
51
|
+
function getCookie(name) {
|
|
52
|
+
if (typeof document === "undefined") return void 0;
|
|
53
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
54
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
55
|
+
}
|
|
56
|
+
function parseGaClientId(gaCookie) {
|
|
57
|
+
const parts = gaCookie.split(".");
|
|
58
|
+
if (parts.length < 4) return void 0;
|
|
59
|
+
return parts.slice(-2).join(".");
|
|
60
|
+
}
|
|
61
|
+
function captureClickIds() {
|
|
62
|
+
if (typeof window === "undefined") return {};
|
|
63
|
+
const ids = {};
|
|
64
|
+
const params = new URLSearchParams(window.location.search);
|
|
65
|
+
for (const key of CLICK_ID_PARAMS) {
|
|
66
|
+
const value = params.get(key);
|
|
67
|
+
if (value) {
|
|
68
|
+
ids[key] = value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const fbp = getCookie("_fbp");
|
|
72
|
+
if (fbp) ids.fbp = fbp;
|
|
73
|
+
const fbc = getCookie("_fbc");
|
|
74
|
+
if (fbc) {
|
|
75
|
+
ids.fbc = fbc;
|
|
76
|
+
} else if (ids.fbclid) {
|
|
77
|
+
ids.fbc = `fb.1.${Date.now()}.${ids.fbclid}`;
|
|
78
|
+
}
|
|
79
|
+
const ga = getCookie("_ga");
|
|
80
|
+
if (ga) {
|
|
81
|
+
const clientId = parseGaClientId(ga);
|
|
82
|
+
if (clientId) ids.gaClientId = clientId;
|
|
83
|
+
}
|
|
84
|
+
return ids;
|
|
85
|
+
}
|
|
86
|
+
var PREFIX = "xpl_";
|
|
87
|
+
var KEY_MAP = {
|
|
88
|
+
gclid: "gclid",
|
|
89
|
+
fbclid: "fbclid",
|
|
90
|
+
ttclid: "ttclid",
|
|
91
|
+
msclkid: "msclkid",
|
|
92
|
+
li_fat_id: "li_fat_id",
|
|
93
|
+
fbp: "fbp",
|
|
94
|
+
fbc: "fbc",
|
|
95
|
+
gaClientId: "ga_client_id"
|
|
96
|
+
};
|
|
97
|
+
function capturedIdsToProperties(ids) {
|
|
98
|
+
const props = {};
|
|
99
|
+
for (const [field, suffix] of Object.entries(KEY_MAP)) {
|
|
100
|
+
const value = ids[field];
|
|
101
|
+
if (value) {
|
|
102
|
+
props[`${PREFIX}${suffix}`] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return props;
|
|
106
|
+
}
|
|
107
|
+
|
|
46
108
|
// src/providers/base.ts
|
|
47
109
|
var BaseProvider = class {
|
|
48
110
|
/**
|
|
@@ -1223,23 +1285,58 @@ var Mytart = class {
|
|
|
1223
1285
|
constructor(config) {
|
|
1224
1286
|
this.config = config;
|
|
1225
1287
|
this.providers = config.providers.filter((c) => c.enabled === true).map(createProvider);
|
|
1288
|
+
if (config.crossProviderLinking) {
|
|
1289
|
+
this.capturedIds = captureClickIds();
|
|
1290
|
+
const props = capturedIdsToProperties(this.capturedIds);
|
|
1291
|
+
this.linkingProperties = Object.keys(props).length > 0 ? props : null;
|
|
1292
|
+
} else {
|
|
1293
|
+
this.capturedIds = null;
|
|
1294
|
+
this.linkingProperties = null;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Returns `true` when `ignoreBots` is enabled and the given (or detected)
|
|
1299
|
+
* User-Agent belongs to a known bot or crawler.
|
|
1300
|
+
*/
|
|
1301
|
+
isBotRequest(userAgent) {
|
|
1302
|
+
if (!this.config.ignoreBots) return false;
|
|
1303
|
+
const ua = userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0);
|
|
1304
|
+
return ua ? (0, import_bot_detection.isBot)(ua) : false;
|
|
1226
1305
|
}
|
|
1227
1306
|
async track(options) {
|
|
1307
|
+
if (this.isBotRequest(options.context?.userAgent)) return [];
|
|
1228
1308
|
const enriched = {
|
|
1229
1309
|
userId: this.config.defaultUserId,
|
|
1230
1310
|
anonymousId: this.config.defaultAnonymousId,
|
|
1231
|
-
...options
|
|
1311
|
+
...options,
|
|
1312
|
+
properties: {
|
|
1313
|
+
...this.linkingProperties,
|
|
1314
|
+
...options.properties
|
|
1315
|
+
}
|
|
1232
1316
|
};
|
|
1233
1317
|
return Promise.all(this.providers.map((p) => p.track(enriched)));
|
|
1234
1318
|
}
|
|
1235
1319
|
async identify(options) {
|
|
1236
|
-
|
|
1320
|
+
if (this.isBotRequest()) return [];
|
|
1321
|
+
const enriched = {
|
|
1322
|
+
...options,
|
|
1323
|
+
traits: {
|
|
1324
|
+
...this.linkingProperties,
|
|
1325
|
+
...options.traits
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
return Promise.all(this.providers.map((p) => p.identify(enriched)));
|
|
1237
1329
|
}
|
|
1238
1330
|
async page(options) {
|
|
1331
|
+
if (this.isBotRequest()) return [];
|
|
1239
1332
|
const enriched = {
|
|
1240
1333
|
userId: this.config.defaultUserId,
|
|
1241
1334
|
anonymousId: this.config.defaultAnonymousId,
|
|
1242
|
-
...options
|
|
1335
|
+
...options,
|
|
1336
|
+
properties: {
|
|
1337
|
+
...this.linkingProperties,
|
|
1338
|
+
...options.properties
|
|
1339
|
+
}
|
|
1243
1340
|
};
|
|
1244
1341
|
return Promise.all(this.providers.map((p) => p.page(enriched)));
|
|
1245
1342
|
}
|
|
@@ -1268,6 +1365,13 @@ var Mytart = class {
|
|
|
1268
1365
|
getProviders() {
|
|
1269
1366
|
return this.providers.map((p) => p.name);
|
|
1270
1367
|
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Returns the click IDs and cookie values captured at construction
|
|
1370
|
+
* time, or `null` when `crossProviderLinking` is disabled.
|
|
1371
|
+
*/
|
|
1372
|
+
getCapturedIds() {
|
|
1373
|
+
return this.capturedIds;
|
|
1374
|
+
}
|
|
1271
1375
|
};
|
|
1272
1376
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1273
1377
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
+
// src/mytart.ts
|
|
2
|
+
import { isBot } from "ua-parser-js/bot-detection";
|
|
3
|
+
|
|
4
|
+
// src/utils/cross-provider-ids.ts
|
|
5
|
+
var CLICK_ID_PARAMS = ["gclid", "fbclid", "ttclid", "msclkid", "li_fat_id"];
|
|
6
|
+
function getCookie(name) {
|
|
7
|
+
if (typeof document === "undefined") return void 0;
|
|
8
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
9
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
10
|
+
}
|
|
11
|
+
function parseGaClientId(gaCookie) {
|
|
12
|
+
const parts = gaCookie.split(".");
|
|
13
|
+
if (parts.length < 4) return void 0;
|
|
14
|
+
return parts.slice(-2).join(".");
|
|
15
|
+
}
|
|
16
|
+
function captureClickIds() {
|
|
17
|
+
if (typeof window === "undefined") return {};
|
|
18
|
+
const ids = {};
|
|
19
|
+
const params = new URLSearchParams(window.location.search);
|
|
20
|
+
for (const key of CLICK_ID_PARAMS) {
|
|
21
|
+
const value = params.get(key);
|
|
22
|
+
if (value) {
|
|
23
|
+
ids[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const fbp = getCookie("_fbp");
|
|
27
|
+
if (fbp) ids.fbp = fbp;
|
|
28
|
+
const fbc = getCookie("_fbc");
|
|
29
|
+
if (fbc) {
|
|
30
|
+
ids.fbc = fbc;
|
|
31
|
+
} else if (ids.fbclid) {
|
|
32
|
+
ids.fbc = `fb.1.${Date.now()}.${ids.fbclid}`;
|
|
33
|
+
}
|
|
34
|
+
const ga = getCookie("_ga");
|
|
35
|
+
if (ga) {
|
|
36
|
+
const clientId = parseGaClientId(ga);
|
|
37
|
+
if (clientId) ids.gaClientId = clientId;
|
|
38
|
+
}
|
|
39
|
+
return ids;
|
|
40
|
+
}
|
|
41
|
+
var PREFIX = "xpl_";
|
|
42
|
+
var KEY_MAP = {
|
|
43
|
+
gclid: "gclid",
|
|
44
|
+
fbclid: "fbclid",
|
|
45
|
+
ttclid: "ttclid",
|
|
46
|
+
msclkid: "msclkid",
|
|
47
|
+
li_fat_id: "li_fat_id",
|
|
48
|
+
fbp: "fbp",
|
|
49
|
+
fbc: "fbc",
|
|
50
|
+
gaClientId: "ga_client_id"
|
|
51
|
+
};
|
|
52
|
+
function capturedIdsToProperties(ids) {
|
|
53
|
+
const props = {};
|
|
54
|
+
for (const [field, suffix] of Object.entries(KEY_MAP)) {
|
|
55
|
+
const value = ids[field];
|
|
56
|
+
if (value) {
|
|
57
|
+
props[`${PREFIX}${suffix}`] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return props;
|
|
61
|
+
}
|
|
62
|
+
|
|
1
63
|
// src/providers/base.ts
|
|
2
64
|
var BaseProvider = class {
|
|
3
65
|
/**
|
|
@@ -1178,23 +1240,58 @@ var Mytart = class {
|
|
|
1178
1240
|
constructor(config) {
|
|
1179
1241
|
this.config = config;
|
|
1180
1242
|
this.providers = config.providers.filter((c) => c.enabled === true).map(createProvider);
|
|
1243
|
+
if (config.crossProviderLinking) {
|
|
1244
|
+
this.capturedIds = captureClickIds();
|
|
1245
|
+
const props = capturedIdsToProperties(this.capturedIds);
|
|
1246
|
+
this.linkingProperties = Object.keys(props).length > 0 ? props : null;
|
|
1247
|
+
} else {
|
|
1248
|
+
this.capturedIds = null;
|
|
1249
|
+
this.linkingProperties = null;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Returns `true` when `ignoreBots` is enabled and the given (or detected)
|
|
1254
|
+
* User-Agent belongs to a known bot or crawler.
|
|
1255
|
+
*/
|
|
1256
|
+
isBotRequest(userAgent) {
|
|
1257
|
+
if (!this.config.ignoreBots) return false;
|
|
1258
|
+
const ua = userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0);
|
|
1259
|
+
return ua ? isBot(ua) : false;
|
|
1181
1260
|
}
|
|
1182
1261
|
async track(options) {
|
|
1262
|
+
if (this.isBotRequest(options.context?.userAgent)) return [];
|
|
1183
1263
|
const enriched = {
|
|
1184
1264
|
userId: this.config.defaultUserId,
|
|
1185
1265
|
anonymousId: this.config.defaultAnonymousId,
|
|
1186
|
-
...options
|
|
1266
|
+
...options,
|
|
1267
|
+
properties: {
|
|
1268
|
+
...this.linkingProperties,
|
|
1269
|
+
...options.properties
|
|
1270
|
+
}
|
|
1187
1271
|
};
|
|
1188
1272
|
return Promise.all(this.providers.map((p) => p.track(enriched)));
|
|
1189
1273
|
}
|
|
1190
1274
|
async identify(options) {
|
|
1191
|
-
|
|
1275
|
+
if (this.isBotRequest()) return [];
|
|
1276
|
+
const enriched = {
|
|
1277
|
+
...options,
|
|
1278
|
+
traits: {
|
|
1279
|
+
...this.linkingProperties,
|
|
1280
|
+
...options.traits
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
return Promise.all(this.providers.map((p) => p.identify(enriched)));
|
|
1192
1284
|
}
|
|
1193
1285
|
async page(options) {
|
|
1286
|
+
if (this.isBotRequest()) return [];
|
|
1194
1287
|
const enriched = {
|
|
1195
1288
|
userId: this.config.defaultUserId,
|
|
1196
1289
|
anonymousId: this.config.defaultAnonymousId,
|
|
1197
|
-
...options
|
|
1290
|
+
...options,
|
|
1291
|
+
properties: {
|
|
1292
|
+
...this.linkingProperties,
|
|
1293
|
+
...options.properties
|
|
1294
|
+
}
|
|
1198
1295
|
};
|
|
1199
1296
|
return Promise.all(this.providers.map((p) => p.page(enriched)));
|
|
1200
1297
|
}
|
|
@@ -1223,6 +1320,13 @@ var Mytart = class {
|
|
|
1223
1320
|
getProviders() {
|
|
1224
1321
|
return this.providers.map((p) => p.name);
|
|
1225
1322
|
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Returns the click IDs and cookie values captured at construction
|
|
1325
|
+
* time, or `null` when `crossProviderLinking` is disabled.
|
|
1326
|
+
*/
|
|
1327
|
+
getCapturedIds() {
|
|
1328
|
+
return this.capturedIds;
|
|
1329
|
+
}
|
|
1226
1330
|
};
|
|
1227
1331
|
export {
|
|
1228
1332
|
AmplitudeProvider,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mytart",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Multi-Yield Tracking & Analytics Relay Tool â framework-agnostic analytics for any project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"analytics",
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"node": ">=18"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"axios": "^1.7.0"
|
|
38
|
+
"axios": "^1.7.0",
|
|
39
|
+
"ua-parser-js": "^2.0.9"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
42
|
"@types/jest": "^29.5.0",
|