{"_id":"@affitor/tracker","_rev":"5-b787632b06fee3b820e9c9284f74db4c","name":"@affitor/tracker","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"@affitor/tracker","version":"1.0.0","keywords":["affitor","affiliate","tracking","analytics","saas","partner"],"license":"MIT","_id":"@affitor/tracker@1.0.0","maintainers":[{"name":"tomto","email":"tomto@affitor.com"}],"homepage":"https://github.com/Affitor/affitor-tracker-js#readme","bugs":{"url":"https://github.com/Affitor/affitor-tracker-js/issues"},"dist":{"shasum":"9ae745cece620305dea9bbaa46279421da2fb2d1","tarball":"https://registry.npmjs.org/@affitor/tracker/-/tracker-1.0.0.tgz","fileCount":14,"integrity":"sha512-J7wBp73dlrysEMZJe/Z53F66FrG4kCjEberu8WKaOtnip37JlscS9jLenA8lSZpfxoOxAcoGUaaGDwI23CowVg==","signatures":[{"sig":"MEQCIE6WELJ+UbVBqf2B/5wAVS1V6wQIauMAnQyysHuOmY0yAiAh6j74Bh7S52Ip3edxWUvoh41OSkvByeYBIQHg6x8Qog==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":34358},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./pure":{"types":"./dist/pure.d.ts","import":"./dist/pure.mjs","require":"./dist/pure.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"scripts":{"dev":"tsup --watch","build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"tomto","email":"tomto@affitor.com"},"deprecated":"moved to @affitor/sdk — npm i @affitor/sdk (browser loader at root, React hooks at @affitor/sdk/react)","repository":{"url":"git+https://github.com/Affitor/affitor-tracker-js.git","type":"git"},"_npmVersion":"10.8.2","description":"Affitor affiliate tracking SDK for JavaScript applications","directories":{},"_nodeVersion":"20.19.4","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0","@types/react":"^19.2.14"},"peerDependencies":{"react":">=17.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tracker_1.0.0_1771036587956_0.4662328323640088","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@affitor/tracker","version":"2.0.0","keywords":["affitor","affiliate","tracking","analytics","saas","partner"],"license":"MIT","_id":"@affitor/tracker@2.0.0","maintainers":[{"name":"tomto","email":"tomto@affitor.com"}],"homepage":"https://github.com/Affitor/affitor-tracker-js#readme","bugs":{"url":"https://github.com/Affitor/affitor-tracker-js/issues"},"dist":{"shasum":"0cb0f7dabc12aaae505cdf7dea181d30d2980743","tarball":"https://registry.npmjs.org/@affitor/tracker/-/tracker-2.0.0.tgz","fileCount":14,"integrity":"sha512-urLEglCSTb5LoyoGVlr6MK0Ka02gyKxlzQLtGlhazTHn1wuw5Petgx67JfbbFWxFq9QF4TViaEyXpPqEAjSZxg==","signatures":[{"sig":"MEUCIQDHuCbJctEbaMtDulfbfhcTr03zB12YeiVSJMFmOSZUgwIgTHOaLEXX3B4uPoaKmM9mgHxw9MH8ye+hnEk1V3sebwI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35061},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./pure":{"types":"./dist/pure.d.ts","import":"./dist/pure.mjs","require":"./dist/pure.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"gitHead":"2b0f6c5789c7f894d4415bdc949094f1321b3a27","scripts":{"dev":"tsup --watch","build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"tomto","email":"tomto@affitor.com"},"deprecated":"moved to @affitor/sdk — npm i @affitor/sdk (browser loader at root, React hooks at @affitor/sdk/react)","repository":{"url":"git+https://github.com/Affitor/affitor-tracker-js.git","type":"git"},"_npmVersion":"10.8.2","description":"Affitor affiliate tracking SDK for JavaScript applications","directories":{},"_nodeVersion":"20.20.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0","@types/react":"^19.2.14"},"peerDependencies":{"react":">=17.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tracker_2.0.0_1773740642897_0.6550879226507929","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-02-14T02:36:27.846Z","modified":"2026-06-14T21:52:09.400Z","1.0.0":"2026-02-14T02:36:28.109Z","2.0.0":"2026-03-17T09:44:03.034Z"},"bugs":{"url":"https://github.com/Affitor/affitor-tracker-js/issues"},"license":"MIT","homepage":"https://github.com/Affitor/affitor-tracker-js#readme","keywords":["affitor","affiliate","tracking","analytics","saas","partner"],"repository":{"url":"git+https://github.com/Affitor/affitor-tracker-js.git","type":"git"},"description":"Affitor affiliate tracking SDK for JavaScript applications","maintainers":[{"name":"sonpiaz","email":"sonxpiaz@gmail.com"},{"name":"tomto","email":"tomto@affitor.com"}],"readme":"# @affitor/tracker\n\nOfficial JavaScript/TypeScript SDK for [Affitor](https://affitor.com) affiliate tracking. A Promise-based wrapper around the Affitor tracker script, inspired by [@stripe/stripe-js](https://github.com/stripe/stripe-js).\n\n## Install\n\n```bash\nnpm install @affitor/tracker\n```\n\n## Entry Points\n\nThe SDK provides two entry points for different use cases:\n\n| Entry Point | Import | Best For |\n|---|---|---|\n| `@affitor/tracker` | `import { loadAffitor } from '@affitor/tracker'` | Any JS/TS application |\n| `@affitor/tracker/react` | `import { AffitorProvider, useAffitor } from '@affitor/tracker/react'` | React / Next.js apps |\n\n---\n\n## `@affitor/tracker` — Core SDK\n\n### `loadAffitor(programId, options?)`\n\nLoads the Affitor tracker script and returns a Promise that resolves to the tracker instance.\n\n- **Singleton** — calling `loadAffitor` multiple times returns the same Promise\n- **SSR-safe** — resolves to `null` on the server\n- **Guaranteed** — the instance is always ready when the Promise resolves\n\n```ts\nimport { loadAffitor } from '@affitor/tracker';\n\nconst affitor = await loadAffitor('59');\n```\n\n### Options\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `env` | `'production' \\| 'uat' \\| 'local'` | `'production'` | Environment preset (selects the tracker script URL) |\n| `debug` | `boolean` | `false` | Enable debug mode (verbose console logs, cookie verification) |\n| `scriptUrl` | `string` | — | Custom script URL (overrides `env` preset) |\n\n### Environment Presets\n\n| `env` | Script URL |\n|---|---|\n| `'production'` | `https://api.affitor.com/js/affitor-tracker.js` |\n| `'uat'` | `https://uat-affitor-cms.vanilla-ott.com/js/affitor-tracker-uat.js` |\n| `'local'` | `http://localhost:1337/js/affitor-tracker-local.js` |\n\n```ts\n// Production (default)\nconst affitor = await loadAffitor('59');\n\n// Local development with debug\nconst affitor = await loadAffitor('29', { env: 'local', debug: true });\n\n// UAT\nconst affitor = await loadAffitor('29', { env: 'uat' });\n\n// Custom URL (overrides env)\nconst affitor = await loadAffitor('29', { scriptUrl: 'https://my-cdn.com/tracker.js' });\n```\n\n### Methods\n\nOnce loaded, the `affitor` instance provides these methods:\n\n| Method | Description |\n|---|---|\n| `signup(customerKey, email)` | Track a signup event. Takes the user's ID and email as positional args. Returns a Promise. |\n| `trackLead(data)` | **Deprecated.** Alias for `signup()`. Accepts `{ email, user_id }`. Use `signup()` instead. |\n| `trackTest(data?)` | Send a test event to verify tracking is working. |\n| `redirectToCheckout(params)` | Redirect the user to the Affitor-powered checkout page. |\n\n### Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `customerCode` | `string \\| null` | The affiliate customer code from cookie |\n| `affiliateUrl` | `string \\| null` | The affiliate referral URL from cookie |\n| `hasAffiliateAttribution` | `boolean` | Whether the current visitor was referred by an affiliate |\n| `debugMode` | `boolean` | Whether debug mode is enabled |\n| `programId` | `number` | The advertiser program ID |\n\n### Example: Track Signup\n\n```ts\nimport { loadAffitor } from '@affitor/tracker';\n\nasync function handleSignup(email: string, password: string) {\n  // 1. Create the user account\n  const { data } = await supabase.auth.signUp({ email, password });\n\n  // 2. Track the signup — awaits script load, guaranteed to fire\n  if (data.user) {\n    const affitor = await loadAffitor('59');\n    await affitor?.signup(data.user.id, data.user.email);\n  }\n\n  // 3. Navigate to dashboard\n  router.push('/dashboard');\n}\n```\n\n### Example: Redirect to Checkout\n\n```ts\nimport { loadAffitor } from '@affitor/tracker';\n\nasync function handleUpgrade() {\n  const affitor = await loadAffitor('59');\n  affitor?.redirectToCheckout({\n    price: 19.99,\n    programId: 59,\n  });\n}\n```\n\n---\n\n## `@affitor/tracker/react` — React Hooks\n\nThe React entry point provides two patterns: **Provider + hook** and **standalone hook**.\n\n### Pattern A: `AffitorProvider` + `useAffitor()`\n\nBest when your whole app needs access to the tracker state (e.g. showing referral badges).\n\n```tsx\nimport { AffitorProvider, useAffitor } from '@affitor/tracker/react';\n\n// 1. Wrap your app (layout.tsx or _app.tsx)\nexport default function RootLayout({ children }) {\n  return (\n    <AffitorProvider programId=\"59\">\n      {children}\n    </AffitorProvider>\n  );\n}\n\n// 2. Read tracker state in any component\nfunction ReferralBadge() {\n  const affitor = useAffitor();\n\n  if (!affitor?.hasAffiliateAttribution) return null;\n\n  return <span>Referred by a partner!</span>;\n}\n```\n\n#### `AffitorProvider` Props\n\n| Prop | Type | Required | Description |\n|---|---|---|---|\n| `programId` | `string \\| number` | Yes | Your Affitor program ID |\n| `debug` | `boolean` | No | Enable debug mode |\n| `scriptUrl` | `string` | No | Custom script URL |\n\n#### `useAffitor()`\n\nReturns `AffitorInstance | null`. Returns `null` while the SDK is loading.\n\n> **Important:** `useAffitor()` is best for reading tracker state in the UI (e.g. `hasAffiliateAttribution`, `customerCode`). For critical tracking events like `signup`, use `await loadAffitor()` directly instead — see [Which approach should I use?](#which-approach-should-i-use) below.\n\n### Pattern B: `useLoadAffitor()` (Standalone)\n\nUse this when you don't need a provider — the hook loads the SDK on mount.\n\n```tsx\nimport { useLoadAffitor } from '@affitor/tracker/react';\n\nfunction MyComponent() {\n  const affitor = useLoadAffitor('59', { debug: true });\n\n  return (\n    <div>\n      {affitor?.hasAffiliateAttribution && <p>Partner referral detected</p>}\n    </div>\n  );\n}\n```\n\n---\n\n## Which approach should I use?\n\n### For tracking events (`signup`, `redirectToCheckout`)\n\nAlways use `await loadAffitor()` directly. This guarantees the script is loaded before the event fires. Critical events must never be silently skipped.\n\n```ts\n// GOOD — guaranteed to fire\nconst affitor = await loadAffitor('59');\nawait affitor?.signup(userId, email);\n\n// BAD — affitor could be null if script still loading\nconst affitor = useAffitor();\nawait affitor?.signup(userId, email); // silently skipped if null\n```\n\n### For reading tracker state in UI\n\nUse `useAffitor()` or `useLoadAffitor()`. If the value is `null` momentarily while loading, the UI simply doesn't render that part yet. No data is lost.\n\n```tsx\n// GOOD — fine for UI, gracefully handles loading state\nconst affitor = useAffitor();\nreturn affitor?.hasAffiliateAttribution ? <Badge /> : null;\n```\n\n### Summary\n\n| Use Case | Approach | Why |\n|---|---|---|\n| `signup` on registration | `await loadAffitor()` | Must not be lost — awaits script load |\n| `redirectToCheckout` | `await loadAffitor()` | Must not be lost — awaits script load |\n| Show referral badge in UI | `useAffitor()` | OK to show nothing while loading |\n| Display customer code | `useAffitor()` | OK to show nothing while loading |\n| Check `hasAffiliateAttribution` for conditional UI | `useAffitor()` | OK to show nothing while loading |\n\n---\n\n## Migrating from Script Tag\n\nIf you're currently using the `<script>` tag approach:\n\n### Before (script tag)\n\n```html\n<script src=\"https://api.affitor.com/js/affitor-tracker.js\"\n        data-affitor-program-id=\"59\"></script>\n\n<script>\n  // Must check if loaded, use queue fallback, handle timing manually\n  if (window.affitor) {\n    window.affitor.trackLead({ email, user_id });\n  } else {\n    window.affitorQueue = window.affitorQueue || [];\n    window.affitorQueue.push(['trackLead', { email, user_id }]);\n  }\n</script>\n```\n\n### After (npm SDK)\n\n```ts\nimport { loadAffitor } from '@affitor/tracker';\n\n// No timing issues — awaits script load automatically\nconst affitor = await loadAffitor('59');\nawait affitor?.signup(userId, email);\n```\n\nNo more:\n- Manual `if (window.affitor)` checks\n- Queue fallback code (`affitorQueue.push`)\n- Race conditions between script load and event firing\n- `(window as any)` type casting in TypeScript\n\n---\n\n## API Reference\n\n### `loadAffitor(programId, options?)`\n\n| Parameter | Type | Description |\n|---|---|---|\n| `programId` | `string \\| number` | Your Affitor program ID |\n| `options.env` | `'production' \\| 'uat' \\| 'local'` | Environment preset |\n| `options.debug` | `boolean` | Enable debug mode |\n| `options.scriptUrl` | `string` | Custom script URL (overrides env) |\n\n**Returns:** `Promise<AffitorInstance | null>`\n\n### `AffitorInstance`\n\n| Method / Property | Type | Description |\n|---|---|---|\n| `signup(customerKey, email)` | `(customerKey: string, email: string) => Promise<void>` | Track a signup event |\n| `trackLead(data)` | `(data: TrackLeadData) => void` | **Deprecated.** Alias for `signup()`. |\n| `trackTest(data?)` | `(data?: TrackTestData) => void` | Send test event |\n| `redirectToCheckout(params)` | `(params: RedirectToCheckoutParams) => void` | Redirect to checkout |\n| `customerCode` | `string \\| null` | Affiliate customer code |\n| `affiliateUrl` | `string \\| null` | Affiliate referral URL |\n| `hasAffiliateAttribution` | `boolean` | Has affiliate attribution |\n| `debugMode` | `boolean` | Debug mode enabled |\n| `programId` | `number` | Program ID |\n\n### `TrackLeadData`\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `email` | `string` | Yes | User's email |\n| `user_id` | `string` | Yes | Your app's user ID (critical for payment attribution) |\n| `additional_data` | `Record<string, unknown>` | No | Extra metadata |\n\n### `TrackTestData`\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `step_id` | `string` | No | Step identifier (default: `'pageview'`) |\n| `message` | `string` | No | Test message |\n| `user_id` | `string` | No | User ID |\n\n### `RedirectToCheckoutParams`\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `price` | `number` | No | Price amount |\n| `programId` | `string \\| number` | No | Override program ID |\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}