Affiliate and Referrals
Rank Pilot AI SEO runs a self-serve affiliate programme, implemented in
src/pages/Affiliate.tsx (the public marketing page) and
src/components/dashboard/AffiliateSection.tsx (the in-dashboard tool where
affiliates generate links and track results), on top of three Supabase
tables: affiliate_codes, affiliate_referrals and affiliate_commissions.
The offer
As stated on /affiliate, the programme pays 10% recurring commission on
every paying customer an affiliate refers, for the lifetime of that
customer's subscription — there is no earnings cap. Key terms shown to
affiliates:
- Free to join — no need to be a paying RankPilot customer.
- Commissions paid monthly via Stripe, with no minimum payout threshold.
- A 30-day cookie window: a visitor who returns and converts within 30 days of first clicking a referral link still counts as that affiliate's referral.
- A conversion is recorded when someone signs up through an affiliate's link and later upgrades to any paid plan.
Affiliate.tsx itself is a marketing/signup landing page (hero, "How it
works" section reused from AffiliateSection on the landing page, perk
tiles, FAQ, and Google/email sign-up CTAs) — it doesn't do any link
generation or tracking itself; that lives in the dashboard component.
Generating a referral link/slug
Inside the dashboard, src/components/dashboard/AffiliateSection.tsx lets a
logged-in user create their own affiliate code:
- A default slug is suggested from the user's full name or the local part of
their email, lower-cased and stripped to alphanumeric characters
(
slugify), capped at 30 characters. - The user can edit this slug before generating it; on submit it's inserted
into
affiliate_codesas{ user_id, code }. A Postgres unique-constraint violation (duplicate code) surfaces as "That slug is already taken — try a different one". - Once created, the slug can be edited later via an inline edit/save flow, again subject to the same uniqueness check.
- The resulting referral link is always of the form:
{origin}/challenge?ref={code}— i.e. affiliate traffic is routed through the/challengelanding page with arefquery parameter carrying the affiliate's slug. - The component also offers Copy link and Download QR code actions
(QR generated client-side via the
qrcodepackage).
Tracking
Referral tracking data is read (not written) by this component from two
tables, both scoped to affiliate_user_id = current user:
affiliate_referrals— one row per person who signed up via the affiliate's link, including astatusfield distinguishing"paying"from a plain signup, and asigned_up_attimestamp. The dashboard lists the 10 most recent referrals with a status badge ("Paying" vs "Signed Up").affiliate_commissions— one row per commissionamountearned by the affiliate; the dashboard sums these into a running "Total Commission" figure.
From these, the UI derives three headline stats:
- Total Referrals — count of all rows in
affiliate_referrals. - Paying Customers — count of referrals with
status === "paying". - Total Commission — sum of all
affiliate_commissions.amount, displayed as£{total.toFixed(2)}with a "10% recurring" caption.
The actual attribution logic (matching a ref query parameter on /challenge
to a click/signup, applying the 30-day cookie window, and flipping a
referral's status to "paying" on conversion) is handled by backend logic
outside this component — the dashboard section is a read/display layer over
the resulting affiliate_codes, affiliate_referrals and
affiliate_commissions tables.
Payouts
Per the public affiliate FAQ, payouts are processed monthly via Stripe
with no minimum threshold — every affiliate with a positive commission
balance is expected to be paid out each cycle rather than needing to
accumulate a minimum first. Payout processing itself (calculating amounts due
from affiliate_commissions and issuing Stripe transfers/payouts) is a
backend/admin operation and is not exposed in the affiliate-facing dashboard
component described above, which is limited to link generation and reporting.