Chargebee Cancel Pages has been powered by the standalone Brightback.js script to trigger cancel pages. Now, this functionality is fully integrated into Chargebee.js, which also supports experiences such as Checkout, Portal, Personalized Offers, and Pricing Table.
Brightback.js is deprecated and, although fully functional, it is no longer maintained. This guide explains how to migrate an existing integration from Brightback.js to the Chargebee.js Cancel Page integration.
If you already use Chargebee Billing, use this guide to migrate your integration.
If you don't use Chargebee Billing yet, you can continue using Brightback.js without interruption. We'll provide a clear migration path to Chargebee.js and notify you when it's available.
No, the Retention dashboard will continue to function as usual. You can access the dashboard, configure cancel page experiences, and view analytics without interruption.
Only the integration and triggering of cancel pages in your application's frontend are affected by this change.
Reasons to migrate
Brightback.js is deprecated and, although fully functional, it is no longer maintained. To keep your integration up-to-date and reliable, migrate to the Chargebee.js Cancel Page integration. This migration provides the following benefits:
- Simpler setup and maintenance: Configure Chargebee.js once for all features, including Checkout, Payment Components, Cancel Page, Pricing Table, and Personalized Offers.
- Unified integration: Initialize with
Chargebee.init()and reuse thechargebeeobject everywhere. - Single configuration: Set context (like
site) once; no duplicate setup for individual features.
- Unified integration: Initialize with
- Faster rollouts: Launch new Chargebee-hosted experiences or cancel page experiments quickly.
- More reliable: One script reduces errors, avoids conflicts, and delivers a smoother experience.
- Future-ready foundation: All upcoming innovations are delivered through this unified setup.
Change summary
To migrate from the Brightback.js library to the Chargebee.js Cancel Page integration, make the following key changes:
- Script source: Replace the Brightback.js script with the Chargebee.js script (
https://js.chargebee.com/v2/chargebee.js). - Container element: Change the container element
idfrombb-canceltocb-cancel. - Initialization: Initialize Chargebee.js and create a
cancelPageobject before using cancel page features. - API usage:
- Replace
window.Brightback.handleData()withcancelPage.attachCancelHandler(). - Replace
window.Brightback.handleDataPromise()withcancelPage.getPage().
- Replace
- API parameters: Update the data structure to match the new schema.
The following code samples illustrate these changes. See the inline comments for more information.
Simple integration (attach handler)
Use this approach to migrate from Brightback.handleData() to the new cancelPage.attachCancelHandler() API with minimal code changes. This method automatically attaches a click handler to your cancel button and initializes the cancel page flow when clicked.
Before (Brightback.js)
<head>
<!-- OLD: Brightback script URL -->
<script src="https://app.retention.chargebee.com/js/current/brightback.js"></script>
</head>
<body>
<!-- OLD: Uses bb-cancel id for the cancel button. -->
<a id="bb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
<script>
// OLD: Check for Brightback object and call handleData()
if (window.Brightback) {
window.Brightback.handleData({
app_id: 'YOUR_RETENTION_APP_ID', // OLD: Uses app_id
subscription_id: 'CHARGEBEE_BILLING_SUBSCRIPTION_ID',
first_name: 'Jane', // OLD: snake_case naming
last_name: 'Doe', // OLD: snake_case naming
email: 'jane.doe@example.com',
save_return_url: 'https://app.yourcompany.com/save?id=jane_doe', // OLD: snake_case
cancel_confirmation_url: 'https://app.yourcompany.com/cancel_confirm?id=jane_doe', // OLD: snake_case
account: {
billing_id: 'CHARGEBEE_BILLING_CUSTOMER_ID', // OLD: billing_id
created_at: '2024-06-26', // OLD: created_at
internal_id: 'jane_doe', // OLD: internal_id
plan: 'enterprise',
value: 1000.00 // OLD: value
},
custom: {
emailCount: 4208
}
});
}
</script>
</body>
After (Chargebee.js)
<head>
<!-- NEW: Chargebee.js script URL -->
<script src="https://js.chargebee.com/v2/chargebee.js"></script>
</head>
<body>
<!-- NEW: Uses cb-cancel id for the cancel button. -->
<a id="cb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
<script>
// NEW: Initialize Chargebee with site configuration
const chargebee = window.Chargebee.init({
site: "YOUR-CHARGEBEE-SUBDOMAIN",
});
(async () => {
// NEW: Create cancelPage instance using chargebee object
const cancelPage = await chargebee.cancelPage();
// NEW: cancelPage.attachCancelHandler() method instead of Brightback.handleData()
cancelPage.attachCancelHandler({
// NEW: subscription object
subscription: {
id: "CHARGEBEE_BILLING_SUBSCRIPTION_ID",
plan: "enterprise"
},
firstName: "Jane", // NEW: camelCase naming
lastName: "Doe", // NEW: camelCase naming
email: "jane.doe@example.com",
externalUserId: "jane_doe", // NEW: externalUserId instead of internal_id
saveReturnUrl: "https://app.yourcompany.com/save?id=jane_doe", // NEW: camelCase
cancelConfirmationUrl: "https://app.yourcompany.com/cancel_confirm?id=jane_doe", // NEW: camelCase naming
account: {
customerId: "CHARGEBEE_BILLING_CUSTOMER_ID", // NEW: customerId instead of billing_id
firstPurchaseDate: "2024-06-26", // NEW: firstPurchaseDate instead of created_at
contractValue: 1000.00 // NEW: contractValue instead of value
},
custom: {
emailCount: 4208
}
});
})();
</script>
</body>
Advanced integration (prefetch and redirect)
Use this approach to migrate from Brightback.handleDataPromise() to the new cancelPage.getPage() API. This method lets you prefetch a personalized cancel page URL and programmatically redirect the user, enabling you to run custom logic before redirection or trigger cancellation from multiple places in your application.
Before (Brightback.js)
<head>
<!-- OLD: Brightback script URL -->
<script src="https://app.retention.chargebee.com/js/current/brightback.js"></script>
</head>
<body>
<!-- OLD: Uses bb-cancel id for the cancel button. -->
<a id="bb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
<script>
function bindLink(id, url) {
document.getElementById(id).addEventListener('click', () => {
window.location.assign(url);
});
}
// OLD: Call Brightback.handleDataPromise()
const p = window.Brightback.handleDataPromise({
app_id: 'YOUR_RETENTION_APP_ID', // OLD: Uses app_id
subscription_id: 'CHARGEBEE_BILLING_SUBSCRIPTION_ID',
first_name: 'Jane', // OLD: snake_case naming
last_name: 'Doe', // OLD: snake_case naming
email: 'jane.doe@example.com',
save_return_url: 'https://app.yourcompany.com/save?id=jane_doe', // OLD: snake_case
cancel_confirmation_url: 'https://app.yourcompany.com/cancel_confirm?id=jane_doe', // OLD: snake_case
account: {
billing_id: 'CHARGEBEE_BILLING_CUSTOMER_ID', // OLD: billing_id
created_at: '2024-06-26', // OLD: created_at
internal_id: 'jane_doe', // OLD: internal_id
plan: 'enterprise',
value: 1000.00 // OLD: value
},
custom: {
emailCount: 4208
}
});
p.then((success) => {
if (success.valid) {
bindLink('bb-cancel', success.url);
} else {
bindLink('bb-cancel', 'https://app.yourcompany.com/cancel?id=jane_doe');
}
});
</script>
</body>
After (Chargebee.js)
<head>
<!-- NEW: Chargebee.js script URL -->
<script src="https://js.chargebee.com/v2/chargebee.js"></script>
</head>
<body>
<!-- NEW: Uses cb-cancel id for the cancel button. -->
<a id="cb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
<script>
// NEW: Initialize Chargebee with site configuration
const chargebee = window.Chargebee.init({
site: "YOUR-CHARGEBEE-SUBDOMAIN",
});
function bindLink(id, url) {
document.getElementById(id).addEventListener('click', () => {
window.location.assign(url);
});
}
(async () => {
// NEW: Create cancelPage instance using chargebee object
const cancelPage = await chargebee.cancelPage();
const options = {
// NEW: subscription object
subscription: {
id: "CHARGEBEE_BILLING_SUBSCRIPTION_ID",
plan: "enterprise"
},
firstName: "Jane", // NEW: camelCase naming
lastName: "Doe", // NEW: camelCase naming
email: "jane.doe@example.com",
externalUserId: "jane_doe", // NEW: externalUserId instead of internal_id
saveReturnUrl: "https://app.yourcompany.com/save?id=jane_doe", // NEW: camelCase
cancelConfirmationUrl: "https://app.yourcompany.com/cancel_confirm?id=jane_doe", // NEW: camelCase naming
account: {
customerId: "CHARGEBEE_BILLING_CUSTOMER_ID", // NEW: customerId instead of billing_id
firstPurchaseDate: "2024-06-26", // NEW: firstPurchaseDate instead of created_at
contractValue: 1000.00 // NEW: contractValue instead of value
},
custom: {
emailCount: 4208
}
};
// NEW: cancelPage.getPage() method instead of Brightback.handleDataPromise()
cancelPage.getPage(options).then((result) => {
if (result.valid) {
bindLink('cb-cancel', result.url);
} else {
bindLink('cb-cancel', 'https://app.yourcompany.com/cancel?id=jane_doe');
}
});
})();
</script>
</body>
Detailed migration steps
1. Load chargebee.js instead of brightback.js
Before
<script src="https://app.retention.chargebee.com/js/current/brightback.js"></script>
After
<script src="https://js.chargebee.com/v2/chargebee.js"></script>
2. Update the cancel button element
Change the id attribute of your cancel button from bb-cancel to cb-cancel.
Before
<a id="bb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
After
<a id="cb-cancel" href="https://app.yourcompany.com/cancel" class="btn btn-danger">
Cancel Subscription
</a>
3. Initialize Chargebee.js
Once the page loads, initialize Chargebee.js with your Chargebee site subdomain to enable the use of the SDK.
Before
Not available in brightback.js.
After
const chargebee = window.Chargebee.init({
site: "YOUR-CHARGEBEE-SUBDOMAIN",
});
4. Create the Cancel Page object
Use the cancelPage() function to instantiate Cancel Page.
Before
Not available in brightback.js.
After
const cancelPage = await chargebee.cancelPage();
5. Replace Retention integration methods
Option A: Simple integration (attach handler)
Use this approach to migrate from Brightback.handleData() to the new cancelPage.attachCancelHandler() API with minimal code changes. This method automatically attaches a click handler to your cancel button and initializes the cancel page flow when clicked.
Before
// OLD: Check for Brightback object and call handleData()
if (window.Brightback) {
window.Brightback.handleData({
app_id: 'YOUR_RETENTION_APP_ID', // OLD: Uses app_id
subscription_id: 'CHARGEBEE_BILLING_SUBSCRIPTION_ID',
first_name: 'Jane', // OLD: snake_case naming
last_name: 'Doe', // OLD: snake_case naming
email: 'jane.doe@example.com',
save_return_url: 'https://app.yourcompany.com/save?id=jane_doe', // OLD: snake_case
cancel_confirmation_url: 'https://app.yourcompany.com/cancel_confirm?id=jane_doe', // OLD: snake_case
account: {
billing_id: 'CHARGEBEE_BILLING_CUSTOMER_ID', // OLD: billing_id
created_at: '2024-06-26', // OLD: created_at
internal_id: 'jane_doe', // OLD: internal_id
plan: 'enterprise',
value: 1000.00 // OLD: value
},
custom: {
emailCount: 4208
}
});
}
After
cancelPage.attachCancelHandler({
// NEW: subscription object
subscription: {
id: "CHARGEBEE_BILLING_SUBSCRIPTION_ID",
plan: "enterprise"
},
firstName: "Jane", // NEW: camelCase naming
lastName: "Doe", // NEW: camelCase naming
email: "jane.doe@example.com",
externalUserId: "jane_doe", // NEW: externalUserId instead of internal_id
saveReturnUrl: "https://app.yourcompany.com/save?id=jane_doe", // NEW: camelCase
cancelConfirmationUrl: "https://app.yourcompany.com/cancel_confirm?id=jane_doe", // NEW: camelCase naming
account: {
customerId: "CHARGEBEE_BILLING_CUSTOMER_ID", // NEW: customerId instead of billing_id
firstPurchaseDate: "2024-06-26", // NEW: firstPurchaseDate instead of created_at
contractValue: 1000.00 // NEW: contractValue instead of value
},
custom: {
emailCount: 4208
}
});
See full list of parameter schema changes.
Option B: Advanced integration (prefetch and redirect)
Use this approach to migrate from Brightback.handleDataPromise() to the new cancelPage.getPage() API. This method lets you prefetch a personalized cancel page URL and programmatically redirect the user, enabling you to run custom logic before redirection or trigger cancellation from multiple places in your application.
Before
function bindLink(id, url) {
document.getElementById(id).addEventListener('click', () => {
window.location.assign(url);
});
}
// OLD: Call Brightback.handleDataPromise()
const p = window.Brightback.handleDataPromise({
app_id: 'YOUR_RETENTION_APP_ID', // OLD: Uses app_id
subscription_id: 'CHARGEBEE_BILLING_SUBSCRIPTION_ID',
first_name: 'Jane', // OLD: snake_case naming
last_name: 'Doe', // OLD: snake_case naming
email: 'jane.doe@example.com',
save_return_url: 'https://app.yourcompany.com/save?id=jane_doe', // OLD: snake_case
cancel_confirmation_url: 'https://app.yourcompany.com/cancel_confirm?id=jane_doe', // OLD: snake_case
account: {
billing_id: 'CHARGEBEE_BILLING_CUSTOMER_ID', // OLD: billing_id
created_at: '2024-06-26', // OLD: created_at
internal_id: 'jane_doe', // OLD: internal_id
plan: 'enterprise',
value: 1000.00 // OLD: value
},
custom: {
emailCount: 4208
}
});
p.then((success) => {
if (success.valid) {
bindLink('bb-cancel', success.url);
} else {
bindLink('bb-cancel', 'https://app.yourcompany.com/cancel?id=jane_doe');
}
});
After
// NEW: Initialize Chargebee with site configuration
const chargebee = window.Chargebee.init({
site: "YOUR-CHARGEBEE-SUBDOMAIN",
});
function bindLink(id, url) {
document.getElementById(id).addEventListener('click', () => {
window.location.assign(url);
});
}
(async () => {
// NEW: Create cancelPage instance using chargebee object
const cancelPage = await chargebee.cancelPage();
const options = {
// NEW: subscription object
subscription: {
id: "CHARGEBEE_BILLING_SUBSCRIPTION_ID",
plan: "enterprise"
},
firstName: "Jane", // NEW: camelCase naming
lastName: "Doe", // NEW: camelCase naming
email: "jane.doe@example.com",
externalUserId: "jane_doe", // NEW: externalUserId instead of internal_id
saveReturnUrl: "https://app.yourcompany.com/save?id=jane_doe", // NEW: camelCase
cancelConfirmationUrl: "https://app.yourcompany.com/cancel_confirm?id=jane_doe", // NEW: camelCase naming
account: {
customerId: "CHARGEBEE_BILLING_CUSTOMER_ID", // NEW: customerId instead of billing_id
firstPurchaseDate: "2024-06-26", // NEW: firstPurchaseDate instead of created_at
contractValue: 1000.00 // NEW: contractValue instead of value
},
custom: {
emailCount: 4208
}
};
// NEW: cancelPage.getPage() method instead of Brightback.handleDataPromise()
cancelPage.getPage(options).then((result) => {
if (result.valid) {
bindLink('cb-cancel', result.url);
} else {
bindLink('cb-cancel', 'https://app.yourcompany.com/cancel?id=jane_doe');
}
});
})();
See full list of parameter schema changes.
Input parameter schema changes
The input parameters for the methods have been changed as follows:
| Brightback.js | Chargebee.js | Notes |
|---|---|---|
app_id | Not needed. | Site is configured globally in Chargebee.init(). |
first_name | firstName | Changed to camel case. |
last_name | lastName | Changed to camel case. |
full_name | fullName | Changed to camel case. |
save_return_url | saveReturnUrl | Changed to camel case. |
cancel_confirmation_url | cancelConfirmationUrl | Changed to camel case. |
account.company_name | account.companyName | Changed to camel case. |
account.company_domain | account.companyDomain | Changed to camel case. |
account.billing_id | account.customerId | Renamed. |
account.value | account.contractValue | Renamed. |
account.created_at | account.firstPurchaseDate | Renamed. |
account.internal_id | externalUserId | Renamed and moved to top level. |
account.plan | subscription.plan | Moved to subscription object. |
account.plan_term | subscription.planTerm | Moved to subscription object. |
subscription_id | subscription.id | Renamed and moved to subscription object. |
Best practices
Local development
By default and for security reasons, Chargebee does not respond to cancel page API requests from localhost. For local development to work, temporarily map a domain to your localhost to verify the XHR request or use a tunnel service like ngrok or localtunnel. Watch the network tab in your DOM inspector to diagnose any additional issues.
Render within iframes
You can embed the Chargebee cancel page within your application using an iframe. To do so securely, you must configure a vanity domain that matches the domain of your website. For example, if your app runs at https://app.yourcompany.com, the iframe must load from a domain like https://cancel.yourcompany.com. Domains like yourcompany.chargebee.com cannot be embedded in an iframe due to cross-origin restrictions.
Additional resources
We're always happy to help you with any questions you might have! Click here to reach out to us.