Skip to main content

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. 
Partners and affiliates are added via the Cello Portal. 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.
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.

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
The Attribution Library (Attribution JS) 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 codegetUcc() for passing into signup and purchase events
  • Get the referrer’s namegetReferrerName() for personalizing landing pages
  • Access campaign configgetCampaignConfig() for displaying referral discounts
  • Manage cookie consent — built-in methods for privacy compliance
You can install it via an embedded script tag or Google Tag Manager.Related docs
You could technically store the ucc as a cookie yourself, but the Attribution Library (Attribution JS) 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, 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
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
  • 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 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 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
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 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.
  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 for report templates.Related docs
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 to send a new-signup event after the customer is created at purchase.Related docs

Stripe / Chargebee events & webhooks

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
  • 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
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
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
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.
  • 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
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.
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:
  • 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.
Customization options depend on your plan and setup. Please coordinate with your Customer Success Manager.
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 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, and Slovak (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 in portal for copy and timing. 
You can test the notification badge by opening your own referral link. Common causes of incorrect positioning:
  • The badge is added on the menu level instead of the menu-item level.
  • The badge is positioned absolute but lacks a relative parent. Set the menu-item container to position: relative.
Cello notifications fall into two categories:
  1. In-product: announcement banners and badge dots displayed inside the widget.
  2. External: emails (welcome, reward earned, first-view, etc.).
These notifications and their triggers are designed to work alongside your existing product engagement touchpoints in a seamless way.
Cello does not currently send out emails for new features or release notes. Reach out to your Cello contact for the latest updates.

If we have major updates, we often post about them directly in a shared slack channel. We also have this section in our docs for updates: Changelog

Fraud, self-referrals & abuse

Cello provides automated capabilities to detect and mitigate self-referrals and fraudulent behavior. You can review marked referrals in our Cello Portal.Related docs
Yes. Reversals are done manually; coordinate with Cello support.
Cello uses multiple signals (including data you provide, e.g. emails) and behavioral patterns to detect likely self-referrals. High-certainty cases can be auto-rejected; others are flagged for review in the portal, where you can accept or reject.Related docs
Cello uses anonymized signals and patterns to detect suspicious behavior (e.g. matching anonymous identifiers across referrer and referee journeys). Exact methods may change over time.Related docs
Currently, the widget may not show a detailed reason. In some cases, communication may happen via the referrer’s payout email (PayPal/Venmo).
If a new user converts to a paying user, Cello looks at multiple data points before issuing a reward. These data points are checked for both sides:
  1. The new user (referred person).
  2. The referrer based on the UCC the new user used.
These datapoints are compared to detect cases where the referrer and referred user are the same person or repeating pattern is used to abuse the program.

Integrations, SDKs & implementation

The Referral Component is an embeddable UI that integrates directly into your application, giving logged-in users a complete referral experience. It is powered by the Cello JS SDK and is separate from Attribution JS, which handles referral tracking on landing pages.The component provides:
  • Referral link sharing — users can copy their link, share via social media, email, or QR code
  • Progress tracking — real-time dashboard showing clicks, signups, and earned rewards
  • Reward payouts — automated payouts via PayPal, Venmo, and other methods
  • Notifications — in-app and email alerts for referral activity and milestones
  • Multi-language support — 10+ languages with automatic detection
  • Dark mode — adapts to your app’s theme
It can be added as a floating button or integrated into your existing navigation using a custom launcher. Native SDKs are available for web, iOS, Android, and React Native.Integration requires three steps: load the SDK, generate a JWT token server-side, and boot the component with the user’s details.Related docs
Cello is framework-agnostic. The Cello JS SDK is a browser-based JavaScript library that works with any web framework whose output is HTML/JavaScript, including:
  • React, Next.js, Vue, Angular, Svelte, and vanilla JavaScript
For server-side rendering frameworks (e.g., Next.js), Cello interactions must occur client-side — the SDK runs in the browser and cannot be initialized server-side. For Angular specifically, avoid using <body> as your AppRoot element to prevent a race condition with Cello’s DOM injection (see the Angular notes in the quickstart).For mobile apps, native SDKs are available:Related docs
No — Cello branding on the Referral Component is required and cannot be removed. This is primarily a trust and compliance requirement, not advertising.When referrers receive reward payouts, the transaction appears on their bank or PayPal account as a payout from Cello. The branding in the widget ensures users understand that the referral program is powered by Cello before they receive a payout. Without it, users may not recognize the payment and could flag it as fraud or issue chargebacks — which can harm both your referral program and your referrers.The branding is designed to be non-intrusive. While the Cello logo cannot be removed, the Referral Component does inherit your app’s theming (colors, dark mode) and many other aspects of the UI can be customized through the Cello Portal.
Yes. Many aspects of the Referral Component are self-serve customizable via the Cello Portal:
  • Brand colors — primary color, button color, and notification badge color
  • Button style and position — choose from 3 styles, set screen position, or use a custom launcher integrated into your own menu
  • Component type — display as a pop-up or a modal, with configurable position
  • Text and language — customize the default text (onboarding, offer description) and provide multiple language options. 10+ languages are supported with automatic detection
  • Sharing options — enable/disable link copy, social sharing (Twitter, LinkedIn, email), and QR codes
  • Payment methods — configure PayPal, Venmo, or other payout options for referrers
  • Announcements — choose between toasts, banners, or anchored announcements
For customizations not available in the Portal, contact the Cello product team to discuss what adjustments can be applied.Related docs
Email and announcement copy in Cello is standardized and cannot be customized self-serve through the Portal. Cello maintains consistent copy across customers to support 10+ languages and multiple reward structures.What you can configure self-serve in the Portal:
  • Enable or disable specific notification types (alerts, announcements, emails)
  • Choose announcement display style — toasts, banners, or anchored to your launcher
  • Configure the activation campaign — recurring announcements to re-engage inactive referrers
  • Set reward amounts and program details — which flow into the standardized email templates automatically
What requires Cello involvement:
  • Email body copy (e.g., “How It Works” page, reward email wording) — custom copy changes may be available depending on your plan. Contact your CSM or the Cello product team to discuss options.
  • Announcement text content — same as above
Based on Cello’s experience across hundreds of programs, modifications to email or announcement copy have minimal impact on referral performance. The biggest drivers of success are creating more impactful in-product touchpoints, such as Moments of Delight and deeper mobile app integration.Related docs
Yes — the referral landing page experience is highly customizable. You control the landing page itself, and Cello provides several approaches for the referee signup flow:
  1. Dedicated landing page (recommended) — build a custom page optimized for referral conversions. Dedicated pages have shown up to 2x higher conversion rates. You have full control over layout, design, messaging, and CTAs.
  2. Home page with inline personalization — use your existing home page and add referral-specific personalization (referrer name, discounts) directly into your headline and CTA using the Attribution JS API (`getReferrerName()`, `getCampaignConfig()`).
  3. Home page with New User Banner (no code) — add the Cello attribution script and enable the New User Banner in the Cello Portal. The banner automatically displays personalization and discount info to visitors arriving via referral links.
For the Referral Component (the in-app widget for logged-in referrers), you can configure its placement (floating button position or custom launcher), display type (pop-up or modal), and brand colors in the Portal.For adjustments beyond what’s available in the Portal, contact your CSM or the Cello product team with screenshots and the desired behavior.Related docs
Use the Referral Codes API endpoint GET /referral-codes/{code} to validate a UCC and identify the referrer it belongs to.The API returns:
  • valid — whether the UCC is a legitimate, active referral code
  • productUserId — the referrer’s user ID in your system
  • campaignId — the campaign the UCC is associated with
Example response for a valid code:
{
  "code": "UIPIWa2Hnnr",
  "productUserId": "12345678",
  "valid": true,
  "campaignId": "campaign_partners_1"
}
Common use cases for UCC validation:
  • Self-referral prevention — compare the returned productUserId (referrer) with the logged-in user’s ID; if they match, ignore the UCC
  • Existing-user attribution — validate the UCC on login before storing it for future purchase attribution
  • Tampered URL detection — if someone modifies the ucc query parameter, the API will return valid: false
  • Discount eligibility — validate the UCC before applying a new-user discount to ensure the code hasn’t been tampered with
Related docs
Yes — the ucc is always present as a query parameter in the URL when a user clicks a referral link (e.g., https://yoursite.com/?ucc=ABC123). You can parse it directly from the URL using standard JavaScript:
const ucc = new URLSearchParams(window.location.search).get('ucc');
However, using getUcc() from the Attribution JS library is recommended because it:
  • Falls back to cookies — if the user navigated away and the ucc is no longer in the URL, getUcc() retrieves it from the stored cookie
  • Handles async loading — waits for the attribution script to initialize before returning data
  • Works across sessions — cookies persist for 3 months, covering indirect signups where the user returns later
If you read the ucc from the URL yourself, make sure to store it in your database linked to the user at signup, so it’s available when sending signup and purchase events to Cello.Related docs
Yes. Cello integrates with Salesforce via Apex triggers that call the Cello API when specific conditions are met in your Salesforce workflow. This is the recommended approach for sales-led referral attribution.A typical setup uses an Apex trigger on the Opportunity object to send events to Cello when:
  • An Opportunity reaches a specific stage (e.g., “Proposal/Price Quote”)
  • The Opportunity has a cello_ucc custom field populated
This allows you to attribute deals and revenue back to the referrer who generated the lead. The trigger calls the Cello API to send demo-attended or purchase events based on your sales flow.The integration is not a native Salesforce app — it uses standard Apex triggers and HTTP callouts to the Cello API, giving you full control over which events are sent and when. You can also send events directly via the Cello API if you prefer not to use Apex triggers.Related docs
This happens because Turbo replaces the page’s DOM during navigation, but the Cello widget iframe persists in an orphaned state. The fix is to shut down the widget before Turbo transitions, then re-initialize it on the new page.Add an event listener to call shutdown before Turbo navigates:
document.addEventListener("turbo:visit", () => {
  window.Cello("shutdown");
});
Or alternatively, just before Turbo renders new content:
document.addEventListener("turbo:before-render", () => {
  window.Cello("shutdown");
});
turbo:visit (recommended) fires at the start of navigation before any network requests, giving the cleanest teardown. turbo:before-render fires later, just before the new page content replaces the DOM.After shutdown, Cello needs to be re-initialized on the new page. If your Cello boot script is in the page layout, it will run automatically after Turbo renders. If not, listen for turbo:load to re-boot:
document.addEventListener("turbo:load", () => {
  window.cello.cmd.push(async function (cello) {
    await cello.boot({ /* your boot config */ });
  });
});
Related docs
This error (InitializationError) typically means the SDK is connecting to the wrong environment. When using Expo, the env property defaults to prod — if your credentials are for the sandbox environment but env is not explicitly set, initialization will fail.Verify that the env value is correctly nested under the @getcello/cello-react-native Expo plugin in your app.json:
{
  "expo": {
    "plugins": [
      [
        "@getcello/cello-react-native",
        {
          "env": "sandbox"
        }
      ]
    ]
  }
}
After changing the plugin configuration, you must rebuild the native app:
npx expo prebuild --clean
Also check:
  • Credentials — ensure productId and token match the environment you selected (sandbox vs prod)
  • Not using Expo Go — the Cello SDK requires a custom native build and will not work in Expo Go (you’ll see a LINKING_ERROR instead)
Related docs
Referral discounts are applied by your subscription platform (Stripe, Chargebee, etc.) during subscription creation — Cello does not apply them automatically. If the discount isn’t showing up, check the following in order:
  1. Is the ucc available at checkout? — verify the referral code was preserved from signup to the payment flow. Check your Stripe/Chargebee customer metadata for cello_ucc, or call getUcc() from the Attribution Library. If it’s missing, the attribution cookie may have been lost (e.g., cookie consent blocked it, or the user is on a different domain).
  2. Is the user eligible for a discount? — use the New User Reward API to validate eligibility, or check for cello_ucc in the customer object in your payment platform.
  3. Is the coupon applied during subscription creation? — discounts must be passed at the time the subscription is created (e.g., via discounts array in Stripe or coupon_ids in Chargebee). They cannot be attached after the fact through the API.
  4. Is the coupon valid? — verify the coupon ID exists in your payment platform, hasn’t expired, and matches the plan type being purchased.
Related docs
This typically happens because the Cello script downloads and executes before the <body> element is available in the DOM. Cello appends its UI to <body>, so if <body> doesn’t exist yet, initialization fails.Recommended fix: Ensure the script tag includes type="module" and async, and is placed in the <head>:
<script type="module" src="https://assets.cello.so/app/latest/cello.js" async></script>
The type="module" attribute defers execution until after the DOM is parsed, which prevents the race condition. If you’re still seeing issues:
  • Use the command queue pattern — initialize Cello through the queue so commands are buffered until the script is ready:
    window.cello = window.cello || { cmd: [] };
    window.cello.cmd.push(async function (cello) {
      await cello.boot({ /* your config */ });
    });
    
  • Move the script to the end of <body> — as a fallback, placing the <script> tag just before </body> ensures the DOM is fully available
  • Angular users — avoid using <body> as your AppRoot element, as this creates a race condition with Cello’s DOM injection. See the Angular notes
Related docs
If the Attribution JS script fails to load (due to network issues, ad blockers, or CSP restrictions), the getUcc() promise will never resolve or reject — it waits indefinitely for the script to initialize.Never place getUcc() on a critical path that blocks your signup or checkout flow. Instead, race it against a timeout:
async function getUccWithTimeout(timeoutMs = 3000) {
  try {
    const ucc = await Promise.race([
      window.CelloAttribution('getUcc'),
      new Promise((_, reject) =>
        setTimeout(() => reject(new Error('Attribution timeout')), timeoutMs)
      )
    ]);
    return ucc;
  } catch {
    return null;
  }
}
If the timeout wins, proceed without the UCC — the user likely didn’t arrive via a referral link, or you can fall back to reading the ucc directly from the URL query parameter as a backup.Related docs
Yes — Cello supports automatic and manual cancellation of rewards depending on your integration:Stripe / Chargebee webhooks (automatic) When you connect Stripe or Chargebee webhooks, Cello automatically detects cancellation and refund events:
  • subscription.deleted — stops future recurring rewards for that referral
  • charge.refunded — automatically cancels any pending reward for that transaction
No additional API calls are needed; Cello reacts to these webhook events as they arrive.Cello API (manual) If you use the Cello API instead of webhooks, send a charge-refunded event via POST /events to cancel pending rewards for a specific transaction:
POST https://api.cello.so/events

{
  "eventName": "ReferralUpdated",
  "payload": {
    "ucc": "cello-ucc",
    "newUserId": "new-user-id",
    "price": 1000,
    "currency": "EUR"
  },
  "context": {
    "event": {
      "trigger": "charge-refunded",
      "timestamp": "2024-01-15 10:00:00"
    },
    "subscription": {
      "invoiceId": "invoice-id"
    }
  }
}
Important nuances:
  • Pending rewards are automatically cancelled when a refund event is received
  • Already paid-out rewards are not clawed back from referrers — Cello does not ask referrers to return money
  • To mitigate refund risk, many programs spread rewards over time (e.g. monthly over 12 months) so future payouts can be stopped if the deal falls through
  • Cello can also configure a payout delay (e.g. 14 days) matching your refund window — contact your CSM to set this up
  • You can review reward status (CREATED, CANCELED, REJECTED, PROCESSED) in the Cello Portal under the Purchases page
Related docs
No. The productId is simply an identifier for your Cello account — it does not need to match your application domain, staging URL, or any specific URL pattern. It may look like a domain, but that is just a naming convention; it has no functional connection to where you deploy Cello.What does matter is using the correct credentials for each environment:
  • Sandbox credentials (productId + PRODUCT_SECRET from the Sandbox environment) for development and staging
  • Production credentials (productId + PRODUCT_SECRET from the Production environment) for your live application
You can find both sets of credentials on the Access Keys page in the Cello Portal.Common errors from mismatched credentials:
  • Using a Sandbox productId with a Production PRODUCT_SECRET (or vice versa)
  • Calling the wrong Cello API environment from your backend
  • Using the wrong webhook signing secret for the environment
Related docs
Cello is designed as a hybrid system — some parts are API-driven and fully headless, while the Referral Component (widget) handles the referrer-facing experience.What is fully headless (API-only):
  • Attribution — capturing referral codes, tracking signups, and tracking purchases all happen via the Cello API or Stripe/Chargebee webhooks, with no widget required
  • Referral code validationGET /referral-codes/{code} to verify a UCC
  • Active link retrievalGET /referral-codes/active-link/{productUserId} to fetch a user’s referral link programmatically
  • Event sendingPOST /events for signup, purchase, and refund events
What the Referral Component provides (and cannot be rebuilt independently): The widget handles the referrer experience — the part where users share their link, see who signed up, track rewards, and manage payouts. This includes:
  • Link sharing (copy, social media, email, QR code)
  • Progress tracking (clicks, signups, earnings)
  • Reward payouts and payment details management (PayPal/Venmo)
  • In-app notifications, announcements, and onboarding
  • Multi-language support and dark mode
Cello does not currently provide an SDK or API to rebuild these features (such as the rewards view or payment details management) as a fully custom UI. The Referral Component is the only way to deliver the complete referrer experience.What you can do — extend with custom placements: While the Referral Component is required for the full experience, you can — and are encouraged to — surface referral information in additional places throughout your product using the Cello JS SDK or API:This allows you to build mini-cards, banners, or menu items that display the referral link and campaign info at moments of delight — for example, after a user completes a milestone or receives positive feedback. These custom placements complement the Referral Component and are a best practice for increasing sharing activity.The Referral Component itself can be themed, repositioned, and launched from a custom launcher (any button, menu item, or link) to feel native to your product.Related docs
Cello supports 10+ languages out of the box: English, German, Spanish, French, Dutch, Italian, Portuguese, Japanese, Danish, and Slovak. Additional languages can be added on request — contact your CSM.Language is determined differently depending on the surface:
SurfaceHow language is selectedFallback
Referral Component (web)Pass language (ISO 639-1) during cello.boot() to match your app’s user preferenceProduct default language
Referral Component (mobile)Pass language during SDK initialization (iOS, Android, React Native, Flutter)Device language, then English
Referee landing pageDetected from the visitor’s browser settingsEnglish
Referrer landing page (mobile)Detected from device settingsEnglish
Changing language at runtime: You can switch the language without re-initializing the component:
  • Web: window.Cello("changeLanguage", "de")
  • Mobile: Cello.changeLanguage("de") (iOS 14+ required on iOS)
Related docs
Yes — campaign details are available through both the Cello JS SDK and the Attribution JS SDK. The Cello REST API does not currently return full campaign config, but the client-side SDKs do.For logged-in users (Referral Component / Cello JS): Use getCampaignConfig() to retrieve the current user’s campaign details:
const config = await window.Cello("getCampaignConfig");
Returns:
  • primaryCurrency — reward currency code
  • revenuePercentage — referrer reward as a percentage of revenue
  • rewardCap — maximum reward per referral
  • newSignupBonus — bonus reward for each signup
  • newPurchaseBonus — bonus reward for each purchase
  • newUserDiscountPercentage — discount for referred new users (decimal: 0.1 = 10%)
  • newUserDiscountMonth — how many months the discount lasts
For landing page visitors (Attribution JS): Use getCampaignConfig() from the Attribution SDK to display discount info before signup:
const config = await window.CelloAttribution("getCampaignConfig");
const discountPercent = config.newUserDiscountPercentage * 100;
const months = config.newUserDiscountMonth;
// e.g. "10% off for 3 months"
Mobile SDKs also expose getCampaignConfig() on iOS, Android, React Native, and Flutter.Note on campaignId in the referral-codes API: When calling GET /referral-codes/{code}, the response includes a campaignId field. For the default campaign, this field returns an empty string — this is expected behavior, not an error. Non-default campaigns return their actual campaign ID.Related docs

Authentication & tokens

The iat (issued at) field in the JWT payload is a Unix timestamp that tells Cello when the token was created. Cello enforces a validation window on this value:
  • The iat cannot be older than 24 hours — tokens issued more than 24 hours ago are considered expired
  • The iat cannot be set in the future — tokens with a future timestamp are rejected as invalid
If your server’s clock is out of sync (even by a few minutes), the iat value may fall outside these bounds and the token will be rejected, causing a boot failure with a token/authorization error.How to fix:
  1. Verify your server’s system clock — ensure it is synchronized using NTP (Network Time Protocol)
  2. Use Math.floor(Date.now() / 1000) (or equivalent in your language) to generate the iat value dynamically rather than hardcoding it
  3. Check your environment — staging and production servers may have different time configurations
Example token payload:
{
  "productId": "your-product-id",
  "productUserId": "user-123",
  "iat": 1662712365
}
Related docs
The Cello REST API uses a two-token authentication model (separate from the widget JWT used for the Referral Component):
  1. Authenticate — call POST /token with your accessKeyId and secretAccessKey (from the Access Keys page). This returns:
    • accessToken — short-lived token used in the Authorization header for API requests
    • refreshToken — longer-lived token used to get new access tokens without re-authenticating
    • expiresIn — how long the access token is valid
  2. Refresh — when the access token expires, call POST /token with the refreshToken to get a new accessToken. This does not return a new refresh token.
  3. Re-authenticate — the refresh token expires after 5 days. Once expired, you must perform a full authentication again with your accessKeyId and secretAccessKey to obtain both a new access token and a new refresh token.
There is no separate endpoint to retrieve only a new refresh token — refresh tokens are only issued during full authentication.Recommended pattern for long-running integrations:
  • Store the refresh token securely after initial authentication
  • Use it to refresh the access token before it expires
  • Implement a fallback to full re-authentication when the refresh token itself expires (after 5 days)
Related docs