# 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)](#conversion-snippet-v2) below.
- **`mtr_pixel.js` (v1 — legacy)** — the original client-side pixel that POSTs events to `metrics.mtr.center`. Kept for backward compatibility; documented under [Legacy Pixel (v1)](#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

1. On `mtr.center`, every outbound link is decorated (in `mtr-cms-platform`) with `mtr_uid` (our GA4 `client_id`) + legacy params + GA4's `_gl`.
2. The client installs `mtr_snippet.js` in their `<head>`. On landing from `mtr.center` it reads those ids and stores them in a **first-party cookie** (`_mtr`) — survives ITP within the client's own domain.
3. The snippet loads **our** GA4 (`gtag.js` with an **MTR-owned** measurement id) and forces `client_id = mtr_uid`, so a purchase fired here lands in the **same MTR property / same user** as the experience session.
4. On the order-confirmation page a per-platform **adapter** reads the order `value`/`transaction_id`/`currency` and fires a GA4 `purchase` event (deduped per transaction).
5. 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.

```html
<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`](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

```bash
npm install
npm run build   # tsc -> dist/mtr_snippet.js + dist/mtr_pixel.js, then stamps the version
```

### Open items before go-live

- **GA4 cross-domain** must list each client domain in the property settings for `_gl` to stitch natively (the `client_id` force is the fallback that always works).
- **Confirm the real dataLayer** of each platform with a completed test order (the VTEX `orderPlaced` field paths are assumptions until verified).
- **CDN**: served via jsDelivr from the `mtr-pixel` npm package (`https://cdn.jsdelivr.net/npm/mtr-pixel@2/dist/mtr_snippet.js`) — a neutral host, **not** `metrics.mtr.center` (the blocked one). Go-live = `npm publish` the new version.
- **Eucerin** maps to a GTM container (`GTM-XXXX`), not a GA4 `G-XXXX` — needs separate handling before its conversion tracking works.
- **Native app webview** may lack the `_ga` cookie → `mtr_uid` can 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

1.  **Clone the repository:**

    ```bash
    git clone https://github.com/morethanrealio/mtr-pixel.git
    cd mtr-pixel
    ```

2.  **Install dependencies:**

    ```bash
    npm install
    ```

3.  **Build or develop:**

    ```bash
    npm run-script build
    ```

    This command will compile the TypeScript code and generate the `mtr_pixel.js` file in the `dist` directory. If you want to develop, you'll need to run the following command:

    ```bash
    npm run-script watch
    ```

    This command will compile and watch for changes in the TypeScript code and generate the `mtr_pixel.js` file in the `dist` directory.

## Usage

To integrate MTR-Pixel into your website, include the generated `mtr_pixel.js` file in your HTML and initialize the `MTRPixel` class.

1.  **Include the script in your HTML:**

    ```html
    <script src="path/to/dist/mtr_pixel.js"></script>
    ```

2.  **Initialize the MTRPixel class:**

    The `MTRPixel` class is automatically initialized when the script loads, but it requires specific local storage parameters to be present: `mtrsessionid`, `mtruserid`, `mtrtimestampstart` and `mtrorigin` to track specific users OR URL Params set like:

    ```
    https://yourwebsite.com/?mtrsessionid=SESSION_ID&mtruserid=USER_ID&mtrtimestampstart=TIMESTAMP&mtrorigin=ORIGIN
    ```

3.  **Track events:**

    Once the MTRPixel is initialized, you can track events using the `trackEvent` method. This method accepts an object with any custom data you want to send. To track user actions use the `CTA` parameter.

    ```javascript
    // 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:

```html
<!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`](demos/website) directory.

