How to track leads and sales from Your own app

Measure signups from your own SaaS or site, attributed to the link that brought them.

AT A GLANCE

What NEMO tracksLeads · Sales
ConnectionNative — activated from the NEMO app
MethodThe hidden form field” · Server-side · highest reliability
Steps6 in total, with a one-minute check at the end
Worth knowingTHE customer IDENTITY: send the EMAIL in clear. Since the call is authenticated by your token, NEMO hashes it with YOUR workspace key (the same identity Stripe or Kit webhooks already use) and never stores it in clear. You compute nothing.

With Your own app, NEMO tracks which link brings each lead and which link brings each sale with no pixels and no Google Analytics. Know which of your links brought each person who signs up or buys in your own application, without relying on Kit or a payment gateway. Two ends. On your SITE, the script lets the link's nm_id travel with the visitor into your backend. In your BACKEND, once the signup is confirmed, your server tells NEMO server-to-server. The email never leaves your house: you send an opaque identifier. The method is “The hidden form field” (server-side · highest reliability): Your form carries an invisible field (nemo_click_id) that travels with every signup to your email platform. NEMO receives it server to server: the lead arrives already attributed to its source link. THE customer IDENTITY: send the EMAIL in clear. Since the call is authenticated by your token, NEMO hashes it with YOUR workspace key (the same identity Stripe or Kit webhooks already use) and never stores it in clear. You compute nothing. The full connection is 6 steps and you verify it with a single test click.

How does each Your own app lead arrive with its source?

The hidden form field · Server-side · highest reliability

Two ends. On your SITE, the script lets the link's nm_id travel with the visitor into your backend. In your BACKEND, once the signup is confirmed, your server tells NEMO server-to-server. The email never leaves your house: you send an opaque identifier.

  1. End 1 · paste the NEMO script on your landing and your app (once). Let the nm_id travel from the link into your site:
    <script src="https://nemolink.app/nemo.js" defer></script>
  2. If your app lives on a different registrable domain than your landing (say the landing on criptoterminal.com and the app on app.other.com), declare it once so the nm_id hops there too:
    window.nemo.hosts(['app.other.com']);
  3. When the user starts the signup, pass your backend the nm_id the frontend sees via window.nemo.id() (a hidden form field, or your fetch body).
  4. End 2 · when your server confirms the signup, tell NEMO. Your ingest URL carries the token inside (you'll find it on the «Your own app» card in Integrations) — treat it as a secret:
    // En tu backend, cuando alguien se da de alta:
    await fetch("https://nemolink.app/api/ingest/YOUR_TOKEN", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        event: "lead",                  // "sale" para una venta (+ amount_cents)
        email: usuario.email,           // NEMO lo hashea; no se guarda en claro
        nm_id: alta.nm_id ?? undefined, // el que llegó del frontend (nemo.js)
      }),
    });
  5. Rather have your coding assistant wire it? Paste this — it carries both ends, with your endpoint and your payload:
    Conecta MI aplicación a NEMO para medir las altas por link (dos extremos).
    
    EXTREMO 1 · el script en mi web (frontend)
    Carga esta etiqueta de la forma idiomática de mi stack (Next.js: next/script
    strategy="afterInteractive" en el layout raíz; Astro/HTML: antes de </body>):
      <script src="https://nemolink.app/nemo.js" defer></script>
    Cárgalo en la landing Y en la app: así el nm_id viaja del link a mi web, y de
    mi web a mi backend (nemo.js decora los enlaces salientes a hosts de MI mismo
    dominio registrable — si mi app vive en otro dominio, lo declaro con
    window.nemo.hosts(['app.midominio.com'])).
    Cuando alguien empieza el alta, pasa el nm_id que ve el frontend
    (window.nemo.id()) al backend junto con el formulario.
    
    EXTREMO 2 · la recepción en mi backend (server-to-server)
    Cuando el alta se confirma en mi servidor, avisa a NEMO. La URL está
    autenticada por su token, así que mando el email en claro y NEMO lo hashea con
    la clave de mi workspace (no se guarda en claro). Guarda el nm_id JUNTO al
    registro del usuario.
      await fetch("https://nemolink.app/api/ingest/YOUR_TOKEN", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          event: "lead",                  // "sale" para una venta (+ amount_cents)
          email: usuario.email,
          nm_id: alta.nm_id ?? undefined, // el que llegó del frontend
        }),
      });
    Trata la URL como un secreto (lleva el token). Verifica al terminar: una alta
    de prueba devuelve {"ok":true} y, con nm_id válido, "attributed":true.

