A referral loop connects an existing participant to a new participant:
eligible sender
→ referral created
→ invitation delivered
→ recipient visits
→ recipient signs up
→ recipient reaches value
→ recipient becomes a sender
This differs from internal team invitations. Use Collaboration and team-adoption analytics when the recipient joins the same customer account. Use this recipe when referrals acquire a new user, customer, creator, buyer, seller, or partner.
Define every participant and grain#
| Grain | Identifier |
|---|---|
| Referral | referral_id |
| Sender | sender_entity_id |
| Recipient | recipient_entity_id after identity is known |
| Delivery | delivery_id |
| Reward decision | reward_decision_id |
| Conversion | Normal product outcome ID |
Do not use the raw referral token as the analytical identifier. Treat referral links and tokens as credentials: store a one-way lookup or opaque referral ID, and never place redeemable values in GraphJSON.
Instrument the referral lifecycle#
Referral created:
{
"event": "referral_created",
"event_id": "evt_referral_01J...",
"referral_id": "ref_782",
"sender_entity_id": "usr_91",
"sender_account_id": "acct_42",
"program": "customer_referral",
"program_version": "v3",
"channel": "email",
"schema_version": 1
}
Recipient visited:
{
"event": "referral_landing_viewed",
"event_id": "evt_visit_01J...",
"referral_id": "ref_782",
"anonymous_id": "anon_204",
"program": "customer_referral",
"landing_variant": "benefit-led",
"schema_version": 1
}
Recipient reached value:
{
"event": "account_activated",
"event_id": "evt_activation_01J...",
"account_id": "acct_99",
"user_id": "usr_210",
"acquisition_referral_id": "ref_782",
"activation_version": "v5",
"schema_version": 1
}
Keep the activation event valid outside the referral program. Referral attribution is context, not the definition of activation.
Resolve identity deliberately#
The landing visit may be anonymous while signup and activation are identified. Use the same first-party identity-stitching approach as other acquisition flows:
referral_id + anonymous_id
→ account created
→ anonymous identity linked to user/account
Do not identify a recipient from an email address copied into analytics. Maintain the invitation-address mapping in the transactional system and send opaque IDs after the recipient is legitimately resolved.
Define:
- whether the first or last referral wins
- attribution window
- cross-device behavior
- self-referral handling
- several senders referring the same recipient
- organic signup after a referral visit
Preserve all observed touches if useful, but choose one versioned attribution rule for reporting and reward evaluation.
Build the referral funnel#
WITH referrals AS (
SELECT
JSONExtractString(json, 'referral_id') AS referral_id,
min(timestamp) AS created_at
FROM growth_events
WHERE JSONExtractString(json, 'event') = 'referral_created'
GROUP BY referral_id
),
outcomes AS (
SELECT
referrals.referral_id,
max(JSONExtractString(events.json, 'event') = 'referral_delivered') AS delivered,
max(JSONExtractString(events.json, 'event') = 'referral_landing_viewed') AS visited,
max(JSONExtractString(events.json, 'event') = 'referral_signup_completed') AS signed_up,
max(JSONExtractString(events.json, 'event') = 'referral_recipient_activated') AS activated
FROM referrals
LEFT JOIN growth_events AS events
ON referrals.referral_id =
JSONExtractString(events.json, 'referral_id')
AND events.timestamp >= referrals.created_at
AND events.timestamp < referrals.created_at + 30 * 24 * 60 * 60
GROUP BY referrals.referral_id
)
SELECT
count() AS created,
sum(delivered) AS delivered,
sum(visited) AS visited,
sum(signed_up) AS signed_up,
sum(activated) AS activated
FROM outcomes
The example uses a 30-day outcome window. Choose and document the interval before launch. Keep undeliverable, expired, and cancelled referrals visible rather than dropping them silently.
Measure the loop, not only conversion#
Useful measures:
- eligible senders
- sender participation rate
- referrals per active sender
- delivery and landing rate
- recipient signup and activation rate
- time from creation to activation
- referred-customer retention and value
- activated recipients who later refer
- complete loop cycle time
A practical descriptive coefficient is:
referrals per active sender
× recipient activation rate
= activated recipients per active sender
This is not automatically an incremental viral coefficient. It can include people who would have joined organically, duplicate referrals, and rewards that change behavior.
Compare recipient quality#
Compare referred and non-referred cohorts on:
- activation
- time to value
- 30- or 90-day retention
- paid conversion
- refund or fraud outcome
- support demand
- contribution margin
Use equivalent acquisition periods, maturity, geographies, plans, and eligibility. Referral recipients may differ systematically from organic customers. Describe observational comparisons as associations unless a valid experiment establishes incrementality.
Keep reward decisions authoritative#
If a program pays credit or cash:
{
"event": "referral_reward_decided",
"event_id": "evt_reward_01J...",
"reward_decision_id": "reward_501",
"referral_id": "ref_782",
"beneficiary_type": "sender",
"decision": "approved",
"reason_code": "recipient_activated_and_settled",
"program_version": "v3",
"amount_minor": 2500,
"currency": "usd",
"schema_version": 1
}
The rewards or ledger system must determine eligibility, settlement, reversal, and balance. GraphJSON analyzes copies of those decisions; it must not issue money from a dashboard query.
Monitor abuse without overcollection#
Review signals such as:
- unusually many recipients per sender
- many referrals resolving to the same account or payment instrument
- self-referral decisions
- rapid create-and-cancel patterns
- repeated reward reversal
- high signup but low settled activation
- concentrated network clusters
Keep network, device, payment, and fraud evidence in the appropriate risk system. Publish bounded decision and outcome codes for analysis. Do not build an uncontrolled fingerprinting dataset in product analytics.
Measure program changes#
Attach:
- program version
- offer version
- channel
- landing variant
- eligibility version
When incentives or messaging change, compare:
- sender participation
- recipient activation
- settled reward cost
- cost per activated recipient
- recipient retention and margin
- abuse and reversal outcomes
Use randomized eligibility or offer experiments when the decision requires incremental impact.
Build the growth-loop dashboard#
Recommended sections:
- eligible senders and participation
- referral creation, delivery, visit, signup, and activation
- cycle time
- activated recipients per sender
- referred-cohort retention and value
- recipients becoming senders
- reward cost and reversals
- abuse outcomes and instrumentation health
Launch checklist#
- Referral, sender, recipient, delivery, and reward grains are separate.
- Raw referral tokens and recipient addresses are excluded.
- Anonymous-to-identified linking is deliberate and consent-aware.
- Attribution rule and window are versioned.
- Funnel stages use stable identities and bounded windows.
- Eligible senders are the participation denominator.
- Referred cohorts are mature before retention comparisons.
- Descriptive loop metrics are not labeled incremental without a valid design.
- Reward decisions and money remain authoritative outside GraphJSON.
- Fraud evidence is minimized and protected.
- Program versions travel with events and decisions.
- Funnel and reward totals reconcile with source systems.