You can customize the customer portal experiences using any of the following Loop's capabilities:
Custom JS events
Customer portal fires custom JavaScript (JS) events whenever a subscriber takes an action, such as adding a product, applying a discount, or skipping an order. Store developers can listen for these events to trigger custom experiences, like sending a contextual email or updating a record in an external tool. Each event carries a payload identifying the exact customer and subscription ID behind the action, so you can scope those experiences to individual subscribers.
This article covers the events available, the payload each one returns, how to set up event listeners, and common use cases.
What's in the event payload
Every customer portal event returns a detail object containing two identifiers:
Property | Description |
| The Shopify Customer ID of the subscriber who triggered the action. |
| The Shopify Subscription ID tied to the action. |
These identifiers let you tie each event to a specific customer and subscription, instead of treating every action as a generic, store-wide ping.
Setting up event listeners
To use these events, set up event listeners in your code. A listener detects when a specific action occurs and runs the function you define.
Read the detail property from the event object to access the customer and subscription IDs:
window.addEventListener('loopAddAsOneTime', (event) => { const { shopifyCustomerId, shopifySubscriptionId } = event.detail;
// write code to trigger the custom experience here,
// now scoped to a specific customer/subscription });
Above example code listens to the loopAddAsOneTime event and pulls the customer and subscription IDs from the payload, so any experience you trigger is scoped to that specific subscriber.
Note: Existing event listeners continue to work without changes. The payload is an additive, non-breaking change, so listeners written without considering these additional details in payload continue to work as-is.
List of customer portal events
The customer portal events are grouped into three categories based on the type of action they represent.
Product-based events
loopAddAsOneTime: Triggered when a product is added as a one-time purchase.loopAddAsSubscription: Triggered when a product is added on a subscription basis.loopRemoveForOneTime: Triggered when a one-time product is removed.loopRemoveFromSubscription: Triggered when a subscription product is removed.loopProductSwap: Triggered when a product swap is made.loopUpdateProductQuantity: Triggered when the quantity of a product is updated.
Subscription-based events
loopAddDiscount: Triggered when a discount is applied to a subscription.loopRemoveDiscount: Triggered when a discount is removed.loopChangeSubscriptionPlan: Triggered when a subscription plan is changed.loopChangeDeliveryMethodRequested: Triggered when a change in delivery method is requested.loopEditDeliveryDetails: Triggered when delivery details are edited.loopUpdatePaymentMethodRequested: Triggered when an update to the payment method is requested.loopCancelSubscription: Triggered when a subscription is canceled.loopReactivateSubscription: Triggered when a subscription is reactivated.loopPauseSubscription: Triggered when a subscription is paused.loopResumeSubscription: Triggered when a subscription is resumed.
Order-based events
loopOrderNow: Triggered when an order is placed immediately.loopSkipNextScheduledOrder: Triggered when the next scheduled order is skipped.loopSkipFutureScheduledOrder: Triggered when future scheduled orders are skipped.loopRescheduleNextOrder: Triggered when the next order is rescheduled.loopDelayNextOrder: Triggered when the next order is delayed.loopUnskipOrder: Triggered when a previously skipped order is reinstated.
Bundle-based events
loopBundleAddAsOneTime: Triggered when a bundle is added as a one-time purchase.loopBundleAddAsSubscription: Triggered when a bundle is added on a subscription basis.loopBundleRemoveForOneTime: Triggered when a one-time bundle is removed.loopBundleRemoveFromSubscription: Triggered when a subscription bundle is removed.loopBundleVariantChange: Triggered when a variant within a bundle is changed.loopPresetBundleUpdateQuantity: Triggered when the quantity of a preset bundle is updated.
Use cases for customer portal events
As each event identifies the customer and subscription behind the action, you can build precise, contextual experiences on top of these events. Common use cases include:
Sending contextual communications: Trigger a Klaviyo event tied to the exact customer who took the action, rather than a generic action ping. For example, send a targeted email when a specific subscriber cancels.
Updating external records: Update a customer-specific record in your CRM or analytics tool the moment a subscriber takes an action.
Building subscription-level personalization: Trigger an experience for a single subscription rather than store-wide.
Tracking behavioral data: Monitor how subscribers interact with customer portal by tracking actions like product additions, updates, or removals.
And more!
Customer portal window variable
Loop's customer portal application offers a window variable making it easier for developers to access information related to customer, subscription, discounts and upgrade offers surfaced on the portal.
Use cases of window variables
The window.loopProps variable gives you access to read live data to trigger or personalize custom experiences in the portal.
Common use cases:
Read the customer's email, tags, or subscription status to conditionally render content for specific segments.
Show subscription details like the next billing date, delivery interval, or line items in a custom UI element.
Use the subscriber's active discounts or volume discount tier to display savings messaging.
Customer portal information available in window variables
The following information is available in the window.loopProps variable:
Customer
Shopify customer ID
Email
First name and last name
Customer tags
Subscription
Subscription ID and Shopify subscription ID
Status
Currency code
Completed orders count
Next billing date and next order date after skip
Upcoming order ID
Created date
Billing policy and delivery policy
Delivery method
Shipping address
Payment method
Line items
Total line item price
Delivery price
Available delivery intervals
Prepaid status and remaining prepaid orders count
Discounts
Applied subscription and line-item discounts
Discount type, title, and value
Total savings on the next order
Volume discounts
Active volume discount programs
Program type, channel, and eligibility
Discount tiers and thresholds
Currently eligible tier
Upgrade profiles
Available upgrade profiles for the subscriber
Customer portal window variable field reference
Field | Meaning |
customer |
|
| Shopify Customer ID |
| Customer's email address |
| Customer's first name |
| Customer's last name |
| Customer tags in Shopify |
subscription |
|
| Loop's internal subscription ID |
| Shopify Subscription ID |
| Subscription status (e.g. active) |
| Whether the subscription contains a bundle |
|
|
| Delivery/shipping price |
| Currency code for the subscription |
| Number of orders completed on this subscription |
| Next billing date (epoch timestamp) |
| Next order date if the upcoming order is skipped (epoch) |
|
|
|
|
| ID of the upcoming order |
| Subscription creation date |
| Maximum billing cycles |
| Minimum billing cycles |
| Billing interval unit (e.g. MONTH) |
| Number of intervals per billing cycle |
|
|
|
|
|
|
|
|
| Delivery interval unit (e.g. MONTH) |
| Number of intervals per delivery cycle |
|
|
|
|
|
|
|
|
| Custom attributes on the subscription |
|
|
| Discount ID |
| Discount type (e.g. MANUAL) |
| Discount title |
| Discount value type, indicating whether the discount is a percentage (SubscriptionDiscountPercentageValue) or fixed amount (SubscriptionDiscountFixedAmountValue) |
| Percentage value, present when the discount is a percentage type |
| Fixed discount amount, present when the discount is a fixed amount type |
| Currency code for the fixed discount amount |
| Whether the fixed amount applies to each item, present for fixed amount discounts |
| What the discount applies to (e.g. LINE_ITEM) |
| Number of times the discount has been used |
| Whether the discount applies to all line items |
| IDs of the specific line items the discount applies to |
|
|
| Number of cycles the discount recurs for |
| Note on the subscription |
|
|
| Total price of line items before discounts |
| Whether the subscription is prepaid |
| Delivery method (e.g. SHIPPING) |
| Shipping address ID |
| ID of the subscription contract the address belongs to |
| Recipient's first name |
| Recipient's last name |
| Recipient's full name |
| Recipient's phone number |
| Company name |
| Address line 1 |
| Address line 2 |
| City |
| Postal/ZIP code |
| Country |
| Province/state |
| Province/state code |
| Country code |
| When the address was created |
| When the address was last updated |
| Selling plan display name |
| Delivery interval unit |
| Number of delivery intervals |
| Billing interval unit |
| Number of billing intervals |
| Shopify selling plan ID |
| Total amount the customer has spent on this subscription |
| Billing date of the last successful order (epoch) |
|
|
|
|
| Whether the subscription is marked for cancellation |
| Payment error message shown to the subscriber |
| Currency code for the delivery price |
| Remaining prepaid orders |
| Whether prepaid auto-renewal is enabled |
| Name on the payment instrument |
| Card brand |
| Payment source (e.g. credit_card) |
| Payment instrument type (e.g. CustomerCreditCard) |
| Card expiry year |
| Last digits of the card |
| Card expiry month |
| Billing address postal/ZIP code |
| Billing address city |
| Billing address country |
| Billing address line 1 |
| Billing address last name |
| Billing address province/state |
| Billing address first name |
| Billing address country code |
| Billing address province/state code |
|
|
| Whether the payment method is revoked |
| Risk level of the payment method |
| When a payment update email was sent |
|
|
|
|
|
|
| When the payment method was last updated |
| Details of the last billing attempt |
| Line item ID |
| Product title |
| Variant title |
| Line item price |
| Quantity |
| Shopify variant ID |
| Shopify product ID |
| Discount amount allocated to this line item |
| Currency code for the allocated discount amount |
| ID of the discount allocated to this line item |
| Discount type (e.g. MANUAL) |
| Discount title |
| Percentage value, present when the discount is a percentage type |
| Fixed discount amount, present when the discount is a fixed amount type |
| Currency code for the fixed discount amount |
| Whether the fixed amount applies to each item, present for fixed amount discounts |
| What the discount applies to (e.g. LINE_ITEM) |
| Number of times the discount has been used |
| Whether the discount applies to all line items |
|
|
| Number of cycles the discount recurs for |
| Base price before discounts |
| Whether added as a one-time item |
| Whether removed as a one-time item |
| Price after discounts |
| Bundle transaction ID, if part of a bundle |
| Selling plan name |
| Selling plan ID |
| Selling plan group ID |
| Selling plan group name |
| SKU |
| Whether the item requires shipping |
|
|
| Variant image URL |
| Available inventory for the variant |
| Product SKU |
| Product handle |
| Whether the item can be swapped |
| Custom attributes on the line item |
|
|
|
|
allSubscriptions |
|
|
|
upgradeProfiles |
|
| Upgrade profile ID |
| Upgrade profile name |
| Priority of the upgrade profile |
volumeDiscountData |
|
| Volume discount type (e.g. ORDER_SIZE) |
| Program ID |
| Program nano ID |
| Program name |
| Program label |
| Program type (e.g. ORDER_SIZE) |
| What eligibility is based on (e.g. PRICE) |
| Program priority |
| Which products are eligible (e.g. ALL) |
| Which purchase options are eligible (e.g. ALL) |
| Channel the program applies to (e.g. CUSTOMER_PORTAL) |
| Tier ID |
| Tier nano ID |
| Minimum threshold to qualify for the tier |
| Discount type (e.g. PERCENTAGE) |
| Discount amount |
| Discount label |
| Whether the tier is recommended |
| Tier ID of the tier the subscriber currently qualifies for |
| Tier nano ID of the currently eligible tier |
| Minimum threshold of the currently eligible tier |
| Discount type of the currently eligible tier |
| Discount amount of the currently eligible tier |
| Discount label of the currently eligible tier |
| Whether the currently eligible tier is recommended |
| Variant IDs eligible for the program |
Custom section on the Customer portal
You can create and host multiple custom sections in the Customer portal with personalized texts powered by Loop's customer/subscription/store based variables.
Learn more about how to add and personalize a custom section.
FAQs
Do I need to change my existing event listeners to get the payload?
No, existing listeners continue to work without any changes. The payload is an additive, non-breaking change, so listeners written before this update keep functioning as-is. To use the new data, read the detail property from the event object.
Can I identify which subscriber triggered an event?
Yes, every customer portal event returns a detail object with shopifyCustomerId and shopifySubscriptionId, so you can tie each action to a specific customer and subscription.
Will the payload work with tools like Klaviyo or my CRM?
Yes, you can pass the shopifyCustomerId and shopifySubscriptionId from the payload into any tool you call inside your event listener, such as sending a customer-specific Klaviyo event or updating a CRM record.
Do these events fire for actions taken outside customer portal?
No, these events fire only for actions subscribers take within customer portal. Bundle builder and storefront actions use a separate set of events covered in Bundle JavaScript events & window variables for custom experience.
Need help?
No worries - we're here for you!
If you have any questions or need assistance, feel free to email us at [email protected] or chat with us using the support beacon at the bottom right of your screen.
Regards,
Loop subscriptions team 🙂
