Skip to Content
Developer Docs

The @dub/embed-react package wraps an <iframe> hosted by RevRoute and exposes it as a single React component. It works in any React 18+ app — Next.js (App Router or Pages), Vite, Remix, CRA.

Install the package

pnpm add @dub/embed-react

Peer dependencies: react@^18 and react-dom@^18 (React 19 is also supported).

Mint a token on your backend

The component needs a short-lived embed token. Generate it from a route that knows which partner the current user corresponds to — never expose the workspace API key to the browser.

import { NextResponse } from "next/server"; export async function POST() { // Replace with your real auth + partner 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 }); }

The response:

{ "publicToken": "dub_embed_eyJhbGc...", "expires": "2026-05-15T13:34:56.789Z" }

publicToken is safe to send to the browser. It is valid only for the referenced partner and expires at the expires timestamp.

Mount the component

"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>Loading…</div>; return ( <DubEmbed data="referrals" token={token} style={{ width: "100%", height: "100vh", border: 0 }} /> ); }

That’s the whole integration — the partner’s referral dashboard is now embedded in your app.

React (Vite, CRA, etc.)

The component is identical in non-Next.js projects. Only the token-minting endpoint changes — implement it in your own server (Express, Fastify, Rails, Django, whatever you use).

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 }} /> ); }

Token refresh

Embed tokens expire after ~1 hour. If a user keeps the dashboard open longer, refetch the token before it expires and pass the new value to <DubEmbed token={...} />. Changing the token prop transparently re-authenticates the iframe without losing state.

A minimal hook:

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

If your app sends a CSP header, allow the RevRoute embed origin:

Content-Security-Policy: frame-src https://app.revroute.ru; connect-src 'self' https://api.revroute.ru;

Next steps

Last updated on