Note: THE customer IDENTITY: send the EMAIL in clear. Since the call is authenticated by your token, NEMO hashes it with YOUR workspace key (the same identity Stripe or Kit webhooks already use) and never stores it in clear. You compute nothing.

Note: ADVANCED — if you'd rather NOT send emails: send an OPAQUE `external_id` instead (HMAC of your internal id with a secret of yours, in hex; never the email, a numeric id, or a uuid from the payload). It's optional: the email is the normal path.

Note: WHAT TO STORE in your database: the nm_id NEXT TO the user's record (a column beside the signup). The UTMs are YOURS — NEMO doesn't need them; keep them for your own analytics if you want.

Note: HOW LONG IT LASTS: the source anchor lives 90 days in the browser (what /legal/cookies declares). On the free plan you see 30 days of history in the panel; the data is still stored — it's the visible window that shrinks.

Note: THE own-hosts LIMIT uses a TRIMMED public-suffix list (the real-world families: .co.uk, .com.br, .com.mx, .com.ar…), not the full list. It covers virtually every domain; if yours is a rare ccTLD that doesn't hop on its own, declare it with window.nemo.hosts(['your.domain']).

Note: PRIVACY — YOURS, AND HERE IT'S TWO PROCESSINGS: you're responsible for the one on your WEBSITE (where nemo.js runs) and the one in your BACKEND (where you store the nm_id beside the user). The nm_id in your database is PSEUDONYMOUS PERSONAL DATA as long as you can cross it with your users table: name it in your privacy policy and your record of processing activities, give it a lawful basis and a retention period, and treat it with the same care as the rest of the user's record. NEMO receives from you an opaque identifier and a source, never the email in clear.

How is each Your own app sale attributed?

The hidden form field · Server-side · highest reliability

The same call, with event: "sale" and the amount in cents. It's an AUTHENTICATED source (your token), so the sale counts for real — it moves money in your panel.

  1. When your backend confirms a charge, tell NEMO just like the signup but as a sale:
    await fetch("https://nemolink.app/api/ingest/YOUR_TOKEN", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        event: "sale",
        email: user.email,          // the SAME email as the signup
        amount_cents: 4900,         // $49.00
        nm_id: signup.nm_id ?? undefined,
      }),
    });

Note: The same email (or the same external_id, in the advanced case) for the signup and the purchase: that's how NEMO ties a person's lead and sale together. The email is hashed; never stored in clear.

Check it in one minute

  1. On the «Your own app» card in Integrations, hit «Send test»: it runs the real circuit and tells you what was accepted.
  2. With a valid nm_id the response carries "attributed": true; if it carries "attributed": false, the nm_id is what fails (expired or not captured), not your call.
  3. A test signup from your backend returns {"ok":true} and shows up on Home, attributed to its link.

Frequently asked questions

What do I do if the signup lands but arrives with no source (attributed:false)?
The nm_id didn't arrive or doesn't resolve. Check the frontend captures it (window.nemo.id()) and passes it to your backend, and that the link was a NEMO one. The call is fine; it's the source that's missing.
What do I do if the ingest returns 422 «weak_external_id»?
Only happens on the advanced path: your `external_id` isn't opaque (an email, a number, a uuid). The normal path is to send `email` in clear and let NEMO hash it — nothing to validate.
What do I do if the ingest returns 404?
Your URL's token isn't valid (or you rotated it). Copy the current URL from the «Your own app» card.
What do I do if the nm_id doesn't hop from my landing to my app on another domain?
nemo.js only decorates hosts on your SAME registrable domain. If the app lives on another domain, declare it: window.nemo.hosts(['app.other.com']).

OFFICIAL SOURCES

Guide verified against the official documentation on 2026-09-11.

ALSO INTEGRATES WITH

Track Your own app from your very first link.

Free during early access. Early users get special terms when paid plans launch.

See all 38 integrations