> ## 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.

# Referee Tag

> Integrate the referee tag on your checkout page so referred friends can claim their reward

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 />

## What is the referee tag used for?

Mention Me allows referrers to share with their friends via word of mouth by using their name. The referee tag allows prospective new customers to search for their friend's name and claim an introductory reward.

The copy on the referee link is controlled via the Mention Me platform and can be changed without any development work. Contact your Client Success Manager about this option.

## How to integrate the referee tag

<Steps>
  <Step title="Add the wrapper div">
    Include the following `<div>` somewhere in the `<body>` tag of the checkout page near where you offer coupon entry (and optionally on other pages of your site too).

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

    This is just a placeholder which is populated via the JavaScript tag. You can optionally apply a class or style to the div if you wish to control the way the contents are styled.
  </Step>

  <Step title="Add the JavaScript tag">
    Include the following JavaScript snippet at the bottom of the `<body>` tag on the checkout page (and optionally on other pages of your site too). The request includes your unique partner code.

    <SignInNotice />

    <Tabs>
      <Tab title="Link (default)">
        Renders a "Been referred by a friend?" link that opens an overlay when clicked.

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

          ```html Live theme={null}
          <!-- Begin Mention Me referee integration -->
          <script type="text/javascript"
            src="https://tag.mention-me.com/api/v2/refereefind/YOUR_PARTNER_CODE?situation=checkout&locale=en_GB">
          </script>
          <!-- End Mention Me referee integration -->
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Embedded form">
        Renders a small form directly in the div above. When submitted, a modal popup opens over your page, captures the customer's registration for the reward, provides them with the coupon to fulfil their reward and finally closes to deposit them back on your page to complete their purchase.

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

          ```html Live theme={null}
          <!-- Begin Mention Me referee integration -->
          <script type="text/javascript"
            src="https://tag.mention-me.com/api/v2/refereefind/YOUR_PARTNER_CODE?situation=checkout&locale=en_GB&implementation=form">
          </script>
          <!-- End Mention Me referee integration -->
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Embedded iframe">
        Embeds the full referee journey as an iframe within the wrapper div.

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

          ```html Live theme={null}
          <!-- Begin Mention Me referee integration -->
          <script type="text/javascript"
            src="https://tag.mention-me.com/api/v2/refereefind/YOUR_PARTNER_CODE?situation=checkout&locale=en_GB&implementation=embed">
          </script>
          <!-- End Mention Me referee integration -->
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Customise the parameters">
    (Optional) Include data parameters passing the customer's details if you have them at the point in the process where you insert the tag — this makes the process smoother for the customer.

    <Snippet file="url-encoding-info.mdx" />
  </Step>
</Steps>

## Mandatory data parameters

<ResponseField name="situation" type="string" required>
  String indicator of where you are including this tag within your site (for example: `checkout`, `postpurchase`, `landingpage`). Used for reporting. Has a maximum of 50 characters. Example: `checkout`
</ResponseField>

<ResponseField name="locale" type="string" required>
  String representing the required locale for the campaign. Used to show the right locale (language, 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 (e.g. `fr_FR` for French/France). Default is empty (which will result in a locale of `en_GB` being assumed). Example: `en_GB`
</ResponseField>

<Accordion title="Optional data parameters">
  <ResponseField name="firstname" type="string">
    The customer's firstname. Pre-fills the form if provided. 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. If you are passing any data which is not a digit (e.g. spaces, +'s), these need to be URL encoded.
  </ResponseField>

  <ResponseField name="call_to_action_url" type="string">
    A URL to send users to after they are rewarded. Only functions on the embedded flow.
  </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>

<Accordion title="Optional implementation parameters">
  <ResponseField name="implementation" type="string">
    Optionally override the way the flow is implemented (one of: `link`, `form`, `embed`). Default can also be set in the merchant dashboard. If in doubt, leave out.
  </ResponseField>
</Accordion>

## Things to watch out for

<AccordionGroup>
  <Accordion title="The tag doesn't seem to be working. What should I do?">
    You can use the browser Console log to check any potential error states relating to the tag integration.

    Further details on error messages and how to resolve them is available in the [error codes and messages](/developer-docs/integration/reference/faqs#common-tag-integration-errors) section.
  </Accordion>

  <Accordion title="Why does the 'Been referred by a friend?' link not appear on the page?">
    This could happen for two reasons:

    1. **The locale is missing** — check if a locale is required for this tag integration
    2. **The `mmWrapper` div is missing from the page** — check that the div is included somewhere in the `<body>` tag of the checkout
  </Accordion>

  <Accordion title="How can I change the wording for the 'Been referred by a friend' link?">
    The copy on the referee link is controlled via the Mention Me platform and can easily be changed. Ask your Client Success Manager about this option.
  </Accordion>

  <Accordion title="I have a dynamic website — how do I get the referee journey to appear?">
    The referee tag has a feature to prevent it showing multiple times. In websites built with React, Angular, Vue, or other dynamic frameworks, this can conflict and prevent the tag from appearing when you would expect it to.

    If this occurs, you will see a message in the browser developer console similar to:

    ```
    A tag has already fired with identifier [linkcheckout] on this page. Suppressing tag
    ```

    To prevent this, ensure the Mention Me tag is aware it can re-run without harm. The code below clears the fired tag state before loading the referee tag:

    ```html theme={null}
    <script type="text/javascript">
      if (window.MentionMeFiredTags != undefined && window.MentionMeFiredTags != '') {
        var situation      = 'checkout';
        var implementation = 'link';
        if (window.MentionMeFiredTags[implementation + situation] == true) {
          delete window.MentionMeFiredTags[implementation + situation];
        }
      }
    </script>
    <script src="the-existing-referee-tag-goes-here"></script>
    ```

    This concatenates the implementation (in this case `link`) and situation (in this case `checkout`) and tells the Mention Me tag that it can re-fire for `linkcheckout`.

    See [SPA Implementation](/knowledge/tags/spa-implementation) for more details.
  </Accordion>
</AccordionGroup>
