> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mlm-platform.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget Embedding

> Securely embed referral widgets in your application

# Widget Embedding

The MLM Platform provides embeddable widgets for displaying referral information and capturing leads.

## Overview

Widgets are embedded using iframes with JWT-based authentication (Widget Access Tokens or WATs).

```
┌─────────────────────────────────────────┐
│  Your Application                       │
│  ┌───────────────────────────────────┐  │
│  │  iframe (MLM Widget)              │  │
│  │  - Referral link                  │  │
│  │  - Commission stats               │  │
│  │  - Lead capture form              │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
```

## Step 1: Configure Allowed Origins

Before embedding widgets, configure allowed origins in the Admin Dashboard:

1. Navigate to **Settings** > **Widget Configuration**
2. Add your application's origin(s):
   * `https://yourapp.com`
   * `https://www.yourapp.com`
   * `http://localhost:3000` (for development)
3. Click **Save**

<Warning>
  Only add origins you control. Unauthorized origins will be rejected.
</Warning>

## Step 2: Generate a Widget Access Token

Request a WAT from your backend:

<CodeGroup>
  ```javascript Node.js theme={null}
  // Backend endpoint to generate WAT
  app.post('/api/widget-token', async (req, res) => {
    const { userId } = req.body;
    
    const response = await fetch(
      'https://app.mlm-platform.com/api/v1/widget/session',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-tenant-api-key': process.env.MLM_API_KEY
        },
        body: JSON.stringify({ user_id: userId })
      }
    );
    
    const { token, expires_at } = await response.json();
    res.json({ token, expires_at });
  });
  ```

  ```python Python theme={null}
  @app.route('/api/widget-token', methods=['POST'])
  def get_widget_token():
      user_id = request.json['userId']
      
      response = requests.post(
          'https://app.mlm-platform.com/api/v1/widget/session',
          headers={
              'Content-Type': 'application/json',
              'x-tenant-api-key': os.environ['MLM_API_KEY']
          },
          json={'user_id': user_id}
      )
      
      return jsonify(response.json())
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2024-01-15T11:30:00Z",
  "user_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

## Step 3: Embed the Widget

Use the token to embed the widget iframe:

```html theme={null}
<iframe
  id="mlm-widget"
  src="https://widget.mlm-platform.example.com/referral?token=YOUR_TOKEN"
  width="400"
  height="300"
  frameborder="0"
  allow="clipboard-write"
></iframe>
```

### React Component

```jsx theme={null}
import { useState, useEffect } from 'react';

function ReferralWidget({ userId }) {
  const [token, setToken] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function fetchToken() {
      const response = await fetch('/api/widget-token', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ userId })
      });
      const { token } = await response.json();
      setToken(token);
      setLoading(false);
    }
    fetchToken();
  }, [userId]);
  
  if (loading) return <div>Loading widget...</div>;
  
  return (
    <iframe
      src={`https://widget.mlm-platform.example.com/referral?token=${token}`}
      width="400"
      height="300"
      frameBorder="0"
      allow="clipboard-write"
      title="Referral Widget"
    />
  );
}
```

## Widget Types

### Referral Link Widget

Displays the user's referral link with copy functionality:

```
https://widget.mlm-platform.example.com/referral?token=TOKEN
```

### Commission Stats Widget

Shows commission balance and history:

```
https://widget.mlm-platform.example.com/stats?token=TOKEN
```

### Lead Capture Widget

Form for capturing leads with referral attribution:

```
https://widget.mlm-platform.example.com/lead-capture?token=TOKEN
```

## Content Security Policy (CSP)

If your application uses CSP, add the widget domain to `frame-src`:

```
Content-Security-Policy: frame-src 'self' https://widget.mlm-platform.example.com;
```

Or in Next.js middleware:

```javascript theme={null}
// middleware.ts
export function middleware(request) {
  const response = NextResponse.next();
  
  response.headers.set(
    'Content-Security-Policy',
    "frame-src 'self' https://widget.mlm-platform.example.com"
  );
  
  return response;
}
```

## Token Refresh

WATs expire after 1 hour. Implement token refresh:

```javascript theme={null}
function ReferralWidget({ userId }) {
  const [token, setToken] = useState(null);
  const [expiresAt, setExpiresAt] = useState(null);
  
  async function refreshToken() {
    const response = await fetch('/api/widget-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ userId })
    });
    const data = await response.json();
    setToken(data.token);
    setExpiresAt(new Date(data.expires_at));
  }
  
  useEffect(() => {
    refreshToken();
    
    // Refresh 5 minutes before expiry
    const interval = setInterval(() => {
      if (expiresAt && new Date() > new Date(expiresAt - 5 * 60 * 1000)) {
        refreshToken();
      }
    }, 60000);
    
    return () => clearInterval(interval);
  }, [userId]);
  
  // ... render iframe
}
```

## Troubleshooting

### Widget Not Loading

1. **Check origin configuration**: Verify your origin is in the allowed list
2. **Check token**: Ensure token is valid and not expired
3. **Check CSP**: Verify frame-src allows the widget domain
4. **Check browser console**: Look for CORS or CSP errors

### CORS Errors

```
Refused to frame 'https://widget.mlm-platform.example.com/' 
because an ancestor violates the following Content Security Policy directive...
```

**Solution**: Add the widget domain to your CSP `frame-src` directive.

### Token Expired

```json theme={null}
{
  "error": "Token expired",
  "code": "TOKEN_EXPIRED"
}
```

**Solution**: Implement token refresh as shown above.

### Origin Not Allowed

```json theme={null}
{
  "error": "Origin not allowed",
  "code": "ORIGIN_NOT_ALLOWED"
}
```

**Solution**: Add your origin to the allowed origins list in the Admin Dashboard.
