npm package: @linkzly/affiliate-web
Description: Lightweight browser SDK for Linkzly affiliate attribution tracking (<3KB gzipped)
Latest version: 1.0.0

# @linkzly/affiliate-web

Lightweight browser SDK for Linkzly affiliate attribution tracking. **< 3KB gzipped.**

## Installation

```bash
npm install @linkzly/affiliate-web
```

Or via CDN (UMD):
```html
<script src="https://cdn.linkzly.com/affiliate-web/latest/index.js"></script>
```

## Quick Start

```typescript
import { init, getClickId, attachToCheckout } from '@linkzly/affiliate-web';

// Initialize (optional — auto-initializes on first call)
init({ debug: true });

// Get click ID for your backend
const clickId = getClickId();

// Attach to checkout form
attachToCheckout('#checkout-form');
```

## How It Works

When a user clicks an affiliate link (`/a/:slug`), the Linkzly tracking worker:
1. Sets an `lz_aff` cookie with signed attribution data
2. Appends `lz_click_id` to the destination URL

This SDK reads both sources and provides the attribution data to your frontend.

## API Reference

### `init(config?)`

Initialize the SDK singleton.

```typescript
const lz = init({
  cookieName: 'lz_aff',       // default
  clickIdParam: 'lz_click_id', // default
  debug: false,                 // default
});
```

### `getAttribution()`

Returns full attribution data:

```typescript
const attr = getAttribution();
// {
//   clickId: '019...',
//   programId: '019...',
//   affiliateId: '019...',
//   timestamp: 1707300000,
//   hasAttribution: true,
//   source: 'both' | 'cookie' | 'url' | 'none'
// }
```

### `getClickId()`

Returns just the click ID (most common use case):

```typescript
const clickId = getClickId();
// Pass to your backend for S2S conversion
```

### `getCookieId()`

Returns the raw `lz_aff` cookie value:

```typescript
const cookieId = getCookieId();
```

### `attachToCheckout(form)`

Injects hidden `lz_click_id` and `lz_cookie_id` fields into a form:

```typescript
attachToCheckout('#checkout-form');
// or
attachToCheckout(document.getElementById('checkout-form'));
```

### `buildConversionPayload(order)`

Builds a conversion payload with attribution data included:

```typescript
const payload = buildConversionPayload({
  order_id: 'ORD-123',
  order_value: 99.99,
  currency: 'USD',
  customer_id: 'cust_abc',
});
// Send payload to your backend → your backend sends to Linkzly S2S API
```

### `getAttributionHeaders()`

Returns attribution data as HTTP headers for fetch/XHR:

```typescript
const lz = init();
fetch('/api/checkout', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    ...lz.getAttributionHeaders(),
  },
  body: JSON.stringify(orderData),
});
```

## Integration Examples

### Next.js / React

```tsx
import { useEffect, useState } from 'react';
import { init, getAttribution } from '@linkzly/affiliate-web';

export function CheckoutPage() {
  const [attribution, setAttribution] = useState(null);

  useEffect(() => {
    const lz = init();
    setAttribution(lz.getAttribution());
  }, []);

  const handleCheckout = async (orderData) => {
    const lz = init();
    const payload = lz.buildConversionPayload({
      order_id: orderData.id,
      order_value: orderData.total,
      currency: 'USD',
    });

    await fetch('/api/conversions', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
  };

  return <button onClick={handleCheckout}>Complete Purchase</button>;
}
```

### Vanilla JS

```html
<form id="checkout-form" action="/api/checkout" method="POST">
  <input type="text" name="email" />
  <button type="submit">Pay Now</button>
</form>

<script type="module">
  import { attachToCheckout } from '@linkzly/affiliate-web';
  attachToCheckout('#checkout-form');
</script>
```

## SPA Support

The SDK automatically persists `lz_click_id` from URL parameters to `sessionStorage`, so attribution survives client-side navigation in SPAs (React Router, Next.js, etc.).

## License

MIT