mtr-pixel
v2.0.0
Published
Rastreamento de conversões via GA4 (snippet universal) + pixel legado
Downloads
229
Readme
MTR-Pixel
This repo ships two things:
mtr_snippet.js(v2 — conversion tracking via GA4) — the snippet a CLIENT installs in their<head>to attribute purchases on their own domain back to an MTR experience. No client backend, no GA access, no GTM required. See Conversion Snippet (v2) below.mtr_pixel.js(v1 — legacy) — the original client-side pixel that POSTs events tometrics.mtr.center. Kept for backward compatibility; documented under Legacy Pixel (v1).
Conversion Snippet (v2)
The problem it solves
MTR can't reliably measure the revenue its experiences generate: the legacy pixel's POSTs are heavily dropped by adblock + Safari ITP, and clients won't give us access to their own GA. The purchase happens on the client's domain, after the user leaves mtr.center.
How it works
- On
mtr.center, every outbound link is decorated (inmtr-cms-platform) withmtr_uid(our GA4client_id) + legacy params + GA4's_gl. - The client installs
mtr_snippet.jsin their<head>. On landing frommtr.centerit reads those ids and stores them in a first-party cookie (_mtr) — survives ITP within the client's own domain. - The snippet loads our GA4 (
gtag.jswith an MTR-owned measurement id) and forcesclient_id = mtr_uid, so a purchase fired here lands in the same MTR property / same user as the experience session. - On the order-confirmation page a per-platform adapter reads the order
value/transaction_id/currencyand fires a GA4purchaseevent (deduped per transaction). - We read the raw event-level data via the GA4 → BigQuery export and join experience → purchase on
mtr_uid. No UI sampling/thresholding.
Install (per client)
The snippet file is identical for every client — only window.MTR_CONFIG changes. Paste both into the <head>, as high as possible. Recommended: bake the MTR-owned GA4 tag (measurementId, G-XXXX) inline. What runs on the client then has zero runtime dependency on MTR servers — only Google's gtag.js loads — so a conversion is never lost because one of our endpoints was slow or down. The CMS holds each client's tag as the source of truth and can generate this block.
<script>
window.MTR_CONFIG = {
measurementId: 'G-XXXXXXXXXX', // MTR-owned GA4 tag for this client (baked in)
purchase: { adapter: 'vtex', event: 'orderPlaced' },
cookieDomain: '.boticario.com.br',
cookieDays: 30,
};
</script>
<script async src="https://cdn.jsdelivr.net/npm/mtr-pixel@2/dist/mtr_snippet.js"></script>Optional — centralized mode. Instead of measurementId, pass a public pixelKey and the snippet resolves the tag from the CMS (https://mtr.center/api/pixel-config/<pixelKey>/). This keeps the mapping fully central, but adds a runtime GET on the conversion path — so it's reserved for cases where editing the installed snippet later is impractical. For revenue data we can't afford to lose, prefer inline.
CDN / versioning: served by jsDelivr straight from the mtr-pixel npm package — publishing a new version (npm publish) rolls out automatically. The URL is not version-pinned (pinned only to major @2) so clients always get the latest within v2 without touching their HTML; a future breaking change would ship as @3. jsDelivr edge-caches unpinned URLs (~7 days) — propagation isn't instant (force a purge if needed).
See examples/install-snippet.html for the centralized, generic (GA4 dataLayer), VTEX, and manual variants.
Adapters
| adapter | When to use | event |
|-------------|-------------|---------|
| datalayer | Store pushes a GA4 EE purchase to window.dataLayer (GTM, Shopify w/ GA4) | dataLayer event name (purchase) |
| vtex | VTEX stores (e.g. boticário) | order-placed event (orderPlaced) |
| gtag | Mirror a purchase the client's own gtag already fires | — |
| url | No event — match the confirmation-page URL + read configured paths | URL substring/regex |
| manual | Custom theme calls window.mtrTrackPurchase({...}) directly | — |
Field paths default to the GA4 Enhanced-Ecommerce schema; override per-store with purchase.map.
Build
npm install
npm run build # tsc -> dist/mtr_snippet.js + dist/mtr_pixel.js, then stamps the versionOpen items before go-live
- GA4 cross-domain must list each client domain in the property settings for
_glto stitch natively (theclient_idforce is the fallback that always works). - Confirm the real dataLayer of each platform with a completed test order (the VTEX
orderPlacedfield paths are assumptions until verified). - CDN: served via jsDelivr from the
mtr-pixelnpm package (https://cdn.jsdelivr.net/npm/mtr-pixel@2/dist/mtr_snippet.js) — a neutral host, notmetrics.mtr.center(the blocked one). Go-live =npm publishthe new version. - Eucerin maps to a GTM container (
GTM-XXXX), not a GA4G-XXXX— needs separate handling before its conversion tracking works. - Native app webview may lack the
_gacookie →mtr_uidcan be empty there.
Legacy Pixel (v1)
MTR-Pixel is a library designed for tracking user interactions and conversions on websites. The library sends tracking events to a specified backend endpoint.
Install
Clone the repository:
git clone https://github.com/morethanrealio/mtr-pixel.git cd mtr-pixelInstall dependencies:
npm installBuild or develop:
npm run-script buildThis command will compile the TypeScript code and generate the
mtr_pixel.jsfile in thedistdirectory. If you want to develop, you'll need to run the following command:npm run-script watchThis command will compile and watch for changes in the TypeScript code and generate the
mtr_pixel.jsfile in thedistdirectory.
Usage
To integrate MTR-Pixel into your website, include the generated mtr_pixel.js file in your HTML and initialize the MTRPixel class.
Include the script in your HTML:
<script src="path/to/dist/mtr_pixel.js"></script>Initialize the MTRPixel class:
The
MTRPixelclass is automatically initialized when the script loads, but it requires specific local storage parameters to be present:mtrsessionid,mtruserid,mtrtimestampstartandmtroriginto track specific users OR URL Params set like:https://yourwebsite.com/?mtrsessionid=SESSION_ID&mtruserid=USER_ID&mtrtimestampstart=TIMESTAMP&mtrorigin=ORIGINTrack events:
Once the MTRPixel is initialized, you can track events using the
trackEventmethod. This method accepts an object with any custom data you want to send. To track user actions use theCTAparameter.// Initialize MTRPixel const mtrPixel = new MTRPixel(); // Track an user action on load mtrPixel.trackEvent({CTA: "Carregar Loja"}); // Track a button click event document.getElementById('myButton').addEventListener('click', () => { mtrPixel.trackEvent({CTA: 'Comprar'}); });
Example
Here is a complete example of how to use MTR-Pixel in an HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MTR - Pixel Demo</title>
<script src="../../dist/mtr_pixel.js"></script>
</head>
<body>
<h1>MTR - Pixel Demo</h1>
<button id="start" onclick="start()">Start</button>
<div id="mtr-div" style="display: none">
<p>Check the console to see the tracking events.</p>
<button id="trackButton" onclick="trackEvent()">Track Event</button>
<button id="clearButton" onclick="clearSession()">Clear Session</button>
</div>
<script>
const STORAGE_PREFIX = "mtr";
function start() {
// simulation of getting the IDs of the user by URL parameters
const sessionId = "7d498726-2ccd-4316-b447-2e8a9e06a7f7";
const userId = "6c257aff-e173-4020-ae12-1a3596122cde";
const timestampStart = "2025-11-11T19:52:48.995Z";
window.location.assign(`${window.location.href}?mtrsessionid=${sessionId}&mtruserid=${userId}&mtrtimestampstart=${timestampStart}`);
}
function trackEvent() {
// start mtr pixel again
const mtrPixel = new MTRPixel();
// add a click event listener to the button
mtrPixel.trackEvent({CTA: 'Comprar'});
}
function clearSession() {
// start mtr pixel again
const mtrPixel = new MTRPixel();
// track a page view event on clear session
mtrPixel.trackEvent({CTA: "Clear"});
localStorage.removeItem(`${STORAGE_PREFIX}sessionid`);
localStorage.removeItem(`${STORAGE_PREFIX}userid`);
localStorage.removeItem(`${STORAGE_PREFIX}timestampstart`);
localStorage.removeItem(`${STORAGE_PREFIX}origin`);
document.getElementById("start").style.display = "block";
document.getElementById("mtr-div").style.display = "none";
}
// check if it needs start button
const urlParams = new URLSearchParams(window.location.search);
const sessionId = urlParams.get("mtrsessionid");
const bShow = !sessionId;
document.getElementById("start").style.display = bShow ? "block" : "none";
document.getElementById("mtr-div").style.display = bShow ? "none" : "block";
</script>
</body>
</html>For more details, you can refer to the demo available in the demos/website directory.
