Пакет @dub/embed-react оборачивает <iframe>, хостящийся у RevRoute, в единый React-компонент. Работает в любом React 18+ приложении — Next.js (App Router или Pages), Vite, Remix, CRA.
Установка пакета
pnpm add @dub/embed-reactPeer-зависимости: react@^18 и react-dom@^18 (React 19 также поддерживается).
Выпуск токена на бэкенде
Компоненту нужен short-lived embed-токен. Генерируйте его в роуте, который знает, какому партнёру соответствует текущий пользователь — никогда не выставляйте workspace API-ключ в браузер.
import { NextResponse } from "next/server";
export async function POST() {
// Замените на вашу реальную авторизацию и lookup партнёра
const partnerId = await getPartnerIdForCurrentUser();
if (!partnerId) return new NextResponse("Not a partner", { status: 403 });
const res = await fetch(
"https://api.revroute.ru/tokens/embed/referrals",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REVROUTE_API_KEY!}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ partnerId, programId: process.env.REVROUTE_PROGRAM_ID }),
},
);
if (!res.ok) return new NextResponse(await res.text(), { status: 500 });
const { publicToken, expires } = await res.json();
return NextResponse.json({ publicToken, expires });
}Ответ:
{
"publicToken": "dub_embed_eyJhbGc...",
"expires": "2026-05-15T13:34:56.789Z"
}publicToken безопасно отправлять в браузер. Он валиден только для указанного партнёра и истекает в указанный момент.
Монтирование компонента
"use client";
import { DubEmbed } from "@dub/embed-react";
import { useEffect, useState } from "react";
export default function ReferPage() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
fetch("/api/embed/token", { method: "POST" })
.then((r) => r.json())
.then(({ publicToken }) => setToken(publicToken));
}, []);
if (!token) return <div>Загрузка…</div>;
return (
<DubEmbed
data="referrals"
token={token}
style={{ width: "100%", height: "100vh", border: 0 }}
/>
);
}Вся интеграция — реферальный дашборд партнёра встроен в ваше приложение.
React (Vite, CRA и т.д.)
Компонент одинаковый в не-Next.js-проектах. Меняется только эндпоинт выдачи токена — реализуйте его в своём сервере (Express, Fastify, Rails, Django — что используете).
import { DubEmbed } from "@dub/embed-react";
export function ReferralTab({ token }: { token: string }) {
return (
<DubEmbed
data="referrals"
token={token}
style={{ width: "100%", height: "100%", border: 0 }}
/>
);
}Обновление токена
Embed-токены истекают через ~1 час. Если пользователь держит дашборд открытым дольше — запрашивайте новый токен до истечения и передавайте новое значение в <DubEmbed token={...} />. Изменение prop token прозрачно реаутентифицирует iframe без потери состояния.
Минимальный хук:
function useEmbedToken() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
let cancelled = false;
async function refresh() {
const r = await fetch("/api/embed/token", { method: "POST" });
const { publicToken, expires } = await r.json();
if (cancelled) return;
setToken(publicToken);
const ms = Math.max(60_000, new Date(expires).getTime() - Date.now() - 60_000);
setTimeout(refresh, ms);
}
refresh();
return () => { cancelled = true; };
}, []);
return token;
}Content Security Policy
Если ваше приложение отправляет CSP-заголовок, разрешите origin embed’а RevRoute:
Content-Security-Policy:
frame-src https://app.revroute.ru;
connect-src 'self' https://api.revroute.ru;Дальше
- Реферальный дашборд — props и кастомизация
- Темизация — настройка под бренд
- Аутентификация API — управление workspace-API-ключом