Website measurement

Install the pixel in any stack

One script tag measures the audience for every website, web app, portal, dashboard, or embedded widget that displays FXMacroData content. It is the same tag everywhere; what changes between frameworks is where you put it and how you hand it route changes. Apps, bots, and assistants have no browser, and use the backend meter instead.

<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

No key, no site id, no account number. The pixel identifies your account from the browser Origin, which is why the domain has to be registered in API Management first. An event from an unregistered origin is rejected with origin is not an approved redistribution domain.

1. Configuration attributes

AttributeValuesWhat it does
data-fxmd-meter-modepage (default), exposureWhether every page view counts, or only views of a tagged FXMacroData component. See below.
data-fxmd-attribution-modeverify (default), injectverify reports whether your own attribution element is present and visible. inject adds a small fixed badge in the bottom-right corner if none is found.
data-fxmd-endpointAn absolute URLOverrides where events are sent. Only needed if you proxy the collector through your own domain.
<script
  async
  src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
  data-fxmd-meter-mode="exposure"
  data-fxmd-attribution-mode="inject"></script>

The shorter forms data-meter-mode and data-attribution-mode are also accepted, for platforms whose tag editors strip vendor prefixes.

What it sends

A page_view on load and on each route change, a module_view when a tagged component becomes visible, one heartbeat 15 seconds in, and an attribution_click if someone clicks your credit link. Each carries an anonymous visitor id, the path, the viewport, timezone and language, and whether the attribution element was visible. Transport is navigator.sendBeacon with a fetch fallback, so it never blocks rendering and never fails loudly. No personal data, no cross-site identifier, and nothing about the individual beyond a random id your browser stores.

2. Which domains to register

  • Apex and www are one entry. Registering https://example.com also accepts https://www.example.com, and the reverse.
  • Every other subdomain is its own entry. app.example.com, portal.example.com, and dashboard.example.com each need registering. Adding a domain never adds a licence fee.
  • The scheme and port matter. Register the origin you actually serve. A non-standard port is part of the origin.
  • Register staging too if you want to test there, or accept that staging events are rejected. Rejected events are not billed, so an unregistered staging site is harmless, just invisible.
  • Localhost is not registerable. Verify on a deployed origin.

The site identity in your reporting is the hostname the page was served from, so a single licence covering five subdomains still shows you five rows and one combined billable total.

3. Page mode vs exposure mode

Page mode (default)

Every human page view counts the visitor. Correct when the pixel only loads on pages that show FXMacroData content: a rates page, a calendar page, a set of market templates.

Do not put a page-mode pixel in a global layout on a site where most pages have no FXMacroData content. You will meter your marketing traffic.

Exposure mode

Only a view of a component you have tagged counts. Correct for a single-page app or a global layout, where you load the pixel once and let the tagging decide.

Exposure mode without tagging measures nobody. If you choose it, you must tag; the two halves are one decision.

There is a safety net: if an exposure-mode site records no tagged component views at all in a period, billing falls back to counting its human page views, so an untagged site is never silently metered at zero. It is a backstop, not a plan. Once you tag correctly the fallback stops applying and your marketing-page visitors go back to being uncounted, which is the whole point of choosing exposure mode.

4. Tagging the data components

Put both attributes on the outermost element of each FXMacroData-powered component. The pixel watches it with an IntersectionObserver and reports the first time at least 10% of it enters the viewport, once per route.

<section data-fxmd-metered data-fxmd-module="release-calendar">
  <!-- your rendering of the FXMacroData calendar -->
</section>

<div data-fxmd-metered data-fxmd-module="usd-cpi-chart">...</div>
<aside data-fxmd-metered data-fxmd-module="rate-differentials">...</aside>
  • Both attributes are required. data-fxmd-module alone names a component in the page payload but does not meter it; data-fxmd-metered is what arms the observer.
  • Module names are lowercase, up to 64 characters, from a-z 0-9 _ . : -. Anything else is dropped silently, which looks exactly like nothing happening. Keep them stable: they are how you read your own usage later.
  • Content added later is picked up. A MutationObserver rescans on DOM changes and on class, style, hidden, and aria-hidden changes, so tabs, accordions, modals, and lazy-loaded panels all work without extra code.
  • Up to 16 module names are collected per event. Tag components, not every row in a table.

5. The JavaScript API

When a component is drawn to a canvas, rendered inside a web component, or only exists after a user action, tag it in code instead.

// Report a module view explicitly.
window.FXMacroDataPixel.trackModule("release-calendar");

// Options: dedupe defaults to true (once per module per route).
window.FXMacroDataPixel.trackModule("usd-cpi-chart", {
  dedupe: false,
  source: "chart-render",
  element_label: "USD CPI, 12m",
});

