mytart 0.6.0 → 0.6.1

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 CHANGED
@@ -6,11 +6,12 @@
6
6
 
7
7
  ## Features
8
8
 
9
- - 🔌 **7 providers out of the box**: Google Analytics 4, Mixpanel, Segment, Amplitude, Plausible, PostHog, Meta Pixel
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)
14
15
  - ✅ **Node.js â‰Ĩ 18**
15
16
 
16
17
  ## Installation
@@ -253,6 +254,64 @@ await provider.updatePixelConsent(true); // fbq('consent', 'grant')
253
254
  await provider.updatePixelConsent(false); // fbq('consent', 'revoke')
254
255
  ```
255
256
 
257
+ ### Microsoft Clarity
258
+
259
+ [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.
260
+
261
+ ```typescript
262
+ {
263
+ provider: 'clarity',
264
+ projectId: 'YOUR_PROJECT_ID',
265
+ enabled: true,
266
+ }
267
+ ```
268
+
269
+ When enabled:
270
+
271
+ - The official `https://www.clarity.ms/tag/{projectId}` script is loaded once on the first `track()`, `identify()`, or `page()` call
272
+ - `track()` fires `clarity('event', eventName)` and sets each property as a custom tag via `clarity('set', key, value)`
273
+ - `identify()` calls `clarity('identify', userId)` with an optional friendly name from `traits.name`, and sets remaining traits as custom tags
274
+ - `page()` fires a `PageView` event and sets `pageUrl`, `pageName`, and `referrer` as custom tags
275
+ - SSR-safe: silently succeeds when `window` is undefined
276
+
277
+ #### Cookie consent
278
+
279
+ By default Clarity operates in cookieless mode. To enable cookie-based tracking, set `cookie: true`:
280
+
281
+ ```typescript
282
+ {
283
+ provider: 'clarity',
284
+ projectId: 'YOUR_PROJECT_ID',
285
+ cookie: true,
286
+ enabled: true,
287
+ }
288
+ ```
289
+
290
+ This calls `clarity('consent')` during initialisation so Clarity can set cookies for more accurate session tracking.
291
+
292
+ ## Bot Filtering
293
+
294
+ 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.
295
+
296
+ ```typescript
297
+ const analytics = new Mytart({
298
+ ignoreBots: true,
299
+ providers: [
300
+ { provider: 'google-analytics', measurementId: 'G-XXXXXXXXXX', enabled: true },
301
+ { provider: 'segment', writeKey: 'YOUR_KEY', enabled: true },
302
+ ],
303
+ });
304
+ ```
305
+
306
+ When a bot is detected, all methods return an empty `TrackResult[]` array — no events are dispatched to any provider.
307
+
308
+ The User-Agent is read from:
309
+
310
+ 1. `context.userAgent` if supplied in the `track()` call
311
+ 2. `navigator.userAgent` in browser environments
312
+
313
+ If no User-Agent is available (e.g. server-side without `context.userAgent`), the call proceeds normally.
314
+
256
315
  ## API Reference
257
316
 
258
317
  ### `new Mytart(config: MytartConfig)`
@@ -263,6 +322,7 @@ interface MytartConfig {
263
322
  defaultUserId?: string; // applied to every track/page call if no userId given
264
323
  defaultAnonymousId?: string; // applied to every track/page call if no anonymousId given
265
324
  debug?: boolean;
325
+ ignoreBots?: boolean; // when true, silently drops all tracking calls from known bots/crawlers
266
326
  }
267
327
  ```
268
328
 
@@ -373,7 +433,7 @@ import type {
373
433
  TrackResult, MytartError, EventContext, ProviderName, GoogleAnalyticsAppType,
374
434
  GoogleAnalyticsConfig, ConsentSettings, ConsentState, MixpanelConfig, SegmentConfig,
375
435
  AmplitudeConfig, PlausibleConfig, PostHogConfig, MetaPixelConfig, MetaPixelAppType,
376
- MetaPixelAdvancedMatching,
436
+ MetaPixelAdvancedMatching, ClarityConfig,
377
437
  } from 'mytart';
378
438
  ```
379
439
 
package/dist/index.d.mts CHANGED
@@ -197,6 +197,17 @@ 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;
200
211
  }
