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 │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
Before embedding widgets, configure allowed origins in the Admin Dashboard:
- Navigate to Settings > Widget Configuration
- Add your application’s origin(s):
https://yourapp.com
https://www.yourapp.com
http://localhost:3000 (for development)
- Click Save
Only add origins you control. Unauthorized origins will be rejected.
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"
}
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"
/>
);
}
Displays the user’s referral link with copy functionality:
https://widget.mlm-platform.example.com/referral?token=TOKEN
Shows commission balance and history:
https://widget.mlm-platform.example.com/stats?token=TOKEN
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
- Check origin configuration: Verify your origin is in the allowed list
- Check token: Ensure token is valid and not expired
- Check CSP: Verify frame-src allows the widget domain
- 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.