DocsRecipes

Recipes

Referral and product-led growth-loop analytics

4 min readReviewed July 2026

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:

  1. eligible senders and participation
  2. referral creation, delivery, visit, signup, and activation
  3. cycle time
  4. activated recipients per sender
  5. referred-cohort retention and value
  6. recipients becoming senders
  7. reward cost and reversals
  8. 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.
Need a hand?

Tell us what you’re building and we’ll point you in the right direction.

Contact support