> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cello.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Cello + Supabase integration

> How to add user referrals to your app built on Supabase

Add a fully automated referral program to your Supabase app using **Auth metadata**, **Database Webhooks**, and **Edge Functions**.

<img className="w-full rounded-xl" src="https://mintcdn.com/cello/fRrhh-kMKt2ac_Xc/coding-apps/supabase_cello.png?fit=max&auto=format&n=fRrhh-kMKt2ac_Xc&q=85&s=8328df795f2c3823c761b88ba6b923df" alt="Cello + Supabase integration" width="1957" height="1104" data-path="coding-apps/supabase_cello.png" />

## 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](https://portal.cello.so/integrations/accesskeys)

<Note>
  Use the Cello **Sandbox environment** when developing and testing your integration.
</Note>

## Optional: Connect the Cello MCP

Connect the [Cello MCP server](/mcp/introduction) 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.

<Card title="Cello MCP Server" icon="plug" horizontal href="/mcp/connect">
  Setup instructions for Cursor, VS Code, and Lovable
</Card>

# Step 1: Capture referral codes on your landing page

Add the [Cello attribution script](/sdk/client-side/attribution-js-introduction) 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:

   <CardGroup cols={2}>
     <Card title="Embedded Script Tag" icon="code" horizontal href="/sdk/client-side/embedded-script-tag" />

     <Card title="Google Tag Manager" icon="google" horizontal href="/sdk/client-side/google-tag-manager" />
   </CardGroup>
2. Verify the installation

   <Check>
     To verify, follow these steps:

     1. Add `?productId=test` and `?ucc=test` to your website URL

        ```html theme={null}
         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

        ```javascript theme={null}
        window.CelloAttribution('getUcc')
        ```

        This method should return a promise with value `test`

        ```javascript theme={null}
        Promise {<fulfilled>: 'test'}
        ```

     **If this check passes, the script is installed correctly.**
   </Check>

# 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`:

```js theme={null}
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-reference/generic-events/send-event) API.

All Cello referral events use `eventName: 'ReferralUpdated'` - the `trigger` field inside `context.event` specifies the event type (`new-signup`, `invoice-paid`, etc.).

```bash theme={null}
supabase functions new cello-track-signup
```

<Accordion title="supabase/functions/cello-track-signup/index.ts">
  ```typescript theme={null}
  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 })
  })
  ```
</Accordion>

Set your Cello API access keys. You can find these in your [Cello Portal](https://portal.cello.so/integrations/accesskeys):

```bash theme={null}
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:

```bash theme={null}
supabase functions deploy cello-track-signup --no-verify-jwt
```

<Note>
  The `--no-verify-jwt` flag is required because the function is called by a Database Webhook, not by an authenticated user.
</Note>

## 2c. Create a Database Webhook on auth.users

In your [Supabase Dashboard](https://supabase.com/dashboard), go to **Database → Webhooks** and create a new webhook:

| Setting       | Value                   |
| ------------- | ----------------------- |
| Name          | `cello-track-signup`    |
| Table         | `auth.users`            |
| Events        | `INSERT`                |
| Type          | Supabase Edge Functions |
| Edge Function | `cello-track-signup`    |

Click **Create webhook**.

<Check>
  Every time a new user signs up via Supabase Auth, the Edge Function fires automatically and sends the referral attribution to Cello.
</Check>

# 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:

```js theme={null}
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
  },
})
```

<Check>
  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.
</Check>

Follow this guide to connect the webhook:

<CardGroup cols={2}>
  <Card title="Stripe Webhook" icon="credit-card" horizontal href="/integrations/webhooks/stripe-webhook">
    Send events using Stripe Webhook
  </Card>
</CardGroup>

# 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:

<CardGroup cols={2}>
  <Card title="Referral Component Quickstart" icon="js" horizontal href="/referral-component/quickstart" />
</CardGroup>

<Warning>
  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](/sdk/client-side/user-authentication) for details.
</Warning>

## Verify your integration

Use the [Event Feed](https://portal.cello.so/integrations/events-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](/guides/support/portal/event-feed) for details on what to check.

## Next steps

<CardGroup cols={2}>
  <Card title="Referral Component" icon="puzzle-piece" href="/referral-component/introduction">
    Customise how the referral widget looks and behaves in your app
  </Card>

  <Card title="Track Purchases" icon="credit-card" href="/attribution/tracking-purchase">
    Set up purchase conversion tracking via Stripe webhooks
  </Card>

  <Card title="Apply Discounts" icon="tag" href="/attribution/apply-discounts">
    Offer new user discounts as part of your referral program
  </Card>

  <Card title="Cello MCP Server" icon="plug" href="/mcp/introduction">
    Connect Cursor or Lovable to Cello for AI-assisted integration
  </Card>
</CardGroup>
