@metrics/web
Browser SDK and tracking pixel of Postlip Metrics. It speaks the Segment Tracking API Spec (see docs/api/tracking-api.md): page views, product events, identity, attribution and consent, plus automatic capture of engagement, clicks, errors, forms and the page layout that heatmaps are drawn on. It is ≤ 12 KB gzip, has no dependencies and sets no cookies.
Bu sayfa derleme sırasında depodaki packages/sdk-web/README.md dosyasından üretilir.
Install
Script tag (recommended for websites): paste the snippet into <head>. It queues calls until m.js arrives.
<script>
!function(){var m=window.metrics=window.metrics||[];if(m.load)return;m.q=[];["page","track","identify","group","alias","reset","consent"].forEach(function(k){m[k]=function(){m.q.push([k].concat([].slice.call(arguments)))}});
var s=document.createElement("script");s.async=1;s.src="https://collect.<your-domain>/m.js";document.head.appendChild(s);
m.load=function(k,o){m.q.unshift(["load",k,o])};}();
metrics.load("pk_live_…", { consent: "required" });
metrics.page();
</script>When m.js is loaded from the collector, the collector's origin is the default host.
npm / bundlers (no globals):
import { createMetrics } from '@metrics/web';
const metrics = createMetrics();
metrics.load('pk_live_…', { host: 'https://collect.<your-domain>' });examples/index.html is a runnable page.
API
Options
host, consent (required · implied · none), autocapture (false or per-toggle overrides), debug (see Debug mode), gaMeasurementId (G-…, see Google Analytics ids), respectGpc, trackHashChanges, remoteConfig: false, flushAt (20), flushInterval (5000 ms), and any remote config field: excludedPaths, maskSelectors, ignoreSelectors, stripQueryParams, sessionTimeoutMinutes, interactionSampleRate, dataLayerEvents. Options override what the panel configured.
Debug mode
debug: true logs every message, drop and server rejection to the console. Opening any page of the site with ?metrics_debug=1 does the same for the rest of the tab's session, without a code change, and also marks the messages as test traffic (context.test): they show up in the live event stream but stay out of the reports. ?metrics_debug=0 turns it off. The switch lives in sessionStorage (mtr_d).
In debug mode the npm build also asks the remote config for the app's tracking plan in brief (?schemaHints=1: planned events with their required properties, blocked events, the schema mode) and warns in the console when a track() call names a blocked event, an unplanned event (will be rejected in strict mode) or misses a required property. The event is still sent; the server decides. The script-tag build (m.js) leaves these hints out to stay within its size budget: there, the server's rejections are logged as before.
Internal traffic
Opening any page of the site with ?metrics_internal=1 marks this browser as internal: every message carries context.internal: true, and the reports leave it out like the app's other internal traffic (traffic filters, internal IP ranges). The flag stays in localStorage (mtr_internal) until a page is opened with ?metrics_internal=0. Share the link with your team; it sets nothing else.
Consent
analyticscontrols persistent identity, the retry queue and interaction capture.marketingcontrols click ids (gclid,fbclid/fbc/fbp,li_fat_id,msclkid,ttclid, …) and whetherfirst_touch/last_non_direct_touchpersist across visits.- Every message carries
context.consent. The choice itself is stored inlocalStorage(mtr_c) so it holds on the next page. context.attribution.methodsays how the touches were kept:consentwhen they persist across visits (marketing consent),same_visitwhen they are only this tab's. A server event that forwardsgetContext()carries it too, so the lead's attribution shows how much of the history was visible.respectGpc: trueturns marketing off whennavigator.globalPrivacyControlis set.
Google Analytics ids
With analytics consent, the SDK reads the Google Analytics cookies the site's GA4 tag already set — _ga (client id) and _ga_<measurement id> (session id) — and sends them as context.ga { clientId, sessionId }. The GA4 Measurement Protocol destination uses them, so the conversions it sends join the visitor's GA4 session instead of starting a new one. If the page runs several GA4 properties, pass gaMeasurementId: 'G-…' to pick the right session cookie (otherwise the first _ga_… cookie is read). Without analytics consent the cookies are not read; the SDK never writes them.
Automatic capture
Every event below can be switched off from the panel or with autocapture. Interaction events (clicks, scroll, layout, forms) follow interactionSampleRate, which is decided once per session. Coordinates are 0…1000 of the document on both axes.
Privacy
data-metrics-ignore: the element and its children are never captured (clicks, layout, forms).data-metrics-mask, or any element matchingmaskSelectors: the label becomes***.- Inputs, textareas, selects and contenteditable regions never yield text.
- Excluded paths (from the panel, same patterns as the server:
/panel,/account/*,/**/private): nothing is captured there automatically. Your owntrack()calls still go out, but with the page reduced to[excluded]. When such a page shows up as a referrer or previous page, it becomeshttps://site/[excluded]. - Captured URLs lose the
stripQueryParamsentries, sensitive keys (email,token,password…), e-mail or phone-looking values, credentials and#…=…fragments.utm_*and click ids are exempt. - No IP handling and no cookies are written. The
_fbc,_fbpandli_fat_idcookies are only read, and only sent with marketing consent. The_gaand_ga_<id>cookies are only read, with analytics consent. - Without consent nothing goes to
localStorage, except the internal-browser switch when someone opens a?metrics_internal=1link on purpose.
Transport
Messages are batched (20 messages, 5 s, or when the page is hidden) into POST {host}/v1/batch with a text/plain body { writeKey, batch, sentAt }, so there is no CORS preflight. Regular sends use fetch(keepalive, credentials: 'omit'), so failures can be retried; when the page is hidden, navigator.sendBeacon is used. Bodies are split under the contract limits (≤ 500 KB / 500 messages, and ≤ 64 KB per beacon). A message over 32 KB is dropped and logged in debug mode. Batches that fail with 5xx, 429 (honouring Retry-After) or a network error are retried with backoff from 10 s up to 24 h. With analytics consent, the bounded retry queue survives reloads in localStorage.