Recharge
Overview
Beam drives an 8% lift in subscription revenue by increasing conversion and lifetime. With Beam, when a customer chooses a nonprofit at checkout for a subscription, a portion of that purchase and each recurring purchase goes to the nonprofit selected.
Our Recharge subscription widget lives in your Recharge customer portal and enables users to visualize the impact they’re making over time as well as the community’s impact for that nonprofit. Users can change their preferred nonprofit at any time. Additionally users who have an active subscription can choose to opt into a Beam donation at any time.
This builds emotional buy in over time as they return to their customer portal, re-affirming their subscription purchase and decreases cancellation.
Customer Journey + Lifecycle
Opt into Beam on the first subscription purchase
-
Customer makes a subscription purchase & chooses Beam in cart or on the post purchase thank you page
-
Customer logs into their Recharge customer portal and can see their impact growing with each subsequent purchase, directly above the point of churn
-
If the customer decides to select a new nonprofit, they can do so for their next subscription renewal
Opt into Beam after the first subscription purchase
-
Customer makes a subscription purchase & does not use Beam
-
Customer logs into their Recharge customer portal and sees the opportunity to select a nonprofit for their active subscription
-
Customer chooses a nonprofit to make an impact with their upcoming subscriptions
Integration Process
- Reach out to your Beam CS Lead if you’re interested in the Beam | Recharge Integration
- Your CS Lead will follow up with mocks of the integration customized to your site for your team to react to
- We’ll schedule a 2-3 day integration window with the Beam team during which we will develop the widget in your Recharge dashboard, QA, and publish it to your users. We’ll work within your preferred dev process to get this up and running without any lift on your end.
Please note that Recharge requires a Recharge Pro plan, or Custom plan, in order to add custom content to your Recharge Customer Portal
Integration Implementation
The following code snippet should be placed in the Footer HTML/CSS/JS section of your Recharge Customer Portal, under Customize styles.
Replace the following in the example
beamApiKey
- This is your Beam-provided API keybeamStoreId
- This is your Beam-provided store id
<!-- BEAM START -->
<script
type="module"
async
crossorigin
src="https://sdk.beamimpact.com/web-sdk/{{ sdk_version }}/dist/components/subscription-management.esm.js"
></script>
<script type="text/html" data-recharge-slot="*.footer">
<div id="beam-subscription-management-section" style="display:none;">
<div id="beam-subscription-management-container" style="margin:16px auto 0; border:none; max-width:100%"></div>
</div>
</script>
<script type="module">
const beamSubscriptionManagementWidgetManager = {
wrapperContainerId: "beam-subscription-management-section",
targetContainerId: "beam-subscription-management-container",
activeSubscriptions: [],
activeCustomer: null,
beamApiKey: "{{ storefront_component_api_key }}",
beamStoreId: "{{ store_id }}",
isBeamLiveForEveryone: true,
session: null,
async getSession() {
const session = await recharge?.auth?.loginCustomerPortal()
.catch((error) => {
console.error("[Beam] Authentication failed:", error);
throw error;
});
return session;
},
async getSubscriptions() {
if (!this.session) {
this.session = await this.getSession();
}
const { subscriptions } = await recharge?.subscription?.listSubscriptions(this.session, {
sort_by: "id-asc",
status: "Active",
})
.catch((error) => {
console.error("[Beam] Fetching subscriptions failed:", error);
throw error;
});
return subscriptions ?? [];
},
async getCustomer() {
if (!this.session) {
this.session = await this.getSession();
}
const customer = await recharge.customer.getCustomer(this.session);
return customer;
},
shouldShowBeam(customerEmail) {
return (
this.isBeamLiveForEveryone || customerEmail?.includes("@beamimpact.com")
);
},
async updateSubscription(subscriptionId, nonprofitId, selectionMethod) {
const requestOptions = {
method: "POST",
headers: {
Authorization: `Api-Key ${this.beamApiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
remoteSubscriptionId: subscriptionId,
nonprofitId: nonprofitId,
selectionMethod: selectionMethod,
}),
};
try {
await fetch("https://api.beamimpact.com/api/v3/subscriptions/updateSubscriptionNonprofit", requestOptions);
} catch (error) {
console.error("[Beam] Error in updateSubscription:", error);
}
},
handleBeamNonprofitSelectEvent(event) {
const selectedNonprofitId = event.detail.selectedNonprofitId;
const selectionSource = event.detail.source;
if (selectionSource != "select-subscription-nonprofit") {
return;
}
await Promise.all(
this.activeSubscriptions.map((subscription) =>
this.updateSubscription(String(subscription?.id), selectedNonprofitId, "dashboard")
)
);
},
unmountWidget() {
window.removeEventListener("beamnonprofitselect", this.handleBeamNonprofitSelectEvent);
document.getElementById(this.wrapperContainerId).style.display = "none";
document.querySelector("beam-subscription-management")?.remove();
},
mountWidget(activeSubscription, customer) {
const subscriptionId = activeSubscription?.id;
const customerEmail = customer?.email;
if (subscriptionId && this.shouldShowBeam(customerEmail)) {
const beamSubscriptionManagementEl = document.createElement("beam-subscription-management");
beamSubscriptionManagementEl.setAttribute("apiKey", this.beamApiKey);
beamSubscriptionManagementEl.setAttribute("subscriptionId", subscriptionId);
beamSubscriptionManagementEl.setAttribute("storeId", this.beamStoreId);
beamSubscriptionManagementEl.setAttribute("email", customerEmail);
const targetElement = document.getElementById(this.targetContainerId);
targetElement?.appendChild(beamSubscriptionManagementEl);
document.getElementById(this.wrapperContainerId).style.display = "block";
}
this.handleBeamNonprofitSelectEvent = this.handleBeamNonprofitSelectEvent.bind(this);
window.addEventListener("beamnonprofitselect", this.handleBeamNonprofitSelectEvent);
},
async init() {
const isBeamAlreadyLoaded = document.querySelector("beam-subscription-management");
if (isBeamAlreadyLoaded) {
return;
}
try {
this.activeSubscriptions = await this.getSubscriptions();
this.activeCustomer = await this.getCustomer();
if (this.activeSubscriptions && this.activeSubscriptions[0]) {
this.mountWidget(this.activeSubscriptions[0], this.activeCustomer);
}
} catch (error) {
console.error("[Beam] Initialization failed:", error);
}
},
};
document.addEventListener("Recharge::slot::mounted", (event) => {
if (event.detail.name === "footer" && event.detail.pathname === "/subscriptions") {
beamSubscriptionManagementWidgetManager.init();
}
});
document.addEventListener("Recharge::slot::unmounted", (event) => {
if (event.detail.name === "footer" && event.detail.pathname === "/subscriptions") {
beamSubscriptionManagementWidgetManager.unmountWidget();
}
});
</script>
<!-- BEAM END -->
Recharge Flow Example
Click to see a screen recording of the user journey below.
https://drive.google.com/file/d/1nXmDCj6f6PVJj50WegF0q8UzEYVqek5y/view?usp=sharing