> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mention-me.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Product Referral Tag

> Enable product-level referral tracking so customers can share specific products

export const SignInNotice = ({message = "To see code snippets pre-filled with your partner code"}) => {
  return <div data-mm-sign-in style={{
    display: "none"
  }}>
      <Info>
        {message}, <a data-mm-sign-in-link href="https://app.mention-me.com/sign-in"><strong>sign in</strong></a>.
      </Info>
    </div>;
};

export const MerchantContext = () => {
  const PARTNER_STORAGE_KEY = "mm-docs-partner";
  const escapeHtml = str => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
  const getStoredPartner = () => {
    try {
      const raw = localStorage.getItem(PARTNER_STORAGE_KEY);
      if (!raw) return null;
      const data = JSON.parse(raw);
      if (data && data.partnerCode) return data;
    } catch (e) {}
    return null;
  };
  const setStoredPartner = data => {
    try {
      localStorage.setItem(PARTNER_STORAGE_KEY, JSON.stringify(data));
    } catch (e) {}
  };
  const clearStoredPartner = () => {
    try {
      localStorage.removeItem(PARTNER_STORAGE_KEY);
    } catch (e) {}
  };
  const captureQueryParams = () => {
    const params = new URLSearchParams(window.location.search);
    const partner = params.get("partner");
    const name = params.get("name");
    if (partner) {
      const data = {
        partnerCode: partner
      };
      if (name) data.displayName = name;
      setStoredPartner(data);
      params.delete("partner");
      params.delete("name");
      const qs = params.toString();
      const clean = window.location.pathname + (qs ? "?" + qs : "") + window.location.hash;
      window.history.replaceState(null, "", clean);
      return data;
    }
    return getStoredPartner();
  };
  const isLocal = typeof window !== "undefined" && window.location.hostname === "localhost";
  const API_BASE = isLocal ? "http://localhost:3001" : "https://app.mention-me.com";
  const SIGN_IN_BASE = isLocal ? "http://localhost:3001/sign-in" : "https://app.mention-me.com/sign-in";
  const MERCHANT_WINDOW_KEY = "__mmMerchantContext";
  const publishMerchant = data => {
    window[MERCHANT_WINDOW_KEY] = data;
    window.dispatchEvent(new CustomEvent("mm-merchant-ready", {
      detail: data
    }));
  };
  const clearMerchant = () => {
    delete window[MERCHANT_WINDOW_KEY];
  };
  const BADGE_ID = "mm-partner-badge";
  const showPartnerBadge = (partnerData, source) => {
    if (document.getElementById(BADGE_ID)) return;
    const nav = document.getElementById("navigation-items");
    if (!nav || !nav.parentNode) return;
    const badge = document.createElement("div");
    badge.id = BADGE_ID;
    badge.className = "mm-partner-badge";
    const hasName = partnerData.displayName && partnerData.displayName !== partnerData.partnerCode;
    const heading = hasName ? escapeHtml(partnerData.displayName) : escapeHtml(partnerData.partnerCode);
    const code = hasName ? escapeHtml(partnerData.partnerCode) : "";
    const codeStr = code ? ' <span class="mm-partner-badge-code">' + code + '</span>' : '';
    const resetTitle = source === "clerk" ? "Sign out and switch account" : "Clear personalisation";
    badge.innerHTML = '<div class="mm-partner-badge-inner">' + '<span class="mm-partner-badge-content">' + '<span class="mm-partner-badge-context">Personalised for </span>' + '<span class="mm-partner-badge-name">' + heading + '</span>' + codeStr + '</span>' + '<button class="mm-partner-badge-reset" title="' + resetTitle + '">&times;</button>' + '</div>';
    nav.parentNode.insertBefore(badge, nav);
    badge.querySelector(".mm-partner-badge-reset").addEventListener("click", e => {
      e.preventDefault();
      e.stopPropagation();
      if (source === "clerk" && window.Clerk && window.Clerk.signOut) {
        clearMerchant();
        const redirect = SIGN_IN_BASE + "?redirect_url=" + encodeURIComponent(window.location.href);
        window.Clerk.signOut().then(() => {
          window.location.href = redirect;
        }).catch(() => {
          window.location.reload();
        });
        return;
      }
      clearStoredPartner();
      window.location.reload();
    });
  };
  const removePartnerBadge = () => {
    const el = document.getElementById(BADGE_ID);
    if (el) el.remove();
  };
  const showNotices = () => {
    document.querySelectorAll("[data-mm-sign-in]").forEach(el => {
      el.style.display = "";
    });
    const redirect = SIGN_IN_BASE + "?redirect_url=" + encodeURIComponent(window.location.href);
    document.querySelectorAll("[data-mm-sign-in-link]").forEach(a => {
      a.href = redirect;
    });
  };
  const hideNotices = () => {
    document.querySelectorAll("[data-mm-sign-in]").forEach(el => {
      el.style.display = "none";
    });
  };
  const walkCodeBlocks = replacements => {
    document.querySelectorAll("pre code").forEach(codeEl => {
      let html = codeEl.innerHTML;
      if (replacements) {
        for (const [from, to] of replacements) {
          html = html.split(from).join(escapeHtml(to));
        }
      }
      const paramStyle = "color:inherit;filter:brightness(110%);font-weight:bold;text-decoration:underline;cursor:pointer";
      html = html.replace(/(\?|&amp;)([a-z_]+)=/g, (match, prefix, name) => {
        const slug = name.replace(/_/g, "-");
        const target = document.getElementById("param-" + slug);
        if (!target) return match;
        return prefix + '<a href="#param-' + slug + '" style="' + paramStyle + '">' + name + "</a>=";
      });
      codeEl.innerHTML = html;
    });
  };
  const observeTabSwitches = callback => {
    let processing = false;
    const observer = new MutationObserver(() => {
      if (processing) return;
      processing = true;
      setTimeout(() => {
        callback();
        processing = false;
      }, 50);
    });
    setTimeout(() => {
      const tabs = document.querySelector("[role='tablist']");
      if (tabs && tabs.parentElement) {
        observer.observe(tabs.parentElement, {
          attributes: true,
          subtree: true,
          childList: true
        });
      }
    }, 500);
  };
  const pollForClerk = (onReady, onTimeout) => {
    let n = 0;
    const tick = () => {
      if (window.Clerk && window.Clerk.loaded) {
        return onReady(window.Clerk);
      }
      if (++n < 40) {
        setTimeout(tick, 250);
      } else {
        onTimeout();
      }
    };
    setTimeout(tick, 100);
  };
  const fetchMerchantFromAPI = () => {
    return fetch(API_BASE + "/api/docs/context", {
      credentials: "include",
      cache: "no-store"
    }).then(res => res.ok ? res.json() : null);
  };
  useEffect(() => {
    let cancelled = false;
    const urlPartner = captureQueryParams();
    const onPersonalised = (merchant, source) => {
      if (cancelled) return;
      const replacements = [["YOUR_PARTNER_CODE", merchant.partnerCode]];
      if (merchant.displayName) {
        replacements.push(["YOUR_TRADING_NAME", merchant.displayName]);
      }
      hideNotices();
      showPartnerBadge(merchant, source);
      walkCodeBlocks(replacements);
      observeTabSwitches(() => walkCodeBlocks(replacements));
    };
    const onUnauth = () => {
      if (cancelled) return;
      clearMerchant();
      removePartnerBadge();
      showNotices();
      walkCodeBlocks(null);
      observeTabSwitches(() => walkCodeBlocks(null));
    };
    const tryUrlFallback = () => {
      if (cancelled) return;
      if (urlPartner) {
        onPersonalised(urlPartner, "url");
      } else {
        onUnauth();
      }
    };
    if (!document.cookie.includes("__client_uat")) {
      tryUrlFallback();
      return;
    }
    pollForClerk(clerk => {
      if (cancelled) return;
      if (!clerk.session) {
        tryUrlFallback();
        return;
      }
      fetchMerchantFromAPI().then(data => {
        if (data) {
          publishMerchant(data);
          onPersonalised(data, "clerk");
        } else {
          tryUrlFallback();
        }
      }).catch(() => tryUrlFallback());
    }, () => {
      if (!cancelled) tryUrlFallback();
    });
    return () => {
      cancelled = true;
    };
  }, []);
  return null;
};

