Personalizing the user journey in Affinity
Use custom flow extensions to intercept regular customer actions (ie. a customer skips or reschedules an order) and provide tailored experiences
NoteCustom flow extensions are supported in both the original Affinity experience (Affinity 1.0) and the new Affinity experience (Affinity 2.0). Where event behavior differs between versions, it's called out below.
Custom flow extensions intercept the initial click before the action occurs. Recharge no longer owns the interaction after the click is intercepted, and gives you full control over the flow. In addition to click events, Affinity emits action events after an action completes and navigation events when a customer moves between pages, which you can use to track customer behavior or trigger custom experiences.
Before you start
- You must be on the Recharge Plus or Custom pricing plans to make advanced customizations to the Affinity customer portal.
Event types
The following event types are available when customizing the Affinity customer portals:
| Event type | When it occurs | Use it for | Available on |
|---|---|---|---|
| Click | When a customer begins an action | Measuring intent or replacing the default Affinity flow |
|
| Action | After an action completes successfully | Measuring completed outcomes |
|
| Navigation | When the customer moves to another Affinity page | Journey analytics or page-specific extension behavior |
|
| Directive | Sent by your code when you want Affinity to perform a supported behavior | Refreshing Affinity after external data changes |
|
Available click and action events
Click and action events describe different points in the same journey. For example, Recharge::click::skip is emitted when the customer clicks Skip, while Recharge::action::skip is emitted only after the order has been skipped. Comparing the two can show where customers abandon a flow.
Implement custom flow extensions to respond when a user clicks one of the following:
| Action | Trigger | Click event | Completion event |
|---|---|---|---|
| Skip | The user clicks on the "Skip" button from an order or the subscription management page. | Recharge::click::skip | Recharge::action::skip |
| Unskip | The user clicks on the "Unskip" button from an order or subscription page. | Recharge::click::unskip | Recharge::action::unskip |
| Manage subscription | The user clicks on the "Manage subscription" button. | Recharge::click::manageSubscription | |
| Order Now | The user clicks on the "Send now" button on the next order page. | Recharge::click::orderNow | Recharge::action::orderNow |
| Reschedule | The user clicks on the "Reschedule" button from an order or the subscription management page. | Recharge::click::reschedule | Recharge::action::reschedule |
| Cancel | The user clicks on the "Cancel this subscription" link on the Overview page (Affinity 2.0) or the Subscription details page. | Recharge::click::cancel | |
| Reactivate | The user clicks on the "Reactivate" link on the subscription management page, or the Affinity overview page if the customer doesn't have active subscriptions. | Recharge::click::reactivate | Recharge::action::reactivate |
| Changes to an upcoming order | Any change affecting an upcoming order | Recharge::action::orderChanged |
Warning
Recharge::click::cancelis gradually replacingRecharge::extension::cancellation_flow. If your existing extension listens toRecharge::extension::cancellation_flow, it continues to work, but useRecharge::click::cancelfor new implementations.
Navigation events
Listen for Recharge::location::change to detect when a customer moves to another page in Affinity. The event detail includes the new path, which can be used for journey analytics:
document.addEventListener('Recharge::location::change', event => {
analytics.track('Affinity page viewed', {
path: event.detail?.pathname,
});
});Directives
Directives work in the opposite direction from events; your code dispatches a supported event for Affinity to receive and act on. Use directives to open common actions or refresh portal data after external changes:
| What you want Affinity to do | Directive | Optional details |
|---|---|---|
| Open Reschedule | Recharge::order::openRescheduleModal | Omit detail to reschedule the complete upcoming charge, or provide subscriptionId to reschedule one active subscription. |
| Open Skip | Recharge::order::openSkipModal | Omit detail to skip the complete upcoming charge, or provide subscriptionId to skip one active subscription. |
| Open Order now | Recharge::order::openOrderNowModal | None |
| Open Unskip | Recharge::order::unskip | None |
| Open Add product | Recharge::order::openAddProductModal | productId opens a product directly; collectionIds opens a filtered product list. When both are provided, productId takes priority. |
| Refresh Affinity data | Affinity:refresh | None |
Dispatch a directive as a CustomEvent on document. Unlike events emitted by Affinity, directive details are placed directly on event.detail rather than inside event.detail.payload. For example, to open Reschedule for the complete upcoming charge:
document.dispatchEvent(new CustomEvent('Recharge::order::openRescheduleModal'));To open Reschedule for one specific subscription:
document.dispatchEvent(
new CustomEvent('Recharge::order::openRescheduleModal', {
detail: { subscriptionId: 12345 },
})
);To open the Add product experience for a specific product:
document.dispatchEvent(
new CustomEvent('Recharge::order::openAddProductModal', {
detail: { productId: '9876543210' },
})
);If custom code changes data outside the standard Affinity flow, dispatch the refresh directive so the page requests the latest data:
document.dispatchEvent(new CustomEvent('Affinity:refresh'));
Note:Directives only work while the part of Affinity that handles them is available. Order directives are intended for the Next order experience, and the Add product directive requires the Add product carousel to be available. A targeted Reschedule or Skip directive is ignored when
subscriptionIddoesn't identify an eligible active subscription.
Track customer behavior
Listen for events with document.addEventListener. The following example records when a customer starts and successfully completes the Skip flow:
document.addEventListener('Recharge::click::skip', event => {
analytics.track('Affinity skip started', event.detail?.payload);
});
document.addEventListener('Recharge::action::skip', event => {
analytics.track('Affinity skip completed', event.detail?.payload);
});Replace a standard flow with a custom flow extension
Click events occur before Affinity continues with its default behavior. A custom flow extension intercepts the click, blocks the standard flow, and displays your own experience instead.
To create a custom flow extension:
- Listen for the specific click event.
- Call
event.preventDefault()to block the standard flow. - Retrieve the relevant subscription IDs. All click events include a list of relevant subscription IDs in the payload under
event.detail.payload.subscriptionIds. - Use the storefront SDK to access additional context about the subscription, address, or customer.
- Display your custom flow based on the gained context.
WarningCalling
preventDefault()transfers full responsibility for that interaction to your code. Affinity won't continue with its standard flow, so your implementation must provide the complete experience, including validation, error handling, confirmation, accessibility, and any required Recharge API calls.
Custom flow example
The following example interrupts the cancelation process for specific products. If the subscription being canceled matches a list of restricted product IDs, a message urges the customer to contact support instead. The standard cancelation flow applies to all other products:
<script>
// Define the list of product IDs that are not eligible for direct cancellation
const uncancellableProductIds = [PRODUCTID];
// Customize the message to guide customers to contact you
const alertMessage = "To cancel this product, please reach out to us at [email protected]";
// Listen for the cancel click event
// Note: Recharge::click::cancel replaces Recharge::extension::cancellation_flow
document.addEventListener(
"Recharge::click::cancel",
(event) => {
const { subscription } = event.detail;
const subscriptionProductId = subscription.shopify_product_id;
// Check if the product is in the list of uncancellable products
if (uncancellableProductIds.includes(subscriptionProductId)) {
// Prevent the default cancellation flow
event.preventDefault();
// Display an alert to guide customers
window.alert(alertMessage);
}
}
);
</script>
WarningIt is important to consider and incorporate Automatic Renewal Laws (ARL) into any custom cancelation process to ensure legal compliance. See Automatic Renewal Law (ARL) and Recharge to learn more about ARLs and how Recharge remains compliant.
Updated 8 days ago
