Skip to main content
Add a fully automated referral program to your Supabase app using Auth metadata, Database Webhooks, and Edge Functions. Cello + Supabase integration

Prerequisites

Before integrating Cello, ensure the following:
  • Your app uses Supabase Auth for user signup and authentication
  • Your app has a Stripe subscription or payment flow (for purchase tracking)
  • You have a Cello account with your Product ID, Product Secret, and API access keys from the Access Keys page
Use the Cello Sandbox environment when developing and testing your integration.

Optional: Connect the Cello MCP

Connect the Cello MCP server to your AI coding tool - it gives your tool access to Cello’s docs, health checks, and best practices so your AI can handle the implementation.

Cello MCP Server

Setup instructions for Cursor, VS Code, and Lovable

Step 1: Capture referral codes on your landing page

Add the Cello attribution script to your referral landing page to capture the referral code (ucc) when users click referral links:
  1. Install the attribution script. Choose the option best suited for your setup:

    Embedded Script Tag

    Google Tag Manager

  2. Verify the installation
    To verify, follow these steps:
    1. Add ?productId=test and ?ucc=test to your website URL
       https://yourwebsite.com/?productId=test&ucc=test
      
    2. Make sure that these values are saved in the cookies as cello-product-id and cello-referral
    3. Navigate to your signup page and try to access the ucc using the getUcc() method from the browser console
      window.CelloAttribution('getUcc')
      
      This method should return a promise with value test
      Promise {<fulfilled>: 'test'}
      
    If this check passes, the script is installed correctly.

Step 2: Track signups with Supabase Auth + Edge Functions

This is the Supabase-specific step. You will pass the referral code through Supabase Auth, then use a Database Webhook and Edge Function to send the signup event to Cello.

2a. Pass the referral code through Supabase Auth signup

During signup, retrieve the ucc and store it in the user’s raw_user_meta_data:
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

const ucc = await window.CelloAttribution('getUcc')

const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'password',
  options: {
    data: {
      ucc: ucc ?? null,
    },
  },
})

2b. Deploy an Edge Function to send signup events to Cello

Create an Edge Function that receives the Database Webhook payload and sends a new-signup event to the Cello POST /events API. All Cello referral events use eventName: 'ReferralUpdated' - the trigger field inside context.event specifies the event type (new-signup, invoice-paid, etc.).
supabase functions new cello-track-signup
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'

async function getCelloAccessToken(): Promise<string> {
  const response = await fetch('https://api.cello.so/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      accessKeyId: Deno.env.get('CELLO_ACCESS_KEY_ID'),
      secretAccessKey: Deno.env.get('CELLO_SECRET_ACCESS_KEY'),
    }),
  })

  if (!response.ok) {
    throw new Error(`Failed to get Cello token: ${await response.text()}`)
  }

  const { accessToken } = await response.json()
  return accessToken
}

serve(async (req: Request) => {
  const payload = await req.json()
  const record = payload.record

  const ucc = record.raw_user_meta_data?.ucc
  const userId = record.id
  const email = record.email

  if (!ucc) {
    return new Response('No referral code - skipping', { status: 200 })
  }

  const accessToken = await getCelloAccessToken()

  const response = await fetch('https://api.cello.so/events', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      eventName: 'ReferralUpdated',
      payload: {
        ucc,
        newUserId: userId,
      },
      context: {
        newUser: {
          id: userId,
          email,
        },
        event: {
          trigger: 'new-signup',
          timestamp: new Date().toISOString(),
        },
      },
    }),
  })

  if (!response.ok) {
    console.error('Cello signup tracking failed:', await response.text())
    return new Response('Error', { status: 500 })
  }

  return new Response('OK', { status: 200 })
})
Set your Cello API access keys. You can find these in your Cello Portal:
supabase secrets set CELLO_ACCESS_KEY_ID=your_access_key_id
supabase secrets set CELLO_SECRET_ACCESS_KEY=your_secret_access_key
Deploy the function:
supabase functions deploy cello-track-signup --no-verify-jwt
The --no-verify-jwt flag is required because the function is called by a Database Webhook, not by an authenticated user.

2c. Create a Database Webhook on auth.users

In your Supabase Dashboard, go to Database → Webhooks and create a new webhook:
SettingValue
Namecello-track-signup
Tableauth.users
EventsINSERT
TypeSupabase Edge Functions
Edge Functioncello-track-signup
Click Create webhook.
Every time a new user signs up via Supabase Auth, the Edge Function fires automatically and sends the referral attribution to Cello.

Step 3: Connect Stripe Webhook for purchase tracking

To send Cello purchase events, connect your Stripe Webhook to Cello. When creating a Stripe Customer, pass the referral metadata so Cello can attribute conversions:
const customer = await stripe.customers.create({
  email: 'user@example.com',
  metadata: {
    cello_ucc: ucc,                       // referral code stored during signup
    new_user_id: supabaseUserId,           // must match the productUserId used to boot the widget
    new_user_organization_id: orgId,       // optional - for organization-level referrals
  },
})
Cello uses the customer.created event to link the Stripe customer to the referral attribution captured in Step 2. Subsequent invoice.paid events trigger purchase tracking and reward calculation.
Follow this guide to connect the webhook:

Stripe Webhook

Send events using Stripe Webhook

Step 4: Integrate the Referral Component

Integrate the Cello Referral Component into your web app so your users can share their referral link. The component is installed using Cello JS - our client-side SDK. You can install it by:
  1. Adding a script tag to the <head> of your application
  2. Generating a JWT token for user authentication
  3. Booting the component with the provided token and user details
Follow this installation guide:

Referral Component Quickstart

Cello requires a server-side JWT token signed with your PRODUCT_SECRET - this is not the Supabase session token (session.access_token). You must generate a separate token on your backend. See User Authentication for details.

Verify your integration

Use the Event Feed in the Cello Portal to confirm that signup and purchase events are arriving correctly and all required fields pass validation. See the Event Feed guide for details on what to check.

Next steps

Referral Component

Customise how the referral widget looks and behaves in your app

Track Purchases

Set up purchase conversion tracking via Stripe webhooks

Apply Discounts

Offer new user discounts as part of your referral program

Cello MCP Server

Connect Cursor or Lovable to Cello for AI-assisted integration