Skip to main content

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
Only add origins you control. Unauthorized origins will be rejected.

Step 2: Generate a Widget Access Token

Request a WAT from your backend:
// Backend endpoint to generate WAT
app.post('/api/widget-token', async (req, res) => {
  const { userId } = req.body;
  
  const response = await fetch(
    'https://api.mlm-platform.example.com/functions/v1/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 });
});
Response:
{
  "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:
<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

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

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:
// 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:
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

{
  "error": "Token expired",
  "code": "TOKEN_EXPIRED"
}
Solution: Implement token refresh as shown above.

Origin Not Allowed

{
  "error": "Origin not allowed",
  "code": "ORIGIN_NOT_ALLOWED"
}
Solution: Add your origin to the allowed origins list in the Admin Dashboard.