@crelora/mark 0.1.1 → 0.2.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Mark is Crelora's lightweight attribution SDK for capturing user journeys, conversions, and consent across browsers and server-side runtimes. The npm package includes both browser and Node entry points so you can send consistent data from any surface.
4
4
 
5
- Use it to feed **OneLence** with first‑party behavioral and conversion data so you can build **analytics**, **insights**, **signals**, and **decisions** on top of a unified event stream.
5
+ Use it to feed [**OneLence**](https://onelence.com) with first‑party behavioral and conversion data so you can build **analytics**, **insights**, **signals**, and **decisions** on top of a unified event stream.
6
6
 
7
7
  ### API keys and documentation
8
8
 
@@ -104,6 +104,7 @@ The Node factory accepts optional custom storage or transport adapters so you ca
104
104
  - `flush()` – flushes queued/persisted delivery items.
105
105
  - `reset()` – clears user/session/attribution state and rotates visitor identity for logout flows.
106
106
  - `getStats()` – returns runtime delivery stats `{ queued, sent, failed, dropped }`.
107
+ - `setInternal(value)` / `getInternal()` – flags the current visitor as internal traffic (QA, staff, smoke tests). While set, every outgoing event is stamped with `is_internal: true` so the backend can exclude it from customer-facing reports by default. See [Flagging internal traffic](#flagging-internal-traffic).
107
108
 
108
109
  Reserved SDK fields (for example `event_name`, `user_id`, `consent_state`, and internal identity metadata) are sanitized from user payloads/traits and cannot override SDK-managed values.
109
110
 
@@ -223,6 +224,77 @@ Mark.identify('user_123', {
223
224
  - Autocapture (optional): set `autocapture: { pageview: true }` (and optionally `track_route_changes: true`) to emit on first load and SPA route changes. If consent is required and not yet granted, initial pageview is deferred and emitted once consent is granted.
224
225
  - All SDK config and event fields use snake_case (`site_id`, `site_host`, etc.) and map directly to stored payloads and database columns.
225
226
 
227
+ ## Extended autocapture (browser)
228
+
229
+ All of the following are **opt-in** under `autocapture`. They respect the same consent, DNT/GPC, and sampling rules as `track()` (see `sample_rate`: conversions are exempt; these modes are **not** conversion events). They are registered when `Mark.init()` runs.
230
+
231
+ | Flag | Event name(s) | Behavior |
232
+ | --- | --- | --- |
233
+ | `click` | `data-mark-event` value, or `click` | Listens for clicks. **Default:** only elements matching `[data-mark-event]`; set `click: { selector: '.my-tracked' }` to use a custom selector. Sends `element_id`, `element_classes`, truncated `text`, and `href` when applicable. |
234
+ | `form_submit` | `form_submit` | Listens for `submit`; sends `form_id`, `form_name`, `action`. |
235
+ | `outbound_link` | `outbound_link_click` | On click, if the link target is another origin, sends `href`. Uses `preferBeacon: true` so the event is more likely to fire before navigation. |
236
+ | `scroll_depth` | `scroll_depth` | Fires at **25%, 50%, 75%, and 100%** of vertical scroll depth (once each per page load). Payload includes `percent`. |
237
+ | `web_vitals` | `web_vital` | Lazy-loads the `web-vitals` dependency and reports **LCP, CLS, INP, and TTFB** with `metric`, `value`, optional `rating`, and `metric_id`. If the module fails to load, only `debug: true` logs a warning. |
238
+
239
+ Example:
240
+
241
+ ```ts
242
+ Mark.init({
243
+ key: 'pk_xxxxx',
244
+ require_consent: 'auto',
245
+ autocapture: {
246
+ pageview: true,
247
+ click: true,
248
+ // or: click: { selector: '[data-analytics]' },
249
+ form_submit: true,
250
+ outbound_link: true,
251
+ scroll_depth: true,
252
+ web_vitals: true,
253
+ },
254
+ });
255
+ ```
256
+
257
+ ## Flagging internal traffic
258
+
259
+ Use the `is_internal` marker to keep QA sessions, staff testing, or automated smoke tests out of customer-facing reports without dropping them on the client. The SDK supports it in two complementary ways:
260
+
261
+ **1. Per-event field.** Any `track` / `conversion` call can carry `is_internal: true`:
262
+
263
+ ```ts
264
+ Mark.track('checkout_started', { value: 1299, is_internal: true });
265
+ ```
266
+
267
+ **2. Persistent visitor flag.** Set it once and every subsequent event is stamped automatically:
268
+
269
+ ```ts
270
+ Mark.setInternal(true); // stamps is_internal: true on all future events
271
+ Mark.setInternal(false); // stops stamping
272
+ Mark.getInternal(); // boolean
273
+ ```
274
+
275
+ The persistent flag is stored in the SDK's browser storage so it survives reloads. It is cleared automatically by `Mark.reset()` and by `Mark.setConsent('denied')`.
276
+
277
+ **Design note.** The SDK intentionally does *not* read a magic URL parameter or write to a well-known `localStorage` key on its own — that would let anyone opt themselves out of your analytics just by visiting a URL, and it would bake a specific policy into every integration. Instead, your app decides when to flip the flag. A common pattern is a URL query parameter for staff onboarding:
278
+
279
+ ```ts
280
+ // After Mark.init(...)
281
+ const params = new URLSearchParams(window.location.search);
282
+ if (params.get('onelence_internal') === '1') Mark.setInternal(true);
283
+ if (params.get('onelence_internal') === '0') Mark.setInternal(false);
284
+ ```
285
+
286
+ Other reasonable triggers: an authenticated admin/staff role, an internal IP range detected server-side, a feature flag, or an explicit toggle in your own settings UI.
287
+
288
+ **Server-side** the same API is available on `NodeMark`:
289
+
290
+ ```ts
291
+ const mark = createNodeMark({ key: process.env.MARK_SECRET_KEY! });
292
+ mark.setInternal(true);
293
+ mark.track('backoffice_action'); // is_internal: true
294
+ ```
295
+
296
+ `is_internal` is a first-class field on the backend: events are still ingested (so you can audit and debug integrations), but excluded from customer-facing reports by default.
297
+
226
298
  ## Support
227
299
 
228
300
  Need help? Reach out through your account team or file a ticket via the OneLence dashboard. Please include the SDK version, runtime (browser or Node), and any reproduction steps so we can assist quickly.