// Read the current anonymous context, e.g. for your own debugging.
window.FXMacroDataPixel.getContext();
// { anonymous_visitor_id, anonymous_session_id, site_id, meter_mode, meter_version }

The script is loaded async, so it may not have booted when your code runs. Use the queue and nothing is lost:

window.FXMacroDataPixel = window.FXMacroDataPixel || { q: [] };
window.FXMacroDataPixel.q.push(["trackModule", "release-calendar"]);

Queued commands run as soon as the pixel initialises, and the same q.push form keeps working afterwards.

6. The attribution link

The licence requires visible FXMacroData credit wherever the data appears. Mark your own element and the pixel confirms it is present, on screen, and not hidden by CSS.

<a href="https://fxmacrodata.com/?utm_source=example.com&utm_medium=partner"
   data-fxmd-attribution>Data powered by FXMacroData</a>

The pixel reports the element position, size, text, and whether it was visible in the viewport at the time of the event. It never moves or restyles your element. Set data-fxmd-attribution-mode="inject" only if you would rather we add a small fixed badge for you; a real credit inside your own layout is better for both sides.

7. Single-page frameworks

Route changes are handled for you. The pixel wraps history.pushState and history.replaceState and listens for popstate and hashchange, so every client-side navigation produces a fresh page view and rescans for tagged components. You do not need a router hook. Load the script once in the shell, choose exposure mode, and tag.

Plain HTML

<!-- before </body>, on pages that display FXMacroData content -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

React (Vite, Create React App)

<!-- index.html -->
<script
  async
  src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
  data-fxmd-meter-mode="exposure"></script>
// ReleaseCalendar.tsx
export function ReleaseCalendar({ events }) {
  return (
    <section data-fxmd-metered data-fxmd-module="release-calendar">
      {events.map((e) => <EventRow key={e.id} event={e} />)}
    </section>
  );
}

Next.js, app router

// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
          strategy="afterInteractive"
          data-fxmd-meter-mode="exposure"
        />
      </body>
    </html>
  );
}

App router navigation uses the History API, so route changes are picked up without a usePathname effect. Keep strategy="afterInteractive"; beforeInteractive would run the pixel before your app renders anything to observe.

Next.js, pages router

// pages/_document.tsx
<Head>
  <script
    async
    src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
    data-fxmd-meter-mode="exposure"
  />
</Head>

Vue 3

<!-- index.html -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

<!-- ReleaseCalendar.vue -->
<template>
  <section data-fxmd-metered data-fxmd-module="release-calendar">
    <EventRow v-for="e in events" :key="e.id" :event="e" />
  </section>
</template>

Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [{
        src: "https://fxmacrodata.com/static/js/fxmacrodata-pixel.js",
        async: true,
        "data-fxmd-meter-mode": "exposure",
      }],
    },
  },
});

Angular

<!-- src/index.html, before </body> -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>
<!-- release-calendar.component.html -->
<section data-fxmd-metered data-fxmd-module="release-calendar">
  <app-event-row *ngFor="let e of events" [event]="e"></app-event-row>
</section>

SvelteKit

<!-- src/app.html, inside %sveltekit.body% wrapper -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

Astro

---
// src/layouts/Base.astro
---
<slot />
<script is:inline async
        src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

is:inline stops Astro from bundling and rewriting the tag, which would strip the data attributes.

Remix and React Router

// app/root.tsx
<body>
  <Outlet />
  <script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
          data-fxmd-meter-mode="exposure" />
  <Scripts />
</body>

Gatsby

// gatsby-ssr.js
export const onRenderBody = ({ setPostBodyComponents }) => {
  setPostBodyComponents([
    <script key="fxmd" async
      src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
      data-fxmd-meter-mode="exposure" />,
  ]);
};

Solid, Qwik, Preact, Alpine, htmx

<!-- Same tag in the shell HTML. Anything that navigates through the
     History API or replaces DOM in place is already handled. -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

8. Server-rendered frameworks

With classic server rendering you have a real choice: put the tag in a partial included only by the templates that show FXMacroData content and stay in page mode, or put it in the base layout and switch to exposure mode. The first is simpler and usually more accurate.

Django