<MerchantContext />

Your customers are already sharing products with friends. Product Referral makes that visible — track which products drive the most word-of-mouth, identify your top advocates, and attribute revenue back to the shares that generated it.

<SignInNotice />

<Tabs>
  <Tab title="Tag integration">
    Install the tag directly on your product pages (recommended for most platforms). Works with any platform.

    <Steps>
      <Step title="Install the tracking tag">
        Include the following JavaScript snippet at the bottom of the `<body>` tag on the product page. The request includes your unique partner code. This is the only required step — it enables URL-based product sharing and tracking.

        <CodeGroup>
          ```html Demo theme={null}
          <!-- Begin Mention Me Product Referral integration -->
          <script type="text/javascript"
            src="https://tag-demo.mention-me.com/api/v2/product/YOUR_PARTNER_CODE?situation=product&implementation=sharelink&locale=en_GB&product_id=<CURRENT_PRODUCT_ID>">
          </script>
          <!-- End Mention Me Product Referral integration -->
          ```

          ```html Live theme={null}
          <!-- Begin Mention Me Product Referral integration -->
          <script type="text/javascript"
            src="https://tag.mention-me.com/api/v2/product/YOUR_PARTNER_CODE?situation=product&implementation=sharelink&locale=en_GB&product_id=<CURRENT_PRODUCT_ID>">
          </script>
          <!-- End Mention Me Product Referral integration -->
          ```
        </CodeGroup>

        Replace `<CURRENT_PRODUCT_ID>` with the product ID of the page where this is being shown. This can usually be accessed through a data layer.

        <Note>
          The verb in the URL path (`product`) can also be written as `tracking` — both behave identically.
        </Note>

        <Info>
          All parameter values must be [URL-encoded](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) — for example, `@` → `%40`, spaces → `%20`.
        </Info>
      </Step>

      <Step title="Track conversions">
        By tracking conversions alongside product shares, you can measure the full impact of word-of-mouth on your sales. This allows you to see which shared products are driving revenue, identify your most influential advocates, and understand the complete customer journey from share to purchase.

        <Accordion title="New clients without a referrer tag">
          If you haven't yet integrated a referrer (conversion) tag, you'll need to set one up to track conversions. Visit our [referrer tag integration page](/developer-docs/integration/entry-points/referrer) for full setup instructions. When configuring your referrer tag, include the product parameters listed below to enable product-level conversion tracking from the start.
        </Accordion>

        <Accordion title="Existing clients with a referrer tag">
          If you already have a referrer (conversion) tag integrated, you can enhance it with product data by adding the following parameters to your existing tag. This will associate product information with each conversion, enabling product-level reporting.

          Add these parameters to your existing referrer tag query string:

          <ResponseField name="product_ids" type="string">
            Comma-separated list of product IDs included in the order.
          </ResponseField>

          <ResponseField name="product_skus" type="string">
            Comma-separated list of product SKUs included in the order.
          </ResponseField>

          <ResponseField name="product_names" type="string">
            Comma-separated list of product names included in the order.
          </ResponseField>

          <ResponseField name="product_prices" type="string">
            Comma-separated list of product prices included in the order.
          </ResponseField>

          <ResponseField name="product_quantities" type="string">
            Comma-separated list of product quantities included in the order.
          </ResponseField>

          For example, append these to your referrer tag URL: `&product_ids=SKU001,SKU002&product_skus=ABC,DEF&product_names=Widget,Gadget&product_prices=9.99,19.99&product_quantities=1,2`
        </Accordion>
      </Step>

      <Step title="Add a share button (optional)">
        If you want to display a share button on the product page, include the following `<div>` somewhere in the `<body>` tag, near the product name or description. This is a placeholder which will be populated by the JavaScript tag. If you skip this step, URL-based product sharing and tracking will still work.

        ```html theme={null}
        <!-- Begin Mention Me Product link placeholder -->
        <div id="mmWrapper"></div>
        <!-- End Mention Me Product link placeholder -->
        ```

        If your technical team is unable to add new elements into the page, we can help by setting up the tag to inject the content next to an existing element. Contact your Onboarding Team and let them know which element should be selected.

        You can optionally apply a class or style to the div if you wish to control the way the contents are styled.
      </Step>
    </Steps>

    <Accordion title="Checkout on a different subdomain">
      If your checkout runs on a different subdomain to the product page (for example product pages on `www.merchant.com` but checkout on `checkout.merchant.com`), append the `storage` parameter to your tag URL. The default behaviour stores the referral identifiers in `sessionStorage`, which is per-origin and won't survive the navigation. This option mirrors them to a cookie scoped to your registrable domain so the bootloader on checkout can read them.

      <CodeGroup>
        ```html Demo theme={null}
        <!-- Begin Mention Me Product Referral integration -->
        <script type="text/javascript"
          src="https://tag-demo.mention-me.com/api/v2/product/YOUR_PARTNER_CODE?situation=product&implementation=sharelink&locale=en_GB&storage=session+cookie&product_id=<CURRENT_PRODUCT_ID>">
        </script>
        <!-- End Mention Me Product Referral integration -->
        ```

        ```html Live theme={null}
        <!-- Begin Mention Me Product Referral integration -->
        <script type="text/javascript"
          src="https://tag.mention-me.com/api/v2/product/YOUR_PARTNER_CODE?situation=product&implementation=sharelink&locale=en_GB&storage=session+cookie&product_id=<CURRENT_PRODUCT_ID>">
        </script>
        <!-- End Mention Me Product Referral integration -->
        ```
      </CodeGroup>

      The cookie is scoped to your registrable domain (e.g. `.merchant.com`), set with `Secure` and `SameSite=Lax`, and expires after 30 days. Cookies cannot bridge a checkout that runs on an entirely different domain (e.g. `www.merchant.com` to `pay.thirdparty.com`). Only different subdomains of the same registrable domain are supported.

      <Warning>
        Setting this cookie is your responsibility under your own privacy policy and consumer-consent process. Only enable `storage=session+cookie` if you have the relevant consent in place on your domain.
      </Warning>
    </Accordion>

    ### Tag parameters

    #### Mandatory

    The following parameters are the minimum required to make the integration work.

    <ResponseField name="locale" type="string" required>
      String representing the required locale. Used to show the right language and currency for the user. The format should be [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code, an underscore (`_`), then the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) country code. Default is `en_GB`. Example: `en_GB`
    </ResponseField>

    <ResponseField name="product_id" type="string" required>
      The unique product identifier from your system. This allows tracking which products are being recommended. Example: `PROD-456`
    </ResponseField>

    #### Recommended

    Add these data parameters to significantly improve performance.

    <ResponseField name="product_sku" type="string">
      The product SKU (Stock Keeping Unit) from your system. This provides an additional identifier for tracking products. Example: `SKU-789`
    </ResponseField>

    <ResponseField name="product_name" type="string">
      The name of the product. Please URL encode. Example: `Blue Widget`
    </ResponseField>

    <ResponseField name="product_price" type="string">
      The price of the product. Example: `29.99`
    </ResponseField>

    <Accordion title="Optional data parameters">
      Pass these additional parameters to enhance tracking and personalisation.

      <ResponseField name="firstname" type="string">
        The customer's firstname. Please URL encode.
      </ResponseField>

      <ResponseField name="surname" type="string">
        The customer's surname. Please URL encode.
      </ResponseField>

      <ResponseField name="fullname" type="string">
        The customer's full name. Please URL encode.
      </ResponseField>

      <ResponseField name="email" type="string">
        The customer's email address. Please URL encode.
      </ResponseField>

      <ResponseField name="customer_id" type="string">
        The unique customer identifier from your system.
      </ResponseField>

      <ResponseField name="phone_number" type="string">
        The customer's phone number(s). Pass as many phone numbers as you have as a comma-separated list.
      </ResponseField>

      <ResponseField name="segment" type="string">
        String representing a customer segment (for example one of: men, women) used to pass segmentation data about your customer to us. Has a maximum of 50 characters.
      </ResponseField>
    </Accordion>
  </Tab>

  <Tab title="Shopify">
    If you're using Shopify, install the Mention Me app from the Shopify App Store for a streamlined setup. No code required.

    <CardGroup cols={2}>
      <Card title="Install the App" icon="shopify" href="https://apps.shopify.com/mention-me">
        Get the Mention Me app from the Shopify App Store.
      </Card>

      <Card title="Setup Guide" icon="book" href="/knowledge/shopify/product-referral">
        Step-by-step instructions for configuring Product Referral in Shopify.
      </Card>
    </CardGroup>
  </Tab>
</Tabs>