201
212
  interface EventContext {
202
213
  ip?: string;
@@ -249,6 +260,11 @@ declare class Mytart {
249
260
  private readonly providers;
250
261
  private readonly config;
251
262
  constructor(config: MytartConfig);
263
+ /**
264
+ * Returns `true` when `ignoreBots` is enabled and the given (or detected)
265
+ * User-Agent belongs to a known bot or crawler.
266
+ */
267
+ private isBotRequest;
252
268
  track(options: TrackOptions): Promise<TrackResult[]>;
253
269
  identify(options: IdentifyOptions): Promise<TrackResult[]>;
254
270
  page(options: PageOptions): Promise<TrackResult[]>;
package/dist/index.d.ts CHANGED
@@ -197,6 +197,17 @@ 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;
200
211
  }
201
212
  interface EventContext {
202
213
  ip?: string;
@@ -249,6 +260,11 @@ declare class Mytart {
249
260
  private readonly providers;
250
261
  private readonly config;
251
262
  constructor(config: MytartConfig);
263
+ /**
264
+ * Returns `true` when `ignoreBots` is enabled and the given (or detected)
265
+ * User-Agent belongs to a known bot or crawler.
266
+ */
267
+ private isBotRequest;
252
268
  track(options: TrackOptions): Promise<TrackResult[]>;
253
269
  identify(options: IdentifyOptions): Promise<TrackResult[]>;
254
270
  page(options: PageOptions): Promise<TrackResult[]>;
package/dist/index.js CHANGED
@@ -43,6 +43,9 @@ __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
+
46
49
  // src/providers/base.ts
47
50
  var BaseProvider = class {
48
51
  /**
@@ -1224,7 +1227,17 @@ var Mytart = class {
1224
1227
  this.config = config;
1225
1228
  this.providers = config.providers.filter((c) => c.enabled === true).map(createProvider);
1226
1229
  }
1230
+ /**
1231
+ * Returns `true` when `ignoreBots` is enabled and the given (or detected)
1232
+ * User-Agent belongs to a known bot or crawler.
1233
+ */
1234
+ isBotRequest(userAgent) {
1235
+ if (!this.config.ignoreBots) return false;
1236
+ const ua = userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0);
1237
+ return ua ? (0, import_bot_detection.isBot)(ua) : false;
1238
+ }
1227
1239
  async track(options) {
1240
+ if (this.isBotRequest(options.context?.userAgent)) return [];
1228
1241
  const enriched = {
1229
1242
  userId: this.config.defaultUserId,
1230
1243
  anonymousId: this.config.defaultAnonymousId,
@@ -1233,9 +1246,11 @@ var Mytart = class {
1233
1246
  return Promise.all(this.providers.map((p) => p.track(enriched)));
1234
1247
  }
1235
1248
  async identify(options) {
1249
+ if (this.isBotRequest()) return [];
1236
1250
  return Promise.all(this.providers.map((p) => p.identify(options)));
1237
1251
  }
1238
1252
  async page(options) {
1253
+ if (this.isBotRequest()) return [];
1239
1254
  const enriched = {
1240
1255
  userId: this.config.defaultUserId,
1241
1256
  anonymousId: this.config.defaultAnonymousId,
package/dist/index.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ // src/mytart.ts
2
+ import { isBot } from "ua-parser-js/bot-detection";
3
+
1
4
  // src/providers/base.ts
2
5
  var BaseProvider = class {
3
6
  /**
@@ -1179,7 +1182,17 @@ var Mytart = class {
1179
1182
  this.config = config;
1180
1183
  this.providers = config.providers.filter((c) => c.enabled === true).map(createProvider);
1181
1184
  }
1185
+ /**
1186
+ * Returns `true` when `ignoreBots` is enabled and the given (or detected)
1187
+ * User-Agent belongs to a known bot or crawler.
1188
+ */
1189
+ isBotRequest(userAgent) {
1190
+ if (!this.config.ignoreBots) return false;
1191
+ const ua = userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0);
1192
+ return ua ? isBot(ua) : false;
1193
+ }
1182
1194
  async track(options) {
1195
+ if (this.isBotRequest(options.context?.userAgent)) return [];
1183
1196
  const enriched = {
1184
1197
  userId: this.config.defaultUserId,
1185
1198
  anonymousId: this.config.defaultAnonymousId,
@@ -1188,9 +1201,11 @@ var Mytart = class {
1188
1201
  return Promise.all(this.providers.map((p) => p.track(enriched)));
1189
1202
  }
1190
1203
  async identify(options) {
1204
+ if (this.isBotRequest()) return [];
1191
1205
  return Promise.all(this.providers.map((p) => p.identify(options)));
1192
1206
  }
1193
1207
  async page(options) {
1208
+ if (this.isBotRequest()) return [];
1194
1209
  const enriched = {
1195
1210
  userId: this.config.defaultUserId,
1196
1211
  anonymousId: this.config.defaultAnonymousId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mytart",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
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",