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

# Landing Page Tag

> Create a dedicated referral landing page for existing customers to register and share

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 landing page used for?

When promoting your refer-a-friend programme, you are likely to want to lead your customers to landing pages on your site which include various pieces of Mention Me functionality. If you send out emails with a referral call to action you can direct your customers to a landing page on your own site. Create that page and embed on it a referrer offer tag.

Unlike the referrer tag, the landing page tag does not require customer or order details — making it suitable for standalone promotional pages, email links, or social campaigns.

## How to integrate the landing page tag

<Steps>
  <Step title="Create a new page on your website">
    Create a dedicated page on your site where customers will land when they click a referral promotion link (e.g. from an email or social post).
  </Step>

  <Step title="Add the wrapper div">
    Include the following `<div>` into your page where you want the referral content to appear.

    ```html theme={null}
    <!-- Begin Mention Me referrer placeholder div -->
    <div id="mmWrapper"></div>
    <!-- End Mention Me referrer 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, via the Mention Me dashboard, if you wish to control the way the contents are styled. If you need to change the id on the wrapper (for example if you need two tags on one page), you can customise from within the Mention Me dashboard.
  </Step>

  <Step title="Add the JavaScript tag">
    Include the following JavaScript snippet at the bottom of the `<body>` tag on your landing page. The request includes your unique partner code.

    <SignInNotice />

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

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

  <Step title="Customise the parameters">
    (Optional) Include data parameters if you have customer details available — 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 landing pages, use `landingpage`. Has a maximum of 50 characters. Example: `landingpage`
</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. 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="title" type="string">
    The customer's title. This allows you to have more formal messaging in your flow. Has a maximum of 20 characters.
  </ResponseField>

  <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="username" type="string">
    The customer's username. Your account is set up for referrers to share using their username not full name. Please URL encode.
  </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="custom_field" type="string">
    Any piece of custom data you wish to pass to us.
  </ResponseField>

  <ResponseField name="custom_share_field" type="string">
    A piece of text you can use to pass into sharing widgets, such as what the user bought or how much they saved.
  </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>
