---
title: "Web SDK"
source: https://docs.myappaffiliate.com/sdk-web
docs: "MyAppAffiliate — Developer Documentation"
index: https://docs.myappaffiliate.com/llms.txt
---
# Web SDK

For web products: capture the referral when the visitor lands, then bind it to the
user at signup. Works with any billing provider — see the
[Web SaaS guide](https://docs.myappaffiliate.com/web-saas) for the end-to-end flow.

**Prompt for an AI coding agent**

```text
Integrate MyAppAffiliate into my project.

Documentation (read these first, they are the source of truth):
- Page: https://docs.myappaffiliate.com/sdk-web.md
- Full docs index: https://docs.myappaffiliate.com/llms.txt

Task: Add the MyAppAffiliate Web SDK to my site: install the package, start it once in my app shell so it auto-captures ?via= referral codes including on client-side route changes, and identify the user at signup with the same id my billing provider reports.

Rules:
- Follow the documented API exactly — no invented method names, endpoints, parameters or field names.
- Match the conventions already used in my codebase.
- Ask me for my SDK key instead of guessing, and never hard-code it — read it from config/environment.
- Do NOT set an API base URL anywhere. Every SDK compiles the production host in; a staging or self-hosted host belongs in a build setting, not in code.
- Tell me afterwards which steps I still have to do by hand (dashboard settings, capabilities, webhook configuration).
```

## Install

**Script tag** — no build tooling, no inline JavaScript. Best for a landing page:

```html
<script
  src="https://cdn.jsdelivr.net/npm/@myappaffiliate/sdk-web@0/dist/sdk.js"
  data-api-key="pk_live_…"
  async
></script>
```

The tag starts the SDK itself and puts the same surface on `window.myAppAffiliate`,
so step 1 is already done and step 2 is one line of inline script. `@0` tracks the
latest 0.x; pin `@0.2.0` if you want a frozen bundle.

**npm** — for app frontends:

```bash
npm i @myappaffiliate/sdk-web
```

## 1. Start it

```ts
import { myAppAffiliate } from "@myappaffiliate/sdk-web";

myAppAffiliate.start("pk_live_…");
```

That is the whole call — no host, no options. Put it in your app shell, root layout,
or a `<script type="module">` on the landing page.

It is safe to call on the server: every function is a no-op when `window` is
undefined, so Next.js / Remix / SvelteKit need no `typeof window` guard.

## 2. Identify the user at signup

Call this when the account is created. The id must be the **same string your billing
provider reports back to us** — your Stripe `metadata.customer_user_id`, Paddle custom
data, or the provider's own customer id. See [Billing & Webhooks](https://docs.myappaffiliate.com/webhooks).

```ts
await myAppAffiliate.identify(user.id);
```

That's the whole integration. (You can do this server-side instead with the
[Node SDK](https://docs.myappaffiliate.com/sdk-node)'s `trackSignup`.)

## What `start` captures, automatically

On the current URL, and again on every client-side route change:

- `?via=LUMI` (also `?ref=`, `?maa_code=`, `?code=`) → referral-code attribution
- `?claim_token=<uuid>` (or `?ct=`) → click-claim attribution from a branded `go.` link

The winner is persisted in `localStorage`, so the referral survives navigation, a
closed tab, and the days between landing and signup. If the network call fails, the
code stays persisted and is retried on the next `start`.

**SPAs need nothing extra.** The SDK hooks `pushState`/`replaceState`/`popstate`, so a
creator linking to a deep route (`/pricing?via=LUMI`) is captured whether or not that
route was the entry page. Turn it off with `spa: false` and call `capture()` yourself.

## Optional

```ts
myAppAffiliate.applyCode("LUMI");             // a referral-code field at checkout
myAppAffiliate.capture();                     // re-scan the URL manually
myAppAffiliate.attribute("https://…?via=…");  // claim from an explicit URL
myAppAffiliate.attributedAffiliateId();       // string | null, for your own UI
myAppAffiliate.reset();                       // on logout / account deletion
```

**Staging or self-hosted API**, custom storage, debug logging:

```ts
myAppAffiliate.start({
  apiKey: "pk_live_…",
  apiBaseUrl: "https://staging.example.com",  // or globalThis.MAA_API_BASE_URL
  storage: myCookieStore,                     // { get, set, remove }
  autoCapture: true,
  spa: true,
  debug: true,
});
```

## API

| Call | Purpose |
|---|---|
| `myAppAffiliate.start(apiKey)` | Start + auto-capture (a string, or an options object) |
| `myAppAffiliate.identify(userId)` | Bind your user id at signup |
| `myAppAffiliate.capture()` | Re-scan the current URL |
| `myAppAffiliate.attribute(url)` | Claim a referral from an explicit URL |
| `myAppAffiliate.applyCode(code)` | Manual referral-code attribution |
| `myAppAffiliate.attributedAffiliateId()` | The attributed affiliate id (or `null`) |
| `myAppAffiliate.reset()` | Clear all persisted SDK state |

Every function is also a named export (`import { start, identify } from …`) if you
prefer that to the namespace.

The SDK persists a generated device id + attribution in `localStorage`. No cookies, no
fingerprinting, first-party only. Network failures resolve to `false`/`null` — never an
uncaught error on your page.
