# Get token
Source: https://docs.cello.so/api-reference/authentication/get-token
POST /token
Obtain accessToken & refreshToken using your accessKeyId and secretAccessKey, or obtain a new accessToken using a refreshToken.
# Send new event
Source: https://docs.cello.so/api-reference/generic-events/send-event
POST /events
Report referral-related events such as signups, purchases, and refunds.
# Introduction
Source: https://docs.cello.so/api-reference/introduction
Overview of Cello API for referral codes, authentication, and quickstart.
## Cello API
The Cello API provides endpoints to:
* Validate referral codes (`ucc`)
* Retrieve active referral links
* Send referral events for signups and purchases
***
## Base URLs
Use the URL that matches your environment:
| Environment | Base URL |
| ----------- | ------------------------------- |
| Sandbox | `https://api.sandbox.cello.so/` |
| Production | `https://api.cello.so/` |
***
## Authentication
Authenticate API requests using an `accessToken` in the Authorization header.
Obtain your `accessKeyId` and `secretAccessKey` from the [Access Keys](https://portal.cello.so/integrations/accesskeys) page in your dashboard.
# Get new user reward info
Source: https://docs.cello.so/api-reference/new-users/get-reward
GET /new-users/{productUserId}/reward
Retrieve details on eligibility for the new user reward (discount) and referral information.
## Common reasons for `eligible: false`
If the response is `{ "eligible": false }` even though the user has a `cello_ucc`, the most common causes are:
* **No active new-user reward on the campaign** - the campaign tied to the UCC has no new-user discount configured, or the reward is inactive/expired.
* **`productUserId` mismatch** - the `productUserId` you passed isn't the user who actually signed up through the referral.
* **Attribution arrived after the first invoice** - `cello_ucc` was added to the customer after the first `invoice.paid`; attribution can be retroactive, but reward eligibility is still evaluated against the reward rules.
* **Self-referral** - the new user signed up using their own UCC, or the signup was flagged as a [self-referral](/guides/fraud-detection) by Cello's fraud detection. Self-referrals are not eligible for new-user discounts.
To verify, compare `referralUcc`, `campaignId`, and `campaignRevision` from the response (when `eligible: true`) against what you expect, and check the [Review Referrals](https://portal.cello.so/manage/reviewreferrals) section in the portal for self-referral flags.
# Fetch active link
Source: https://docs.cello.so/api-reference/referral-codes/fetch-active-link
GET /referral-codes/active-link/{productUserId}
Retrieve an active UCC and invite link for a given user to support contextual sharing.
# Fetch referral code info
Source: https://docs.cello.so/api-reference/referral-codes/fetch-referral-code-info
GET /referral-codes/{code}
Validate a referral code (UCC) and discover associated user/campaign.
# Apply Discounts
Source: https://docs.cello.so/attribution/apply-discounts
Learn how to apply discounts to referred users when the purchase a subscription
## Implementation steps
Implementing automated discounts for referred users follows a consistent pattern across all subscription platforms. Here's the complete workflow:
Create discount coupons in your subscription platform (Stripe, Chargebee, Paddle, Recurly, etc.):
**Platform Setup:**
* Configure discounts at the plan/price level
* Create multiple variations for different subscription plans:
* Monthly plans: e.g., 25% off for 3 months
* Annual plans: e.g., 50% off first year
* Store provider coupon IDs in application configuration. You will need them later to apply the correct coupon at subscription time based on plan/price and referral status.
Once you’ve set up discounts in your subscription platform, a potential next step would be to [display the discount information on your pricing or landing page](/guides/user-experience/new-user-discounts).
During subscription creation, check if the new user is a Cello referral and discount needs to be assigned:
* New ⭐: Use our [New User Reward API](/api-reference/new-users/get-reward) to validate the eligibility for a new user reward (discount)
or
* **Using Stripe or Chargebee only:** Check your Stripe/Chargebee Customer if a `cello_ucc` is present in the [**Customer Object**](https://apidocs.chargebee.com/docs/api/customers)**.**
* **Using CelloAPI to track signups and Stripe/Chargebee to track purchases:** Check your Stripe/Chargebee customer if a `cello_ucc` is present in the [**Customer Object**](https://apidocs.chargebee.com/docs/api/customers)
* **Cello API to track all conversion events:** Check if the new user with this id has a `cello_ucc` in your profile you stored during [signup tracking](/attribution/tracking-signups).
During subscription creation, pass the determined coupon code to your subscription platform:
**Required Data for Subscription:**
* Plan/Price information
* Coupon/discount code
**Platform-Specific Application:**
* **Stripe**: Use `discounts` array or `coupon` parameter on Checkout Session
* **Chargebee**: Apply `coupon_ids` on Subscription or via Hosted Pages (not at customer creation)
### Key Implementation Notes
* **Timing**: Discounts must be applied during initial subscription creation, not afterward
* **Validation**: Always verify the user is eligible for referral discounts
* **Fallback**: Handle cases where discount codes are invalid or expired
* **Configuration**: Maintain an application-level mapping of coupon IDs to plan type and referral status so the correct coupon can be applied at subscription time
## Stripe implementation
Stripe offers flexible discount mechanisms through **coupons**. For referral discounts, apply coupons during Subscription creation or Checkout. You cannot attach discounts at customer creation.
### Overview
There are two ways to apply coupons in Stripe, depending on your integration style:
* Server-side Subscription API (apply during `subscriptions.create`) - best for custom UIs. See [Stripe documentation](https://stripe.com/docs/billing/subscriptions/discounts).
* Prebuilt Checkout Session (apply during `checkout.sessions.create`) - best for hosted checkout. See [Stripe documentation](https://stripe.com/docs/payments/checkout/discounts).
Stripe's discount system works through:
* **Coupons**: Define the discount structure (percentage, duration, limits)
* **Application methods**: Apply coupons to Subscriptions or Checkout Sessions
Set up discount coupons for your referral program:
**Via Stripe Dashboard:**
1. Go to [Stripe Dashboard > Coupons](https://dashboard.stripe.com/coupons)
2. Click "Create coupon"
3. Configure discount parameters:
* **Name**: e.g., `Referral Discount - Monthly 25%`
* **Type**: Percentage
* **Percent off**: 25%
* **Duration**: Repeating (3 months)
* After creation, store the returned coupon ID in your config
**Via Stripe API:**
```javascript theme={null}
const stripe = require('stripe')('sk_live_...');
const coupon = await stripe.coupons.create({
name: 'Referral Discount - Monthly 25%',
percent_off: 25,
duration: 'repeating',
duration_in_months: 3,
metadata: {
campaign_type: 'user-referrals',
plan_type: 'monthly'
}
});
// Save coupon.id to your configuration
```
```javascript theme={null}
const subscription = await stripe.subscriptions.create({
customer: user.customerId,
items: [{
price: 'price_monthly_plan'
}],
discounts: [{
coupon: couponId
}]
});
```
### Handle checkout sessions with discounts
For Stripe Checkout, include discounts in session creation:
```javascript theme={null}
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{
price: 'price_monthly_plan',
quantity: 1
}],
customer: user.customerId,
discounts: [{
coupon: couponId
}],
success_url: 'https://yoursite.com/success',
cancel_url: 'https://yoursite.com/cancel'
});
```
The Stripe UI automatically displays the discount during checkout:
### Manual discount application (not recommended)
For testing or special cases, you can manually attach coupons on a Subscription in the Stripe Dashboard:
1. Navigate to the subscription in [Stripe Dashboard](https://dashboard.stripe.com/subscriptions)
2. Click **Update subscription** → **Add coupon**
3. Select the appropriate referral coupon
Manual application is not scalable for automated referral programs. Use the API methods above for production implementations.
## Chargebee implementation
Chargebee uses **coupons** to apply discounts on subscriptions. For referral discounts, apply coupons during subscription creation or via Hosted Pages.
### Overview
There are two ways to apply coupons in Chargebee:
* Subscription API (apply during `subscription.create`) - for server-side subscription creation. See [Chargebee documentation](https://apidocs.chargebee.com/docs/api/subscriptions?prod_cat_ver=2#create_a_subscription).
* Hosted Pages (apply via `coupon_ids` during checkout) - for provider-hosted checkout. See [Chargebee documentation](https://apidocs.chargebee.com/docs/api/hosted_pages?prod_cat_ver=2#checkout_new_subscription).
Chargebee's discount system works through:
* **Coupons**: Define discount rules (percentage, amount, duration)
* **Application methods**: Apply to subscriptions or via Hosted Pages
Set up discount coupons for your referral program:
**Via Chargebee Dashboard:**
1. Go to [Chargebee Dashboard > Coupons](https://www.chargebee.com/docs/2.0/coupons.html#creating-coupons)
2. Click "Create Coupon"
3. Configure discount parameters:
* **Coupon Name**: e.g., `Referral Discount - Monthly 25%`
* **Discount Type**: Percentage
* **Discount**: 25%
* **Duration Type**: Limited Period (3 months)
* After creation, store the coupon ID in your config
**Via Chargebee API:**
```javascript theme={null}
const chargebee = require('chargebee');
chargebee.configure({
site: 'your-site',
api_key: 'your-api-key'
});
const coupon = await chargebee.coupon.create({
id: 'YOUR_COUPON_ID',
name: 'Referral Discount - Monthly 25%',
discount_type: 'percentage',
discount_percentage: 25,
duration_type: 'limited_period',
period: 3,
period_unit: 'month'
});
```
```javascript theme={null}
const subscription = await chargebee.subscription.create({
customer_id: user.id,
plan_id: 'monthly_plan',
coupon_ids: [couponId]
});
```
### Handle Hosted Pages with discounts
For Chargebee Hosted Pages, include coupons in checkout URLs:
```javascript theme={null}
const hostedPage = await chargebee.hosted_page.checkout_new({
subscription: {
plan_id: 'monthly_plan',
coupon_ids: [couponId]
},
customer: {
id: user.id,
email: user.email
}
});
// Redirect user to hostedPage.url
```
## Cello API integration (for other platforms)
If you use another billing platform (for example, Paddle, Recurly, Braintree) or a home-grown system, follow the same general approach described above:
1. Create and manage coupons/discounts in your billing system.
2. Keep an application-level mapping of coupon IDs by plan and referral status.
3. Apply the correct coupon at subscription/checkout creation time.
# Mobile Signup Flow
Source: https://docs.cello.so/attribution/for-mobile
Learn how to set up mobile app referral attribution
This guide explains how to add referral tracking capabilities to your existing attribution links without creating new ones. In this guide, we'll use Branch.io as an example. The implementation is similar if you use other attribution libraries like [AppsFlyer](https://www.appsflyer.com/), [Singular](https://www.singular.net/) or [Adjust](https://www.adjust.com/).
Mobile attribution builds on top of [web attribution](/attribution/for-web) since users typically click referral links on web before downloading your app. The web setup captures the initial referral code that will later be attributed to the mobile app installation and signup.
## Overview
The referral flow works as follows:
* Existing user shares their unique referral link
* New user clicks the link and is directed to your landing page
* User then clicks on AppStore or Google Play app download
* New user installs and opens the app
* App receives referral data and attributes the installation
* Backend records the referral during signup
## Basic Concept
Instead of creating new links for each referrer, you'll append referral data to your existing Branch.io (or other attribution library) app install link:
```html theme={null}
Original: https://yourbrand.app.link/abc123
With Referral: https://yourbrand.app.link/abc123?referral_ucc=A1B2C
```
## Data Persists Through Installation
When a user clicks the referral link, Branch.io stores the referral data (including the referral\_ucc) in their servers and associates it with the user's device fingerprint. This allows the data to persist through:
* App Store redirect
* App download
* First app launch
## Data Flow Sequence
#### Link Click
```html theme={null}
https://yourbrand.app.link/abc123?referral_ucc=A1B2C
↓
Branch.io captures and stores:
- referral_ucc: A1B2C
- Device fingerprint
- Click timestamp
```
#### App Installation
```html theme={null}
User installs app from store
↓
Branch SDK initializes on first launch
↓
Branch matches device to stored click data
↓
Delivers referral data to app
```
## Accessing Referral Data in Your App
#### iOS Implementation
```swift theme={null}
import Branch
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// Check if the user came from a Branch link
if let clickedBranchLink = params?["+clicked_branch_link"] as? Bool,
clickedBranchLink {
// Extract referral code
if let referralCode = params?["referral_ucc"] as? String {
print("Referral Code: \(referralCode)")
// Store for use during signup
UserDefaults.standard.set(referralCode,
forKey: "pending_referral_code")
}
}
}
return true
}
}
```
#### Android Implementation
```kotlin theme={null}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Branch.getAutoInstance(this).initSession({ branchUniversalObject, linkProperties, error ->
if (error == null) {
// Check if user came from Branch link
if (linkProperties?.has("+clicked_branch_link") == true) {
// Get referral code
val referralCode = linkProperties.get("referral_ucc")
referralCode?.let {
Log.d("Branch", "Referral Code: $it")
// Store for signup
getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
.edit()
.putString("pending_referral_code", it)
.apply()
}
}
}
}, this.intent.data, this)
}
}
```
#### React Native Implementation
```javascript theme={null}
import branch from 'react-native-branch';
function DeepLinkHandler() {
useEffect(() => {
// Handle deep link when app is already running
const subscription = branch.subscribe({
onNewIntent: ({ error, params, uri }) => {
if (error) {
console.error('Branch link error:', error);
return;
}
if (params['+clicked_branch_link']) {
handleDeepLink(params);
}
}
});
return () => subscription();
}, []);
const handleDeepLink = async (params) => {
const referralCode = params.referral_ucc;
if (referralCode) {
await AsyncStorage.setItem('pending_referral_code', referralCode);
// Handle navigation or other logic based on deep link
}
};
return null;
}
```
## Using the Referral Data During Signup
When the user completes signup, retrieve the stored referral code and include it in your signup API call:
#### iOS Implementation
```swift theme={null}
// iOS Example
class SignupViewController: UIViewController {
func completeSignup(email: String, password: String) {
// Get stored referral code
let referralCode = UserDefaults.standard.string(forKey: "pending_referral_code")
// Include in signup API call
let signupData = [
"email": email,
"password": password,
"referral_code": referralCode
]
api.signup(signupData) { result in
if result.success {
// Clear stored referral data after successful signup
UserDefaults.standard.removeObject(forKey: "pending_referral_code")
}
}
}
}
```
#### Android Implementation
```kotlin theme={null}
// Android Example
class SignupActivity : AppCompatActivity() {
private fun completeSignup(email: String, password: String) {
val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
val referralCode = prefs.getString("pending_referral_code", null)
val signupData = HashMap().apply {
put("email", email)
put("password", password)
referralCode?.let { put("referral_code", it) }
}
api.signup(signupData) { success ->
if (success) {
// Clear stored referral data
prefs.edit().remove("pending_referral_code").apply()
}
}
}
}
```
#### React Native Implementation
```javascript theme={null}
function SignupScreen({ navigation }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSignup = async () => {
try {
const referralCode = await AsyncStorage.getItem('pending_referral_code');
const response = await api.signup({
email,
password,
referral_code: referralCode
});
if (response.success) {
await AsyncStorage.removeItem('pending_referral_code');
navigation.navigate('Home');
}
} catch (error) {
console.error('Signup error:', error);
}
};
return (
// Your signup form JSX
);
}
```
# Web Signup Flow
Source: https://docs.cello.so/attribution/for-web
Learn how to capture referral codes on your website
When users click referral links, they land on your website first. Capture the referral code (`ucc`) on this landing page to properly attribute future conversions.
Follow these steps to set up referral code capture:
## Step 1: Set up your landing page
Create a landing page for referral traffic. Choose one approach:
* Dedicated referral landing page
* Home page with Cello New User Banner
See the [landing page optimization guide](/guides/user-experience/optimizing-landing-pages) for best practices.
## Step 2: Install attribution script
The attribution script detects the `ucc` query parameter and stores it as a first-party cookie for later attribution of conversion events.
Install the Cello attribution script - [Attribution JS](/sdk/client-side/attribution-js-introduction) - using one of these methods:
The attribution script also enables you to:
* Fetch referrer names for [landing page personalization](/guides/user-experience/personalizing-referrals)
* Get campaign parameters to [display discounts](/guides/user-experience/new-user-discounts)
* Attach `ucc` to signup forms
See the [Attribution JS reference](/sdk/client-side/attribution-js-introduction) for complete details.
## Step 3: Verify installation
Verify that the `ucc` is available on your signup page:
1. Test your website with these query parameters:
```html theme={null}
https://yourwebsite.com/?productId=test&ucc=test
```
2. Verify these values are saved as cookies: `cello-product-id` and `cello-referral`
3. On your signup page, test `ucc` access from the browser console:
```javascript theme={null}
window.CelloAttribution('getUcc')
```
Expected response:
```javascript theme={null}
Promise {: 'test'}
```
If this test passes, the script is installed correctly.
**Using referral codes at signup**
Use `getUcc()` during user signup to retrieve the referral code, then pass it in the [signup event](/attribution/tracking-signups) to Cello.
For complex flows, save the `ucc` with your user record so it's available when sending [signup events](/attribution/tracking-signups).
# HubSpot Forms
Source: https://docs.cello.so/attribution/hubspot
Integrate the Cello attribution library with HubSpot forms to track referral conversions
## Overview
This guide shows you how to capture referral codes (`ucc`) from visitors and automatically populate them into HubSpot forms when users submit lead generation or contact forms. This enables you to track which referrals lead to qualified leads and conversions.
## Considerations when creating the `ucc` property in HubSpot
When creating a custom property in HubSpot, it is important that the internal name of the property is `ucc`. This sets up the property in either company or deal. The one to choose depends on your specific sales process and the corresponding HubSpot setup.
These instructions describe creating the `ucc` property in the object type **Company**, group **Company information**. Often, it can make sense to create the `ucc` property in the **Deal** object type. A custom property can be created following the instructions of HubSpot [here](https://knowledge.hubspot.com/properties/create-and-edit-properties).
## Step 1: Create a form with a hidden `ucc` field in HubSpot
To properly capture referral data, you need to add a `ucc` field to your HubSpot form:
1. Create a customized form in HubSpot by following the instructions [here](https://knowledge.hubspot.com/forms/create-forms).
2. In your form, create a hidden field called `ucc`. This field automatically picks up the `ucc` from the link and feeds it into the create `ucc` property in HubSpot. The result should look like this:
## Step 2: Include the Cello Attribution Library
Add the Cello attribution script to your website's `` section or before the closing `` tag:
```html theme={null}
```
## Step 3: Add the Attribution Command Queue
Since HubSpot forms are loaded dynamically, include this script to handle race conditions between your code and the Cello library loading:
```html theme={null}
```
**Important:** This script must be added before any calls to `window.CelloAttribution()` to prevent race conditions.
## Step 3: Integrate with HubSpot Form Creation
When creating your HubSpot form, use the `onFormReady` callback to populate the referral code. Replace the placeholder values with your actual HubSpot configuration:
```javascript theme={null}
hbspt.forms.create({
region: "AAA", // Replace with your HubSpot region (e.g., "na1")
portalId: "BBB", // Replace with your HubSpot Portal ID
formId: "CCC", // Replace with your HubSpot Form ID
onFormReady(form, ctx) {
window.CelloAttribution('getUcc').then((celloUcc) => {
console.log('Incoming Referral:', celloUcc);
// Find all ucc fields and populate them
document.querySelectorAll('input[name="ucc"]').forEach(
el => {
el.value = celloUcc;
}
);
}).catch((error) => {
console.log('No referral code found or error occurred:', error);
});
}
});
```
## Test Your Implementation
### 1. Test Referral Code Capture
1. Visit your page with a referral parameter:
```
https://yoursite.com/landing-page?ucc=test123&productId=yourproduct
```
2. Open browser developer tools and check:
```javascript theme={null}
// Test if ucc is available
window.CelloAttribution('getUcc')
```
Expected response: `Promise {: 'test123'}`
### 2. Test Form Integration
1. Open the page with the created form
2. Add `?ucc=demo12345687` to the link and reload the page. After the initialization of the config, this will be added automatically to the link by Cello
3. Enter some test data into the form. The result should look similar to the following
4. Submit your HubSpot form
5. HubSpot should now have created a new contact and a new company. In the new company, you should find the `ucc` property filled with the entered value `demo12345687`
6. The test was successful. You can now move ahead to the section on providing the required data to Cello.
## Troubleshooting
### Common Issues and Solutions
**1. "getReferral is not supported" error**
* Make sure you're using `getUcc()` instead of `getReferral()`
* This is the correct method for the latest attribution library
**2. Form fields not getting populated**
* Verify your form has a field with `name="ucc"`
* Check that the field selector in `querySelectorAll()` matches your form
* Ensure the `onFormReady` callback is executing
**3. Referral code is undefined**
* Test with a URL containing the `ucc` parameter: `?ucc=test123`
* Check browser cookies for `cello-referral`
* Verify the attribution script loaded properly
**4. Script loading order issues**
* Always include the command queue script before any attribution calls
* Use the `async` attribute on the attribution library script
## HubSpot Scheduling Pages Integration
You can also use the Cello attribution library with HubSpot scheduling pages to capture referral codes when prospects book meetings or demos. This is particularly useful for sales-led referral programs where referrals often lead to booked consultations or product demos.
### How it works
HubSpot scheduling pages include built-in forms that collect contact information before allowing visitors to book meetings. You can integrate Cello attribution with these forms using the same approach as regular HubSpot forms.
### Setup Steps
The integration process for scheduling pages is identical to regular forms:
1. Include the Cello Attribution Library (Steps 2-3 above remain the same)
2. Set up the `ucc` property in your HubSpot contacts/companies
3. Add a hidden `ucc` field to your scheduling page form
4. Configure the scheduling page to populate the referral code
### Adding `ucc` Field to Scheduling Pages
1. Create or edit a scheduling page ([HubSpot's scheduling page guide](https://knowledge.hubspot.com/meetings/create-scheduling-pages))
2. In the "Form" section, add the created `ucc` parameter to the form. You can't hide this field on a scheduling page. This field automatically picks up the `ucc` parameter from the link and feeds it into the created `ucc` property in HubSpot. The result should look like this:
### JavaScript Integration for Scheduling Pages
Since scheduling pages are embedded HubSpot components, you'll add the same integration code to the page where your scheduling page is embedded:
```html theme={null}
```
### Testing Your Scheduling Page Integration
1. Visit your scheduling page with a referral parameter:
```
https://yoursite.com/book-demo?ucc=demo12345687
```
2. Start the booking process and fill out the form
3. Complete the booking
4. Check the created contact in HubSpot - the `ucc` field should contain `demo12345687`
### Key Differences from Regular Forms
* **Timing**: Scheduling pages load asynchronously, so we use MutationObserver to detect when the form is ready
* **Form structure**: Scheduling page forms are embedded HubSpot components with specific styling
* **Optional field**: Make the `ucc` field optional since not all meeting bookings will come from referrals
* **Meeting context**: The referral code will be associated with the contact and any resulting deals from the meeting
**For sales-led businesses**: Integrating referral tracking with scheduling pages is crucial for tracking which referrals lead to qualified sales conversations and ultimately closed deals.
# Introduction
Source: https://docs.cello.so/attribution/introduction
Learn how to implement referral attribution to track signups and purchases back to their original referrers
Referral conversion enables you to track and attribute user signups and purchases back to their original referrers and reward them for conversions.
Cello helps you capture referral codes `ucc` from landing pages and maintains attribution throughout the entire user journey, from initial visit to final purchase.
# How it works
The referral conversion process follows a four-step attribution flow:
1. **Referral Link Sharing** - Referrers share links containing unique codes (`ucc` parameters)
2. **Landing Page Capture** - Your website captures and stores referral codes `ucc` as first-party cookies
3. **Signup Tracking** - New user registrations are linked to their referrer
4. **Purchase Tracking** - Revenue events are attributed back to the original referrers
Accurate referral conversion tracking depends on properly passing the referral code `ucc` through each step of the referral journey.
**Attribution based on organization level**
If the buying persona is the organization and you want to attribute purchases on the organization level always provide the **ID of the organization** in the parameter `payload.newUserId`
# Getting started with referral conversion tracking
Learn how to track conversions with Cello in the following resources:
Capture referral code during web signup flow
Capture referral code during mobile signup
A full guide on tracking signup events
A full guide on tracking purchase events
or choose a step-by-step quickstart guide for your integration scenario:
# Track Purchases
Source: https://docs.cello.so/attribution/tracking-purchase
Learn how to track purchase events with Cello
To complete the conversion tracking and reward referrers, you will need to send Cello purchase events. A purchase event is sent when a user pays for a subscription or a product.
After sending purchase events, check [Integration Status](/guides/support/portal/integration-status) to confirm Purchases tracking is **Connected**. For per-event detail and to troubleshoot any field validation errors, open the [Event Feed](https://portal.cello.so/integrations/events-feed) in the Cello Portal.
# Prerequisites
Before you can send Cello purchase events, make sure you are already:
* [Capturing referral code on your landing page](https://docs.cello.so/attribution/for-web)
* [Tracking signups](https://docs.cello.so/attribution/tracking-signups)
**Attribution based on organization level**
If the buying persona is the organization and you want to attribute purchases at the organization level, always provide the **ID of the organization** in the parameter `payload.newUserId`
If you are providing discounts to new users, they need to be [applied at the point of creating a subscription](/attribution/apply-discounts) in your subscription platform
# Track purchase events with Webhooks
Depending on which payment gateway you’re using, we offer webhooks for the following:
}
href="/integrations/webhooks/stripe-webhook"
>
Send events using Stripe Webhook
}
href="/integrations/webhooks/chargebee-webhook"
>
Send events using Chargebee Webhook
# Track purchase events with Cello API
If you’re not using any of the gateways listed above, you can also send purchase events using Cello API `POST /events` API endpoint. Here are the 2 events you will need to send:
## `invoice-paid`
This event is sent every time a transaction based on the provided subscription is successful or a new user buys a one-time plan, a license or something similar.
```bash theme={null}
POST https://api.cello.so/events
{
"eventName": "ReferralUpdated",
"payload": {
"ucc": "cello-ucc",
"newUserId": "new-user-product-user-id", // or 'new-user-organization-id'
"price": 100,
"currency": "EUR"
},
"context": {
"newUser": {
"id": "new-user-product-user-id",
"email": "new-user@gmail.com",
"organizationId": "new-user-organization-id"
},
"event": {
"trigger": "invoice-paid",
"timestamp": "2022-10-05 14:14:34"
},
"subscription": {
"invoiceId": "34hsjdh34jfksd",
"interval": "one-time",
"productKey": "Pro License"
}
}
}
```
Here are the properties you can include when sending a `invoice-paid` event:
| Property | Required | Description |
| ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ucc` | yes | A referral code (`ucc`) identifying the referrer. You can retrieve this code using [attribution script](/sdk/client-side/attribution-js-introduction) `getUcc ()` method, you have installed as a prerequisite to this guide |
| `newUserId` | yes | A unique ID in your system, identifying the **new user** who just signed up. Can also be **organization ID**, if your referrers can refer organizations and you want to **reward them for organization account expansion** |
| `price` | yes | Amount on the invoice |
| `currency` | yes | Currency of the amount |
| `newUser.id` | yes | A unique ID of the new user (not the organization, if you are rewarding on organization level). This should be the same ID (`productUserId`) you will use to boot the [Referral component](/referral-component/introduction), when this user logs into your app |
| `newUser.email` | yes | New user email |
| `newUser.organizationId` | no | Organization ID. Add this field if your referrers can **refer an organization** and you want to reward them for **organization account expansion** |
| `event.trigger` | yes | `invoice-paid` |
| `event.timestamp` | yes | Event timestamp in **ISO8601 format** |
| `subscription.invoiceId` | yes | ID of the invoice that was paid or refunded |
| `subscription.interval` | yes | Interval of the payment. Available options: `one-time`, `weekly`, `bi-weekly`, `monthly`, `quarterly`, `semi-annual`, `yearly`, `biennial`, `triennial`, `lifetime` |
| `subscription.productKey` | yes | Name of the product or plan purchased |
Full API referrence for `POST /events` API endpoint can be found [here](/api-reference/generic-events/send-event).
## `charge-refunded`
This event is sent if the payment of the new user was refunded. When Cello receives this event, it automatically cancels any pending reward for that transaction.
```bash theme={null}
POST https://api.cello.so/events
{
"eventName": "ReferralUpdated",
"payload": {
"ucc": "cello-ucc",
"newUserId": "new-user-product-user-id", // or 'new-user-organization-id'
"price": 1000,
"currency": "EUR"
},
"context": {
"newUser": {
"id": "new-user-product-user-id",
"email": "new-user@gmail.com",
"organizationId": "new-user-organization-id"
},
"event": {
"trigger": "charge-refunded",
"timestamp": "2022-10-05 14:14:34"
},
"subscription": {
"invoiceId": "34hsjdh34jfksd"
}
}
}
```
Here are the properties you can include when sending a `charge-refunded` event:
| Property | Required | Description |
| ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ucc` | yes | A referral code (`ucc`) identifying the referrer. You can retrieve this code using [attribution script](/sdk/client-side/attribution-js-introduction) `getUcc ()` method, you have installed as a prerequisite to this guide |
| `newUserId` | yes | A unique ID in your system, identifying the **new user** who just signed up. Can also be **organization ID**, if your referrers can refer organizations and you want to **reward them for organization account expansion** |
| `price` | yes | Amount refunded |
| `currency` | yes | Currency of the amount |
| `newUser.id` | yes | A unique ID of the new user (not the organization, if you are rewarding on organization level). This should be the same ID (`productUserId`) you will use to boot the [Referral component](/referral-component/introduction), when this user logs into your app |
| `newUser.email` | yes | New user email |
| `newUser.organizationId` | no | Organization ID. Add this field if your referrers can **refer an organization** and you want to reward them for **organization account expansion** |
| `event.trigger` | yes | `charge-refunded` |
| `event.timestamp` | yes | Event timestamp in **ISO8601 format** |
| `subscription.invoiceId` | yes | ID of the invoice that was paid or refunded |
Full API referrence for `POST /events` API endpoint can be found [here](/api-reference/generic-events/send-event).
# Track Signups
Source: https://docs.cello.so/attribution/tracking-signups
Learn how to track signup events with Cello
When a referee signs up or otherwise shows interest in your product - like booking or attending a demo - you need to send this event to Cello. This allows Cello to attribute this conversion to the referrer, so they can be rewarded if a purchase happens later.
You can also choose to reward users for actions like signups or demos by configuring this in your [Campaign settings](/guides/campaigns/setting-up-campaigns).
After sending signup events, check [Integration Status](/guides/support/portal/integration-status) to confirm Signups tracking is **Connected**. For per-event detail and to troubleshoot any field validation errors, open the [Event Feed](https://portal.cello.so/integrations/events-feed) in the Cello Portal.
# Prerequisites
Before you can send Cello signup events, you need to make sure that you are able to **capture the referral code** `ucc`**during signup or demo booking**:
* [When users sign up in your web app](/attribution/for-web)
* [When users sign up in your mobile app](/attribution/for-mobile)
* When users book a demo using [Hubspot](/attribution/hubspot) or [Typeform](/attribution/typeform) forms or scheduling
**Attribution based on organization level**
If the buying persona is the organization and you want to attribute purchases at the organization level, always provide the **ID of the organization** in the parameter `payload.newUserId`
# Tracking signup events
For a SaaS application signup flow, you will track a signup event or equivalent.
Depending on how you create a new user and which payment gateway you are using, you can choose from the following options to send Cello signup events.
## Option 1: Using Stripe - I create Stripe Customer at Signup
Use this option if your payment gateway is Stripe and you **create a Stripe customer at signup**
To track a signup, you can pass the following `metadata` to Stripe [Customer Object](https://docs.stripe.com/api/customers/object?api-version=2024-09-30.acacia#customer_object-metadata) on customer creation.
* `cello_ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](https://docs.cello.so/sdk/client-side/attribution-lib) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `new_user_id` - a unique user ID in your system, identifying the new user who just signed up. This should be the same ID (`productUserId`) you will use to boot the [Referral component](https://docs.cello.so/sdk/client-side/cello-js), when this user logs into your app
* `new_user_organization_id` (optional) - add this, if your referrers can refer an organization rather then a single user and you want to reward based on that.
Modify customer fields you send upon customer creation. Here is an example for a NodeJS App that does that:
```javascript theme={null}
const stripe = require('stripe')('sk_test_51KiCYYCSMQAUBF...');
const customer = await stripe.customers.create({
description: 'New Stripe Customer',
metadata: {
cello_ucc: "hdz7afhs7",
new_user_id: "xcsdad", // product user id of the new user
new_user_organization_id: "123456" // organization id of the new user
}
});
```
Now that the customer is created in Stripe with Cello metadata, a `customer.created` event will be sent with [Stripe Webhook](/integrations/webhooks/stripe-webhook), which we will count as a signup event in Cello.
## Option 2: Using Chargebee - I create Chargebee customer at signup
Use this option if your payment gateway is Chargebee and you **create a Chargebee customer at signup**
You can pass the following metadata to Chargebee on customer creation.
You can also choose to use **Chargebee custom fields (CF\_)** to add referral data to the event. Learn more about custom fields in the [**Chargebee documentation**](https://www.chargebee.com/docs/billing/2.0/site-configuration/custom_fields)
* `cello_ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](/sdk/client-side/attribution-js-introduction) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `new_user_id` - a unique user ID in your system, identifying the new user who just signed up. This should be the same ID (`productUserId`) you will use to boot the [Referral component](/referral-component/introduction), when this user logs into your app
* `new_user_organization_id` (optional) - add organization ID, if your referrers can **refer an organization** and you want to reward them for **organization account expansion**.
Modify customer fields you send upon customer creation. Here is an example for a NodeJS App that does that:
```javascript theme={null}
var chargebee = require("chargebee");
chargebee.configure({site : "getmoonly-v3-test", api_key : "test_jqXGuQLkBHUSR2PM0qgUV21W1VqSFJIU"});
chargebee.customer.create({
first_name : "Bob",
last_name : "Bobsky",
//...
// other customer fields
//...
meta_data: {
cello_ucc: "hdz7afhs7",
new_user_id: "xcsdad", // product user id of the new user
new_user_organization_id: "123456" // organization id of the new user
}
// ..
// })
```
Now that the customer is created in Chargebee with Cello metadata, a `Customer Created` event will be sent with [Chargebee Webhook](/integrations/webhooks/chargebee-webhook), which we will count as a signup event in Cello.
## Option 3: Using Cello API POST /events API endpoint
Use this option for all other use cases. For example:
* You use Stripe or Chargebee, but customer is created in the payment gateway **at purchase**.
* Your payment gateway is Paddle, Recurly or other, including in-house built payment gateways
Send a `new-signup` event to the Cello API with the following values in the payload:
* `ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](/sdk/client-side/attribution-js-introduction) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `newUserId` - a unique ID in your system, identifying the **new user** who just signed up. Can also be **organization ID**, if your referrers can refer organizations and you want to **reward them for organization account expansion**.
* `newUser.id` - unique ID of the new user (not the organization, if you are rewarding on organization level). This should be the same ID (`productUserId`) you will use to boot the [Referral component](/referral-component/introduction), when this user logs into your app
* `newUser.email` - new user email
* `newUser.name` - new user name
* `newUser.organizationId`(optional) - add organization ID, if your referrers can **refer an organization** and you want to reward them for **organization account expansion**.
Here is an example of the `POST /events` call to send a `new-signup` event:
```bash theme={null}
POST https://api.cello.so/events
{
"eventName": "ReferralUpdated",
"payload": {
"ucc": "cello-ucc",
"newUserId": "new-user-product-user-id", // or "new-user-organization-id"
"price": 0,
"currency": ""
},
"context": {
"newUser": {
"id": "new-user-product-user-id",
"email": "new_user@gmail.com",
"name": "new-user-name",
"organizationId": "new-user-organization-id"
},
"event": {
"trigger": "new-signup",
"timestamp": "2022-10-05 14:14:34"
}
}
}
```
# Tracking "demo attended" event
Use this option if your product follows a sales-led model where successful conversions are driven by users attending a demo call.
Send a `demo-attended` event to the Cello API with the following values in the payload:
* `ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](/sdk/client-side/attribution-js-introduction) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `newUserId` - a unique ID in your system, identifying the **new user** who just signed up. Can also be **organization ID**, if your referrers can refer organizations and you want to **reward them for organization account expansion**.
* `newUser.id` - unique ID of the new user (not the organization, if you are rewarding on organization level). This should be the same ID (`productUserId`) you will use to boot the [Referral component](/referral-component/introduction), when this user logs into your app
* `newUser.email` - new user email
* `newUser.name` - new user name
* `newUser.organizationId`(optional) - add organization ID, if your referrers can **refer an organization** and you want to reward them for **organization account expansion**.
Here is an example of the `POST /events` call to send a `new-signup` event:
```bash theme={null}
POST https://api.cello.so/events
{
"eventName": "ReferralUpdated",
"payload": {
"ucc": "cello-ucc",
"newUserId": "product-user-id" // or 'new-user-organization-id'
},
"context": {
"newUser": {
"id": "new-user-product-user-id",
"email": "new-user@gmail.com",
"name": "new-user-name",
"organizationId": "new-user-organization-id"
},
"event": {
"trigger": "demo-call-attended",
"timestamp": "2022-10-05 14:14:34"
}
}
}
```
# Typeform Forms
Source: https://docs.cello.so/attribution/typeform
Ingest Cello's referral code (ucc) into HubSpot using Typeform forms
This page guides you through the required steps to ingest **Cello's referral code (`ucc`) into HubSpot using Typeform forms**.
## Create a form with a hidden ucc field in Typeform
Create a new form in Typeform
On the initial question in your form, go to **Hidden Fields** via **Logic → Hidden Fields** on the panel on the right
Add a new field named `ucc` and click Save
## Setup of Sync from Typeform to HubSpot
Navigate to the **Connect** Section in the header of Typeform and connect HubSpot
After the authorization is done, you can select the HubSpot object to which you want to sync the `ucc`. In the below example the `ucc` is synced to a deal in HubSpot.
You can also sync the `ucc` to multiple objects at the same time: contact, company and deals.
If you sync the `ucc` to a deal, you have to specify in which pipeline at which stage the deals should be created
After finalizing the setup of the integration, save the settings and run a short test run
## Test the created Typeform and HubSpot integration
Open the created Typeform
Add either `?ucc=12341234` or `&ucc=12341234` to the link depending on if there is already a "?" present in the link
Submit the Typeform
Open HubSpot and check that the contact, company or deal was created and the `ucc` was synced correctly
## Further hints
You can also embed a Calendly in Typeform to allow customers to schedule e.g. a demo from the Typeform. Documentation can be found [here](https://www.typeform.com/connect/calendly/).
# Chargebee Webhook Quickstart
Source: https://docs.cello.so/attribution/use-cases/chargebee
Learn how to integrate Cello if you are using Chargebee JS to create Chargebee customer and Chargebee Webhook to send Cello conversion events.
This guide is **optimized for the typical freemium scenario with Chargebee**.
Use this guide if you:
* Create Chargebee customer on signup
* Use Chargebee webhook to send Cello referral conversion events
# Step 1: Integrate the Referral Component
First, integrate Cello Referral Component into your web app to provide referrers with full referral experience.
Referral Component is integrated using one of our SDKs. For your web app, use Cello JS - our client-side SDK. You can install it by:
1. Adding a script tag to the `` 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:
You can also integrate Referral Component into your mobile applications:
# Step 2: Capture referral codes on landing page
Next, you will need to add [Cello attribution script](https://docs.cello.so/sdk/client-side/attribution-lib) to your referral landing page:
1. Setup a [landing page](https://docs.cello.so/docs/optimize-landing) for your referral links to redirect to
2. Install attribution script. Choose one of the following installation options best suited for your setup:
3. Verify the installation
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 {: 'test'}
```
**If this check passes, the script is installed correctly.**
For capturing referral code in your mobile signup flow, follow this guide:
# Step 3: Add Cello metadata or custom fields on Chargebee customer creation
To track a signup, you can pass the following metadata to Chargebee on customer creation.
You can also choose to use **Chargebee custom fields (CF\_)** to add referral data to the event. Learn more about custom fields in the [**Chargebee documentation**](https://www.chargebee.com/docs/billing/2.0/site-configuration/custom_fields)
* `cello_ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](https://docs.cello.so/sdk/client-side/attribution-lib) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `new_user_id` - a unique user ID in your system, identifying the new user who just signed up. This should be the same ID (`productUserId`) you will use to boot the [Referral component](https://docs.cello.so/sdk/client-side/cello-js), when this user logs into your app
* `new_user_organization_id` (optional) - add this, if your referrers can refer an organization rather then a single user and you want to reward based on that.
Modify customer data you send upon customer creation. Here is an example for a NodeJS App that does that with `meta_data`:
```javascript theme={null}
var chargebee = require("chargebee");
chargebee.configure({site : "getmoonly-v3-test", api_key : "test_jqXGuQLkBHUSR2PM0qgUV21W1VqSFJIU"});
chargebee.customer.create({
first_name : "Bob",
last_name : "Bobsky",
//...
// other customer fields
//...
meta_data: {
cello_ucc: "hdz7afhs7",
new_user_id: "xcsdad", // product user id of the new user
new_user_organization_id: "123456"
}
// ..
// })
```
Now that the customer is created in Chargebee with Cello metadata, a `Customer Created` event will be sent with [Chargebee Webhook](https://docs.cello.so/integrations/webhooks/chargebee-webhook), which we will count as a signup event in Cello.
# Step 4: Connect Chargebee Webhook to send signup and purchase events
To send Cello signup and purchase events, you will need to connect Chargebee Webhook to Cello.
Follow this guide to connect the webhook:
}
href="/integrations/webhooks/chargebee-webhook"
>
Send events using Chargebee Webhook
**Congratulations!** You are done and now able to try out the full Cello referral experience 🎉
# HubSpot + Zapier Quickstart
Source: https://docs.cello.so/attribution/use-cases/hubspot-zapier
Learn how to send Cello signup events from HubSpot deal stage changes using a no-code Zapier workflow.
This guide is **optimized for sales-led products** where conversions are driven by demos, sales calls, or other manual qualification steps tracked in HubSpot.
Use this guide if you:
* Use **HubSpot** as your source of truth for deals
* Want to send Cello signup events (e.g. `demo-call-attended`) **without writing any backend code**
* Trigger events based on **HubSpot deal stage changes** (e.g. "Demo Done", "Qualified", "Purchase Consideration")
# Overview
This guide walks you through building a no-code Zapier workflow that:
1. **Watches HubSpot** for deals moving into a specific stage (e.g. "Demo Done")
2. **Filters** deals to only those with a captured `ucc` referral code
3. **Authenticates** with the Cello API to obtain an access token
4. **Sends a signup event** to Cello using the `POST /events` endpoint
By the end, every qualified deal in HubSpot will automatically generate a Cello conversion event — letting you reward referrers as soon as their referee attends a demo or hits any milestone in your sales pipeline.
# Prerequisites
Before you start, make sure you have:
* A **HubSpot account** with deals flowing through your sales pipeline
* A **Zapier account** (Starter plan or above — Code by Zapier steps require a paid plan)
* A **Cello account** with API credentials (`accessKeyId` and `secretAccessKey`) — generate these in the [Cello Portal](https://portal.cello.so)
* A **`ucc` property** on your HubSpot deal or company object, populated when the referral lands. Follow the [HubSpot Forms attribution guide](/attribution/hubspot) to set this up.
* [Cello JS Referral Component](/referral-component/quickstart) integrated in your product so referrers can share referral links
If `ucc` is not being captured on your HubSpot deals, the Zap will skip every event. Complete the [HubSpot Forms attribution setup](/attribution/hubspot) first and verify with a test referral before continuing.
# The completed Zap
Your finished Zap will have four steps:
# Step 1: Trigger on HubSpot deal stage change
The Zap fires whenever a deal enters the stage you choose (typically the one that represents a qualified conversion — "Demo Done", "Purchase Consideration", or similar).
1. In Zapier, create a new Zap and choose **HubSpot** as the trigger app.
2. Pick the event **"Deal in stage"** (or "Deal Property Changed" depending on your HubSpot plan).
3. Select your **Deal Pipeline** and the **Deal Stage** that should trigger the event (e.g. `Demo Done/Purchase Consideration`).
4. Under **Additional properties to retrieve**, add the `ucc` property so it's available in later steps.
The HubSpot trigger checks for matching deals every 15 minutes and only picks up deals moved into the stage in the **last 30 minutes**. Plan your stage transitions accordingly.
Test the trigger and confirm Zapier returns a sample deal with the expected fields: `dealname`, `hs_object_id`, `ucc`, plus any contact/company info you want to forward.
# Step 2: Filter deals without a `ucc`
You only want to send events for deals that came from a referral. Add a **Filter by Zapier** step:
1. Choose **Filter by Zapier**.
2. Set the rule to: `1. Deal information: ucc` **Exists**.
Deals without a `ucc` will stop here and no Cello event will be sent.
# Step 3: Create a Cello access token
Cello uses short-lived access tokens for API auth. Add a **Code by Zapier** step using Python:
1. Choose **Code by Zapier** → **Run Python**.
2. Leave **Input Data** empty (credentials are hardcoded in this step).
3. Paste the snippet below and replace `` and `` with your Cello API credentials.
```python theme={null}
import json
import urllib.request
ACCESS_KEY_ID = ""
SECRET_ACCESS_KEY = ""
body = {
"accessKeyId": ACCESS_KEY_ID,
"secretAccessKey": SECRET_ACCESS_KEY
}
req = urllib.request.Request(
url="https://api.cello.so/token",
data=json.dumps(body).encode("utf-8"),
method="POST",
headers={"Content-Type": "application/json"}
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode("utf-8"))
output = {
"access_token": data.get("accessToken"),
"expires_in": data.get("expiresIn"),
"status": resp.status
}
except urllib.error.HTTPError as e:
output = {
"access_token": "",
"status": e.code,
"error": e.read().decode("utf-8")
}
```
Test the step — you should see an `access_token` value and `status: 200` in the output.
For production, store your `accessKeyId` and `secretAccessKey` in Zapier's **Storage by Zapier** or as **Code by Zapier environment variables** rather than hardcoding them. See [Zapier's guide on storing credentials](https://help.zapier.com/hc/en-us/articles/8496300064525) for details.
Reference: [Cello Authentication API](/api-reference/authentication/get-token).
# Step 4: Send the signup event to Cello
Add a second **Code by Zapier (Python)** step that posts the event to `POST /events`.
1. Choose **Code by Zapier** → **Run Python**.
2. Map the following **Input Data** fields from the previous steps:
| Input Data key | Map from |
| -------------- | ----------------------------------------------------------------------------- |
| `access_token` | Step 3 → `Access Token` |
| `ucc` | Step 1 → `Deal information: ucc` |
| `user_id` | Step 1 → `Deal information: Record ID` (or your own product user ID property) |
| `email` | Step 1 → `Deal information: email_of_demo_request` (or contact email) |
| `name` | Step 1 → `Deal information: Deal Name` (or contact name) |
| `org_id` | Step 1 → company / organization ID (optional) |
3. Paste the snippet below:
```python theme={null}
import json
import urllib.request
from datetime import datetime, timezone
access_token = input_data.get("access_token", "")
ucc = input_data.get("ucc", "")
user_id = input_data.get("user_id", "")
email = input_data.get("email", "")
name = input_data.get("name", "")
org_id = input_data.get("org_id", "")
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
body = {
"eventName": "ReferralUpdated",
"payload": {
"ucc": ucc,
"newUserId": user_id
},
"context": {
"newUser": {
"id": user_id,
"email": email,
"name": name,
"organizationId": org_id
},
"event": {
"trigger": "demo-call-attended",
"timestamp": timestamp
}
}
}
req = urllib.request.Request(
url="https://api.cello.so/events",
data=json.dumps(body).encode("utf-8"),
method="POST",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
response_body = resp.read().decode("utf-8")
output = {"status": resp.status, "response": response_body}
except urllib.error.HTTPError as e:
output = {"status": e.code, "response": e.read().decode("utf-8")}
```
The `event.trigger` value (`demo-call-attended` in this example) determines how Cello classifies the event. Common values:
* `new-signup` — user signed up but no demo yet
* `demo-call-attended` — user attended a sales/demo call
* `qualified-lead` — user has been qualified by sales
Match the trigger to the HubSpot deal stage you're firing from.
Test the step and confirm you receive `status: 200` from Cello.
# Step 5: Verify and publish
1. **Publish your Zap.**
2. Move a test deal into the trigger stage in HubSpot.
3. Wait up to 15 minutes for Zapier to pick up the change.
4. Open the [Event Feed](https://portal.cello.so/integrations/events-feed) in the Cello Portal and confirm the event was received with the correct `ucc`, `newUserId`, and `trigger`.
5. Check [Integration Status](/guides/support/portal/integration-status) — **Signups** should now show as **Connected**.
**You're done!** Every qualified deal in HubSpot will now generate a Cello signup event automatically. To also track purchase events, pair this with the [Stripe](/attribution/use-cases/stripe) or [Chargebee](/attribution/use-cases/chargebee) webhook integrations — or extend this Zap with an additional Code step that posts a `purchase` event when the deal closes won.
# Variations
* **Different trigger stages.** Duplicate the Zap and change the HubSpot deal stage + `event.trigger` value to track multiple milestones (e.g. one Zap for `demo-call-attended`, another for `qualified-lead`).
* **Reward at the organization level.** Set `newUserId` to the HubSpot company ID instead of the deal/contact ID, and populate `newUser.organizationId` accordingly. See [Tracking Signups](/attribution/tracking-signups) for the organization-level attribution model.
* **Use the Zapier HTTP action instead of Code steps.** If you prefer not to write Python, both API calls can be done with **Webhooks by Zapier → POST**. The body and headers are the same as in the snippets above.
# Stripe Webhook Quickstart
Source: https://docs.cello.so/attribution/use-cases/stripe
Learn how to integrate Cello if you are using Stripe JS to create Stripe customer and Stripe Webhook to send Cello conversion events.
This guide is **optimized for the typical freemium scenario with Stripe**.
Use this guide if you:
* Create Stripe customer on signup
* Use Stripe webhook to send Cello referral conversion events
# Step 1: Integrate the Referral Component
First, integrate Cello Referral Component into your web app to provide referrers with full referral experience.
Referral Component is integrated using one of our SDKs. For your web app, use Cello JS - our client-side SDK. You can install it by:
1. Adding a script tag to the `` 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:
You can also integrate Referral Component into your mobile applications:
# Step 2: Capture referral codes on landing page
Next, you will need to add [Cello attribution script](https://docs.cello.so/sdk/client-side/attribution-lib) to your referral landing page:
1. Setup a [landing page](https://docs.cello.so/docs/optimize-landing) for your referral links to redirect to
2. Install attribution script. Choose one of the following installation options best suited for your setup:
3. Verify the installation
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 {: 'test'}
```
**If this check passes, the script is installed correctly.**
For capturing referral code in your mobile signup flow, follow this guide:
# Step 3: Add Cello metadata on Stripe customer creation
To track a signup, you can pass the following `metadata` to Stripe [Customer Object](https://docs.stripe.com/api/customers/object?api-version=2024-09-30.acacia#customer_object-metadata) on customer creation.
* `cello_ucc` - ucc, a referral code identifying the referrer. You can retrieve this code using [attribution script](https://docs.cello.so/sdk/client-side/attribution-lib) `getUcc ()` method, you have installed as a prerequisite to this guide.
* `new_user_id` - a unique user ID in your system, identifying the new user who just signed up. This should be the same ID (`productUserId`) you will use to boot the [Referral component](https://docs.cello.so/sdk/client-side/cello-js), when this user logs into your app
* `new_user_organization_id` (optional) - add this, if your referrers can refer an organization rather then a single user and you want to reward based on that.
Modify customer fields you send upon customer creation. Here is an example for a NodeJS App that does that:
```javascript theme={null}
const stripe = require('stripe')('sk_test_51KiCYYCSMQAUBF...');
const customer = await stripe.customers.create({
description: 'New Stripe Customer',
metadata: {
cello_ucc: "hdz7afhs7",
new_user_id: "xcsdad", // product user id of the new user
new_user_organization_id: "123456" // organization id of the new user
}
});
```
Now that the customer is created in Stripe with Cello metadata, a `customer.created` event will be sent with [Stripe Webhook](https://docs.cello.so/integrations/webhooks/stripe-webhook), which we will count as a signup event in Cello. You will connect Stripe Webhook in the next step.
# Step 4: Connect Stripe Webhook to send signup and purchase events
To send Cello signup and purchase events, you will need to connect Stripe Webhook to Cello.
Follow this guide to connect the webhook:
}
href="https://docs.cello.so/integrations/webhooks/stripe-webhook"
>
Send events using Stripe Webhook
**Congratulations!** You are done and now able to try out the full Cello referral experience 🎉
# Cello + Claude integration
Source: https://docs.cello.so/coding-apps/claude-integration
How to add user referrals to your app using Cello with Claude
Claude can implement Cello user referrals end-to-end if you give it the **right guide** and force it to create a plan before coding. Use **Claude Code** (the CLI coding agent) to build the integration, and connect the Cello MCP so Claude can look up docs and verify your setup as it goes.
This page covers using **Claude Code** to build your referral integration. To connect the **Claude desktop or web app** so you can chat about your program, see the [Claude](/mcp/connect#claude) section of the MCP connect guide.
## Prerequisites
Before integrating Cello, ensure the following prerequisites are met:
* User signup and authentication is functional
* Stripe subscription flow is functional
* You have a Cello account and API keys at hand.
Make sure to use Cello **Sandbox environment** when developing and testing
## Optional: Connect the Cello MCP
The [Cello MCP server](/mcp/introduction) gives Claude direct access to Cello's documentation, integration health checks, and best-practice recommendations. Connecting it before you start means Claude can look up the right docs itself, verify your setup as it goes, and follow best practices automatically - instead of relying only on the guide link you paste.
This step is optional but recommended. The integration steps below work either way. See [Connect your client → Claude Code](/mcp/connect#claude-code) for the setup steps.
## Cello user referrals integration
For a step-by-step technical implementation (source of truth + acceptance criteria), follow the detailed guide:
* [React + Node.js Integration Guide](/resources/react-nodejs-integration)
The guide uses React + Node.js as an example, but it can be any other combination - the steps stay the same.
* Signup and authentication flow is functional
* Stripe subscription flow is functional
* Cello API keys are handy
* Get your webhook URL from [Cello Portal](https://portal.cello.so/integrations/webhooks)
* Add a Webhook endpoint in Stripe (Log into your Stripe Dashboard -> Go to Developer Mode -> Add a Webhook endpoint and enter endpoint URL -> Select the events to send -> Click "Add endpoint")
* Secure the Webhook with "Signing secret"
Events to send:
* `charge.refunded`, `charge.succeeded`, `charge.updated`
* `customer.created`, `customer.deleted`, `customer.updated`
* `customer.subscription.created`, `customer.subscription.deleted`, `customer.subscription.updated`
* `invoice.paid`
See [Stripe Webhook Integration](/integrations/webhooks/stripe-webhook#steps) for more details.
Ask Claude Code to create a plan first - it stays in **plan mode** until you approve. Paste this prompt:
```text theme={null}
I want to add user referrals to my app using Cello.
Use the Cello MCP to search the integration documentation, check my current integration status, and create a thorough implementation plan. Follow all best-practice recommendations from Cello.
```
Claude will pull the relevant guides, check what's already set up, and tailor the plan to your project.
```text theme={null}
I now want to add user referrals. I chose platform Cello for this.
I added a Cello integration guide according to which you should do the implementation. parsed the documentation more carefully from the start rather than assuming standard patterns would work. create a thorough implementation plan based on guidance, patterns and AC from the provided guide. Don't skip any content, it is all relevant
Guide: https://docs.cello.so/resources/react-nodejs-integration
```
Claude asks you guiding questions and creates an implementation plan based on your answers.
Review the plan carefully. It should cover:
* Cello JS SDK initialization and user authentication
* Referral component placement and configuration
* Attribution setup for tracking referred signups
* Stripe webhook integration for conversion tracking
If it looks correct, tell Claude to proceed and start implementing it.
Run your app and test the end-to-end flow. If everything was implemented correctly, you should see events coming in to [Cello Dashboard](https://portal.cello.so/dashboard/referrer).
If you have the Cello MCP connected, ask Claude to run a health check after deploying:
*"Use Cello to check my integration status and confirm all four components are connected."*
## After you're live
If you have the Cello MCP connected, it continues to be useful after the initial integration:
| Prompt | What happens |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| *"Is my Cello integration working?"* | Checks all four integration components and reports which are connected or broken |
| *"Why aren't referral rewards being triggered?"* | Inspects recent events to find missing or malformed fields preventing attribution |
| *"How can I improve my referral program?"* | Returns a prioritized list of recommendations across activation, sharing, and conversion |
| *"How do I set up a custom referral launcher?"* | Searches the docs for custom launcher implementation guides |
# Cello + Cursor integration
Source: https://docs.cello.so/coding-apps/cursor-integration
How to add user referrals to your app using Cello with Cursor
Cursor can implement Cello user referrals end-to-end if you give it the **right guide** and force it to create a plan before coding.
## Prerequisites
Before integrating Cello, ensure the following prerequisites are met:
* User signup and authentication is functional
* Stripe subscription flow is functional
* You have a Cello account and API keys at hand.
Make sure to use Cello **Sandbox environment** when developing and testing
## Optional: Connect the Cello MCP
The [Cello MCP server](/mcp/introduction) gives Cursor direct access to Cello's documentation, integration health checks, and best-practice recommendations. Connecting it before you start means Cursor can look up the right docs itself, verify your setup as it goes, and follow best practices automatically - instead of relying only on the guide link you paste.
This step is optional but recommended. The integration steps below work either way. See [Connect your client → Cursor](/mcp/connect#cursor) for the setup steps.
## Cello user referrals integration
For a step-by-step technical implementation (source of truth + acceptance criteria), follow the detailed guide:
* [React + Node.js Integration Guide](/resources/react-nodejs-integration)
The guide uses React + Node.js as an example, but it can be any other combination - the steps stay the same.
* Signup and authentication flow is functional
* Stripe subscription flow is functional
* Cello API keys are handy
* Get your webhook URL from [Cello Portal](https://portal.cello.so/integrations/webhooks)
* Add a Webhook endpoint in Stripe (Log into your Stripe Dashboard -> Go to Developer Mode -> Add a Webhook endpoint and enter endpoint URL -> Select the events to send -> Click "Add endpoint")
* Secure the Webhook with "Signing secret"
Events to send:
* `charge.refunded`, `charge.succeeded`, `charge.updated`
* `customer.created`, `customer.deleted`, `customer.updated`
* `customer.subscription.created`, `customer.subscription.deleted`, `customer.subscription.updated`
* `invoice.paid`
See [Stripe Webhook Integration](/integrations/webhooks/stripe-webhook#steps) for more details.
Switch Cursor to **Plan mode**, then paste this prompt:
```text theme={null}
I want to add user referrals to my app using Cello.
Use the Cello MCP to search the integration documentation, check my current integration status, and create a thorough implementation plan. Follow all best-practice recommendations from Cello.
```
Cursor will pull the relevant guides, check what's already set up, and tailor the plan to your project.
```text theme={null}
I now want to add user referrals. I chose platform Cello for this.
I added a Cello integration guide according to which you should do the implementation. parsed the documentation more carefully from the start rather than assuming standard patterns would work. create a thorough implementation plan based on guidance, patterns and AC from the provided guide. Don't skip any content, it is all relevant
Guide: https://docs.cello.so/resources/react-nodejs-integration
```
Cursor asks you guiding questions and creates an implementation plan based on your answers.
Review the plan carefully. It should cover:
* Cello JS SDK initialization and user authentication
* Referral component placement and configuration
* Attribution setup for tracking referred signups
* Stripe webhook integration for conversion tracking
If it looks correct, tell Cursor to proceed and start implementing it.
Run your app and test the end-to-end flow. If everything was implemented correctly, you should see events coming in to [Cello Dashboard](https://portal.cello.so/dashboard/referrer).
If you have the Cello MCP connected, ask Cursor to run a health check after deploying:
*"Use Cello to check my integration status and confirm all four components are connected."*
## After you're live
If you have the Cello MCP connected, it continues to be useful after the initial integration:
| Prompt | What happens |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| *"Is my Cello integration working?"* | Checks all four integration components and reports which are connected or broken |
| *"Why aren't referral rewards being triggered?"* | Inspects recent events to find missing or malformed fields preventing attribution |
| *"How can I improve my referral program?"* | Returns a prioritized list of recommendations across activation, sharing, and conversion |
| *"How do I set up a custom referral launcher?"* | Searches the docs for custom launcher implementation guides |
# Cello + Lovable integration
Source: https://docs.cello.so/coding-apps/lovable-integration
How to add user referrals to your app using Cello with Lovable
Lovable now lets you integrate Cello user referrals entirely through **chat**. Just ask Lovable to **"Add user referrals to your app"** and it will do the rest - no manual coding required.
## Prerequisites
Before integrating Cello, ensure the following prerequisites are met:
* The project **must** be connected to Supabase. [Learn more about Supabase](https://docs.lovable.dev/integrations/supabase)
* User signup and authentication via Supabase is functional
* Stripe subscription flow is functional
* You have a Cello account and API keys at hand.
Make sure to use Cello **Sandbox environment** when developing and testing
## Connect the Cello MCP
The [Cello MCP server](/mcp/introduction) gives Lovable direct access to Cello's documentation, integration health checks, and best-practice recommendations. Connecting it before you start means Lovable can look up the right docs itself, verify your setup as it goes, and follow best practices automatically - instead of relying only on the guide link you paste.
This step is optional but recommended. The integration steps below work either way. See [Connect your client → Lovable](/mcp/connect#lovable) for the setup steps.
## Cello user referrals integration
For a step-by-step technical implementation (source of truth + acceptance criteria), follow the detailed guide:
* [Cello + Lovable Detailed Integration Guide](/resources/cello-lovable-detailed-integration)
* [Cello + Lovable Detailed Integration (Credit-based Rewards)](/resources/cello-lovable-detailed-integration-credit-based-rewards)
* Signup and authentication flow with Supabase is functional
* Stripe subscription flow is functional
* Cello API keys are handy
* Get your webhook URL from [Cello Portal](https://portal.cello.so/integrations/webhooks)
* Add a Webhook endpoint in Stripe (Log into your Stripe Dashboard -> Go to Developer Mode -> Add a Webhook endpoint and enter endpoint URL -> Select the events to send -> Click "Add endpoint")
* Secure the Webhook with "Signing secret"
Events to send:
* `charge.refunded`, `charge.succeeded`, `charge.updated`
* `customer.created`, `customer.deleted`, `customer.updated`
* `customer.subscription.created`, `customer.subscription.deleted`, `customer.subscription.updated`
* `invoice.paid`
See [Stripe Webhook Integration](/integrations/webhooks/stripe-webhook#steps) for more details.
Switch Lovable to **Plan mode**, then paste this prompt:
```text theme={null}
I want to add user referrals to my app using Cello.
Use the Cello MCP to search the integration documentation, check my current integration status, and create a thorough implementation plan. Follow all best-practice recommendations from Cello.
```
Lovable will pull the relevant guides, check what's already set up, and tailor the plan to your project.
```text theme={null}
I now want to add user referrals. I chose platform Cello for this.
I added a Cello integration guide according to which you should do the implementation. parsed the documentation more carefully from the start rather than assuming standard patterns would work. create a thorough implementation plan based on guidance, patterns and AC from the provided guide. Don't skip any content, it is all relevant
Guide: https://docs.cello.so/resources/cello-lovable-detailed-integration
```
Lovable asks you guiding questions and creates an implementation plan based on your answers.
Review the plan carefully. It should cover:
* Cello JS SDK initialization and user authentication
* Referral component placement and configuration
* Attribution setup for tracking referred signups
* Stripe webhook integration for conversion tracking
If it looks correct, tell Lovable to proceed and start implementing it.
You cannot try the full end-to-end flow in Preview mode. Publish your changes to test.
If everything was implemented correctly, you should see events coming in to [Cello Dashboard](https://portal.cello.so/dashboard/referrer).
If you have the Cello MCP connected, ask Lovable to run a health check after publishing:
*"Use Cello to check my integration status and confirm all four components are connected."*
## After you're live
If you have the Cello MCP connected, it continues to be useful after the initial integration:
| Prompt | What happens |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| *"Is my Cello integration working?"* | Checks all four integration components and reports which are connected or broken |
| *"Why aren't referral rewards being triggered?"* | Inspects recent events to find missing or malformed fields preventing attribution |
| *"How can I improve my referral program?"* | Returns a prioritized list of recommendations across activation, sharing, and conversion |
| *"How do I set up a custom referral launcher?"* | Searches the docs for custom launcher implementation guides |
# Cello + Replit integration
Source: https://docs.cello.so/coding-apps/replit-integration
How to add user referrals to your app using Cello with Replit
Replit Agent can implement Cello user referrals end-to-end if you give it the **right guide** and force it to create a plan before coding.
## Prerequisites
Before integrating Cello, ensure the following prerequisites are met:
* Signup and authentication flow with a database to store user records is functional
* Stripe subscription flow is functional
* You have a Cello account and API keys at hand.
Make sure to use Cello **Sandbox environment** when developing and testing
## Cello user referrals integration (Coding-agent flow)
For a step-by-step technical implementation (source of truth + acceptance criteria), follow the detailed guide:
* [React + Node.js Integration Guide](/resources/react-nodejs-integration)
The guide uses React + Node.js as an example, but it can be any other combination - the steps stay the same.
**Prep your project**
* Signup and authentication flow with a database to store user records is functional
* Stripe subscription flow is functional
* Cello API keys are handy
**Add Cello Webhook Endpoint to Stripe**
* Get your webhook URL from [Cello Portal](https://portal.cello.so/integrations/webhooks)
* Add a Webhook endpoint in Stripe (Log into your Stripe Dashboard -> Go to Developer Mode -> Add a Webhook endpoint and enter endpoint URL -> Select the events to send -> Click "Add endpoint")
* Secure the Webhook with "Signing secret"
Events to send:
* `charge.refunded`, `charge.succeeded`, `charge.updated`
* `customer.created`, `customer.deleted`, `customer.updated`
* `customer.subscription.created`, `customer.subscription.deleted`, `customer.subscription.updated`
* `invoice.paid`
See [Stripe Webhook Integration](/integrations/webhooks/stripe-webhook#steps) for more details.
**Prompt Replit Agent to add User Referrals to your app**
Paste this prompt into Replit Agent (includes the detailed guide):
```text theme={null}
I now want to add user referrals. I chose platform Cello for this.
I added a Cello integration guide according to which you should do the implementation. parsed the documentation more carefully from the start rather than assuming standard patterns would work. create a thorough implementation plan based on guidance, patterns and AC from the provided guide. Don't skip any content, it is all relevant
Guide: https://docs.cello.so/resources/react-nodejs-integration
```
Replit Agent asks you guiding questions and creates an implementation plan based on your answers.
**Confirm executing the plan**
Review the plan carefully. If it looks correct, tell Replit Agent to proceed and start implementing it.
**Publish & Test**
Run your app and test the end-to-end flow. If everything was implemented correctly, you should see events coming in to [Cello Dashboard](https://portal.cello.so/dashboard/referrer).
# AI Assistant
Source: https://docs.cello.so/guides/ai-assistant/overview
Get answers about your referral program performance and take action faster - directly in the Cello portal
The Cello AI Assistant helps you understand program performance and take action faster - directly inside the Cello portal. It answers questions using your Cello data, metrics, benchmarks, and documentation.
This feature is available to growth managers in the Cello portal. Your feedback helps us improve - see [Providing feedback](#providing-feedback) below.
Prefer to work from your own AI client like Claude? The same data is available through the [Cello MCP server](/mcp/growth/use-cases).
## Using the assistant
The assistant is available in the Cello portal. To get started:
1. Open the assistant from the portal navigation
2. Type your question or select an example from the [AI Prompt Library](/guides/ai-assistant/prompt-library)
3. Review the response - the assistant will link to relevant charts, reports, or settings when applicable
The assistant works best with specific questions about your program. See the [AI Prompt Library](/guides/ai-assistant/prompt-library) for examples organized by category.
## How responses are generated
Responses are grounded in your portal context, Cello metrics, benchmarks (when available), and Cello documentation. The assistant links to relevant charts, reports, or settings so you can verify data and take action quickly.
## When the assistant can't help
If the assistant can't answer a question confidently, it will let you know and help you reach Support so your request is handled quickly.
## Providing feedback
Your feedback helps us improve quality and coverage:
* **Rate responses** using thumbs up/down to help us understand what's working
* **Share details** when something is off - what you asked, what you expected, and a screenshot if possible
We use feedback to improve prompts, add missing documentation, expand the AI Prompt Library, and refine the assistant's capabilities.
## Privacy and data
The AI Assistant runs in Cello's EU-hosted AWS environment. Customer content is not used to train foundation models. The assistant only uses the minimum context needed to answer using approved Cello sources.
# AI Prompt Library
Source: https://docs.cello.so/guides/ai-assistant/prompt-library
Example questions to ask the Cello AI Assistant
The AI Assistant handles a wide range of questions about your referral program. Here are examples organized by category - you'll also find these in the Prompt Library inside the assistant.
## Performance and analytics
Understand how your referral program is performing and how it compares to similar programs.
* "How do my metrics compare to benchmarks?"
* "What's my conversion rate from views to signups?"
* "How does my activation rate compare to benchmark?"
## Optimization
Get recommendations on where to focus your efforts to improve program performance. The assistant can help you prioritize actions from your [Performance Recommendations](/guides/attribution/recommendations) score.
* "What are the most impactful improvements I should prioritize?"
* "Which improvements require the least dev effort?"
* "How can I improve my sharing rate?"
* "How can I improve my active rate?"
## Referrers
Identify your top-performing referrers and understand where users are dropping off.
* "Which referrers drive the most signups?"
* "Which referrers drive the most revenue?"
* "What's causing my biggest drop-offs?"
## Conversion
Find ways to improve conversion rates at each stage of the referral funnel.
* "How can I increase new user signups to meet benchmarks?"
* "How can I improve purchase conversion vs. benchmark?"
## Fraud and review
Get help reviewing flagged referrals and potential fraud cases.
* "Can you help me review open fraud cases?"
## Notifications
Configure notification settings and get recommendations for engaging referrers.
* "How can I configure my notification settings?"
* "Which notification updates are recommended?"
# Performance Benchmarks
Source: https://docs.cello.so/guides/attribution/benchmarks
Understand how your program performance compares to similar companies
Cello provides industry benchmarks to help you understand how your referral program stacks up against similar companies. Benchmarks appear as horizontal reference lines on your dashboard charts, making it easy to identify where your program excels and where there's room for improvement.
Cello uses these benchmarks along with deep analysis of your program data to generate specific, actionable [Performance Recommendations](/guides/attribution/recommendations) tailored to your situation. Visit the [Recommendations page](https://portal.cello.so/dashboard/recommendations) in the Cello Portal to see exactly what to focus on next.
## Benchmarked Metrics
Cello provides benchmarks for four key metrics across the referral funnel. Benchmarks are hidden by default. Toggle them on from any supported chart to see how you compare.
* **Active Rate**: Percentage of enabled users who open the referral widget. Calculated as `Active Referrers / Enabled Referrers`.
* **Sharing Rate**: Percentage of active users who share their referral link. Calculated as `Sharing Referrers / Active Referrers`.
* **Signup Rate**: Percentage of unique referral link views that convert to signups. Calculated as `New User Signups / Unique Views`.
* **Unique Views per Share**: Average number of unique people who view each shared referral link. Calculated as `Unique Views / Sharing Referrers`.
Sharing rate benchmarks are adjusted based on your active rate. Cello automatically determines which benchmark band applies to you, so you're always comparing against relevant peers.
## Methodology
Benchmarks are calculated from anonymized, aggregated monthly performance rates across all Cello customers. Your performance is compared using your latest 30-day rolling rates.
Charts show two benchmark lines:
* **Median (Average)**: The 50th percentile, half of customers perform better, half perform worse
* **Best in Class**: The 75th percentile, top 25% of customers achieve this or better
Benchmarks are segmented by Go-to-Market model so you're compared against similar businesses:
* **Free Trial**: Customers offering free trials before purchase
* **Freemium**: Customers with free tiers and paid upgrades
* **Demo Only**: Customers requiring demos before purchase
* **Overall**: All customers combined (used when your GTM model doesn't match the above)
Cello automatically detects your GTM model and shows the appropriate benchmarks.
## Interpreting Your Results
Visit [Performance Recommendations](/guides/attribution/recommendations) to understand your score, or go directly to the [Recommendations page](https://portal.cello.so/dashboard/recommendations) in the Cello Portal to see your specific next steps.
**Above Best in Class**\
Your program is in the top 25% for this metric. This is a strength worth maintaining - consider what's driving this success and whether those practices can be applied elsewhere.
**Between Median and Best in Class**\
You're performing above average but have room to reach best-in-class status. Review the relevant best practices guides to identify optimization opportunities.
**Below Median**\
There's a clear opportunity for improvement. See recommendations in the [Cello Portal](https://portal.cello.so/dashboard/recommendations) or explore these best practices:
* **Low active rate?** See [Increase Discoverability](/guides/best-practices/Increase-discoverability-of-your-referral-program) to get more users opening the widget
* **Low sharing rate?** Review [Contextual Sharing](/guides/best-practices/contextual-sharing) to prompt referrals at high-intent moments
* **Low signup rate?** Check [Optimizing Signup Conversion](/guides/best-practices/optimizing-signup-conversion) for landing page and flow improvements
You can query benchmark data from your own AI client using [`cello_get_program_metrics`](/mcp/tools#cello_get_program_metrics) via the [Cello MCP](/mcp/growth/use-cases).
# Manual Attribution
Source: https://docs.cello.so/guides/attribution/manual-attribution
At Cello, we understand that there may be instances where automated referral attribution doesn't work as expected
At Cello, we understand that there may be instances where automated referral attribution doesn't work as expected. In such cases, our platform provides the flexibility to manually attribute referrals to ensure that your users receive the proper rewards for their efforts. This guide will walk you through the steps of manually attributing referrals within the Cello platform.
## When to Manually Attribute Referrals
1. **Technical Glitches**: If you encounter technical issues or glitches that prevent automated attribution, manual attribution allows you to override these challenges.
2. **User Disputes**: In cases where users claim they referred someone but the system did not capture it correctly, manual attribution provides a resolution path.
3. **Custom Scenarios**: For unique situations or custom referral setups, manual attribution offers a tailored solution.
Cello will only import transaction events linked to a manually attributed referral that is less than 30 days old. If a purchase is older, please reach out to the Cello support team.
## How to Manually Attribute Referrals
1. Customer gets `cello_ucc` of referrer from the Cello Portal and retrieves `cello_ucc` of referrer and `new_user_id` (former product\_user\_id) new user from their own system. If data cannot be found, please reach out to Cello.
2. Customer adds `cello_ucc` of referrer and `new_user_id` (former product\_user\_id) ID of new user to the existing Stripe customer of new user in Stripe.
3. Cello receives a `customer.updated` event from Stripe for the customer.
4. If there were already paid invoices, please resend the past `invoice.paid` events of the new user to Cello. This can be done by:
1. Go to the transaction
2. Select the `invoice.paid` event in the feed at the bottom
3. Click **View event details**
4. Check webhook attempts and resend the event
1. Customer gets `cello_ucc` of referrer from the Cello Portal and retrieves `cello_ucc` of referrer and `new_user_id` (former product\_user\_id) ID of new user from their own system. If data cannot be found, please reach out to Cello.
2. In Chargebee, you add `cello_ucc` of referrer and `new_user_id` (former product\_user\_id) of new user to the metadata of the new user's Chargebee customer.
3. We automatically receive a `customer_changed` event via the webhook.
4. If there were already payments from the new user, you need to resend the past `payment_succeeded` events via the webhook. You can trigger this inside Chargebee manually.
1. Customer gets `cello_ucc` of referrer from the Cello Portal and retrieves `new_user_id` ID of new user from their own system. If data cannot be found, please reach out to Cello.
2. Customer resends the signup event manually via the Cello API. Fields are filled as in the automated Cello API events. The detailed documentation can be found in the [Example Requests](/api-reference/generic-events/send-event).
3. To add the parameters to the metadata in your payment gateway and resend past transactions, follow step 2-4 from the tab applicable for your payment gateway.
In case Cello API events can not be resend via API, manual reports can be provided to Cello. The reports need to contain equivalent information as the specific event. The report templates will be provided by Cello Support team.
1. Customer gets `cello_ucc` of referrer from the Cello Portal and retrieves `new_user_id` ID of new user from their own system. If data cannot be found, please reach out to Cello.
2. Customer resends the signup event manually via the Cello API. Fields are filled as in the automated Cello API events. The detailed documentation can be found in the [Example Requests](/api-reference/generic-events/send-event).
3. Customer resends past transaction events manually via the Cello API. Fields are filled as in the automated Cello API events. The detailed documentation can be found in the [Example Requests](/api-reference/generic-events/send-event).
In case Cello API events can not be resend via API, manual reports can be provided to Cello. The reports need to contain equivalent information as the specific event. The report templates will be provided by Cello Support team.
## Contact Support
If you encounter challenges or have questions during the manual attribution process, our support team is here to assist you. Reach out to us via [support@cello.so](mailto:support@cello.so) with detailed information about the referral in question, and we'll promptly assist you in resolving the matter.
# Program Performance and ARR
Source: https://docs.cello.so/guides/attribution/program-performance
Understand how Cello calculates Annual Recurring Revenue to measure your referral program's performance
Cello tracks **Net New Annual Recurring Revenue (ARR)** - the annualized value of recurring revenue from referred customers. ARR is calculated from **invoice paid events** rather than looking at subscription objects in Stripe or Chargebee. This approach reflects actual revenue collected and works consistently across different billing systems.
## Why invoice-based?
Using invoice paid events means you see real revenue collected, not theoretical subscription values. It also handles complex scenarios like prorations, upgrades, and plan changes automatically - without requiring special configuration.
## Annualizing different billing intervals
Customers pay on different schedules, so Cello normalizes everything to an annual basis. This lets you compare the true value of different customers regardless of how they chose to pay.
Here are examples of how subscription intervals are annualized:
* A \$50 **monthly** subscription becomes \$600 ARR
* A \$150 **quarterly** subscription becomes \$600 ARR
* A \$600 **yearly** subscription stays at \$600 ARR
* A \$1,200 two-year **biannual** contract becomes \$600 ARR
## Rolling forward recurring revenue
When a customer pays for a yearly subscription in January, that revenue represents value for the entire year. Cello "rolls forward" non-monthly subscriptions so your monthly ARR charts reflect ongoing revenue, not just the months when invoices happen to be paid.
This also means churn is detected automatically - if a renewal invoice doesn't arrive when expected, the ARR stops being rolled forward and drops off your charts.
### What this means for your dashboard
The ARR shown in Cello represents actual paid revenue from referred customers, annualized. When comparing to your billing system's total ARR, remember that Cello shows only **attributed ARR** - revenue from customers who came through your referral program.
## Handling real-world billing scenarios
Cello automatically adjusts for common situations:
* **Late invoicing** – If an invoice comes in a few days late (within 7 days), it's attributed to the expected month to prevent artificial dips or jumps in your charts
* **Early renewals** – Overlapping subscription periods are detected to avoid double-counting
* **Prorations** – When customers upgrade mid-cycle, proration credits are factored in to show the true subscription value
The Proration feature gradually being rolled out gradually across customers where applicable.
## ARR movement breakdown
Cello breaks down ARR changes into components so you can understand what's driving growth:
* **New ARR** – Revenue from newly referred customers
* **Expansion ARR** – Increases from existing customers upgrading or adding seats
* **Contraction ARR** – Decreases from downgrades
* **Churned ARR** – Lost revenue when customers cancel or don't renew
You can choose to enable or disable the ARR movement from the **New User ARR** chart menu.
You can query program performance data from your own AI client using [`cello_get_program_metrics`](/mcp/tools#cello_get_program_metrics) via the [Cello MCP](/mcp/growth/use-cases).
# Performance Recommendations
Source: https://docs.cello.so/guides/attribution/recommendations
Prioritized actions to improve your referral program performance
The Recommendations page in the Cello portal shows you a prioritized list of actions to improve your referral program. Each recommendation includes a point value indicating its potential impact on your overall score.
## How it works
Your **Recommendations Score** reflects how well your referral program is configured for success. The score is based on proven best practices across activation, sharing, and conversion.
Each recommendation shows:
* **Point value** – the impact on your score when completed
* **Category** – which area of your program it affects
* **Action** – what you need to do, with links to settings or documentation
As you complete recommendations, your score increases and you'll see new recommendations unlock.
## Recommendation areas
### Activation
Actions that help users discover your referral program and understand its value. This includes launcher visibility, announcements, and activation campaigns.
### Sharing
Actions that encourage users to share more often and more effectively. This includes contextual prompts, reward messaging, and launcher configuration.
### Conversion
Actions that improve signup and purchase rates for referred users. This includes dual-sided rewards and personalization.
To see how your current metrics compare to industry benchmarks, see [Performance Benchmarks](/guides/attribution/benchmarks).
## Using recommendations with AI
You can ask the [AI Assistant](/guides/ai-assistant/overview) built into the portal to help you prioritize recommendations:
* "What are the most impactful improvements I should prioritize?"
* "Which improvements require the least dev effort?"
The assistant will reference your current recommendations and help you decide where to focus.
Prefer working from your own AI client? The same data is available via the [Cello MCP](/mcp/growth/use-cases) using the `cello_get_recommendations` tool.
# Increase Discoverability Of Your Referral Program
Source: https://docs.cello.so/guides/best-practices/Increase-discoverability-of-your-referral-program
Learn how to drive organic activation of your referral program with high discoverability
To drive organic activation for your referral program, high discoverability is key.
1. **1st-level visibility** - Creating basic awareness for your referral program with a launcher that is always visible is an absolute must-have to see success.
2. **Multiple referral launchers** - Add launchers in positions where they naturally attract user attention, the biggest lever for recurring traction
## **1st-level visibility**
+4.4x activation rate+21 performance points
Display the **CTA link in the navigation menu at 1st-level**. When the link is displayed in a prominent position on screen, it can improve activation significantly. **Its positioning is crucial.** If the CTA is placed in a secondary menu, the activation rate is drastically reduced (\<1%).
### How to implement?
1. Choose a 1st level menu position and give it a unique html identifier.
2. Decide what your CTA is. We advice [adding a reward amount](https://docs.cello.so/referral-component/custom-launcher#add-reward-in-launcher) as it **increases activation by 1.5x** and give you score uplift by **6 performance points**.
3. Set the Custom Launcher Selector in [Cello Portal -> User Experience](https://portal.cello.so/setup/user-experience) to match your element identifier.
For a step-by-step guide, go to [Custom Launcher documentation](/referral-component/custom-launcher).
## **Multiple referral launchers**
+8.8x activation rate+14 performance points
Integrating multiple launchers into your product pages can significantly increase activation, especially on pages where users are **primed for sharing such as upgrades, subscriptions, sharing content, and inviting team members.** The benefits of adding a custom launcher is that you can craft an activation message specific to that particular context.
### How to implement?
You can add a custom button anywhere in your UI and have it open the Referral Component.
1. Identify where to add the button together with your growth manager and UX designer.
2. Use [window.Cello("open")](/sdk/client-side/cello-js-usage#open-destination) method to open the Referral Component when the button is clicked.
```javascript theme={null}
window.Cello("open");
```
## Performance impact
The chart below shows all Cello average active users rates. User activation increases by 8.8x when applying these 2 recommendations.
# Contextual Sharing
Source: https://docs.cello.so/guides/best-practices/contextual-sharing
Guide for increasing referral sharing at key moments
Increase sharing by creating referral program awareness, keeping it top of mind for users and making referrals part of your main user flow. To achieve this, we recommend utilizing **moments of delight** and regular communication.
How to encourage referrers to share at key moments in the user journey:
* [Add a CTA to refer your product](#add-a-cta-to-refer-your-product)
* [Send an instant message to introduce the referral program](#send-an-instant-message-to-introduce-the-referral-program)
* [Add referral link to regular emails](#add-referral-link-to-regular-emails)
**Contextual sharing can increase sharing rates by 3.4x**
Adding sharing prompts to just a few moments of delight can increase sharing rates more than x3.
## Add a CTA to refer your product
A product lifecycle naturally has **moments of delight** when a user would be more likely to share their satisfaction with the product within their network. Add a CTA to open the [referral component](/sdk/client-side/cello-js-usage) at such moments and make referring part of this flow.
### How to implement?
For Developers
You can add a custom button anywhere in your UI at the moment of delight and have it open the Referral Component.
1. Identify where to add the button together with your Growth manager and UX designer
2. Use [window.Cello("open")](/sdk/client-side/cello-js-usage#open-destination) method to open the Referral Component when the button is clicked.
```javascript theme={null}
window.Cello("open");
```
## Send an instant message to introduce the referral program
When your user reaches a **moment of delight** in their journey, that's the time to prompt them to share your product with an introductory in-product message i.e. [announcement](/guides/user-experience/referral-notifications-and-emails#announcement). This introduces the referral program to the user at the time they feel compelled to share their experience and effectively boost the conversion rate from users to referrers.
### How to implement?
For Developers
You can trigger [an announcement](/guides/user-experience/referral-notifications-and-emails#announcement) using [Cello.js](/sdk/client-side/cello-js-usage) client-side JS method at any point of the user journey. Here is how to do it:
1. Add [announcement to your custom launcher](/referral-component/custom-launcher#add-announcement-selector), so they are displayed when triggered.
2. Use [window.Cello("showAnnouncement")](/sdk/client-side/cello-js-usage#showannouncement-announcement) method to open the Referral Component when the button is clicked.
Below example will trigger a default [welcome announcement](/guides/user-experience/referral-notifications-and-emails#announcement):
```javascript theme={null}
window.Cello("showAnnouncement", { "type": "welcome-announcement-1" } );
```
You can also use a server-side API to trigger the announcement. Check out this guide [on behaviour-based triggers](/guides/best-practices/behavior-based-triggers).
## Add referral link to regular emails
Use regular communication with your users as an opportunity to remind them about the referral program and keep it top of mind. For example, add their personal invite link to your weekly updates or transactional emails.
### How to implement?
For Developers
Depending on your email sending service, you can add additional content to your email, in this case, a personal invite link. To get the link for each referrer, you can use our Cello API [/active-link endpoint](/api-reference/referral-codes/fetch-active-link) and enrich the emails you already send to your users with information about referral program and their personal invite link.
# Optimize signup conversion
Source: https://docs.cello.so/guides/best-practices/optimizing-signup-conversion
Recommendations to optimize the signup conversion of referred users
Improve signup conversion for referred users with personalized experiences. These best practices can significantly increase conversion rates.
1. **Show personalization and discounts** - Display the referrer's name and discount offer on your website
2. **Custom referral landing page** - Create a dedicated landing page and disable the Cello-hosted page
## **Show personalization and discounts**
\~50% higher signup rate
When a referred user lands on your website, showing them who referred them and what discount they're getting makes the offer feel personal.
They're not seeing a generic signup page. They're seeing a recommendation from someone they know, with a clear incentive to act.
### How it works
1. **Personalization**: Referrer names can be integrated into your website or into Cello's new user banner. The name is provided via the Cello boot inside your product.
2. **Full integration**: Your developer can set up personalization directly in your website based on URL parameters and cookie information provided by Cello.
3. **New user banner**: Cello can activate a banner on your website to display the offer to referred users. Personalization is optional.
4. **Disable Cello-hosted landing page**: The Cello hosted-landing page can be disabled since discount information is displayed on your website. One conversion step is eliminated.
### How to implement
Your developer can add personalization in two ways:
* **Inline personalization**: Use the [Cello Attribution script](/sdk/client-side/attribution-js-usage) to fetch referrer info and display it in your page headlines, banners, or CTAs
* **New user banner**: Enable the no-code [Cello banner](/guides/user-experience/personalizing-referrals#add-personalization-with-the-new-user-banner) that automatically appears for referred visitors
To fetch referrer information for personalization, use the [referral code API](/api-reference/referral-codes/fetch-referral-code-info).
For detailed implementation guides, see:
* [Personalizing referrals](/guides/user-experience/personalizing-referrals)
* [New user discounts](/guides/user-experience/new-user-discounts)
### Examples
🔗 [Wise referral program with personalization](https://wise.com/invite/dic/tanjam2?utm_source=desktop-invite-tab-copylink\&utm_medium=invite\&utm_campaign=\&utm_content=\&referralCode=tanjam2)
🔗 [MeetGeek with personalized new user banner](https://meetgeek.ai/meetgeek-referral?productId=app.meetgeek.ai\&ucc=vTlj7ne4Fkf\&n=VG9iaWFz)
***
## **Custom referral landing page**
\~2x higher signup rate
Instead of sending referred users to the Cello-hosted landing page, send them directly to a page you control. You can tailor the messaging, show your product's value, and get them to signup without an extra redirect. Fewer steps can lead to less drop-offs.
### Key building blocks
1. **Personalized headline** - Include the referrer's name
2. **New user discount** - Make the discount clear and visible
3. **Hero message** - Your key value proposition
4. **Product visual** - Show what the product does
5. **CTA** - Direct signup with the offer highlighted
6. **Social proof** - G2/Capterra badges, Trustpilot, customer logos
7. **Customer quotes** - Real testimonials
8. **FAQs** - Answer common questions
**Leverage existing assets** - Do you already have an optimized landing page for ads? Reuse the content and directly include the signup form for the fastest path to success.
### How to set up
1. Create your landing page using the building blocks above
2. Go to [New User Experience setup](https://portal.cello.so/setup/new-user-experience) in Cello Portal
3. Switch to **Custom landing page** and add your URL
For a detailed guide, see [Optimizing referral landing pages](/guides/user-experience/optimizing-landing-pages).
### Examples
🔗 [Typeform landing page](https://www.typeform.com/refer-a-friend/invite/?utm_medium=referrerlink\&utm_source=typeform\&utm_campaign=refer_a_friend_cello\&productId=admin.typeform.com\&ucc=ARn30TGHAsq)
🔗 [Superhuman landing page with personalization](https://superhuman.com/refer?utm_source=product\&utm_medium=signature\&utm_campaign=bob%40bobinsky.me)
🔗 [Heyflow standalone landing page](https://get.heyflow.app/referral-lp?productId=go.heyflow.app\&utm_source=cello\&utm_medium=referral\&utm_campaign=Cello-RS20-C1000-D50\&ucc=2dRGoRjgP7A#start)
🔗 [Cello standalone landing page with direct signup](https://cello.so/invitation/)
# Setting Up Campaigns
Source: https://docs.cello.so/guides/campaigns/setting-up-campaigns
Cello makes it easy to automatically notify and reward your users for making successful referrals
Cello makes it easy to automatically notify and reward your users for making successful referrals. This is done by creating **campaigns** with specific **payout rules.**
Your rules are then automated based on confirmation of **events** and **purchases.** These can be based on transactions for referred contacts, but can also be based on free trials, demos, or events you define.
## Example: Recurring Rewards Encourage Continuous Sharing
In this typical example, a referrer is rewarded **50%** for each referral up to a **\$100 maximum reward cap** with a **\$5 signup bonus**. The referee initially purchases a **\$10** subscription for herself, and then **upgrades her team** in the following month.
The referrer earns recurring rewards with each payment until they reach the **maximum cap of \$100** for this referral. In this example, that happens to take 6 months based on the referred user's spending. These regular rewards encourage further sharing.
It's important to note that the **new user also receives an exclusive 50% discount** from the referrer when purchasing for the first 6 months. Our research shows that **symmetric rewards** (i.e., the referrer and the referred have incentives of similar values) work best because referrers invest their social capital when recommending a product; having similar incentives makes the referral look fair to both parties involved.
## Campaign Settings
All campaigns must have one or more rules to reward referrers for the referrals they made. **Campaign** settings can be configured in the [Cello portal in the Setup section](https://portal.cello.so/setup/campaigns).
Rewards are typically based on a **percentage** of the transaction amount generated when new customers make a payment up to a **maximum** amount per referral. Additional rewards can also be set on other key events such as **signups** and **purchases** to help encourage more engagement and sharing.
| **Section** | **Rule** | **Description** |
| --------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Referrer Reward | Percentage of revenue | Percentage of attributed new revenue that will be paid as a reward |
| Referrer Reward | Maximum reward (per referrer) | The maximum reward that can be earned per referral |
| Referrer Reward | Bonus rewards | Additional rewards that can be set for signups or purchases to encourage more sharing. Bonus rewards are also recommended for products with longer free to paid conversion times. |
| New User Reward | Percent Discount and Months | The new user discount to encourage additional sharing. |
Cello uses the new user reward settings to display to the new user on your signup screens. You will need to take additional steps to implement the discount at the point of purchase. See the docs [here](referee-rewards-in-stripe) for more information.
### Running promotional campaigns
Cello supports one active campaign at a time. To run a time-limited promotion (e.g., Black Friday):
1. Adjust your reward percentages and new user discounts in [Campaign Settings](https://portal.cello.so/setup/campaigns)
2. Revert the settings when the promotion ends
There's no automated scheduling, so set a reminder to update your settings before and after the promotional period.
# Cello vs. FirstPromoter
Source: https://docs.cello.so/guides/competitor-comparison/cello-vs-firstpromoter
Compare Cello and FirstPromoter for referral programs: integration effort, server vs client tracking, in‑app UI, notifications, campaign rules, payouts, and trade‑offs.
If you're deciding between **Cello and FirstPromoter** for referrals, this page gives a practical comparison to help you choose. You'll find what you need to build for each option and the trade‑offs across attribution reliability, in‑app UX, notifications, campaigns, and payouts.
**Cello** embeds a native referral component, coordinates in‑app + email journeys, and uses server‑side attribution via Stripe and webhooks. **FirstPromoter** provides a tracking snippet and hosted affiliate portal; teams typically build or embed the user experience themselves.
## Overview
* **In‑product referral UI**: Cello provides a native in‑app referral panel for web and mobile; users see their link, status, and rewards inside your app.
* **Affiliate portal model**: FirstPromoter centers on a JavaScript tracking snippet (`fpr.js`) and a hosted portal; there is no pre‑built in‑app referral panel.
## Integration and UX embedding
| **Topic** | **Cello** | **FirstPromoter** |
| ------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Referral UI embedding** | Native Referral Component; in‑app panel shows link, status, rewards. | JS tracking snippet; no embedded referral widget. Affiliate UI is hosted externally or embedded via iframe. |
| **Custom launcher / placement** | Custom Launcher to open panel from any UI element with full styling control. | No equivalent launcher pattern; developers wire UI to APIs or redirect to hosted pages. |
| **Branding & control** | Inherits your design system; theming is automatic. | Branding primarily on the hosted portal or via white‑label settings. |
### Example
Open Cello’s referral panel from a profile menu item; keep the experience fully in‑app and on‑brand.
### Notifications and engagement
Cello includes an in‑app and email notification system for referral programs:
* **In‑app alerts and badges:** e.g., an alert under a “Rewards” tab and a badge on the launcher when a reward is earned.
* **Announcements (callouts):** prompts for next actions such as adding payout details after earning a reward.
* **Email notifications:** lifecycle emails at moments like welcome, first share, reward earned, and unclaimed reminders.
* **Journey logic:** behavior‑based timing (e.g., alert now, then announcement after 7 days if no action).

FirstPromoter offers **email notifications** and **webhooks** for events. There is **no native in‑app notification layer**; teams implement journeys via external tooling, **requiring additional development effort**.
## Mobile SDKs
| **Topic** | **Cello** | **FirstPromoter** |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| **Native mobile SDKs** | iOS, Android, and React Native SDKs with a plug‑and‑play referral component. | No native mobile SDK; web‑first via JavaScript (`fpr.js`) and REST API/webhooks. |
| **Integration pattern** | Quick install (SPM/CocoaPods/Gradle). Initialize with product ID/user token; supports custom launchers and native share sheets. | Mobile apps embed a web view/portal or build custom flows against the REST API and webhooks. |
| **In‑app referral UI** | Embedded panel inside the mobile app; users copy links, view progress, manage rewards natively. | No pre‑built in‑app panel; experiences are web/portal‑based or custom‑built. |
| **Payout support** | Platform includes automated payouts via PayPal/Venmo with credit note issuance and VAT handling (outside SDK code). | Payouts handled externally via dashboard/API; not native to the mobile app. |
If you need native, in‑app referral UX on iOS/Android with minimal build, Cello’s SDKs provide a faster path. FirstPromoter requires custom mobile implementation or redirecting to a web portal.
## Attribution: client vs server flow
| **Topic** | **Cello** | **FirstPromoter** |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Tracking model** | Backend‑centric attribution using secure IDs and event webhooks (e.g., Stripe). No reliance on cookies or client scripts. | Client‑side cookie tracking by default (`_fprom_ref`, `_fprom_tid`). API‑only mode exists but requires custom setup. |
| **Conversion flow** | Ties referrals to backend payment events via Stripe metadata (`cello_ucc`, `new_user_id`) or API payloads. Deterministic even in blocked/mobile contexts. | Attributes sales by matching customer emails from client‑recorded leads to billing events; sensitive to missing cookies or mismatched emails. |
| **Resilience** | Works in privacy‑restricted or JS‑disabled environments; ideal for mobile, embedded, or secure checkout flows. | Dependent on browser state; cookie‑less or JS‑restricted scenarios require custom logic. |
In environments with strict CSP, script blockers, mobile apps, or server‑rendered checkouts, server‑first attribution reduces reliance on client events. FirstPromoter can be configured via API but requires additional work.
## Campaigns, rewards, and payouts
### Campaign design and reward rules
| Aspect | **Cello** | **FirstPromoter** |
| ------------------------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Campaign flexibility** | Multi‑condition campaigns (percentage, fixed, discount) within one rule set. | One primary reward per campaign; advanced structures require manual setup. |
| **Double‑sided** | Native friend incentives (“give $X, get $Y”) built into campaign logic. | Implemented via coupon codes synced with Stripe; manual configuration required. |
| **Recurring rewards** | Recurring rewards with configurable caps per campaign. | Recurring commissions supported; limits are defined per campaign manually. |
| **Computation** | Reward logic executed server‑side; rewards auto‑registered via events. | Tracked on client lead creation; resolved by matching purchase webhooks. |
### Payout management
| Aspect | **Cello** | **FirstPromoter** |
| ------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **Fulfillment** | Automated reward registration and payout initiation. | Aggregates commissions; payouts executed manually or via PayPal API. |
| **User experience** | Users select payout method (e.g., PayPal, Venmo) inside your application. | Payouts managed on the hosted portal; not within your product UI. |
## Summary: key differences
1. **In‑app referral UX vs portal**: Cello provides a native embedded panel; FirstPromoter uses a hosted affiliate portal and snippet.
2. **Engagement**: Cello offers in‑app + email journeys; FirstPromoter relies on email and webhooks with no in‑app layer.
3. **Attribution**: Cello is server‑first via metadata/webhooks; FirstPromoter defaults to client cookies and email matching.
4. **Campaigns**: Cello supports multi‑type and double‑sided rewards in one campaign; FirstPromoter is more single‑reward oriented.
5. **Payouts**: Cello manages payouts inside your app; FirstPromoter manages payouts externally.
6. **Mobile SDKs**: Cello offers native iOS/Android/React Native SDKs with a plug‑and‑play component; FirstPromoter has no native mobile SDK and is web‑first.
Select the option that fits your integration model (in‑app vs portal), attribution requirements (server‑side vs client‑side), and operational preferences (built‑in journeys vs custom tooling).
# Cello vs. Impact Advocate (SaaSquatch)
Source: https://docs.cello.so/guides/competitor-comparison/cello-vs-impact-advocate
Compare Cello and Impact Advocate (SaaSquatch): integration effort, widgets vs embedded UI, server vs client attribution, notifications, campaign rules, and payouts.
If you're deciding between **Cello and Impact Advocate (SaaSquatch)** for referrals, this page gives a practical comparison across integration effort, attribution reliability, in‑app experience, notifications, campaigns, and payouts.
**Cello** embeds a native referral component, coordinates in‑app + email journeys, and uses server‑side attribution via Stripe metadata. **Advocate** relies on embeddable widgets and external portals that often require additional styling and setup to feel native.
## Overview
* **Embedded referral UI**: Cello’s Referral Component integrates natively in your app (web/mobile) with automatic theming and a launcher.
* **Widget/portal model**: Advocate provides widgets (`squatch.js`, ``), which are external elements styled separately or surfaced via a portal.
## Integration and UX embedding
| **Topic** | **Cello** | **Impact Advocate (SaaSquatch)** |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Referral UI embedding** | Native Referral Component; in‑app panel with link, status, rewards; floating or custom launcher supported. | Widgets via `squatch.js` or ``; iframe‑like embeds requiring separate styling; no pre‑built native referral panel. |
| **Custom launcher / placement** | Custom Launcher to open panel from any UI element, keeping the flow in context. | Developers manually wire triggers (e.g., ``); no built‑in launcher button. |
### Example
Open Cello’s referral panel from a menu item; keep users in‑app with a cohesive look and feel. Widgets typically need extra work to match your design system.
### Notifications and engagement
Cello includes an in‑app and email notification system for referral programs:
* **In‑app alerts and badges** for important moments like reward earned.
* **Announcements (callouts)** to prompt next actions, such as adding payout details.
* **Email lifecycle notifications** (welcome, first share, reward earned, unclaimed reminders).
* **Behavior‑based timing** to coordinate in‑app and email touchpoints.

**Advocate** provides **event webhooks** and **email templates** but no native in‑app notification layer. Teams typically build in‑app nudges with other systems, **requiring additional development effort**.
## Mobile SDKs
| **Topic** | **Cello** | **Impact Advocate (SaaSquatch)** |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Native mobile SDKs** | iOS, Android, React Native SDKs with a plug‑and‑play referral component. | iOS and Android SDKs available; mobile widgets and deep‑linking supported. |
| **Integration pattern** | Quick install (SPM/CocoaPods/Gradle). Initialize with product ID/user token; supports native share sheets and custom launchers. | Hybrid model: combine SDK with server‑side REST API calls; SDKs do not support payment‑provider programs. |
| **In‑app referral UI** | Embedded mobile panel showing link, progress, rewards; theming aligns with app UI. | SDK gives control over in‑app presentation; also offers mobile widgets to embed experiences. |
| **Payout support** | Platform includes automated payouts via PayPal/Venmo with credit note issuance and VAT handling (outside SDK code). | Rewards tracked in platform; payout fulfillment handled via platform/integrations, not SDK. |
Impact’s SDKs cover core referral mechanics but require server APIs and do not support payment‑provider programs. Cello’s SDKs include a pre‑built component and platform payout automation to reduce custom work.
## Attribution: client vs server flow
| **Topic** | **Cello** | **Impact Advocate (SaaSquatch)** |
| -------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **Client dependency** | Backend‑centric attribution driven by webhooks and secure metadata; resilient without client scripts. | Client + cookie‑based tracking by default; server API integration is optional and requires extra setup. |
| **Payment/Stripe linkage** | Stripe metadata (`cello_ucc`, `new_user_id`) for direct backend attribution - no client JS required. | Relies on browser cookies or manual event calls; payment integrations exist but typically require more config. |
In strict CSP environments, with script blockers, mobile apps, or server‑rendered checkouts, server‑first attribution reduces points of failure. Advocate can reach parity with extra server work.
## Campaigns, rewards, and payouts
### Campaign design and reward rules
| Aspect | **Cello** | **Impact Advocate (SaaSquatch)** |
| ------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| **Campaign flexibility** | Multiple reward types in one campaign (fixed, %, signup bonus, discounts); double‑sided supported. | Complex structures via rules engine but often split across multiple programs. |
| **Reward types** | Combines cash, % commissions, and friend discounts in one flow. | Wide catalog (points, gift cards, coupons) but often one primary type per program. |
| **Configuration** | Managed in Cello dashboard or via API. | Configured mainly in Advocate portal; APIs for advanced use cases. |
### Payout management
| Aspect | **Cello** | **Impact Advocate (SaaSquatch)** |
| ------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **Fulfillment** | Fully automated payouts (PayPal, Venmo) with tracking and tax handling. | Tracks rewards; fulfillment via provider integrations (PayPal, Tango Card) or manual. |
| **User experience** | Users claim and manage payouts inside your app. | Users redeem via portal, email, or third‑party sites. |
| **Workflow** | End‑to‑end: reward earned → notified → paid. | Requires configuration of a payout provider or manual redemption flow. |
### Recurring rewards and multi‑month commissions
| Aspect | **Cello** | **Impact Advocate (SaaSquatch)** |
| ------------------------- | ------------------------------------------------ | ----------------------------------------------------- |
| **Recurring commissions** | Native recurring rewards with configurable caps. | Supports recurring events; caps require custom logic. |
| **Granular controls** | Built‑in duration and cap settings per campaign. | Requires advanced rule setup or calculated fields. |
## Summary: key differences
1. **Embedded UI vs widgets/portal**: Cello is native in‑app; Advocate relies on widgets and portals.
2. **Engagement**: Cello provides in‑app + email journeys; Advocate requires external tooling for in‑app nudges.
3. **Attribution**: Cello is server‑first via Stripe metadata; Advocate defaults to client/cookie tracking.
4. **Campaigns**: Cello composes multiple reward types in one campaign; Advocate often splits across programs.
5. **Payouts**: Cello automates payouts inside your product; Advocate integrates with providers or uses manual flows.
6. **Mobile SDKs**: Both provide native iOS/Android SDKs; Cello includes a plug‑and‑play component and platform payout automation, while Advocate’s SDK is hybrid (server APIs) and does not support payment‑provider programs.
Choose the option that aligns with your integration model (embedded vs widgets/portal), attribution requirements, and operations (built‑in journeys vs custom assembly).
# Cello vs. PartnerStack
Source: https://docs.cello.so/guides/competitor-comparison/cello-vs-partnerstack
Compare Cello and PartnerStack for referrals: embedded UI vs external portal, server vs client tracking, notifications, campaign rules, payouts, and trade‑offs.
If you're evaluating **Cello vs PartnerStack** for referral programs, this guide summarizes integration effort, attribution reliability, in‑app experience, notifications, campaigns, and payouts to inform your choice.
**Cello** embeds a native referral panel with server‑side attribution and in‑app + email journeys. **PartnerStack** focuses on a broad partner portal and JS SDK; users typically manage links and payouts on an external dashboard.
## Overview
* **In‑product referral UI**: Cello’s Referral Component lives inside your app; users can copy links, view stats, and manage rewards without leaving.
* **Portal‑centric model**: PartnerStack centers on an external portal and SDK; in‑app referral UI is minimal and often redirects to PartnerStack.
## Integration and UX embedding
| **Topic** | **Cello** | **PartnerStack** |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Referral UI embedding** | Embedded referral panel in‑app; shows each user’s link, stats, rewards, fully native to your UX. | JS SDK and simple iFrame form for collecting emails/generating links. No in‑app referral dashboard; users manage referrals on PartnerStack’s site. |
| **Custom launcher / placement** | Flexible launcher: attach panel open to any element (menu item, button). Replace or hide the default floating button for a fully branded UX. | No native launcher concept; teams create custom buttons/links to open forms or redirect to the portal. |
### Example
Open Cello’s panel from an “Invite Friends” button in your app; PartnerStack typically takes users out to an external dashboard for management.
### Notifications and engagement
Cello includes an in‑app and email notification system for referral programs:
* **In‑app alerts & badges** for referral joins or rewards earned.
* **Announcements** prompting next steps (e.g., add payout details).
* **Email lifecycle** for welcome, reward earned, and unclaimed reminders.
* **Behavior‑based timing** to coordinate prompts and reminders.

**PartnerStack** does not provide native in‑app notifications. It relies on **webhooks** and external email triggers; custom in‑app messaging requires manual builds, **requiring additional development effort**.
## Mobile SDKs
| **Topic** | **Cello** | **PartnerStack** |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Native mobile SDKs** | iOS, Android, React Native SDKs with a plug‑and‑play referral component. | No native mobile SDK; focuses on partner portal, JS tracking, and referral iFrame. |
| **Integration pattern** | Quick install (SPM/CocoaPods/Gradle). Initialize with product ID/user token; supports native share sheets and custom launchers. | Mobile apps embed a portal/iFrame or build custom UI against REST APIs; referrals managed in external portal. |
| **In‑app referral UI** | Embedded mobile panel that is themable and aligns with app UI. | No pre‑built in‑app referral panel; experiences are portal/web‑based. |
| **Payout support** | Platform includes automated payouts via PayPal/Venmo with credit note issuance and VAT handling (outside SDK code). | Payouts managed via PartnerStack portal on monthly cycles; not inside your app. |
If you need native iOS/Android referral experiences, Cello’s SDKs provide the in‑app component. PartnerStack is portal‑centric and requires custom app work or redirects.
## Attribution: client vs server flow
| **Topic** | **Cello** | **PartnerStack** |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Client dependency** | Backend‑centric tracking: attribution on server events (e.g., Stripe webhooks); no cookies or client scripts required. | Client‑centric tracking via JS snippet and cookies; requires a front‑end call to confirm conversions. Missing scripts or blockers can break attribution. |
| **Stripe / metadata** | Server metadata‑based: referral codes stored on Stripe objects; attribution via webhooks. | Cookie & ID matching: matches by email or client IDs, often with delays. Server‑side setup is optional and more complex. |
Server‑first attribution remains reliable across strict privacy environments, mobile apps, and blocked scripts. PartnerStack’s JS flow is browser‑dependent unless hardened with server integrations.
## Campaigns, rewards, and payouts
### Campaign design and reward rules
| Aspect | **Cello** | **PartnerStack** |
| ------------------------ | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| **Campaign flexibility** | Multiple reward types in one campaign: % commissions, bonuses, caps, and friend discounts. | Managed via Triggers: one reward per trigger; complex logic requires multiple triggers. |
| **Reward types** | Combine % and fixed bonuses, plus new‑user discounts, in a single setup. | Each trigger offers a single flat or % reward; no native friend‑gets‑X incentives in the same flow. |
### Payout management
| Aspect | **Cello** | **PartnerStack** |
| ------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------ |
| **Fulfillment** | Automated payout calculation and initiation. | Monthly batch payouts via the portal or manual approval. |
| **User Experience** | Referrers choose payout method (e.g., PayPal, Venmo) inside your app. | Users get paid via PartnerStack’s portal, not inside your product. |
| **Workflow** | Real‑time payout updates and in‑app notifications. | External batch payout cycle, disconnected from your UX. |
### Recurring rewards and multi‑month commissions
| Aspect | **Cello** | **PartnerStack** |
| ------------------------- | ------------------------------------------------ | ----------------------------------------------------------- |
| **Recurring commissions** | Native recurring rewards with configurable caps. | Recurring commissions supported; caps require manual setup. |
| **Control** | Built‑in duration and reward caps. | Requires manual review or multi‑trigger management. |
## Summary: key differences
1. **In‑app UI vs portal**: Cello is embedded; PartnerStack is portal‑centric.
2. **Engagement**: Cello provides in‑app + email journeys; PartnerStack relies on external comms.
3. **Attribution**: Cello is server‑first via metadata/webhooks; PartnerStack defaults to client/cookie tracking.
4. **Campaigns**: Cello composes multiple rewards in one campaign; PartnerStack uses single‑reward triggers.
5. **Payouts**: Cello supports in‑app payout flows; PartnerStack manages payouts externally.
6. **Mobile SDKs**: Cello offers native iOS/Android/React Native SDKs with an embedded component; PartnerStack has no native mobile SDK (portal‑centric).
Choose the platform that matches your desired integration model, attribution requirements, and operational ownership.
# Cello vs. Rewardful
Source: https://docs.cello.so/guides/competitor-comparison/cello-vs-rewardful
Evaluate and prototype Cello vs Rewardful: what to build, risks, and trade‑offs across attribution, UI, notifications, rewards, and payouts.
If you're deciding between **Cello and Rewardful** for referrals, this page gives a practical comparison to help you choose. You'll find a concise overview of what you need to build for each option, the trade‑offs around attribution reliability, in‑app UX, notifications, campaigns, and payouts, and practical pros/cons to inform your architecture.
**Cello** offers an embedded referral UI, built‑in journeys, and server‑first attribution that can reduce time‑to‑value; **Rewardful** provides a lightweight tracking layer suited to teams that plan to build out user experience and messaging orchestration themselves.
## Overview
* **In‑product referral UI**: Cello embeds a panel directly in your application so users can copy links, view progress, and manage rewards without leaving your app.
* **Snippet‑based tracking**: Rewardful centers on a JavaScript snippet and REST API. You implement the user‑facing UI yourself or link out to an external portal.
## Integration and UX embedding
| **Topic** | **Cello** | **Rewardful** |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Referral UI embedding** | Cello’s referral component embeds in your UI. Use a floating action button or a custom launcher to open an in‑app panel with a user’s referral link, status, and rewards. | Implements a JS snippet that exposes a browser API (`rewardful` function) to track conversions. No pre‑built in‑app referral panel; you build the user‑facing experience or use their portal. |
| **Custom launcher / placement** | Cello supports a custom launcher: attach any element (button, menu item, etc.) to open the referral panel; you may hide the default floating button. | No native embedded launcher. Teams wire up their own UI to call methods like `rewardful('ready', ...)` and `rewardful('convert', {...})`. |
### Example
**Cello** Referral Component opens from a custom launcher in your product menu. This keeps the experience in‑app and aligned with your UI.
**Rewardful** does not provide a pre‑built in‑app referral panel; you build the user‑facing experience or use their portal.
### Notifications and engagement
Cello includes an in‑app and email notification system for referral programs:
* **In‑product alerts and badges:** e.g., an alert under a “Rewards” tab with a badge on the launcher when a reward is earned.
* **Announcements (callouts):** anchored prompts for next actions (e.g., add payout details after earning a reward). Dismissible.
* **Email notifications:** lifecycle emails at moments such as welcome, first share, reward earned, and unclaimed reminders.
* **Journey logic:** timing based on behavior (e.g., alert now, follow‑up announcement after 7 days if no action; recurring reminders only for recently active users).
### Example
**Cello** in‑app “new reward” notification prompts a user to add payout details in the referral component.

**Rewardful** does not include a native in‑app notification framework; Instead Rewardful exposes webhooks for events (e.g., referral created, converted, payout due). Teams typically connect these to their email/in‑app systems, **requiring additional development effort**.
## Attribution: client vs server flow
| **Topic** | **Cello** | **Rewardful** |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Client dependency** | Backend‑centric attribution. Attribution runs on backend events (e.g., Stripe webhooks). SDK initialization can pass `productUserDetails` for identification and fraud checks ([docs.cello.so](http://docs.cello.so/)). | Client‑side default. Requires snippet load and `rewardful('convert', { email })` on a confirmation page. Referrals are linked via email lookup in Stripe (\~24 h) ([developers.rewardful.com](http://developers.rewardful.com/)). |
| **Stripe / metadata** | Server‑side, metadata‑based. Add `cello_ucc` and `new_user_id` to Stripe Customer / Checkout Session. Webhooks link and reward automatically - no client conversion call required ([docs.cello.so](http://docs.cello.so/)). | Client‑dependent linking. Uses Stripe `client_reference_id` and a \~24 h email‑match window. Can be hardened with custom server logic ([help.rewardful.com](http://help.rewardful.com/)). |
In environments with strict CSP, script blockers, mobile apps, or server‑rendered checkouts, a server‑first pattern reduces dependency on client events. Rewardful can be configured server‑side but requires additional work.
## Campaigns, rewards, and payouts
### Campaign design and reward rules
| Aspect | **Cello** | **Rewardful** |
| --------------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| **Campaign flexibility** | Multiple payout rules within one campaign: % commissions, fixed bonuses, reward caps, and new‑user discounts. | One reward type/rate per campaign. |
| **Reward types** | Combine % of revenue, fixed bonuses (e.g., signup or first purchase), and new‑user discounts in a single flow. | Choose either % commission or fixed amount per conversion. |
| **Example setup** | 50% of payments up to $100, plus $5 signup bonus, and 50% discount for 6 months - in one configuration. | Set a % or fixed reward per conversion. |
| **Double‑sided incentives** | New‑user discounts integrated into campaign logic. | Possible via Stripe coupons (plan‑dependent). |
| **Configuration** | Managed in‑app or via API. | Configurable via REST API. |
### Payout management
| Aspect | **Cello** | **Rewardful** |
| --------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------- |
| **Fulfillment** | Automated reward registration and payout initiation. | Tracks payout data; execution handled externally. |
| **User experience** | End‑users choose payout method (e.g., PayPal, Venmo) inside your app. | No native end‑user payout UI. |
| **Workflow** | Rules calculate rewards, trigger notifications, and mark payouts ready. | Commissions accumulate; payouts marked paid via dashboard/API. |
| **Integration depth** | In‑app payout management via hosted component. | Developer‑level API integration. |
### Recurring rewards and multi‑month commissions
| Aspect | **Cello** | **Rewardful** |
| ------------------------- | ------------------------------------------------------------ | ------------------------------------------ |
| **Recurring commissions** | Native support for recurring rewards with configurable caps. | Recurring commissions via Stripe renewals. |
| **Granular controls** | Reward caps configurable in campaign setup. | Reward caps often require custom logic. |
| **Common use cases** | Multi‑month or capped rewards configured directly. | Lifetime or one‑off bounties are typical. |
| **Implementation** | Defined in campaign configuration. | Tracked via Stripe events. |
## Summary: key differences
1. **In‑app referral UI vs snippet‑only**: Cello includes an embedded panel; Rewardful provides tracking APIs.
2. **Notifications**: Cello includes in‑app and email journeys; Rewardful relies on webhooks to power your own stack.
3. **Attribution**: Cello is server‑first via Stripe metadata; Rewardful defaults to client conversion calls (server hardening is possible).
4. **Campaigns**: Cello supports multiple reward rules per campaign; Rewardful focuses on a single reward type/rate.
5. **Payouts**: Cello provides in‑app payout flows; Rewardful tracks balances and leaves payout UX external.
Select the option that best aligns with your integration model (in‑app vs external), attribution requirements (server‑side vs client‑side), and operational preferences (built‑in journeys vs custom tooling).
# Fraud Detection
Source: https://docs.cello.so/guides/fraud-detection
Cello provides automated capabilities to detect and automatically mitigate potential cases of self-referrals and fraudulent activity
Cello provides automated capabilities to detect and automatically mitigate potential cases of self-referrals and fraudulent activity. With Cello, you can maintain complete control of how any potential cases are handled, either by automatically rejecting or reviewing some on a case-by-case basis.
### Reviewing potential cases
Potential cases of self-referrals or other fraudulent activity are flagged in the Cello portal under the **[Review Referrals](https://portal.cello.so/manage/reviewreferrals)** section. You can then see all cases that are **In Review** or **Completed** using the filters at the top of the table.
### Automation and risk factors
Cello automates detection based on a number of factors to determine the potential risk of fraudulent activity. A complete list can be provided upon request. To see the individual risk factors that are available, you can hover over the status column for a referral.
Note that risk factors can change over time during the initial 30 day review period.
### Manually accepting or rejecting
For pending referrals, you can manually accept or reject them at any time by clicking on the **Review** button and selecting your choice. You can optionally provide additional reasons for accepting or rejecting. This information is used by Cello to improve and customize detection.
When reviewing transactions manually, we recommend looking for the following factors:
* Issuing chargebacks or canceling within a short amount of time
* Unusual patterns of usage
* Is the referrer still a paying user?
### Payout delays
Long payout delays are typically not required. Programs using spaced rewards with low percentages naturally have less exposure, and Cello automatically cancels pending rewards when refunds occur.
If your program requires additional protection, Cello can configure a longer waiting period before rewards are paid out. Contact your CSM or [support@cello.so](mailto:support@cello.so) to set this up.
You can review fraud analysis from your own AI client using [`cello_get_fraud_analysis`](/mcp/tools#cello_get_fraud_analysis) via the [Cello MCP](/mcp/growth/use-cases).
# Introduction
Source: https://docs.cello.so/guides/introduction
Your complete playbook for building and optimizing successful referral programs with Cello
Welcome to the Cello Growth Guides – your comprehensive resource for maximizing the impact of your referral program. These guides are designed specifically for growth managers, marketing leaders, and customer success teams who want to turn their users into their most valuable acquisition channel.
## What You'll Find Here
Our guides are organized into strategic areas that address the full lifecycle of referral program management, from initial setup to advanced optimization techniques.
### Campaign Management
**Set up reward structures that drive results**
* [Campaign Setup](/guides/campaigns/setting-up-campaigns) – Configure reward percentages, caps, and payout rules that motivate both referrers and new users
* Master symmetric reward strategies that balance **referrer incentives** with **new user discounts**
### User Experience Optimization
**Create seamless referral experiences that users love**
* [Referral Component Overview](/guides/user-experience/overview) – Understand all the features available in your referral widget
* [Component Configuration](/guides/user-experience/configuring-referral-component) – Customize appearance, messaging, and behavior
* [Landing Page Optimization](/guides/user-experience/optimizing-landing-pages) – Design high-converting referral landing pages
* [In-app and Email Notifications](/guides/user-experience/referral-notifications-and-emails) – Keep users engaged with timely updates
* [Personalized Experiences](/guides/user-experience/personalizing-referrals) – Add referrer names and custom messages
* [New User Discounts](/guides/user-experience/new-user-discounts) – Configure discount strategies for referred users
### Growth Best Practices
**Proven strategies to increase sharing and conversions**
* [Contextual Sharing](/guides/best-practices/contextual-sharing) – Prompt referrals at high-intent moments
* [Behavior-Based Triggers](/guides/best-practices/behavior-based-triggers) – Automate referral prompts based on user actions
* [User Activation Improvement](/guides/best-practices/improve-user-activation) – Convert more referrals into active users
* [Conversion Optimization](/guides/best-practices/optimizing-signup-conversion) – Maximize signup rates from referral traffic
### Partner Program Management
**Scale beyond user referrals with strategic partnerships**
* [Partner Program Overview](/guides/partners/partner-overview) – Set up affiliate and influencer programs
* [Partner Portal](/guides/partners/partner-portal) – Provide partners with dedicated dashboards and resources
* [Partner Management](/guides/partners/manage-partners) – Invite, onboard, and manage your partner network
### Attribution & Reporting
**Track performance and prove ROI**
* [Auto-Attribution](/guides/attribution/auto-attribution) – Automatically track referral conversions
* [CRM Integration Reports](/guides/attribution/hubspot-reports) – Connect referral data to HubSpot, Salesforce
* [Payment Platform Reports](/guides/attribution/stripe-reports) – Track revenue attribution through Stripe
### Data & Integrations
**Connect Cello to your growth stack**
* [Integration Status](/guides/support/portal/integration-status) – Get a real-time health view of your integration
* [Event Feed](/guides/support/portal/event-feed) – Monitor and debug your integration events
## Getting Started
If you're new to Cello or referral programs:
1. **Start with [Campaign Setup](/guides/campaigns/setting-up-campaigns)** to configure your reward structure
2. **Review [User Experience Overview](/guides/user-experience/overview)** to understand the referral component features
3. **Implement [Contextual Sharing](/guides/best-practices/contextual-sharing)** strategies to increase sharing rates
4. **Set up [Attribution](/guides/attribution/auto-attribution)** to track and reward successful referrals
## Need Help?
Each guide includes actionable steps and real examples from successful Cello customers. For additional support:
* Contact your Customer Success team via Slack
* Email [support@cello.so](mailto:support@cello.so) for technical questions
* Schedule a strategy session to review your program performance
These guides focus on growth strategy and program optimization. For technical implementation details, visit our [Developer Documentation](/referral-component/quickstart) and [API Reference](/api-reference/introduction).
# Manage Partners
Source: https://docs.cello.so/guides/partners/manage-partners
Cello allows you to manage your partners and affiliates to provide them with a full portal experience
Cello allows you to manage your partners and affiliates, providing them with a full portal experience for accessing their affiliate links, tracking referral progress, and receiving rewards for successful referrals. Inviting partners takes only a few clicks.
## Inviting New Partners to Your Program
1. Navigate to the **Partner Users** page in the Cello Portal and click **Add New Partner** in the upper right.
If you don't see the **Partner Users** or **Partner Resources** pages, check that the **Sandbox / Production** toggle in the upper left of the portal is set to **Production**. Partner pages are only visible in Production mode. If you've switched to Production and the pages are still missing, contact Cello support to have the necessary permissions applied to your account.
2. Enter the **email** and **campaign** you want to assign to the partner user. **Product User ID** is optional and should be added if you want to update an existing user to partner status.
**What is the Product User ID?** It is the unique identifier your product already assigns to that user - the same ID you pass as `productUserId` when generating the JWT token and booting the Referral Component. You can look up an existing user's ID in the **Referrer Id** column of the Referrals dashboard in the Cello Portal.
**When to provide it:** always fill in the Product User ID when the person you're inviting as a partner is already a user in your product. This ensures their existing referral code (`ucc`) is retained through the transition, so their referral link stays the same.
If you do not specify the Product User ID, Cello automatically creates a new identifier, and the user will end up with two separate referral links: one inside your product and one in the Cello partner portal, with split referral tracking.
3. Click **Send Invite**.
4. The partner user will receive a branded email invitation with instructions to register.
5. From this email, they can click a link to register quickly, either using **sign up with Google** or by providing an email and password. (Note: If a user signs up using email, they can later use Google to sign in with the same email address.)
# Overview
Source: https://docs.cello.so/guides/partners/partner-overview
Cello allows you to set up and manage all aspects of your own partner program, unifying user referrals and partners in one platform
Cello allows you to set up and manage all aspects of your own partner program, unifying user referrals and partners in one platform. All partner features are offered as part of the core Cello platform without additional technical effort needed.
Cello provides support on setting up your partner program or if you have an existing program that you would like to transfer to Cello. Feel free to contact our support team via Slack to guide you through the setup.
You can find a [walkthrough of the Partner Portal](https://www.loom.com/share/f8f5c502832b485da6ffb1186bd00d89?sid=2f71041c-ab22-4088-9c71-e19757c229d8) end-user experience here
## Steps for setup:
#### 1. Integrate Cello
If you are already using Cello for user referrals, there is no additional technical effort required to enable partners. If you are not yet using Cello, your teams will need to setup a [landing page for referrals](/guides/user-experience/optimizing-landing-pages) and [referral conversion tracking](/attribution/introduction) to automate rewarding.
#### 2. Set Reward Structure
To incentivize affiliates, influencers, and other partners to share your product, you can offer partners exclusive reward structures. Lifetime rewards and one-off compensation components increase the engagement of your partners and make the program more attractive. You can also see what other customers are doing in [this slide deck](https://app.pitch.com/app/presentation/e0b19633-db69-4984-840e-59184b90c2cf/1f57b9cf-0721-401e-89e8-f14f4f84980c/8ee44ff9-aac6-49cb-84e8-d31e1b118d89)
#### 3. Invite Partners
The Cello [Partner Portal](/guides/partners/partner-portal) provides partners with a full experience that includes details of your program, their personal sharing link, updates on the status of their referrals and rewards. You can invite new partners to your program from the [Manage Partners](/guides/partners/manage-partners) page in the Cello portal.
## Optional steps:
For an optimal partner experience, we recommend several best practices to improve performance. You can find more information [here](https://pitch.com/v/h7cf3r/99812f2e-e331-4c58-b84b-009723fc3220).
**1. Create a Media Kit (Optional)**
We recommend providing [media kits](https://pitch.com/v/h7cf3r/46528f51-d7b5-4e45-a94c-e4521d3b55b1) for partners on your ambassador page. Prewritten messages and branded assets make sharing frictionless for your partners and allows you to ensure brand consistency across all collaborations.
**2. Create an Ambassador Landing Page (Optional)**
Implementing a dedicated [ambassador landing page](https://pitch.com/v/h7cf3r/467b3ed2-b50f-4dd9-a280-e358ce2e8ea3) for your partners provides clear guidance on how they can get access to your program, what your program offers, and guidelines for collaboration. Moreover, an ambassador landing page can allow you to effortlessly collect applications from potential partners interested in joining your program.
## Transfer an existing program (optional):
It's easy to transfer an existing partner program using another product or in-house tools to Cello. Once transferred your existing partners can get rewarded on Cello and use the new links to make referrals. Cello can share details and assist upon request.
# Partner Portal
Source: https://docs.cello.so/guides/partners/partner-portal
The partner portal provides full portal experience for accessing their affiliate link, tracking progress on referrals, and getting rewarded for successful referrals
The partner portal provides full portal experience for accessing their affiliate link, tracking progress on referrals, and getting rewarded for successful referrals. Inviting partners only take a few clicks.
Accessing Program Details
Partners can access program details by clicking on **Your Sharing Link** on the left navigation. All details are provided from the Cello referrals component, in the same way your users access Cello from within your application.
## Getting Rewarded
Clicking on **Your Reward Details** opens the Cello component with details of all rewards. Partners who have not provided payment details can do so from this page.
## Partner Analytics
Cello provides partners with detailed analytics for tracking program performance on their referrals. An overview is provided on the **Home** page, with more details provided on the full funnel from the **New User Signups** and **New User Purchases** page .
# Partner Resources
Source: https://docs.cello.so/guides/partners/partner-resources
This guide is designed to help Partner Managers effectively use the Partner Resources feature to add, manage, and share guides and resources with partners
This guide is designed to help Partner Managers effectively use the Partner Resources feature to add, manage, and share guides and resources with partners.
The Partner Resources section is a dedicated space for creating and managing guides and content that can be shared with your partners. It allows you to:
1. Add new guides with detailed descriptions and cover images.
2. Organize resources for easy partner access.
3. Provide links to videos, articles, or pages to help partners promote your products or services.
### Adding a New Guide
If no resources are added yet, you'll see a placeholder message encouraging you to create your first guide.
1. **Click the "Add New Guide" Button**:
* Located at the top right of the Partner Resources dashboard.
2. **Fill Out the Form**:
* **Title**: Enter a clear and concise title for the guide.
* **Description**: Provide a brief description of the guide's purpose.
* **Cover Image**: Upload an image to visually represent the guide. Use the "Select files" area to drag and drop or browse files from your machine.
* **Link**: Add a URL to direct partners to the guide's content, such as a video, article, or webpage.
3. **Save the Guide**:
* Click the **Add** button to save the guide.
💡 **Once added, guide is instantly visible for your partners.**
### Managing Existing Guides
Once guides are added, they appear as individual cards in the Partner Resources dashboard. Each card includes:
1. **Title and Description**: A quick summary of the guide.
2. **Actions**:
* **Edit**: Use the pencil icon to update the guide's details.
* **Delete**: Use the trash icon to remove the guide.
3. **Call-to-Action Buttons**:
* Depending on the link type, buttons like "Watch Video," "Read Article," or "Go to Page" will appear, directing users to the linked resource.
## Best Practices for Creating Guides
1. **Use Descriptive Titles and Images**:
* Ensure titles are specific and relevant to the guide's content.
* Upload visually appealing and professional cover images to attract attention.
2. **Organize by Purpose**:
* Group guides by themes, such as "Overview," "Sharing Tips," or "Content Creation Examples," for easier navigation.
3. **Test Links**:
* Verify that all links lead to the correct resource and are accessible to partners.
## Example Use Cases
### Case 1: Sharing Partner Links
Create a guide titled **"Overview"** with a description like: "Share your partner link with contacts and followers." Include a video tutorial link to help partners understand how to use their referral links.
### Case 2: Promoting Your Product
Add a guide titled **"Share"** with instructions on promoting your product. Link to an article that offers best practices for sharing content on social media.
### Case 3: Content Creation Support
Provide a guide titled **"Content"** with social media post templates and examples. Link to a page where partners can download assets or view tips.
## Frequently Asked Questions (FAQs)
### Q: Can I reorder the guides?
A: Currently, guides are displayed in the order they were added. You may delete and recreate guides to adjust the sequence if necessary.
### Q: What file formats are supported for cover images?
A: Common image formats like JPG, PNG, and GIF are supported.
### Q: How do I ensure partners can access the links?
A: Use publicly accessible links or grant appropriate permissions to ensure partners can view the resources.
***
# Support FAQ
Source: https://docs.cello.so/guides/support/faqs
Frequently asked questions about integrating, running, and troubleshooting Cello
## Partners & affiliate programs
Switch to the **Partner Campaign** in the upper-right of the Cello portal. Your dashboard will filter to display the affiliate/partner program numbers. Note: ensure you have the toggle in the upper-left toggled to production.
See [Partner resources](/guides/partners/partner-resources).
Partners and affiliates are added via the [Cello Portal](https://portal.cello.so/partners/management). There is no API endpoint for bulk partner creation today.
For complex migrations or large partner onboarding, Cello works directly with customers to handle bulk imports. Contact your CSM to coordinate.
Cello's attribution is link-based - referral links with a `ucc` parameter are the supported tracking method. Standalone coupon-code tracking (where a code is shared and attributed at checkout without a referral link) is not available today.
If your referrers promote through channels where links aren't practical (podcasts, video, print), consider using a short, memorable referral URL instead. If coupon-code-only tracking is important for your program, share the use case with your CSM.
The **Product User ID** is the unique identifier your product already assigns to that user - the same value you pass as `productUserId` when generating the JWT token and booting the Referral Component. It is not a Cello-generated ID.
To look up an existing user's ID: go to the **Referrals** dashboard in the Cello Portal. The **Referrer Id** column shows the `productUserId` for each referrer.
You should provide the Product User ID whenever the person you're inviting as a partner is already a user in your product. This links their new partner identity to their existing referrer identity, so their referral link (`ucc`) stays the same and their referral tracking remains unified. If you skip it, Cello creates a new identity and the user ends up with two separate referral links.
In general, Cello is designed to be seamless across **user referrals** and **partner/affiliate referrals**:
* Users access Cello via the in-product Referral Component.
* Partners can access a separate Cello partner portal, and can also use the in-product Referral Component.
* The same campaign code can be shared across your product and the partner portal. To do so: when adding the partner in the Cello admin portal, ensure the partner is mapped using their `productUserId` so they retain the same UCC/link across your product and the Cello partner portal.
If the partner is mapped correctly to the existing user via `productUserId`, the intent is for the partner to retain their current UCC and associated performance history across your product and the Cello partner portal.
No. When a referrer is upgraded to a partner campaign, existing signups keep the reward terms from the campaign that was active when they signed up. Only new signups after the upgrade use the new campaign’s reward structure. This grandfathering is handled automatically.
No. Partners can still use the Cello widget to access their referral link and rewards experience.
The partner pages are only visible in **Production** mode. Check the **Sandbox / Production** toggle in the upper left of the portal and make sure it is set to **Production**. If the pages are still not visible after switching, contact Cello support to have the necessary permissions enabled on your account.
## Attribution & cookies
Attribution is the process of tracking and linking new user signups and purchases back to the referrer who originally shared the referral link. It ensures referrers are correctly rewarded and that your referral analytics stay accurate.
Cello's attribution works in four steps:
1. **Referral link sharing** - referrers share links containing a unique referral code (`ucc` parameter)
2. **Landing page capture** - your website or app captures and stores the `ucc` as a first-party cookie
3. **Signup tracking** - new user registrations are linked to their referrer via the stored `ucc`
4. **Purchase tracking** - revenue events are attributed back to the original referrer
Attribution is available for both web and mobile signup flows. For mobile apps, the referral code is passed through deep-link attribution providers (e.g., Branch.io, AppsFlyer) so it persists through app store redirects and installation.
**Related docs**
* [Attribution introduction](/attribution/introduction)
* [Web attribution](/attribution/for-web)
* [Mobile attribution](/attribution/for-mobile)
The Attribution Library ([Attribution JS](/sdk/client-side/attribution-js-introduction)) is a lightweight JavaScript library that captures the referral code (`ucc`) from referral links and stores it as a first-party cookie. This cookie persists for 3 months, which is critical because users often don’t sign up immediately - they may click a referral link, browse your site, leave, and return days later before converting.
Without the library, the `ucc` parameter would be lost as soon as the user navigates away from the landing page URL, breaking attribution for these indirect signups.
Beyond persistence, the library also provides APIs to:
* **Retrieve the referral code** - `getUcc()` for passing into signup and purchase events
* **Get the referrer’s name** - `getReferrerName()` for personalizing landing pages
* **Access campaign config** - `getCampaignConfig()` for displaying referral discounts
* **Manage cookie consent** - built-in methods for privacy compliance
You can install it via an [embedded script tag](/sdk/client-side/embedded-script-tag) or [Google Tag Manager](/sdk/client-side/google-tag-manager).
**Related docs**
* [Attribution JS introduction](/sdk/client-side/attribution-js-introduction)
* [Web attribution](/attribution/for-web)
You could technically store the `ucc` as a cookie yourself, but the Attribution Library ([Attribution JS](/sdk/client-side/attribution-js-introduction)) does significantly more than cookie storage:
* **Automatic form injection** - the library auto-injects a hidden `ucc` field into signup forms, so attribution works without custom form logic
* **API access** - provides `getUcc()`, `getReferrerName()`, and `getCampaignConfig()` methods for programmatic access to referral data, referrer personalization, and discount display
* **Fraud detection signals** - the script collects telemetry that feeds into Cello's [fraud and self-referral detection](/guides/fraud-detection), which is not possible with a plain cookie
* **Cross-session persistence** - stores the `ucc` as a first-party cookie with a 3-month lifetime, handling delayed and indirect signups automatically
Skipping the library means you would need to manually parse the `ucc` from the URL, store it, inject it into forms, and lose fraud detection capabilities. For most integrations, using the library is the simpler and more reliable path.
**Related docs**
* [Attribution JS introduction](/sdk/client-side/attribution-js-introduction)
* [Attribution JS usage & API](/sdk/client-side/attribution-js-usage)
Yes. The Attribution Library stores the referral code in first-party cookies (`cello-referral` and `cello-productId`) that are scoped to your root domain. This means:
* **Across pages** - the cookies are available on every page of your site, as long as the attribution script is installed on each page (recommended in the `` tag site-wide)
* **Across subdomains** - the cookies work across subdomains of the same root domain (e.g., `www.example.com` and `app.example.com`). Cross-subdomain attribution is supported natively
The cookies persist for 3 months, so they survive across sessions and return visits.
Note: cookies are **not** shared across different root domains (e.g., `example.net` and `example.app`). If your landing page and product use different root domains, see the FAQ below on cross-domain strategies.
**Related docs**
* [Manage cookie consent](/landing-pages/manage-cookies)
* [Attribution JS introduction](/sdk/client-side/attribution-js-introduction)
The Attribution Library stores the `ucc` in a first-party cookie scoped to the root domain where it was set. This means the cookie set on `example.net` is **not** automatically available on `example.app` - browsers enforce this as a security boundary.
If your landing page and product use different root domains, here are your options (in order of preference):
1. **Use the same root domain** (recommended) - host your landing page on a subdomain of your product domain (e.g., `www.example.app` for landing, `app.example.app` for the product). This makes attribution seamless with no extra work, since cookies are shared across subdomains of the same root domain.
2. **Persist the `ucc` in URLs across domains** - install the Attribution Library on both domains and ensure all links between them append the `?ucc={ucc}` parameter. This way the `ucc` is recaptured by the Attribution Library when the user arrives on the second domain.
3. **Build a custom cross-domain bridge** - implement server-side logic to store and forward the `ucc` when users transition between domains (e.g., pass it through your authentication or redirect flow so it’s available on the product domain at signup time).
**Related docs**
* [Web attribution setup](/attribution/for-web)
* [Attribution JS introduction](/sdk/client-side/attribution-js-introduction)
Yes. Cello's Attribution Library supports integration with cookie consent management platforms so that referral cookies are only stored after the user grants consent.
**Supported platforms:**
* **OneTrust** - fully supported. Cello enables the integration on their side; no setup required from you
* **CookieFirst** - coming soon
* **CookieBot** - coming soon
* **Civic Cookie Control** - coming soon
If your consent platform isn't listed above, you can use the **custom consent method** via the Attribution JS API:
```javascript theme={null}
// After user grants consent
window.CelloAttribution('allowCookies');
// If user withdraws consent
window.CelloAttribution('deleteCookies');
```
This gives you full control to integrate Cello's cookie handling with any consent management platform or custom consent flow.
**Related docs**
* [Manage cookie consent](/landing-pages/manage-cookies)
* [Attribution JS introduction](/sdk/client-side/attribution-js-introduction)
* **Direct signup**: user clicks a referral link and signs up immediately.
* **Indirect signup**: user clicks a referral link, navigates around, and signs up later from a different page.
For both, ensure attribution rules are followed so the referrer’s UCC is tracked and rewards are correctly attributed.
Yes, but Cello still needs to know *who* the referred user is before attributing a purchase. If you skip the standard signup flow, you'll need to send a `new-signup` or `sign_in` event via the [Cello API](/attribution/tracking-signups) before sending `invoice-paid` events - otherwise the purchase has no user to attribute to.
A common use case is **existing-user attribution**, where a current user clicks a referral link and you want to credit the referrer for their next purchase. The recommended approach:
1. **Check for a `ucc` on login** - not just on signup. Use `getUcc()` from the Attribution Library or read the `ucc` URL parameter directly.
2. **Validate the `ucc`** - call Cello’s [Referral Codes API](/api-reference/referral-codes/fetch-referral-code-info) to confirm the code is valid and identify the referrer.
3. **Prevent self-attribution** - compare the referrer’s `productUserId` with the logged-in user’s ID. If they match, ignore the `ucc`.
4. **Store the `ucc`** - save it in your database linked to the user, so it’s available when sending events.
5. **Send events to Cello** - send a `sign_in` event (to establish the attribution) followed by `invoice-paid` events as purchases occur.
**Related docs**
* [Track signups](/attribution/tracking-signups)
* [Track purchases](/attribution/tracking-purchase)
* [Fetch referral code info](/api-reference/referral-codes/fetch-referral-code-info)
If a referral wasn’t automatically attributed - due to a technical issue, missing metadata, or a user dispute - you can manually backfill it. The exact steps depend on your integration type:
**For Stripe or Chargebee webhook integrations:**
1. Get the referrer’s `cello_ucc` from the [Cello Portal](https://portal.cello.so) and the new user’s `new_user_id` from your system.
2. Add `cello_ucc` and `new_user_id` to the new user’s customer metadata in Stripe or Chargebee.
3. Cello will receive a `customer.updated` (Stripe) or `customer_changed` (Chargebee) event automatically.
4. If past invoices were already paid, resend the `invoice.paid` (Stripe) or `payment_succeeded` (Chargebee) events from within your payment platform’s dashboard.
**For Cello API integrations:**
1. Get the referrer’s `cello_ucc` and the new user’s ID.
2. Resend the signup event via the [POST /events API](/api-reference/generic-events/send-event).
3. Resend any past transaction events via the same API.
If events cannot be resent via API, Cello Support can accept manual reports - contact [support@cello.so](mailto:support@cello.so) for report templates.
**Related docs**
* [Manual Attribution guide](/guides/attribution/manual-attribution)
* [Track purchases](/attribution/tracking-purchase)
* [Stripe webhook](/integrations/webhooks/stripe-webhook)
* [Chargebee webhook](/integrations/webhooks/chargebee-webhook)
Yes, this is a supported pattern. Cello can handle flows where the payment gateway customer is created at checkout (purchase) rather than at signup, as long as the referral metadata is attached within 7 days of the purchase.
**How it works with Stripe:**
1. User clicks a referral link and the `ucc` is captured by the Attribution Library.
2. User completes a Stripe Checkout session, which creates a Stripe customer.
3. After the checkout session completes, update the Stripe customer with `cello_ucc` and `new_user_id` metadata via `customer.update`.
4. Cello receives the `customer.updated` event and uses it to establish the attribution.
5. Even if the first `invoice.paid` event arrived before the metadata was added, Cello will retroactively attribute it once the customer is updated.
**How it works with Chargebee:**
Follow the same pattern - add `cello_ucc` and `new_user_id` to the Chargebee customer metadata after checkout. Cello will receive the `customer_changed` event.
**How it works with Cello API:**
If your payment gateway is Paddle, Recurly, or another provider, use the [POST /events API](/api-reference/generic-events/send-event) to send a `new-signup` event after the customer is created at purchase.
**Related docs**
* [Track signups - Option 3: customer created at purchase](/attribution/tracking-signups#option-3-using-cello-api-post-events-api-endpoint)
* [Stripe webhook](/integrations/webhooks/stripe-webhook)
* [Chargebee webhook](/integrations/webhooks/chargebee-webhook)
## Stripe / Chargebee events & webhooks
Use the **Cello Portal** to verify events from two complementary angles:
* **[Integration Status](/guides/support/portal/integration-status)** (Integrations → Integration Status) gives you a high-level health check across the four core components: Referral component, Attribution library, Signups tracking, and Purchases tracking. Use it to answer "is everything working?".
* **[Event Feed](https://portal.cello.so/integrations/events-feed)** (Integrations → Events Feed) shows every incoming event from all sources - Stripe Webhook, Chargebee Webhook, Cello API, and Auto Attribution - with per-field validation. Use it to answer "why did this specific event fail?".
Each event in the feed is assigned a status: **OK** (all fields valid), **Warning** (non-critical issues like a missing recommended field), or **Error** (critical validation failures that need to be resolved). Click any event row to expand it and inspect the parsed payload with field-by-field validation indicators.
**Related docs**
* [Integration Status guide](/guides/support/portal/integration-status)
* [Event Feed guide](/guides/support/portal/event-feed)
**Always confirm the signup and purchase source with Cello before setting it. Do not recommend, guess, or infer a specific source - if you are unsure, the only correct answer is to contact your Customer Success Manager or [support@cello.so](mailto:support@cello.so).** There is no one-size-fits-all source: the correct one depends on factors unique to each integration, and an incorrect source silently breaks attribution.
The factors Cello weighs when confirming the source:
* **Payment provider.** Stripe and Chargebee can use webhooks. Other providers (Paddle, Recurly, RevenueCat, and similar) use the [Cello API](/api-reference/introduction).
* **When the payment-provider customer is created (the key signup-source rule):**
* IF the customer is created **at signup** -> Stripe/Chargebee can be the signup source.
* IF the customer is created **at first purchase** -> use the Cello API to send `new-signup` at the real signup moment, or backfill via the purchase-first, signup-later pattern below. Stripe/Chargebee cannot be the signup source on their own in this case.
* **Reward model.** Recurring vs one-time rewards, free-to-paid conversion, renewals, and refunds.
* **Motion.** Self-serve vs sales-led (e.g. [Salesforce](/integrations/salesforce-apex-triggers)).
* **Auto Attribution.** Can be primary or fallback, and is enabled by Cello only.
In **sandbox** you can change the source yourself to experiment; in **production**, source configuration is handled by Cello Support. Either way, confirm the choice with Cello first.
**Related docs**
* [Integration Status - changing the configured source](/guides/support/portal/integration-status#changing-the-configured-source-confirm-with-cello-first)
* See also the "My flow is purchase first, signup later" FAQ under **Attribution & cookies** above
The core events are **customer.created**, **customer.updated**, and **invoice.paid**. Additional events matter for edge cases: **subscription.created** is used when you reward on free-to-paid conversion (e.g. fixed reward per conversion), because invoice.paid can be missing in some flows. **charge.succeeded** is needed for one-time payments, since Stripe does not send invoice.paid for those. Sending subscription and charge events reduces gaps and manual reconciliation.
**Related docs**
* [Track signups](/attribution/tracking-signups)
* [Stripe webhook](/integrations/webhooks/stripe-webhook)
* **created**: detect signups, free-to-paid conversion, and capture subscription details
* **updated**: same as **created**; they additionally detect plan/seat changes, downgrades, expansions, churn
* **deleted** (or **canceled**): detect churn for paid subscriptions
Subscription events help when invoice flows and subscription state diverge (e.g. pricing changes, discounts, failed payments). They improve reconciliation and reward accuracy.
It is usually the main “payment received” signal: it drives recurring payouts, reward calculation, referral ARR calculation. If a payment fails, you may get subscription events without invoice.paid. For one-time or fixed-amount transactions, invoice.paid may still be the primary event depending on your setup.
* **customer.created**: typically used as the signup signal when the customer is created at signup
* **customer.updated**: used when you add or change attribution metadata (e.g. `cello_ucc`, `new_user_id`) after the customer already exists (e.g. at first purchase)
It indicates a payment. For subscriptions, invoice.paid is usually preferred for interval logic. For **one-time payments**, Stripe does not send invoice.paid, so charge.succeeded (or equivalent) is what Cello uses.
It signals refunds/cancellations so Cello can correct attribution and reward outcomes (e.g. cancel or adjust pending rewards).
* Send signup events via API.
* Send at least purchase events (e.g. invoice-paid equivalent) via the Cello API.
* Include amount (in **cents**), currency, and payment frequency (monthly vs annual) where applicable.
* Send renewal purchase events for continuous rewarding and referral ARR computation.
**Related docs**
* [API reference](/api-reference/introduction)
* [Track signups](/attribution/tracking-signups)
* [Track purchases](/attribution/tracking-purchase)
Connect the Stripe or Chargebee webhooks, add `cello_ucc` and `new_user_id` to the **customer object** (on customer.created or customer.updated, depending on when you create the customer). That customer update is the signup signal; subscription and invoice events are then used automatically for rewards.
**Related docs**
* [Track signups](/attribution/tracking-signups)
* [Stripe webhook](/integrations/webhooks/stripe-webhook)
* [Chargebee webhook](/integrations/webhooks/chargebee-webhook)
Use the **Cello API** from your backend to send conversion events (signups and purchases). You keep full control over which events are sent. First time purchases and renewals have to be shared as purchase events.
**Related docs**
* [Integration overview](/integration-overview)
* [API reference](/api-reference/introduction)
Send the **new user (referee)** ID. The referrer is identified via the UCC in the referral link; the referee is identified by this ID.
No. Cello only **listens** to webhook events. Your payment flow and architecture stay unchanged.
In the **Stripe webhook** context they are used interchangeably. Everywhere else (API, portal, docs) the product identifier is referred to as **productId**.
Check that amounts are sent in **cents** (or smallest currency unit). For example, 100 USD should be **10000**. If you send 100, Cello treats it as 1.00 USD.
Verify that the **Webhooks** section of the Cello Portal is populated with the correct Stripe signing secret. Without it, events will fail to authenticate. Ensure the signing secret matches the environment (staging vs prod). In a next step verify in your **Stripe dashboard** if the webhook url is correct and active. In the webhook event feed in Stripe's dashboard you can check if an event resulted in an error. You can also check the [Event Feed](https://portal.cello.so/integrations/events-feed) in the Cello Portal to see if events are arriving.
* Send `new-signup` events via the Cello API.
* Connect Stripe or Chargebee webhooks.
* Add `cello_ucc` and `new_user_id` to the **customer object** (on `customer.created` or `customer.updated`).
* Subscription and invoice events are detected automatically once the above is triggered - no need to add `cello_ucc` and `new_user_id` to subscription or transaction events.
There is no fully automated deduplication (similar to idempotency rules) yet. However, Cello has simple deduplication logic based on `new_user_id` + time difference + `invoiceId` (if provided).
* The current time-difference threshold for detecting duplicate `invoice-paid` events is **one minute**.
* Flagged events go through manual review, and the threshold is adjusted if there are too many false positives.
* There are scenarios where a customer can buy multiple subscriptions within a minute, so the threshold is kept conservative.
* If you can send an `invoiceId`, this significantly improves deduplication accuracy since it becomes the primary identifier for detecting duplicates.
## Rewards, payouts, taxes & billing
Currently, payouts are primarily via **PayPal** (and **Venmo** for the US on request). Bank transfer/SEPA are not offered today.
Most customers receive two separate invoices: one for the Platform Fee and one for the Advertising Fee, issued as part of Cello's Advertising Services. Invoices are typically issued monthly, though frequency and timing may vary based on your specific arrangement. For questions about your invoicing setup, contact your Cello representative.
Invoices are routinely sent around the middle of the month. Timing may differ based on your agreement or customer setup; your Cello contact can confirm the schedule that applies to you.
Cello campaign rules are designed to mitigate refund risk. Rewards are spaced and delayed so that during the delay period no payment is made, and when a subscription is refunded or canceled, future payouts can be automatically stopped. Programs set up with the recommended delay and spacing significantly reduce the risk of incorrect payouts.
If you believe rewards have been incorrectly issued, contact Cello support to discuss your options.
Referee discounts are usually implemented on your side. Many customers use Stripe discounts/coupons for this.
**Related docs**
* [New user discounts](/guides/user-experience/new-user-discounts)
Referral rewards are tied to the referred customer's activity, not the referrer's subscription status. If a referrer is no longer a user of your product, they can continue to access their referral dashboard and claim rewards through the Cello portal, provided they have access to the email address they used to register for rewards.
If the payment record is the same and the UCC metadata is preserved, rewarding can continue. One-time bonus rewards typically do not repeat.
If rewards are recurring percentage-based, the monthly reward typically stops when the subscription stops.
By default, rewards are prorated with the referrer reward spread over the payment period rather than paid on the full year upfront. Spaced rewards reduce risk and the need to introduce long payout delays, while also driving better referrer engagement through regular, recurring payouts. Some customers opt for front-loading, but this is generally not recommended as it reduces these benefits.
Cello's campaign design favors capping based on reward amounts rather than time horizons. User research across referral programs has shown that time-based caps are less well received by referrers and can reduce sharing rates.
If you have a specific requirement around time-based caps, discuss it with your CSM to explore what configuration options are available.
Cello supports multiple currencies for setting a campaign’s primary currency (configured in the portal).
Rewards are typically paid in the local currency supported by the referrer’s PayPal/Venmo account. Additional payout methods may be added in the future.
Users from countries not on the [supported payout list](/guides/user-experience/overview#reward-countries-and-payout-methods) (e.g. Mexico, Argentina) will not be able to set up a payout method - their country won't appear in the payout country dropdown. This is due to PayPal-side restrictions and compliance, tax, or regulatory rules. Cello cannot issue payouts to unsupported countries.
**Two approaches:**
1. **Hide the widget for unsupported countries** - pass `productUserCountryCode` in `cello.boot()`. If the country is unsupported, the component won't be shown to that user, preventing a confusing experience where they can share and earn but not receive payouts.
2. **Show the widget to everyone** - simpler to implement. Users in unsupported countries can still share and earn, but won't be able to complete payout setup. This avoids incorrectly hiding the widget from users who might actually be eligible.
**Why the hide approach is imperfect:** `productUserCountryCode` reflects the country in your system, which may differ from the user's actual PayPal payout country. Three scenarios:
* Product country unsupported, payout country also unsupported → hiding works correctly.
* Product country supported, payout country unsupported → user sees the widget and can share/earn, but can't receive payouts. No way to prevent this upfront.
* Product country unsupported, payout country supported → worst case: user is incorrectly hidden even though they could use Cello and receive payouts.
The right choice depends on how accurately your system reflects your users' actual locations.
**Edge case - PayPal account country vs. physical location:** A user may live in an unsupported country (e.g. Argentina) but hold a PayPal account registered in a supported country (e.g. Brazil). They should enter the address matching their PayPal account's registered country in the widget. Cello cannot issue payouts to unsupported countries regardless of physical location.
The country list shown to referrers during payout setup is not restricted because referrers and partners can earn rewards from any country they participate in. Restricting the list could prevent eligible referrers from setting up their payout details and receiving rewards.
If you need to limit who can participate in your referral program, you can control eligibility on your side by restricting which users see the Referral Component (e.g., only booting the Cello SDK for users in eligible regions).
The “Rewards earned” indicator reflects how much has been **credited to a PayPal account**. Until a referrer enters valid PayPal credentials, it will show \$0. Attributed rewards still accumulate in the rewards list below.
Referrers can see link views, signup history, and reward history in the **rewards tab** inside the referral widget.
For a more detailed dashboard, the Partner add-on provides a unified view of user referrals and affiliate programs on a single platform - with no extra technical setup required.
Referral activity should be visible in the Cello Portal dashboards. If data is missing, check the following:
* Open [Integration Status](/guides/support/portal/integration-status) and confirm the relevant tracking component (Signups or Purchases) is **Connected**. If it shows **Connected with warnings** or **Not connected**, that's where the problem is.
* Check the [Event Feed](https://portal.cello.so/integrations/events-feed) to verify events are arriving with the correct field values and passing validation
* Verify that signup and purchase events are being sent correctly and contain the expected `cello_ucc` and `new_user_id` values
* Confirm that the `productUserId` is consistent - if the same user signs up via different channels with different IDs, attribution may not match
* Check whether there have been any recent code changes that could affect how events are sent to Cello
Referrers are responsible for determining and complying with their own tax obligations. Cello may provide general informational materials and, where applicable, payout statements, credit notes, or similar documentation relating to rewards paid through the platform. Such information and documentation are provided for informational and record-keeping purposes only, are not exhaustive, and do not constitute tax, legal, or financial advice.
An invoice may be triggered within the first **3–5 days** after the close of the previous month. For cancellations, the corresponding credit-note rewards are triggered **14 days later**, which means they appear on the following month’s invoice.
Note: this adjustment only applies to the invoice covering rewards that Cello pays to referrers on your behalf - not to the platform/subscription fee invoice.
Cello rewards users on a daily basis, barring any additional reward-delay policy you have configured for your program. Because rewarding runs daily, it typically takes only a few days for referrers to receive their reward (assuming they add their payment details promptly).
* Cello allows you to select only **one default currency** for your rewards (configured in the Campaigns tab).
* Cello covers transfer and transaction fees, including currency conversion from the subscription event currency back to your nominated default currency.
* Referrers receive rewards in their PayPal account in your default currency. If they convert to a different currency (e.g. their local one), the exchange rate depends on PayPal's currency exchange and may include additional PayPal fees.
Grandfathering of the prior campaign when a referrer moves to a new one is handled automatically.
When a referee signs up through a referral link, the campaign rate at the time of signup is locked in for that referral. If you later move the referrer to a new campaign:
* **Existing signups** keep the reward structure from the campaign that was active when they signed up
* **New signups** (after the move) use the new campaign's reward structure
For major campaign updates, coordinate with the Cello team to ensure the transition is configured correctly for your program.
Moving a referrer between Partner Campaigns is handled automatically. The referrer keeps the same referral link, and:
* **Existing signups** retain the reward terms from the original campaign
* **New signups** (after the move) use the new campaign's reward structure
No data migration or new referral links are required. For major campaign updates, coordinate with the Cello team to ensure the transition is configured correctly for your program.
Cello's campaign design favors capping based on reward amounts rather than time horizons. User research across referral programs has shown that time-based caps are less well received by referrers and can reduce sharing rates.
If you have a specific requirement around time-based caps, discuss it with your CSM to explore what configuration options are available.
## Notifications & emails
Yes. Referrers will see an in-product notification prompting them to add payout details. If emails are enabled, they may also receive an email.
If a reward payment has not been received by one of your users, check that they have added payment details. Verify that account details, country, and other mandatory fields are filled out in the correct format.
All notification templates can be reviewed in the [Cello Portal](https://portal.cello.so/setup/notifications).
Yes - you can customize email templates self-serve directly in the [Cello Portal](https://portal.cello.so/setup/notifications). Open any email notification row to bring up the preview panel. Editable elements are highlighted on hover - click to change them.
The following can be customized:
* **Logo** - upload your company logo
* **Presentation image** - upload a hero image shown prominently in the email body
* **CTA link** - set the URL for the main call-to-action button
The **Welcome email** has one additional option: a second CTA link, letting you point new users to a specific page alongside the referral program link.
Changes apply across all email types at once. See [Email template customization](/guides/user-experience/referral-notifications-and-emails#email-template-customization) for full details.
For changes to email body copy or wording, contact your Customer Success Manager.
Go to **Notifications** in the [Cello Portal](https://portal.cello.so/setup/notifications) and click any email row to open the preview panel. Hover over the logo or image - a prompt will appear to click and replace it. Your changes apply across all email types automatically.
Welcome emails are typically sent to existing users after the referral program goes live, as well as to any new user who signs up after the program has gone live.
Common behavior:
* Sent on the 6th day after a new user first signs up to introduce the referral program and its details.
* Includes the referral link.
* Sent only once per user.\
\
Please review the [notifications tab](https://portal.cello.so/setup/notifications) in portal for copy and timing.
Email language is generally based on the last language used in the widget. Supported languages include English, German, Spanish, French, Dutch, Italian, Portuguese, Japanese, Danish, Slovak, and Romanian (more may be added on request).\
\
Enabling of email text in different languages requires config customization on the Cello side. Please coordinate with your Customer Success Manager for the additional languages required.
The dot is designed as an alerting mechanism to bring users into the widget when there’s something new. By design, it disappears once the user has seen the update.\
\
What we have seen work well for other customers are small "NEW" stickers on the right side of the menu items.
Typical sequence (often with \~1 day delay):
* `welcome-dot`: after first boot if user remains inactive
* `welcome-announcement`: a few days after first activity (or after the welcome-dot is displayed)
* `welcome-email`: about one week after first boot. All other emails are transactional, meaning they are only sent in order to update the referrer on their referral activity.
Note: actual timing can vary with payout delays and fraud/self-referral review. Please review the [notifications tab](https://portal.cello.so/setup/notifications) in portal for copy and timing.
Most common cause: your **Announcement Selector** matches more than one element, and Cello (which uses `document.querySelector`) anchored the announcement to a hidden or zero-sized one. A fulfilled `showAnnouncement` promise only means the SDK accepted the call - it does **not** mean the announcement is visible.
Run this in the browser console on the page where the announcement should appear:
```javascript theme={null}
document.querySelectorAll("")
```
* If the result is **more than one element**: narrow the selector. Cello uses the **first match in DOM order**, which may be a wrapper `
` and an inner `` share the same class), Cello will use the first one, which may be invisible. Either narrow the selector with a parent prefix or use an `id`. See [Troubleshooting: announcement not showing](#troubleshooting-announcement-not-showing) for the same diagnostic flow applied to announcements.
**Problem:** In single-page applications, elements are dynamically added/removed.
**Solution:** Keep the launcher element persistent in the DOM, use CSS to control visibility instead of conditional rendering.
## Add reward in launcher
1.5x activation rate3.5x sharing rate
Increase the sharing activity of your users by highlighting the reward directly in the referral launcher inside your menu item.
You can get the text for the menu launcher from [cello.js](/sdk/client-side/cello-js). Text will be localized to the [referrer's language](/guides/user-experience/overview#texts-and-language) and the reward amount is based on the [referrer's campaign](/guides/campaigns/setting-up-campaigns).
```javascript theme={null}
const labels = await window.Cello("getLabels")
const myCustomLauncherLabel = labels.customLauncher
```
## Disable Cello button
**Cello button** is a floating action button or bookmark style button provided as a default Referral Component launcher. When integrating a Customer Launcher, you may choose to disable the Cello button or keep it as an additional launcher.
You can choose to disable the default launcher, the Cello button. Go to [Referrer experience](https://portal.cello.so/setup/referrer-experience) settings in Cello Portal and **uncheck** "Show Cello Button".
## Configure notification badge
You can control the behaviour of the [notification badge](/guides/user-experience/referral-notifications-and-emails#alert-and-badge), which is attached to your Custom Launcher Selector by default:
This is the default behavior - the element opens the Referral Component on click and shows notification badges.
```html theme={null}
```
Add `data-cello-badge="false"` to hide the notification badge while keeping the element clickable.
Use this when you have multiple launchers but only want badges on some of them.
```html theme={null}
```
Add `data-cello-click="false"` to show the notification badge but prevent clicks from opening the panel.
Use this to show badge notifications on parent menu items for better visibility.
```html theme={null}
Settings Menu
```
The `data-cello-badge` and `data-cello-click` attributes are **optional modifiers**. If you want the default behavior (clickable with badge), you don't need these attributes at all.
**Testing notification badge position**
To trigger a notification badge to be shown on your Custom Launcher simply visit the referral link, of the same user you are testing with, e.g. `moonly.cello.so/pNRB1aYqArN` . A link visit will trigger a [view notification](/guides/user-experience/referral-notifications-and-emails#alert-and-badge) and a badge will be displayed.
## Add announcement selector
Announcement are callout style notifications used to [communicate important information](/guides/user-experience/referral-notifications-and-emails#announcement) to the user if we need to grab their attention and direct them to the Referral Component.
If the Cello button is disabled, the announcement needs to be anchored to one of your Custom Launchers.
Depending on the implementation, the Announcement Selector can be the same as for Custom Launcher, i.e. you can use exactly the same class ID, attribute selector or element ID.
Add this identifier as Announcement Selector under [Referrer Experience in Cello Portal](https://portal.cello.so/setup/referrer-experience).
**Critical requirements for Announcement Selector:**
* The selector **MUST resolve to exactly one element** when passed to `document.querySelector`. Cello uses the **first match** in DOM order and does not fall back to siblings.
* The matched element **MUST be visible and have a non-zero bounding box** at announcement time. `display: none`, `visibility: hidden`, or `width: 0 / height: 0` will cause the announcement to render against an invisible anchor.
* If multiple elements share the same class or attribute (e.g. a wrapper `
` and an inner `` both have `.my-launcher`), narrow the selector with a parent prefix or use an `id`.
* Verify in the browser console: `document.querySelectorAll("")` should return exactly one element with non-zero size. See [Troubleshooting: announcement not showing](#troubleshooting-announcement-not-showing).
Here you can also configure where you want announcement to be shown relative to the Announcement Selector by specifying **Announcement position** and **Announcement position offset.**
**Testing Announcement position**
While choosing Announcement Selector and choosing its position, you will want to see how it looks and make necessary adjustments. You can trigger an [announcement](/guides/user-experience/referral-notifications-and-emails#announcement) using [Cello JS](/sdk/client-side/cello-js-usage#showannouncement-announcement) `showAnnouncement(announcement)` method.
Example below will trigger the default welcome announcement:
```javascript theme={null}
window.Cello("showAnnouncement", { "type": "welcome-announcement-1" })
```
A fulfilled promise from `showAnnouncement` only means the SDK accepted the request. It does **not** mean the announcement is visible. If you see `Promise {: undefined}` in the console but no announcement on the page, see [Troubleshooting: announcement not showing](#troubleshooting-announcement-not-showing).
## Troubleshooting: announcement not showing
**Short answer:** The most common cause is that your **Announcement Selector** matches more than one element, and the first match in DOM order is invisible (zero-sized, hidden, or off-screen). Cello uses `document.querySelector`, which always picks the first match. Narrow the selector until `document.querySelectorAll()` returns exactly one visible element.
### How announcement positioning works
* Cello calls `document.querySelector()` once when an announcement is rendered.
* `document.querySelector` returns the **first matching element in DOM order**, not the most visible one.
* The matched element must be present in the DOM, have non-zero width and height, and not be `display: none` or `visibility: hidden` at the moment the announcement renders.
* A fulfilled `showAnnouncement` promise means the SDK accepted the request. It does **not** mean the announcement is visible to the user.
* Cello does not retry, fall back to siblings, or rescan the DOM if the matched element is invisible.
### Symptom: `showAnnouncement` returns a fulfilled promise but nothing appears
If your browser console shows:
```
> window.Cello("showAnnouncement", { "type": "welcome-announcement-1" })
< Promise {}
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
```
...this only means the SDK accepted the call. The announcement may still be invisible because of the selector resolving to a hidden or zero-sized element.
### Symptom map
| Symptom | What to run in DevTools | What it means | Fix |
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `showAnnouncement` returns fulfilled promise but no announcement appears | `document.querySelectorAll("").length` | If `> 1`, your selector is too broad. Cello picked the first match, which is likely invisible. | Use a more specific selector (add a parent class, or use an `id`). Update **Announcement Selector** in [Referrer Experience](https://portal.cello.so/setup/referrer-experience). |
| Announcement renders at the top-left of the viewport (0,0) | `document.querySelector("").getBoundingClientRect()` | If width/height is `0`, the matched element has no layout box. | Move the class/attribute to the visible element (icon/button), not a wrapper `
` or ``. |
| Announcement renders but is cut off or off-screen | Same as above; check `top` / `left` values | The matched element is off-screen or inside a scrolled container. | Anchor to an in-viewport element, or adjust **Announcement position offset** in the Portal. |
| `querySelectorAll` returns `0` matches | n/a | Element does not exist when the announcement renders, or the selector has a typo. | Confirm the element exists before `cello.boot()`; check `#`, `.`, `[]` prefixes match your element. |
| `querySelectorAll` returns `1` and the element is visible, but still no announcement | Inspect computed styles | The matched element may be missing `position: relative`. | Add `position: relative` to the matched element. |
### Related questions this section answers
* Why does `showAnnouncement` resolve but no announcement appears?
* Why is my Cello announcement invisible?
* Why does my Cello announcement render at the top-left of the screen?
* How do I fix "announcement selector matches multiple elements"?
* Why does Cello pick the wrong element for my announcement?
* Cello announcement not working / not showing / not appearing
# Introduction
Source: https://docs.cello.so/referral-component/introduction
Add a referral program to your application with Cello's embeddable referral component
The Cello Referral Component is an all-in-one referral experience that integrates directly into your web and mobile applications with just a few lines of code, enabling users to share referral links, track progress, and receive rewards.
## What is the Referral Component?
The Referral Component provides a complete referral experience within your product through:
* **First-time onboarding** that explains how your referral program works
* **Multiple sharing options** including link copy, social media, email, and QR codes
* **Progress tracking** showing clicks, signups, and earned rewards in real-time
* **Automated reward payouts** via PayPal, Venmo, and other payment methods
* **In-app and Email notifications** to keep users engaged with referral activity
Learn more about the [complete user experience](/guides/user-experience/overview).
## Key Features
* **Easy Integration** - Add as a floating button to launch the Referral Component or integrate into your existing menu with [custom launcher](/referral-component/custom-launcher)
* **Customizable Offer** - [Configure reward amounts, text, and program details](/guides/campaigns/setting-up-campaigns)
* **In-app Notifications** - [Alerts and announcements](/guides/user-experience/referral-notifications-and-emails) to keep users engaged with updates, promotions, and milestones
* **Email Notifications** - [Automated emails for signups, rewards, and milestones](/guides/user-experience/referral-notifications-and-emails)
* **Multi-language Support** - Available in 10+ languages with automatic detection
* **Cross-platform** - Native SDKs [for Web](/sdk/client-side/cello-js), [iOS, Android, and React Native](/sdk/mobile/introduction)
* **Dark mode** - Support for light and dark theme to match your app’s interface
## Installation Options
JavaScript library for React, Vue, Angular, and vanilla JS applications
Native Swift/Objective-C SDK with CocoaPods and SPM support
Native Kotlin/Java SDK with Gradle integration
Cross-platform mobile SDK for React Native apps
## How to Use
### Basic Implementation
1. **Load the SDK** - Add Cello script or SDK to your application
2. **Generate JWT Token** - Create server-side authentication token
3. **Initialize Component** - Boot with your product ID and user details
### Quick Example (Web)
```javascript theme={null}
// Load and initialize Cello
window.cello.cmd.push(async function (cello) {
await cello.boot({
productId: "YOUR_PRODUCT_ID",
token: "JWT_TOKEN",
productUserDetails: {
email: "user@example.com",
firstName: "John"
}
});
});
```
## Next Steps
Get started with the [Quickstart guide](/referral-component/quickstart) to integrate the Referral Component in under 15 minutes.
# Quickstart
Source: https://docs.cello.so/referral-component/quickstart
Learn how to install Cello Referral Component into your web application
This guide follows basic steps to **integrate Referral Component into your web application** using [Cello JS SDK](/sdk/client-side/cello-js-introduction).
[Cello JS SDK](/sdk/client-side/cello-js-introduction) is a browser-based JavaScript library compatible with all web frameworks that output HTML/JavaScript, including React, Next.js, Vue, and Angular.
For server-side rendering frameworks like Next.js, Cello interactions must occur client-side, not server-side.
## Prerequisites
First, you'll need your `productId` and `PRODUCT_SECRET` from your Cello dashboard's [Access Keys page](https://portal.cello.so/integrations/accesskeys) for the right environment (Sandbox or Production)
## Installation Steps
Follow these steps to integrate the Referral Component:
1. Load the Cello script from our CDN
2. Generate a JWT token server-side for user authentication
3. Initialize the component with the token to connect your user session
## Step 1: Load the script
Add the Cello script to your HTML. The script loads asynchronously to avoid blocking page rendering and can be included anywhere on your website. This approach is recommended for optimal SEO performance.
Add this script to the `head` tag of your HTML:
```javascript theme={null}
```
```javascript theme={null}
```
Once loaded, the script:
1. Registers `window.Cello` for communication between your page and Cello
2. Processes any queued commands from `window.cello.cmd` and maintains the command interface
### Content Security Policy (CSP)
Most applications don't need any changes here. This section only applies if your site enforces a Content Security Policy - if you don't set CSP headers, or your policy is permissive, you can skip it.
The Cello widget loads its script and assets from Cello domains at runtime. If your policy is restrictive, extend it with the following sources so the widget can load and run:
```text theme={null}
script-src https://assets.cello.so
connect-src https://share.cello.so
img-src https://cdn.cello.so https://p.typekit.net blob: data:
style-src https://use.typekit.net 'unsafe-inline'
font-src https://use.typekit.net https://p.typekit.net
```
* These directives extend your existing policy; if you use a restrictive `default-src`, keep all of the above explicit.
* Sandbox environments use the equivalent `*.sandbox.cello.so` domains (for example `https://assets.sandbox.cello.so` and `https://share.sandbox.cello.so`).
If the widget fails to load and your browser console shows errors like `Refused to connect because it violates the document's Content Security Policy`, see [Troubleshooting](#the-widget-doesnt-load-and-the-console-shows-content-security-policy-errors) below.
## Step 2: Generate a JWT token
Create a JWT token to securely connect your user's session to Cello. The token authenticates your application and provides user identity for generating unique referral links.
Generate JWT tokens server-side only. Never create tokens in the browser.
See [User Authentication](/sdk/client-side/user-authentication) for complete JWT token generation instructions.
## Step 3: Initialize the library
Initialize Cello with a single function call that includes your **product ID**, **JWT token**, and configuration options.
User details (email, first name) are required for fraud detection and features like email notifications and personalized messaging.
```javascript JavaScript theme={null}
window.cello = window.cello || { cmd: [] };
window.cello.cmd.push(async function (cello) {
try {
await cello.boot({
productId: "CELLO_PRODUCT_ID",
token: "REPLACE_ME",
language: "en",
productUserDetails: {
firstName: "Bob",
lastName: "Bobsky",
fullName: "Bob B Bobsky",
email: "bob@gmail.com",
},
});
} catch (error) {
console.error("Failed to boot cello:", error);
// Handle the error appropriately
}
});
```
This implementation works with asynchronous script loading. For complete configuration options, see [SDK Reference](/sdk/client-side/cello-js-usage#cello-boot-options).
After initialization, the library:
1. Adds a Cello button to your page or [connects to your custom element](https://docs.cello.so/referral-component/custom-launcher)
2. Creates a session to handle configured callbacks
**Congratulations!** You have successfully integrated Cello Referral Component!
Next, you can integrate Referral Component into your mobile applications:
***
## Controlling access to Referral component
If you want to enable the Cello referral component only to selected users or control its visibility dynamically, we provide the following options:
During the new referral program rollout with Cello, you may want to pilot with a small cohort of selected users. This can be achieved using our Named user whitelist.
All you need to do is to provide a list of selected users UIDs (productUserIds) to Cello. After they are added to the whitelist, only these users will have access to the Referral component until you are ready to rollout to your entire user base.
To control dynamically when and who sees the Referral component, you can use `show()` and `hide()` methods.
For example, you may decide to only show the Referral component after the user has completed onboarding. In that case, when a user first logs in, boot the component with `hideDefaultLauncher = true` configuration option. Then, when the onboarding is complete, use `cello.show()` to show the Cello button.
## Opening the Referral Component with a Link
You can automatically open the Referral Component with a link to your product by adding a `cello-open=true` param to your URL.
For example, add a link to the referral component to your email communication to help your users access the sharing options directly from the email.
If a user is redirected between URLs on login, make sure to re-attach this param to the final URL the user lands on in order to automatically open the Cello Referral Component.
You may also pass one of `invite`, `rewards` and `edit-payments` values to the param for the Referral Component to open a specific tab automatically e.g.:
```html theme={null}
https://your-product.com?cello-open=edit-payments
```
## Troubleshooting
### `Error 1200: Invalid Tenant`
The main cause for this error is that the used URL for the referral component, the product ID, and the Product Secret do not fit together. Make sure that you are using all three components of the same environment.
### `Error 1100: Invalid JWT token`
This means that the token is not valid and the main cause is that some of the attributes for constructing the token are not correct. You can decode your token using [https://jwt.io/](https://jwt.io/). After decoding, please check all the attributes against the requirements in User Authentication, specifically make sure that productUserId is a string, iat is valid, algorithm is H512 and the secret is the correct one for the environment you are using (Sandbox or Production)
### `Failed to load resource: the server responded with a status of 401 () [Cello]: "User is not authorized to load the widget"`
Most likely, the created JWT token is not valid. Common causes for this error are:
* The use of an incorrect `PRODUCT_SECRET`.
* The `productUserId` is not passed as a `string` in the payload for the JWT token creation.
* The use of an incorrect `productId`.
* `issuedAt` (`iat`) date cannot be older than 24h or set in the future.
### `Error: User is not authorized to load the widget`
Most likely you are not passing the `productUserId` as a `string` into the payload for the JWT token creation.
### `[Cello]: Cannot read properties of null (reading ‘__H')`
Most likely, you are using `http` in your script’s source: `src="http://assets.cello.so/app/latest/cello.js"` . Please use `https`.
### The widget doesn't load and the console shows `Content Security Policy` errors
If your browser console shows errors like these, your site's Content Security Policy (CSP) is blocking Cello resources:
```text theme={null}
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src ..."
Refused to load the script 'https://assets.cello.so/app/latest/cello.js' because it violates the following Content Security Policy directive: "script-src ..."
Fetch API cannot load https://share.cello.so/api/products/.../initialize/v2. Refused to connect because it violates the document's Content Security Policy.
Refused to load the image because it violates the following Content Security Policy directive: "img-src ..."
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src ..."
Refused to load the font because it violates the following Content Security Policy directive: "font-src ..."
```
Any error containing `violates the following Content Security Policy directive` or `violates the document's Content Security Policy` means your CSP headers need to be updated: add the Cello domains to your policy. The directive named in the error (`script-src`, `connect-src`, `img-src`, `style-src`, `font-src`) tells you which one is missing. See [Content Security Policy (CSP)](#content-security-policy-csp) above for the full list of required sources. Remember that sandbox environments use `*.sandbox.cello.so` domains.
## Frequently asked questions
### How much effort on tech side is the integration of Cello?
The complexity of integrating Cello can vary greatly, depending on your individual setup. Integration generally consists of frontend integration and user authentication. For our typical customer, setting up these components on a development environment requires hours, not days. The integration of attribution and reward automation is also relatively straightforward, though it depends on your existing setup.
### The Cello Floating Action Button is overlaying or covering another component within my product. What can I do?
Sometimes, the Cello Floating Action Button or the Referral Component might overlay another component in your product. Here's what you can do:
* **Adjust the z-index**: Cello can modify the z-index of the Floating Action Button or the Referral Component. This ensures that your other components can cover the Cello elements.
* **Hide the element**: Using the `cello.hide()` function, you can hide the Floating Action Button or the Referral Component when other components are open. Implement this function in your frontend.
You can also use the `cello.hide()` function to hide the Cello Floating Action Button on specific pages.
### Is it possible to hide the Cello Floating Action Button on certain pages?
You can hide the Cello Floating Action Button using the [cello.hide()](/sdk/client-side/cello-js-usage#hide) function when other components open. The implementation has to be done in your frontend.
### What exactly is the `productUserId` that is required in the user authentication?
The `productUserId` is the internal user id that you are using inside your product to uniquely identify users.
### Do you support server-side rendering?
Yes, for server-side rendering frameworks like Next.js, Cello interactions must occur client-side, not server-side.
### Do you support Angular?
As mentioned before, the Cello Referral Component is being loaded independently from your angular app and appends itself to `` tag. That being said, you need to just make sure that the injected HTML code is not being overridden by your angular app. This can be achieved in various ways. The safest choice would be not to use `` as your AppRoot element as it would create a race condition.
```typescript theme={null}
@Component({
selector: 'app-root',
...
})
```
```html theme={null}
```
The other option that we have seen customers implement is to load the cello javascript dynamically from your angular app, making sure that it is being loaded after angular is finished rendering its own components.
Here is an example that has been provided by one of our customers:
```typescript theme={null}
export interface CelloReferralPayload {
productId: string;
token: string;
showOnBoot: boolean;
productUserId: string;
language: string;
iat: string;
}
@Injectable({ providedIn: 'root' })
export class CelloReferralAdapter {
constructor(@Inject(DOCUMENT) private document: Document, @Inject(WINDOW) private window: Window) {}
async init(payload: CelloReferralPayload, isProd: boolean){
await this.loadScript(isProd
? 'https://assets.cello.so/app/latest/cello.js'
: 'https://assets.sandbox.cello.so/app/latest/cello.js');
await this.wait(1000);
(this.window as Window & {Cello: any}).Cello('boot', payload);
}
async wait(timeout: number) {
// due to a race condition a timeout is needed after initializing the script.
return new Promise(resolve => setTimeout(() => resolve(), timeout));
}
async loadScript(src: string): Promise {
return new Promise(resolve => {
const script = this.document.createElement('script');
script.onload = () => resolve();
script.type = 'module';
script.src = src;
this.document.head.appendChild(script);
});
}
}
```
***
### What about other frameworks?
Since Cello is a Javascript library running on browser, then it works naturally with all frameworks that end up resulting in a standard HTML/Javascript application. That includes React, Angular, Vue and all similar JS/TS libraries.
# Introduction
Source: https://docs.cello.so/sdk/client-side/attribution-js-introduction
JavaScript library for capturing and tracking referral codes throughout the conversion funnel
## What is Attribution JS?
Attribution JS is a lightweight JavaScript library that captures referral codes (`ucc`) from landing pages and maintains attribution throughout the user journey. When users click referral links and land on your website, this library ensures their referral source is properly tracked through signup and purchase events.
The library automatically:
* Detects referral code (`ucc`) query parameters from referral links
* Stores referral code (`ucc`) as first-party cookies for persistent tracking
* Attaches referral code (`ucc`) to signup forms
* Provides APIs to retrieve referrer information for personalization
## Installation Options
Choose your preferred installation method:
Add directly to your HTML pages with a script tag
Deploy through GTM without code changes
## Key Capabilities
Attribution JS enables you to:
### Referral Tracking
* **Capture referral codes** - Automatically detect and store `ucc` parameters from referral links
* **Retrieve referral data** - Access referral codes programmatically with `getUcc()`. Returns data from URL parameters or stored cookies (persisted for 3 months)
* **Form integration** - Auto-inject hidden referral fields into signup forms for seamless attribution
### Personalization & Campaigns
* **Get referrer names** - Display personalized messages using `getReferrerName()` to retrieve the name of the person who sent the referral
* **Access campaign config** - Use `getCampaignConfig()` to retrieve discount percentages (in decimal format: 0.1 = 10%) and duration in months for referred users
* **Dynamic discount display** - Show referral incentives based on campaign parameters with proper percentage conversion for user display
### Cookie Management
* **Privacy compliance** - [Manage cookie consent](/landing-pages/manage-cookies) with built-in methods
* **Allow cookies** - Enable cookie storage after user consent
* **Delete cookies** - Remove stored data when consent is withdrawn
* **Custom handling** - Implement your own consent flow with full API control
## How It Works
1. **User clicks referral link** - Link contains referral code (`ucc`) parameter (e.g., `yoursite.com?ucc=ABC123`)
2. **Script captures code** - Attribution JS detects referral code (`ucc`) and makes it accessible via `window.CelloAttribution("getUcc")` method
3. **Code persists** - Stored as first-party cookie for 3 months to handle return visits and cross-session attribution
4. **Methods available** - All attribution methods (`getUcc`, `getReferrerName`, `getCampaignConfig`) become available asynchronously after script initialization
5. **Signup attribution** - Referral code (`ucc`) is automatically attached to forms or retrieved programmatically for user registration
6. **Referral conversion tracking** - Pass the referral code (`ucc`) to Cello when tracking signups and purchases for complete attribution
## Next Steps
Choose between [embedded script](/sdk/client-side/embedded-script-tag) or [GTM installation](/sdk/client-side/google-tag-manager)
Test that referral codes are being captured correctly
Review all [available methods](/sdk/client-side/attribution-js-usage) for advanced functionality
## API Method Calls
All Cello Attribution methods use the unified `CelloAttribution` function syntax:
```javascript theme={null}
const ucc = await window.CelloAttribution("getUcc");
const referrerName = await window.CelloAttribution("getReferrerName");
const campaignConfig = await window.CelloAttribution("getCampaignConfig");
```
Attribution JS works alongside [Cello JS](/sdk/client-side/cello-js-introduction) for complete referral program functionality. While Attribution JS handles tracking and data retrieval, Cello JS provides the referral component interface.
# Usage
Source: https://docs.cello.so/sdk/client-side/attribution-js-usage
Below is the full list of commands to call the Cello Attribution JS SDK with.
## Script Initialization and Timing
The attribution script loads asynchronously. To avoid race conditions between script loading and your application calls, you have two options:
### Option 1: Queue Function (Recommended)
Add this JavaScript code before any calls to the library to queue commands until the script loads:
```javascript expandable theme={null}
window.CelloAttribution=window.CelloAttribution||function(t,...o){if("getReferral"===t)throw new Error("getReferral is not supported in this context. Use getUcc instead.");let e,n;const i=new Promise((t,o)=>{e=t,n=o});return window.CelloAttributionCmd=window.CelloAttributionCmd||[],window.CelloAttributionCmd.push({command:t,args:o,resolve:e,reject:n}),i}
```
### Option 2: Wait for Script Initialization
Alternatively, wait for the script to load before making calls:
```javascript theme={null}
document.addEventListener('DOMContentLoaded', async function() {
// Wait for script initialization
await new Promise(resolve => setTimeout(resolve, 1000));
if (typeof window.CelloAttribution === 'function') {
// Now safe to call methods
const ucc = await window.CelloAttribution("getUcc");
console.log('UCC:', ucc);
} else {
console.error('Cello Attribution script failed to load');
}
});
```
## `attachTo(formElement)`
Attaches hidden input to the passed `HTMLFormElement` node, or array of nodes.
```javascript theme={null}
window.CelloAttribution("attachTo", formElement);
```
### Accepts
Form(s) to attach the hidden input to
### Example
```javascript theme={null}
window.CelloAttribution("attachTo", document.querySelector("form"));
```
***
## `getCampaignConfig()`
Returns campaign configuration for new users, including discount information.
```javascript theme={null}
const campaignConfig = await window.CelloAttribution("getCampaignConfig");
```
### Returns
The campaign config object:
Duration of discount in months (e.g., 12 for 12 months)
Discount as decimal format (0.1 = 10%, 0.25 = 25%)
### Complete Example
```javascript theme={null}
const config = await window.CelloAttribution("getCampaignConfig");
console.log(config);
// Output:
// {
// newUserDiscountPercentage: 0.1, // 10% discount
// newUserDiscountMonth: 12 // For 12 months
// }
// Convert to display format:
const displayPercentage = config.newUserDiscountPercentage * 100; // 10
const message = `${displayPercentage}% off for ${config.newUserDiscountMonth} months`;
console.log(message); // "10% off for 12 months"
// Use in your UI:
document.getElementById('discount-banner').innerHTML =
`🎉 Special offer: ${displayPercentage}% off your first ${config.newUserDiscountMonth} months!`;
```
## `getReferrerName()`
Returns the referrer's name, if provided in the referral link.
```javascript theme={null}
const name = await window.CelloAttribution("getReferrerName");
```
### Returns
Referrer's name or `undefined`
## `getUcc()`
Retrieves the referral code `ucc` from the URL or the cookie (if cookies are enabled).
```javascript theme={null}
const ucc = await window.CelloAttribution("getUcc");
```
### Returns
Unique campaign code/referral code
## ~~`attachAll()`~~
> ⚠️ **Deprecated**: forms are now auto-detected and the hidden `ucc` input is injected automatically.
> Use [`attachTo(formElement)`](#attachto-formelement) for targeted cases instead.
```javascript theme={null}
window.CelloAttribution("attachAll");
```
***
## Troubleshooting
### Attribution Script Not Loading
```javascript theme={null}
// Check if script loaded correctly
if (typeof window.CelloAttribution !== 'function') {
console.error('Cello Attribution script failed to load');
// Implement fallback logic
// For example, proceed without attribution or show error message
}
```
### Methods Returning undefined or null
**Common causes:**
* Script not fully initialized - wait for DOM load or use the queue function
* Incorrect method syntax - ensure you use `window.CelloAttribution("methodName")`
* No referral data available - user didn't come from a referral link
**Solutions:**
```javascript theme={null}
// Always check return values
const ucc = await window.CelloAttribution("getUcc");
if (ucc) {
console.log('Referral code found:', ucc);
} else {
console.log('No referral code - user came directly');
}
// Handle missing referrer names gracefully
const referrerName = await window.CelloAttribution("getReferrerName");
const greeting = referrerName
? `Welcome! ${referrerName} referred you`
: 'Welcome to our platform';
```
### Testing Attribution Methods
Test all methods in your browser console:
```javascript theme={null}
// Test UCC retrieval
await window.CelloAttribution("getUcc");
// Returns: string (referral code) or null
// Test referrer name
await window.CelloAttribution("getReferrerName");
// Returns: string (referrer name) or undefined
// Test campaign config
await window.CelloAttribution("getCampaignConfig");
// Returns: { newUserDiscountPercentage: number, newUserDiscountMonth: number }
```
### Network and Loading Issues
```javascript theme={null}
// Check if attribution script is blocked
fetch('https://assets.cello.so/attribution/latest/cello-attribution.js')
.then(response => {
if (!response.ok) {
console.error('Attribution script blocked or unavailable');
}
})
.catch(error => {
console.error('Network error loading attribution script:', error);
});
```
### Common Integration Patterns
```javascript theme={null}
// Safe attribution check with fallbacks
async function initializeWithAttribution() {
try {
// Wait for script if needed
let retries = 0;
while (typeof window.CelloAttribution !== 'function' && retries < 10) {
await new Promise(resolve => setTimeout(resolve, 500));
retries++;
}
if (typeof window.CelloAttribution === 'function') {
const ucc = await window.CelloAttribution("getUcc");
const referrerName = await window.CelloAttribution("getReferrerName");
const campaignConfig = await window.CelloAttribution("getCampaignConfig");
return { ucc, referrerName, campaignConfig };
} else {
throw new Error('Attribution script not available');
}
} catch (error) {
console.warn('Attribution initialization failed:', error);
return { ucc: null, referrerName: null, campaignConfig: null };
}
}
// Use in your application
initializeWithAttribution().then(({ ucc, referrerName, campaignConfig }) => {
// Proceed with or without attribution data
if (ucc) {
console.log('Referral detected:', { ucc, referrerName, campaignConfig });
}
});
```
***
## ~~`getReferral()`~~
> ⚠️ **Deprecated**: use [`getUcc()`](#getucc) instead.
```javascript theme={null}
const ucc = window.CelloAttribution("getReferral");
```
### Returns
Unique campaign code/referral code
# Introduction
Source: https://docs.cello.so/sdk/client-side/cello-js-introduction
JavaScript SDK for embedding the Cello Referral Component in web applications
## What is Cello JS?
Cello JS is a browser-based JavaScript SDK that enables you to embed a fully-featured referral component directly into your web application. It provides a seamless way for your users to share referral links, track their performance, and receive rewards - all without leaving your product.
The SDK works with any web framework that outputs HTML/JavaScript, including:
* React, Next.js, and Gatsby
* Vue and Nuxt
* Angular
* Vanilla JavaScript applications
* Server-rendered applications (with client-side initialization)
## Getting Started
Follow our quickstart guide to integrate Cello JS in under 15 minutes:
Step-by-step instructions to add the Referral Component to your web app
## Key Capabilities
With Cello JS, you can:
### Core Functionality
* **Initialize the component** - Boot with user authentication and configuration
* **Manage visibility** - Show, hide, or programmatically open the component
* **Handle user sessions** - Update user details and manage authentication tokens
### Customization & Control
* **Change language** - Switch languages dynamically without re-initialization
* **Custom launchers** - Replace the default button with your own UI elements
* **Event callbacks** - React to component events like open, close, and token expiration
### Data & Communication
* **Retrieve referral links** - Get active referral codes and URLs programmatically
* **Access campaign config** - Fetch reward amounts and program details
* **Display announcements** - Show targeted messages and updates to users
### Advanced Features
* **Localization** - Access and customize all UI text labels
* **Country restrictions** - Automatically handle unsupported regions
* **Graceful shutdown** - Clean component removal when needed
## Mobile Applications
Looking to add referral functionality to your mobile app? Check out our native mobile SDKs:
Swift/Objective-C SDK for iOS apps
Kotlin/Java SDK for Android apps
Cross-platform mobile SDK
## Next Steps
[Follow the quickstart](/referral-component/quickstart) to add Cello JS to your application
[Set up JWT authentication](/sdk/client-side/user-authentication) for secure user sessions
[View all available methods](/sdk/client-side/cello-js-usage) in the usage documentation
# Usage
Source: https://docs.cello.so/sdk/client-side/cello-js-usage
Below is the full list of commands to call the Cello JS SDK with.
## `cello.boot(options)`
Initializes Cello Referral Component in your product.
Returns a promise that is resolved once the whole initialization process is finished or rejected if the boot command failed.
```javascript theme={null}
window.cello = window.cello || { cmd: [] };
window.cello.cmd.push(async (cello) => {
try {
await cello.boot(options);
} catch (error) {
// Handle the error appropriately
}
});
```
The solution above is designed so that you don't have to wait for the library to finish loading before you call the command - follow it and use the `window.cello` object to avoid that particular race condition.
For any other commands, or when you are sure that the command is called after the library has finished loading, you can opt to use the regular command syntax:
```javascript theme={null}
await window.Cello("boot", options);
```
### Accepts
The initialization options object:
Identifier of the product your users will refer.
You can obtain this in your Cello Portal.
Access token generated for the given user.
More in [User Authentication](/referral-component/user-authentication).
Product user details object. Required for select features
Email of the product user. This data is used in the personalization of the referral
experience, e.g. email notifications. Required for select features
First name of the product user.
This data is used in the personalization of the referral experience, e.g. email notifications and the [personalized message to referees](/docs/add-personalized-message).
Required for select features
Last name of the product user
Full name of the product user.
Use this option if you do not have first name and last name separately.
Product user country, if known. ISO 3166 Alpha-2 standard e.g. `DE`.
If the country is not on the [supported payout countries list](/guides/user-experience/overview#reward-countries-and-payout-methods), the Referral Component will not be booted for this user.
If no country is passed, Cello will still be booted.
Note: this uses the country your product has on file, which may differ from the user's actual PayPal payout country. See the [unsupported countries guidance](/guides/user-experience/overview#reward-countries-and-payout-methods) for tradeoffs before using this to gate visibility.
The language, in which the Referral Component will be loaded in ISO 639-1.
Default: `undefined`. If undefined, we use default language set for your product.
Note: the language must be enabled for your product by Cello - if the language is not enabled, this parameter has no effect and the component falls back to your product's default language. Contact Cello support to enable additional languages.
Set light or dark theme to match your app’s interface. Accepts `light` and `dark`.
Default: `light`.
Hides the entire default Cello launcher button. Use this when you want to provide your own launcher element via `customLauncherSelector`.
Default: `false`.
Note: this hides the **button**, not just the notification badge. To hide only the badge on a custom launcher element, add `data-cello-badge="false"` to your HTML element instead - see [Configure notification badge](/referral-component/custom-launcher#configure-notification-badge). There is no `hideDefaultBadge` boot option.
Callback event for when Referral Component widget is opened.
Callback event for when Referral Component widget is closed.
Callback handler for user interactions within the Referral Component.
Receives two parameters: `action` (string) and `payload` (any).
Currently supports `linkCopied` action which provides the copied URL as payload.
### Example
```javascript theme={null}
window.cello = window.cello || { cmd: [] };
window.cello.cmd.push(async (cello) => {
try {
const options = {
productId: "REPLACE_WITH_PRODUCT_ID",
token: "REPLACE_WITH_TOKEN",
language: "en",
productUserDetails: {
firstName: "Bob",
lastName: "Bobsky",
fullName: "Bob B Bobsky",
email: "bob@gmail.com",
},
onUserInteraction: (action, payload) => {
console.log('user interaction', action, payload)
if (action === 'linkCopied') {
const urlThatWasCopied = payload
// Handle the copied link (e.g., track analytics, show notification)
}
}
};
await cello.boot(options);
// Call other Cello commands, if necessary
} catch (error) {
console.error("Failed to boot cello:", error);
}
});
```
***
## `changeLanguage(language)`
Changes the Referral Component language at runtime without re-initializing it.
```javascript theme={null}
window.Cello("changeLanguage", "de");
```
### Accepts
The language string in ISO 639-1
## `setThemeMode(theme)`
Changes the Referral Component theme at runtime without re-initializing it.
```javascript theme={null}
window.Cello("setThemeMode", "dark");
```
### Accepts
The theme mode to apply. Accepted values are `light` or `dark`.
## `close()`
Closes Referral Component.
```javascript theme={null}
window.Cello.close();
```
***
## `getActiveUcc()`
Returns active `ucc` and invite `link` for the currently logged-in user.
```javascript theme={null}
const { ucc, link } = await window.Cello("getActiveUcc");
```
### Returns
The active ucc object:
Active unique campaign code or referral code for the current logged-in user
Personal invite link for the current logged-in user
## `getCampaignConfig()`
Returns campaign config values for the currently logged-in user.
```javascript theme={null}
const campaignConfig = await window.Cello("getCampaignConfig");
```
### Returns
The campaign config object:
Primary currency code
Percentage of attributed new revenue that will be paid as a reward
Maximum reward that can be earned per referral
Additional reward for signups to encourage more sharing
Additional reward for purchases to encourage more sharing
How long new users get a discount
The discount new users get
## `getLabels()`
Returns select labels used in our Referral Component.
```javascript theme={null}
const labels = await window.Cello("getLabels");
```
### Returns
The labels object:
A welcome text useful for building custom launchers
## `hide()`
Hides the Cello button or bookmark that launches the Referral Component.
```javascript theme={null}
window.Cello("hide");
```
***
## `open(destination)`
Opens Referral Component.
```javascript theme={null}
window.Cello("open", destination);
```
### Accepts
Optional destination string to open Referral Component on a specific tab or page:
* `"rewards"` - open Referral Component on the rewards tab
* `"edit-payments"` - open Referral Component on the payment details page
## `show()`
Shows the Cello button or bookmark that launches the Referral Component.
```javascript theme={null}
window.Cello("show");
```
***
## `showAnnouncement(announcement)`
Triggers an [announcement](/docs/notifications#announcement).
```javascript theme={null}
window.Cello("showAnnouncement", announcement);
```
### Accepts
### Example
Example below triggers a default welcome announcement:
```javascript theme={null}
const announcement = { type: "welcome-announcement-1" };
window.Cello("showAnnouncement", announcement);
```
A fulfilled promise from `showAnnouncement` only means the SDK accepted the request. It does **not** mean the announcement is visible to the user.
The announcement is anchored to the element matched by your **Announcement Selector** using `document.querySelector` (first match in DOM order). If that element is hidden, zero-sized, or off-screen, the announcement renders but is invisible. If you see `Promise {: undefined}` but no announcement, run `document.querySelectorAll("")` in the console - the result must be exactly one visible element.
See [Troubleshooting: announcement not showing](/referral-component/custom-launcher#troubleshooting-announcement-not-showing) for the full diagnostic flow.
## `shutdown()`
Shuts down connection to Cello and unmounts the Referral Component.
```javascript theme={null}
window.Cello("shutdown");
```
***
## `updateProductUserDetails(productUserDetails)`
Updates user details at runtime without re-initializing the Referral Component.
```javascript theme={null}
window.Cello("updateProductUserDetails", productUserDetails);
```
### Accepts
The product user details object
Email of the product user. This data is used in the personalization of the referral
experience, e.g. email notifications. Required for select features
First name of the product user.
This data is used in the personalization of the referral experience, e.g. email notifications and the [personalized message to referees](/docs/add-personalized-message).
Required for select features
Last name of the product user
Full name of the product user.
Use this option if you do not have first name and last name separately.
### Example
```javascript theme={null}
const productUserDetails = {
email: "bob@gmail.com",
firstName: "Bob",
lastName: "Bobsky",
fullName: "Bob Bobsky",
};
window.Cello("updateProductUserDetails", productUserDetails);
```
# Embedded Script Tag
Source: https://docs.cello.so/sdk/client-side/embedded-script-tag
Learn how to add Cello attribution script to your website
Attribution script helps you to capture referral code on your landing pages and make it available at signup to attribute referral conversions to the right referrers. In addition, it helps you to personalize messages for referees on the landing page, get discount information and detect potential fraud and abuse of your referral program.
**Script Loading Context:** The attribution script loads asynchronously and methods become available shortly after page load. All attribution methods use the unified `window.CelloAttribution("methodName")` syntax.
# Adding the script
You can add attribution script to your website like any other third party JavaScript code by inserting the following code snippet into the `` tag of **each page** on your website.
Make sure to use `type="module"` and `async` html params in the script tag
```javascript theme={null}
```
```javascript theme={null}
```
# Verifying the installation
Now that you have added the attribution script to your website, make sure that the `ucc` is available on the signup page. To verify, follow these steps:
## Step 1: Test with URL parameters
Add `?productId=test` and `?ucc=test` to your website URL:
```html theme={null}
https://yourwebsite.com/?productId=test&ucc=test
```
## Step 2: Check cookie storage
Open browser developer tools (F12) and verify these values are saved in cookies:
* `cello-product-id` should contain `test`
* `cello-referral` should contain `test`
## Step 3: Test method access
Navigate to your signup page and test the attribution methods from the browser console:
```javascript theme={null}
// Wait for script to load if needed
setTimeout(async () => {
try {
const ucc = await window.CelloAttribution('getUcc');
console.log('UCC test result:', ucc); // Should return 'test'
// Test other methods
const referrerName = await window.CelloAttribution('getReferrerName');
const campaignConfig = await window.CelloAttribution('getCampaignConfig');
console.log('Attribution methods working:', {
ucc,
referrerName,
campaignConfig
});
} catch (error) {
console.error('Attribution test failed:', error);
}
}, 2000);
```
Expected result:
```javascript theme={null}
Promise {: 'test'}
```
## Troubleshooting Installation Issues
### Script not loading
```javascript theme={null}
// Check if script loaded
if (typeof window.CelloAttribution !== 'function') {
console.error('Attribution script failed to load');
// Check network tab for loading errors
// Verify script URL is accessible
}
```
### Methods return undefined
* Wait longer for script initialization (try 3-5 seconds)
* Check browser console for JavaScript errors
* Verify script tag has `type="module"` and `async` attributes
* Ensure no ad blockers are interfering
### Cookie issues
* Check if cookies are enabled in browser
* Verify no GDPR/cookie consent is blocking storage
* Test in incognito mode to rule out extensions
**Installation successful** if methods return expected values and cookies are stored properly.
**Need help?** Check the [troubleshooting guide](/sdk/client-side/attribution-js-usage#troubleshooting) for common issues and solutions.
# Google Tag Manager
Source: https://docs.cello.so/sdk/client-side/google-tag-manager
How to add the Cello attribution script to your site using Google Tag Manager
Learn how to install the Cello attribution script on your website using Google Tag Manager (GTM). This method is ideal for teams who want to manage tracking scripts without direct code changes.
## Prerequisites
Before you begin, ensure you have:
* A Google Tag Manager account and container set up on your website
* Admin access to your GTM container
* Your Cello product ID from the Cello Portal
## Step 1: Create a New Tag
1. Log in to your Google Tag Manager account
2. Select the container for your website
3. Click **Tags** in the left sidebar
4. Click the **New** button to create a new tag
5. Click the **Tag Configuration** area
## Step 2: Add the Cello Attribution Script
1. Select **Custom HTML** as the tag type
2. In the HTML field, paste the following code:
```html theme={null}
```
3. Name your tag (e.g., "Cello Attribution Script")
## Step 3: Configure Consent Settings
If your GTM container uses a Consent Management Platform (such as Cookiebot, OneTrust, or CookieFirst) with Google Consent Mode, you must configure the tag's consent settings to prevent the script from being blocked.
1. In the tag editor, expand **Advanced Settings**
2. Scroll down to **Consent Settings**
3. Select **"No additional consent required"**
If you leave consent settings as **"Not set"** (the default), the tag inherits your container's consent behavior. When Consent Mode is active, this typically means the tag will be blocked until cookie consent is granted - causing the attribution script to **load inconsistently or not at all**.
Cello's attribution cookies are classified as [strictly necessary / essential cookies](/landing-pages/manage-cookies). They store only the referral campaign code (`ucc`) and do not track user identity. Many customers treat them as essential and load them independently of cookie consent banners. Consult your legal team to confirm this aligns with your compliance requirements.
## Step 4: Configure the Trigger
1. Click the **Triggering** area
2. Choose when you want the Cello attribution script to load:
### Option A: All Pages (Recommended)
* Select **All Pages** trigger
* This ensures referral codes are captured on any landing page
### Option B: Specific Pages Only
If you only want to track attribution on specific pages:
1. Click the **+** to create a new trigger
2. Select **Page View → Some Page Views**
3. Configure conditions (e.g., Page URL contains "landing" or "signup")
## Step 5: Save and Publish
1. Click **Save** to save your tag
2. Give your tag a descriptive name (e.g., "Cello Attribution - All Pages")
3. Click **Submit** to create a new version
4. Add a version description (e.g., "Added Cello referral attribution tracking")
5. Click **Publish** to make the changes live
## Step 6: Test Your Installation
### Method 1: Browser Console Test
1. Open your website in a new browser tab
2. Open the browser's developer console (F12)
3. Type the following command:
```javascript theme={null}
window.CelloAttribution('getUcc')
```
If the script is installed correctly, you should see a Promise response:
```javascript theme={null}
Promise {}
```
### Method 2: Test with Referral Parameters
1. Add the `?ucc=test123&productId=test` query parameters to your website URL:
```
https://yourwebsite.com/?ucc=test123&productId=test
```
2. Check that the referral cookies are being set in your browser:
* Open Developer Tools → Application → Cookies
* Look for `cello-referral` and `cello-product-id` cookies
3. Test `ucc` retrieval in the console:
```javascript theme={null}
window.CelloAttribution('getUcc').then(ucc => console.log('ucc:', ucc))
```
Expected output: `ucc: test123`
### Method 3: GTM Preview Mode
1. In GTM, click **Preview** to enter debug mode
2. Visit your website - you should see the GTM debug panel
3. Verify that your "Cello Attribution Script" tag is firing on the correct pages
**Success indicators:**
* Cello attribution tag fires in GTM preview
* `window.CelloAttribution` function is available in console
* `ucc` cookies are set when visiting with referral parameters
* `getUcc()` method returns referral codes correctly
## Troubleshooting
### Attribution script loads inconsistently
If the Cello attribution script only loads on some page views (works on one refresh but not the next), this is almost always caused by **Google Consent Mode** blocking the tag.
**Why it happens:** When your GTM container has Consent Mode configured, the default consent state is set to "denied." If the Cello tag's consent settings are left as "Not set," GTM may block the tag before the returning visitor's prior consent choice is restored from the cookie - creating a race condition where the script sometimes fires and sometimes doesn't.
**Fix:** Edit the Cello Attribution Script tag → **Advanced Settings** → **Consent Settings** → select **"No additional consent required"**. See [Step 3](#step-3-configure-consent-settings) above.
You can verify this is the cause by opening **GTM Preview** mode and checking whether the Cello tag shows as "Blocked" or displays a consent-related note next to it.
# User Authentication
Source: https://docs.cello.so/sdk/client-side/user-authentication
The Cello Referral Component contains sensitive data such as the identity of the referee, amounts of payouts and details regarding your user's referral flow e.g. notifications. We use JWT (JSON Web token) to authenticate the user and authorize access to the data in the Referral Component.
The expected flow is as follows:
1. User logs into your system.
2. Your **backend** provides your frontend code with a **Cello JWT token**.
3. Your frontend code initializes the Referral Component with the **token**.
## Generating the token
Keep your credentials safe. **Never** generate a token or store your secret on the client side!
To generate a valid Cello JWT token, you'll need:
1. Your Cello credentials: **productId** and **product secret**
2. A **productUserId** that uniquely identifies the logged-in user
3. A token signing library for your tech stack of choice. A good variety can be found in the [JWT community](https://jwt.io/libraries)
For more resources on **server-side token** generation see [JWT community](https://jwt.io/introduction).
### Credentials
You will require both **productId** and **product secret** to generate tokens for your users. You can find these in your [Cello Portal](https://portal.cello.so/integrations/accesskeys):
### User identity
Cello requires a **productUserId** - a unique user identifier to be passed when initializing the Referral Component.
This can be a user id that you already use to identify users in your product. It can also be any other new unique identifier you generate - the main requirement is that it is unique per user accross your application.
It is important that this ID is **unique per user**, rather than organisation.
### JWT signing library
Regardless of the signing library you choose, make sure you use the `HS512` signing algorithm:
```json theme={null}
{
"alg": "HS512",
"typ": "JWT"
}
```
### Token generation
Token payload attributes:
Identifier of the product your users will refer
Your logged-in user's unique identifier within your system
A token issuing Unix timestamp. Example: `1661876739`
Original signup date of the user. This helps to improve [accuracy](/guides/attribution/auto-attribution) for auto-attributions.
List of organizations the user is assigned to. This is required to enable automatic attribution when referrals are based on organizations. [More information](/guides/attribution/auto-attribution).
Note that some libraries do not require you to pass `iat` in the payload and default to the current time if you don't.
### Example
Example of token generation in a NodeJS backend with JavaScript:
```javascript theme={null}
import { sign } from 'jsonwebtoken';
const tokenPayload = {
productId: 'REPLACE_WITH_PRODUCT_ID',
productUserId: 'REPLACE_WITH_CURRENT_USER_ID',
signupDate: '2022-10-05T14:14:34Z',
orgIds: ['ORG_1, ORG_2']
};
const secret = 'REPLACE_WITH_PRODUCT_SECRET';
const token = sign(tokenPayload, secret, {
algorithm: 'HS512',
});
```
Creating a JWT token should **always** be done in your backend code and **not in the browser**!
Below is an example content of the generated JWT token.
```json theme={null}
{
"productId": "acme.com",
"productUserId": "123456",
"iat": 1662712365
}
```
## Using the token
Finally, provide the server side-generated token in the `token` property when initializing the Referral Component.
```javascript theme={null}
window.cello = window.cello || { cmd: [] };
window.cello.cmd.push(async (cello) => {
await cello.boot({
productId: "REPLACE_WITH_PRODUCT_ID",
token: "REPLACE_WITH_TOKEN",
...otherOptions,
});
});
```
# Introduction
Source: https://docs.cello.so/sdk/introduction
Explore our SDKs for adding referrals to your web and mobile apps.
# Web SDKs
Referral component for your web app
Script for tracking referrals on landing pages
# Mobile SDKs
Referral component for your iOS app
Referral component for your Android app
Referral component for iOS and Android
# Cello for Android
Source: https://docs.cello.so/sdk/mobile/android
The Cello SDK for Android enables you to add a referral program into your Android app. With a plug-n-play mobile component, your users can easily share their invite link with their friends and network using mobile sharing options convenient for them, receive rewards and get paid out.
## Installation
You can install Cello for Android using Gradle or manually. A basic installation takes around 15 minutes but will take a little longer if you want to customize the way the Cello Referral Component is launched.
### Compatibility
Cello SDK for Android is compatible with API 21 and up.
### SDK size
The size of Cello for Android once installed varies depending on your app’s configuration. Around 7MB is the average size increase we would expect to see if you're minifying your app correctly.
## Setup
Install Cello to see and give your users the option to spread the word from your Android app. Cello for Android supports API 21 and above.
**Note:** We recommend using the latest available `compileSdkVersion`.
### Install Cello
Add the following dependency to your app’s `build.gradle` file:
#### Groovy (or Kotlin DSL)
```gradle theme={null}
dependencies {
implementation("so.cello.android:cello-sdk:0.9.1")
}
```
Also, ensure that Maven Central is added to your root `build.gradle`:
```gradle theme={null}
allprojects {
repositories {
mavenCentral()
}
}
```
### Choose an Environment
In your Cello SDK setup, you have the flexibility to select the environment in which your application will run. This feature is especially useful for different stages of development, such as testing in a development or staging environment before going live in production. The available environments are:
* `prod` (Production) – *default*
* `sandbox` (Sandbox)
#### Configuration Steps
In your Android project, open or create `res/values/config.xml`, then add:
```xml theme={null}
prod
```
To change the environment, simply replace the value of `cello_env`. For instance, to set the environment to sandbox:
```xml theme={null}
sandbox
```
Save and rebuild your project to apply.
Using this configuration, the Cello SDK will adapt to the specified environment, allowing for more controlled development and testing processes.
## Initialize Cello
In this step, you will need your **product ID** and a **token** you have generated for the user, similar when [**implementing the web based Referral component**](https://docs.cello.so/docs/user-authentication).
Then, initialize Cello by calling the following in the `onCreate()` method of your application class:
```kotlin theme={null}
Cello.initialize(this, "YOUR_PRODUCT_ID", token)
```
> **Note:** If you don't currently implement a custom application, you’ll need to create one. A custom application looks like this:
#### Kotlin
```kotlin theme={null}
class CustomApplication : Application() {
override fun onCreate() {
super.onCreate()
Cello.initialize(this, "YOUR_PRODUCT_ID", token)
}
}
```
#### Java
```java theme={null}
public class CustomApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Cello.initialize(this, "YOUR_PRODUCT_ID", token);
}
}
```
> **Note:** Cello SDK must be initialized inside the application `onCreate()` method. Initializing anywhere else will result in the SDK not behaving as expected and could even result in the host app crashing.
## Customize the Cello Referral Component
The Cello SDK allows for various levels of customization to better fit into your app's design and flow. One of the main components you might want to customize is the [**Referral component**](https://docs.cello.so/docs/component-overview)
You have two options to launch the referral component:
### Default Launcher
If you choose to go with the default launcher, you can call the `showFab()` method from the Cello SDK to present a Floating Action Button (FAB) within your app. This FAB is pre-styled but may not perfectly match your app's look and feel.
```kotlin theme={null}
Cello.client().showFab()
```
### Custom Launcher
If the default launcher does not fit your needs, you can implement your own custom launcher. This could be any UI element like a button, menu item, or even a gesture. To open the Referral component using a custom launcher, you can call `Cello.openWidget()`.
```kotlin theme={null}
Cello.client().openWidget()
```
Example using Compose:
```kotlin theme={null}
Button(onClick = { Cello.client().openWidget() }) {
Text("Open Referral")
}
```
## Android API
### `Cello.initialize()`
Initializes the Cello referral component.
| Name | Type | Description | Required |
| ------------------ | ------------------ | ----------------------------------------------- | -------- |
| activity | Activity | This is the reference to the MainActivity | Yes |
| productId | String | Identifier of the product your users will refer | Yes |
| token | String | Access token generated for the given user | Yes |
| productUserDetails | ProductUserDetails | Product user details | No |
| language | String | Initial language of the widget | No |
| themeMode | String | Initial theme mode: `"light"` or `"dark"` | No |
```kotlin theme={null}
import com.cello.cello_sdk.ProductUserDetails
val productUserDetails = ProductUserDetails(
firstName = "John",
lastName = "Doe",
fullName = "John Doe",
email = "john.doe@example.com"
)
Cello.initialize(this, "YOUR_PRODUCT_ID", token, productUserDetails = productUserDetails, language = 'de', themeMode = 'light')
```
### `Cello.showFab()`
Shows the Floating action button or bookmark that launches the Referral Component
```kotlin theme={null}
Cello.client().showFab()
```
### `Cello.hideFab()`
Hides the Floating action button or bookmark that launches the Referral Component
```kotlin theme={null}
Cello.client().hideFab()
```
### `Cello.openWidget()`
Opens the referral component.
```kotlin theme={null}
Cello.client().openWidget()
```
### `Cello.hideWidget()`
Hides the referral component.
```kotlin theme={null}
Cello.client().hideWidget()
```
### `Cello.getActiveUcc()`
A method to get an active `ucc` and invite link for the currently logged in user.
```kotlin theme={null}
val result = Cello.client().getActiveUcc()
```
## `getCampaignConfig()`
Returns campaign config values for the currently logged-in user.
```kotlin theme={null}
let result = Cello.client().getCampaignConfig()
```
### Returns
The campaign config object:
Primary currency code
Percentage of attributed new revenue that will be paid as a reward
Maximum reward that can be earned per referral
Additional reward for signups to encourage more sharing
Additional reward for purchases to encourage more sharing
How long new users get a discount
The discount new users get
### `Cello.changeLanguage()`
A method to change the language of the Referral component at runtime without re-initialising it.
```kotlin theme={null}
Cello.client().changeLanguage("de")
```
### `Cello.setThemeMode()`
A method to change the theme mode of the Referral component at runtime without re-initialising it.
```kotlin theme={null}
Cello.client().setThemeMode("dark")
```
**Parameters:**
* `themeMode` (*String*): The theme mode to set. Valid values are `"light"` or `"dark"`.
### `Cello.shutdown()`
Shuts down connection to Cello and unmounts the component
```kotlin theme={null}
Cello.client().shutdown()
```
***
## Error Handling
### Common Error Scenarios
#### 1. Invalid Parameters
**What it means:** The product ID or token provided during initialization is empty or blank.
**Error behavior:**
* SDK initialization is **silently skipped**
* Warning logged: `"Initialization skipped: productId and token must not be empty or blank"`
* No exception thrown
**Common causes:**
* Empty strings for productId or token
* Whitespace-only strings
***
#### 2. Network/API Errors
**What it means:** The network request to initialize the SDK or update token failed.
**Error type:** `RuntimeException("Response not successful")`
**Common causes:**
* No internet connection
* Server errors (5xx responses)
* HTTP errors (4xx responses)
* Timeout issues
* Firewall or proxy blocking requests
***
#### 3. Activity State Errors
**What it means:** The Activity is destroyed, finishing, or not available when trying to perform UI operations.
**Error type:** `IllegalStateException("Activity is not valid")`
**Error message:** `"Cannot perform UI operation - Activity is not available or destroyed"`
**Common causes:**
* Calling SDK methods after Activity is destroyed
* Activity finishing during async operations
* Attempting UI operations during Activity transitions
***
#### 4. Initialization Failures
**What it means:** The SDK failed to initialize due to an error in the initialization process.
**Error behavior:**
* Exception passed to callback
* Error logged: `"Error initializing widget: {exception message}"`
* Pending operations cleared
**Common causes:**
* Network connectivity issues
* Invalid credentials (product ID or token)
* Server-side configuration issues
***
### Error Handling Best Practices
**1. Always handle both success and error cases:**
```kotlin theme={null}
Cello.initialize(this, productId, token) { config, exception ->
if (exception != null) {
// Handle error
Log.e("Cello", "Error: ${exception.message}")
showErrorMessage("Unable to initialize referral system")
} else {
// Handle success
Log.d("Cello", "Initialized successfully")
setupReferralFeatures(config)
}
}
```
**2. Validate parameters before SDK calls:**
```kotlin theme={null}
fun initializeCello(productId: String, token: String) {
// Validate product ID
if (productId.isBlank()) {
Log.e("Cello", "Product ID cannot be empty")
showError("Configuration error")
return
}
// Validate token
if (token.isBlank()) {
Log.e("Cello", "Token cannot be empty")
showError("Authentication error")
return
}
// Check Activity state
if (isFinishing || isDestroyed) {
Log.e("Cello", "Cannot initialize - Activity is finishing")
return
}
Cello.initialize(this, productId, token) { config, error ->
// Handle result
}
}
```
**3. Implement retry logic for network errors:**
```kotlin theme={null}
class CelloManager(private val activity: Activity) {
private var retryCount = 0
private val maxRetries = 3
fun initializeWithRetry(productId: String, token: String) {
Cello.initialize(activity, productId, token) { config, exception ->
if (exception != null) {
handleInitializationError(exception, productId, token)
} else {
retryCount = 0
onInitializationSuccess(config)
}
}
}
private fun handleInitializationError(
exception: Exception,
productId: String,
token: String
) {
Log.e("Cello", "Initialization error: ${exception.message}")
// Retry for network errors
if (exception is RuntimeException && retryCount < maxRetries) {
retryCount++
val delay = (2000L * retryCount) // Linear backoff
Handler(Looper.getMainLooper()).postDelayed({
Log.d("Cello", "Retrying initialization (attempt $retryCount)")
initializeWithRetry(productId, token)
}, delay)
} else {
// Max retries reached or non-recoverable error
retryCount = 0
showFinalError("Failed to initialize after $maxRetries attempts")
}
}
}
```
**4. Track initialization state:**
```kotlin theme={null}
class CelloStateManager(private val activity: Activity) {
private var initializationState = InitState.NOT_INITIALIZED
enum class InitState {
NOT_INITIALIZED,
INITIALIZING,
INITIALIZED,
FAILED
}
fun initialize(productId: String, token: String) {
if (initializationState == InitState.INITIALIZING) {
Log.w("Cello", "Initialization already in progress")
return
}
initializationState = InitState.INITIALIZING
Cello.initialize(activity, productId, token) { config, exception ->
if (exception != null) {
initializationState = InitState.FAILED
Log.e("Cello", "Initialization failed")
} else {
initializationState = InitState.INITIALIZED
Log.d("Cello", "Initialization successful")
}
}
}
fun showWidget() {
when (initializationState) {
InitState.NOT_INITIALIZED -> {
Log.w("Cello", "SDK not initialized")
}
InitState.INITIALIZING -> {
Log.w("Cello", "SDK still initializing")
}
InitState.FAILED -> {
Log.e("Cello", "Cannot show widget - initialization failed")
}
InitState.INITIALIZED -> {
Cello.openWidget()
}
}
}
}
```
**5. Handle Activity lifecycle properly:**
```kotlin theme={null}
class MainActivity : AppCompatActivity() {
private var isCelloReady = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initializeCello()
}
private fun initializeCello() {
Cello.initialize(this, productId, token) { config, error ->
if (error == null && !isFinishing && !isDestroyed) {
isCelloReady = true
}
}
}
fun performCelloAction() {
// Always check Activity and SDK state
if (isFinishing || isDestroyed) {
Log.w("Cello", "Activity is finishing - cannot perform action")
return
}
if (!isCelloReady) {
Log.w("Cello", "SDK not ready")
return
}
Cello.openWidget()
}
override fun onDestroy() {
super.onDestroy()
if (isFinishing) {
isCelloReady = false
Cello.shutdown()
}
}
}
```
### Getting Help
If you encounter an error you can't resolve:
1. Check the error scenario in the reference above
2. Verify your integration follows the code examples
3. Check logcat for detailed error messages: `adb logcat | grep cello-sdk`
4. Verify network connectivity and firewall settings
5. Ensure product ID and token are valid and not empty
6. Check Activity lifecycle (not finishing or destroyed)
7. Contact Cello support with:
* Full error message and stack trace from logcat
* Steps to reproduce
* SDK version
* Android OS version and device model
* Network conditions when error occurred
# Cello for Flutter
Source: https://docs.cello.so/sdk/mobile/flutter
Beta
The Cello Flutter SDK allows you to use Cello for iOS and Cello for Android in your Flutter apps. With a plug-n-play mobile component, your users can easily share their invite link with their friends and network using mobile sharing options convenient for them, receive rewards and get paid out.
## Installation
A basic installation takes around 15 minutes, but will take a little longer if you want to customize the way the Cello Referral Component is launched.
**Compatibility**
* The Cello Flutter SDK supports Flutter **3.3.0** and above (Dart 3+).
* Cello for iOS supports **iOS 15+**.
* Cello for Android supports **API 21+**.
### Install Cello
```bash theme={null}
flutter pub add cello_sdk
```
Or add to your `pubspec.yaml`:
```yaml theme={null}
dependencies:
flutter:
sdk: flutter
cello_sdk: ^0.0.1
```
Then run:
```bash theme={null}
flutter pub get
```
### Android Setup
The Flutter plugin automatically handles linking for Android. Ensure your app's `android/app/build.gradle` has the correct configuration:
```gradle theme={null}
android {
compileSdk 34
defaultConfig {
minSdk 21
// ... other config
}
}
```
Ensure your project's `android/build.gradle` (or app-level) includes:
```gradle theme={null}
repositories {
google()
mavenCentral()
}
```
#### Internet Permission
Add internet permission in `android/app/src/main/AndroidManifest.xml`:
```xml theme={null}
```
### iOS Setup
The Flutter plugin automatically handles linking for iOS via CocoaPods.
From your `ios/` directory, run:
```bash theme={null}
cd ios
pod install
cd ..
```
Ensure your `ios/Podfile` specifies iOS 15.0+:
```ruby theme={null}
platform :ios, '15.0'
```
## Choose an Environment
In your Cello SDK setup, you have the flexibility to select the environment in which your application will run. This feature is especially useful for different stages of development, such as testing in a development or staging environment before going live in production. The available environments are:
* `production` or `prod` (Production) *(default)*
* `sandbox` (Sandbox)
You specify the environment when initializing Cello:
```dart theme={null}
await Cello.initialize(
CelloInitializeOptions(
productId: 'your-product-id',
token: 'your-token',
environment: 'sandbox', // or 'production'
),
);
```
## Customize the Cello Referral Component
The Cello Flutter SDK allows for various levels of customization to better fit into your app's design and flow. One of the main components you might want to customize is the [**Referral component**](https://docs.cello.so/docs/component-overview)
### Choose Your Launcher
The library provides two ways to launch the Referral component:
**Default launcher**
If you choose to go with the default launcher, you can call the `showFab()` method from the Cello library to present a Floating Action Button (FAB) within your app. This FAB is pre-styled but may not perfectly match your app's look and feel.
```dart theme={null}
import 'package:cello_sdk/cello_sdk.dart';
await Cello.showFab();
```
**Custom launcher**
If the default launcher does not fit your needs, you can implement your own custom launcher. This could be any UI element like a button, menu item, or even a gesture. To open the Referral component using a custom launcher, you can call `Cello.openWidget()`.
```dart theme={null}
import 'package:cello_sdk/cello_sdk.dart';
ElevatedButton(
onPressed: () async {
await Cello.openWidget();
},
child: Text('Open Referral'),
)
```
## Flutter API
### `Cello.initialize(CelloInitializeOptions): Future`
Initializes the Cello referral component.
### CelloInitializeOptions
| Property | Type | Required | Description |
| ------------------ | ------------------ | -------- | ------------------------------------------------------ |
| productId | String | yes | Your product ID from Cello Portal |
| token | String | yes | User authentication token |
| environment | String? | no | Environment: `"production"` or `"sandbox"` |
| productUserDetails | ProductUserDetails | no | User details object (see below) |
| language | String? | no | Initial language of the widget |
| themeMode | String? | no | Initial theme mode: `"light"`, `"dark"`, or `"system"` |
### ProductUserDetails
Optional object with user information:
| Property | Type | Description |
| --------- | ------ | -------------------- |
| firstName | String | User's first name |
| lastName | String | User's last name |
| fullName | String | User's full name |
| email | String | User's email address |
```dart theme={null}
import 'package:cello_sdk/cello_sdk.dart';
final config = await Cello.initialize(
CelloInitializeOptions(
productId: 'your-product-id',
token: 'your-token',
environment: 'production',
productUserDetails: ProductUserDetails(
firstName: 'John',
lastName: 'Doe',
fullName: 'John Doe',
email: 'john.doe@example.com',
),
language: 'de',
themeMode: 'system',
),
);
```
### `Cello.showFab(): Future`
Shows the default Cello button that launches the Referral Component
```dart theme={null}
await Cello.showFab();
```
### `Cello.hideFab(): Future`
Hides the default Cello button that launches the Referral Component
```dart theme={null}
await Cello.hideFab();
```
### `Cello.openWidget(): Future`
Opens the referral component.
```dart theme={null}
await Cello.openWidget();
```
### `Cello.hideWidget(): Future`
Hides the referral component.
```dart theme={null}
await Cello.hideWidget();
```
### `Cello.getActiveUcc(): Future