{# templates/partials/fxmd_pixel.html #}
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

{# templates/markets/calendar.html #}
{% include "partials/fxmd_pixel.html" %}

Flask / Jinja

{# templates/base.html #}
{% block fxmd_pixel %}{% endblock %}

{# templates/calendar.html #}
{% block fxmd_pixel %}
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
{% endblock %}

Ruby on Rails

<%# app/views/layouts/application.html.erb %>
<%= yield :fxmd_pixel %>

<%# app/views/markets/calendar.html.erb %>
<% content_for :fxmd_pixel do %>
  <script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
<% end %>

Laravel / Blade

{{-- resources/views/layouts/app.blade.php --}}
@stack('fxmd')

{{-- resources/views/markets/calendar.blade.php --}}
@push('fxmd')
  <script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
@endpush

ASP.NET Core, Razor

@* Views/Shared/_Layout.cshtml *@
@await RenderSectionAsync("FxmdPixel", required: false)

@* Views/Markets/Calendar.cshtml *@
@section FxmdPixel {
  <script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
}

Spring Boot, Thymeleaf

<!-- templates/fragments/fxmd.html -->
<script th:fragment="pixel" async
        src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

<!-- templates/calendar.html -->
<div th:replace="fragments/fxmd :: pixel"></div>

Express with EJS, Handlebars, Pug

<%- include('partials/fxmd-pixel') %>      <!-- EJS -->
{{> fxmd-pixel}}                            <!-- Handlebars -->
script(async, src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js")  //- Pug

Plain PHP

<?php if ($page_shows_fxmd_data): ?>
  <script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
<?php endif; ?>

9. CMS and no-code platforms

Most hosted platforms give you a custom-code box for the site head or footer. Paste the tag there, then decide the mode: site-wide box plus exposure mode plus tagging, or a page-level box on just the data pages plus page mode.

WordPress, no plugin

// functions.php in a child theme
add_action('wp_footer', function () {
    if (!is_page(['market-calendar', 'rates'])) return;   // data pages only
    echo '<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>';
});

WordPress, site-wide

<!-- Any header/footer scripts plugin, or theme options -> custom code -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

<!-- then wrap the shortcode/block output -->
<div data-fxmd-metered data-fxmd-module="release-calendar">[fxmd_calendar]</div>

Shopify

<!-- layout/theme.liquid, before </body> -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

Use the theme file, not a Custom Pixel in the Customer Events sandbox: the sandbox has no access to your DOM, so tagged components would never be seen.

Webflow

Project Settings -> Custom Code -> Footer Code
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

Then on the wrapper element: Settings -> Custom attributes
  data-fxmd-metered  =  (leave blank)
  data-fxmd-module   =  release-calendar

Squarespace

Settings -> Advanced -> Code Injection -> Footer
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

Per page: Page Settings -> Advanced -> Page Header Code Injection

Wix

Settings -> Custom Code -> Add Custom Code
  Place in: Body - end
  Load on: All pages, or Choose specific pages
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

Ghost

Settings -> Code injection -> Site footer
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"
        data-fxmd-meter-mode="exposure"></script>

Drupal

// mytheme.theme
function mytheme_page_attachments_alter(array &$attachments) {
  $attachments['#attached']['html_head'][] = [[
    '#tag' => 'script',
    '#attributes' => [
      'src' => 'https://fxmacrodata.com/static/js/fxmacrodata-pixel.js',
      'async' => TRUE,
      'data-fxmd-meter-mode' => 'exposure',
    ],
  ], 'fxmd_pixel'];
}

Joomla, HubSpot, Framer, Bubble, Webnode

Site settings -> custom head or footer code -> paste the tag.
Add the two data attributes to the container element in whichever
element-settings panel the platform provides.

10. Static site generators

Hugo

<!-- layouts/partials/fxmd-pixel.html -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

<!-- layouts/_default/baseof.html -->
{{ if .Params.fxmd }}{{ partial "fxmd-pixel.html" . }}{{ end }}

Jekyll

<!-- _includes/fxmd-pixel.html -->
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>

<!-- _layouts/default.html -->
{% if page.fxmd %}{% include fxmd-pixel.html %}{% endif %}

Eleventy

<!-- _includes/layouts/base.njk -->
{% if fxmd %}
<script async src="https://fxmacrodata.com/static/js/fxmacrodata-pixel.js"></script>
{% endif %}

Docusaurus, MkDocs, VitePress

// docusaurus.config.js
scripts: [{
  src: "https://fxmacrodata.com/static/js/fxmacrodata-pixel.js",
  async: true,
  "data-fxmd-meter-mode": "exposure",
}]

11. Tag managers

Google Tag Manager

Tag type: Custom HTML
<script>
  var s = document.createElement("script");
  s.async = true;
  s.src = "https://fxmacrodata.com/static/js/fxmacrodata-pixel.js";
  s.setAttribute("data-fxmd-meter-mode", "exposure");
  document.body.appendChild(s);
</script>

Trigger: All Pages (exposure mode), or a Page View trigger
         limited to your data pages (page mode).

Build the element in code rather than pasting a raw script tag: GTM strips unknown attributes from injected tags, which would silently drop your mode setting. Do not tick Support document.write.

Segment, Tealium, and similar

// Any "custom JavaScript" destination, loaded once per page:
!function(){
  var s = document.createElement("script");
  s.async = true;
  s.src = "https://fxmacrodata.com/static/js/fxmacrodata-pixel.js";
  s.setAttribute("data-fxmd-meter-mode", "exposure");
  document.body.appendChild(s);
}();

A tag manager adds a layer that can be misconfigured, blocked by consent tooling, or deployed late. If you control the site template, put the tag in the template.

12. CSP, consent, and privacy

Content Security Policy

script-src  'self' https://fxmacrodata.com;
connect-src 'self' https://fxmacrodata.com;

connect-src is the one people forget. Without it the script loads, runs, and every beacon is blocked, so the pixel looks installed and measures nothing. If you use nonces, put the nonce on the script tag; the pixel adds no inline script of its own.

What it stores on the visitor device

KeyWhereLifetimeContents
fxmd_partner_vidCookie, first-party, SameSite=Lax, Secure on HTTPS395 daysA random id generated in the browser
fxmd_partner_vidlocalStorageUntil clearedThe same random id, so a cleared cookie does not double-count
fxmd_partner_sidsessionStorageThe tab sessionA random session id

All three are first-party to your domain and meaningless anywhere else. Nothing is read from or written to any other site, there is no cross-site identifier, and no advertising use. If storage is unavailable the pixel falls back to an in-memory id for that page view, which over-counts rather than under-counts.

Consent

This is a licence-compliance meter, not analytics or advertising, and most operators treat it the way they treat any first-party measurement they are contractually obliged to run. Where your counsel decides it needs consent, gate the tag the same way you gate the rest, and understand the trade: an unconsented visitor is not metered, is not billed, and is not visible in your reporting.

Disclose it in your privacy policy the way you disclose other first-party measurement: the cookie name, the retention, and that it counts unique readers for a data licence and nothing else.

Ad blockers and network filtering

Some visitors block third-party scripts by hostname. That under-counts you, which is not a problem for us. If it is a problem for your own reporting, serve the file from your own domain and point the collector back with data-fxmd-endpoint="https://example.com/fxmd-collect", proxying to https://fxmacrodata.com/fxmacrodata-pixel/v1/events and preserving the Origin header. Do not modify the script itself: a changed meter is not a meter.

13. Verify and troubleshoot

Open a data page in a normal browser, then check the Network tab for a POST to /fxmacrodata-pixel/v1/events returning 200. Then open the redistribution panel in API Management: it shows registered surfaces, combined users, pixel status, and the estimated next invoice. Pixel status turns active after the first accepted event.

SymptomCauseFix
origin is not an approved redistribution domainThe hostname is not registered, or you registered a different subdomainAdd the exact origin in API Management. Apex and www alias each other; nothing else does.
No network request at allThe script was not loaded, or a bundler rewrote the tag and dropped the attributesCheck the tag in view-source, not in your source file. Astro needs is:inline; GTM needs the createElement form.
Script loads, requests blockedconnect-src missing from your CSPAdd https://fxmacrodata.com to connect-src.
Events accepted, zero users countedExposure mode with no tagged componentsAdd data-fxmd-metered data-fxmd-module="..." to the data containers, or switch to page mode.
Module views never fireModule name has uppercase, spaces, or is over 64 characters, or only one of the two attributes is presentLowercase, a-z 0-9 _ . : -, both attributes on the same element.
Counted far higher than expectedPage mode in a global layout across a whole marketing siteSwitch to exposure mode and tag, or load the tag only on data pages.
Visitors classified as botsAutomated tests, headless browsers, prefetch or preview fetches, or a burst of events from one visitorExpected. Bot traffic is never billed. Verify with a real browser.
Attribution reported as not visibleThe element is hidden, zero-size, fully transparent, or below the fold at event timePut the credit where a reader can see it on the data screen.

Related

AI Answer-Ready

Key Facts

Page
Redistribution Pixel Integrations
Section
Documentation
Canonical URL
https://fxmacrodata.com/documentation/redistribution-pixel-integrations
Source
FXMacroData editorial and official publisher references
Last Updated
See page metadata

Provenance And Trust

Cite the canonical URL and source field above. Where available, this page maps to official publisher releases and timestamped updates.

Quick Q&A

What is this page about? This page explains Redistribution Pixel Integrations with directly usable context for trading, research, and API workflows.

What source should be cited? Use the canonical URL and the listed source field; cite official publisher references when available.

How fresh is this content? The last updated value above reflects the page metadata or latest available data timestamp.

Can this be used in AI assistants? Yes. This section is intentionally structured for retrieval and citation in chat assistants.

Prompt Packs

Use these in ChatGPT, Claude, Gemini, Mistral, Perplexity, or Grok for consistent source-aware outputs.