Refport

Embedded Portal

Add a partner referral dashboard to your app with hosted iframe rendering or custom React components.

The embedded portal is the partner-facing part of Refport. It lets signed-in users copy their referral link, view clicks and conversions, track earnings, and manage payouts without leaving your product.

This is a core Refport integration path. Install tracking first, start sending conversions, then embed the portal where partners already work inside your app.

Integration options

OptionBest forWhat you build
Hosted iframeFastest launch and low maintenanceA server route that creates tokens and a <RefportEmbed> component
Custom React UINative product experienceA server route that creates tokens and UI built with Refport hooks

Both options use the same short-lived embed token.

How it works

  1. A signed-in user opens the referral area in your app.
  2. Your server verifies the user and calls embedTokens.create().
  3. Refport creates or finds the partner enrollment for that user.
  4. Your app passes the public token to the iframe or React provider.
  5. The portal fetches partner-scoped data without exposing your private API key.

Setup

npm install refport @refport/react @tanstack/react-query

Create an API route or server function that only runs after your app has authenticated the user.

app/api/referrals/embed-token/route.ts
import { Refport } from "refport";

const refport = new Refport({ apiKey: process.env.REFPORT_API_KEY! });

export async function GET(request: Request) {
  const user = await getCurrentUser(request);

  if (!user?.email) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const result = await refport.embedTokens.create({
    tenantId: user.id,
    partner: {
      email: user.email,
      name: user.name,
    },
  });

  if (result.error) {
    return Response.json(
      { error: result.error.message },
      { status: result.error.status }
    );
  }

  return Response.json({
    expires: result.data.expires,
    token: result.data.publicToken,
  });
}

Generate tokens from the server only. The private Refport API key must never be available in browser code.

Use <RefportEmbed> when you want the fastest path.

app/dashboard/referrals/page.tsx
import { RefportEmbed } from "@refport/react";

async function getEmbedToken(): Promise<string> {
  const response = await fetch("/api/referrals/embed-token");
  const data = await response.json();
  return data.token;
}

export default async function ReferralsPage() {
  const token = await getEmbedToken();

  return <RefportEmbed token={token} theme="system" />;
}

Hosted iframe

The hosted portal gives you a complete partner dashboard with minimal product work. Partners can view performance, copy their referral link, review payouts, and complete payout setup from the embedded experience.

<RefportEmbed
  token={token}
  theme="system"
  cssVars={{
    "--border-radius": "8px",
    "--font-family": "Inter, sans-serif",
  }}
/>

Use the onError prop to recover from expired tokens.

<RefportEmbed
  token={token}
  onError={({ code }) => {
    if (code === "TOKEN_EXPIRED") {
      refreshEmbedToken();
    }
  }}
/>

Custom React UI

Use RefportProvider and useRefportPartner() when the referral experience should look and behave like the rest of your product.

app/dashboard/referrals/referral-portal.tsx
"use client";

import { RefportProvider, useRefportPartner } from "@refport/react";

export function ReferralPortal({ token }: { token: string }) {
  return (
    <RefportProvider token={token}>
      <ReferralPortalContent />
    </RefportProvider>
  );
}

function ReferralPortalContent() {
  const partner = useRefportPartner({ limit: 10 });

  if (partner.isLoading) {
    return <p>Loading...</p>;
  }

  if (partner.error) {
    return <p>Could not load referral data.</p>;
  }

  const { earnings, link, payouts, stats } = partner.data;

  return (
    <section>
      <h1>Your referrals</h1>
      <input readOnly value={link.referralUrl} />
      <dl>
        <dt>Clicks</dt>
        <dd>{stats.clicks}</dd>
        <dt>Leads</dt>
        <dd>{stats.leads}</dd>
        <dt>Sales</dt>
        <dd>{stats.sales}</dd>
        <dt>Total earnings</dt>
        <dd>
          {earnings.total} {earnings.currency}
        </dd>
      </dl>
      <ul>
        {payouts.payouts.map((payout) => (
          <li key={payout.id}>
            {payout.amount} {payout.currency} - {payout.status}
          </li>
        ))}
      </ul>
    </section>
  );
}

Portal dataset

useRefportPartner() returns the complete portal dataset in one request.

FieldDescription
statsClick, lead, sale, and earnings totals
timeseriesClick, lead, and sale trends
linkReferral code, referral URL, and program name
earningsEarnings breakdown and commission settings
payoutsPayout history
portalConfigPortal branding and visibility configuration

Granular hooks are available when a component only needs part of the dataset.

HookData
useRefportAffiliateStats()Click, lead, sale, and earnings totals
useRefportAffiliateTimeseries()Click, lead, and sale trends
useRefportAffiliateLink()Referral code, referral URL, and program name
useRefportAffiliateEarnings()Earnings breakdown and commission settings
useRefportAffiliatePayouts()Payout history
useRefportPortalConfig()Portal branding and visibility configuration

Security model

  • Create embed tokens on the server after your app authenticates the user.
  • Scope each token to one partner or tenant.
  • Generate a fresh token on page load or session refresh.
  • Treat the public token as browser-safe but short lived.
  • Keep REFPORT_API_KEY in server-only environment variables.

Without React

If you are not using React, create the iframe URL yourself.

const params = new URLSearchParams({
  dynamicHeight: "true",
  theme: "system",
  token: publicToken,
});

const iframeSrc = `https://app.refport.co/embed/referrals?${params}`;

Next steps

On this page