This guide follows basic steps to integrate Referral Component into your web application using Cello JS SDK.
Cello JS SDK 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 for the right environment (Sandbox or Production) Portal Credentials Access Keys productId and PRODUCT_SECRET for Referral Component Cello JS

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.
Avoiding CORS Issues: When loading third-party scripts like Cello at runtime, ensure your Content Security Policy (CSP) allows loading from *.cello.so domains. If your application has strict CSP headers, add script-src 'unsafe-inline' https://assets.cello.so https://assets.sandbox.cello.so to your CSP configuration to prevent CORS-related loading issues.
Add this script to the head tag of your HTML:
<script
  type="module"
  src="https://assets.sandbox.cello.so/app/latest/cello.js"
  async>
</script>
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

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 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.
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. After initialization, the library:
  1. Adds a Cello button to your page or connects to your custom element
  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:
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.:
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/. 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.

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() 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 <body> 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 <body> as your AppRoot element as it would create a race condition.
@Component({
  selector: 'app-root',
  ...
})
<body>
    <app-root></app-root>
</body>
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:
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<void>(resolve => setTimeout(() => resolve(), timeout));
  }

  async loadScript(src: string): Promise<void> {
     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.