Notify Me CTA
When a product or selected variant is out of stock, the primary Call to Action (CTA) button on the Product Detail Page (PDP) can display “Notify Me” instead of “Add to Cart”. This applies to both simple products and configurable products with multiple options (for example, size and color). When the shopper switches to a different variant, the CTA updates dynamically based on that variant’s stock status.
Prerequisites
Before following these steps, you should understand:
- Events —
pdp/data,pdp/valid, and subscription patterns - Functions —
getProductConfigurationValuesfor reading selected options - Cart Events —
cart/datafor detecting when the product is already in the cart
This how-to uses the basic tools exposed by the Product Details drop-in: the event bus and a CTA element in your block. For a full implementation reference example in the Commerce boilerplate, see hlxsites/aem-boilerplate-commerce#1116.
Overview
These are the basic steps to implement the “Notify Me” CTA:
- Target a DOM element for the primary CTA (in many PDP blocks, this is the Add to Cart button).
- Subscribe to events —
pdp/data,pdp/valid, andcart/data— to know when product data, validation state, or cart state changes. - In each callback, update the CTA text and enabled/disabled state based on stock status, configuration validity, and whether the item is already in the cart.
Implementation steps
Implement a CTA update function
Create a function that updates the CTA element based on stock status, update mode (item in cart), and labels. When out of stock, set the button text to “Notify Me”, remove the cart icon, and keep the button enabled. When in stock, show “Add to Cart” or “Update in Cart” with the cart icon based on cart context.
The following examples use variable names from the boilerplate; adjust to match your block’s structure.
function updatePrimaryCTA(buttonInstance, { isOutOfStock, isUpdateMode, labels }) { if (!buttonInstance) return;
if (isOutOfStock) { buttonInstance.setProps((prev) => ({ ...prev, children: labels.Global?.NotifyMe || 'Notify Me', icon: null, disabled: false, })); } else { const buttonText = isUpdateMode ? labels.Global?.UpdateProductInCart : labels.Global?.AddProductToCart; buttonInstance.setProps((prev) => ({ ...prev, children: buttonText, icon: h(Icon, { source: 'Cart' }), })); }}Track stock and update mode state
Maintain state variables for the currently selected product’s stock status and whether the item is in the cart (update mode). These drive the CTA update logic.
let isUpdateMode = false;let isOutOfStock = false;Subscribe to pdp/data for stock status
Subscribe to pdp/data with { eager: true } so the handler runs on initial load and whenever the product or variant changes. Read inStock from the payload and update the CTA accordingly.
Why: Product data (including stock) changes when the page loads or when the shopper selects a different variant. You need to react to both.
events.on('pdp/data', (data) => { isOutOfStock = data?.inStock === false; updatePrimaryCTA(addToCart, { isOutOfStock, isUpdateMode, labels });}, { eager: true });See the pdp/data event reference for the full event payload.
Subscribe to pdp/valid for configuration validity
Subscribe to pdp/valid with { eager: true }. When the product is in stock, disable the button if the configuration is invalid (for example, required options not selected). When out of stock, keep the “Notify Me” button enabled regardless of configuration validity.
Why: For Add to Cart, the button should be disabled until the shopper completes required selections. For Notify Me, the button can stay enabled so the shopper can request notification even before selecting options.
events.on('pdp/valid', (valid) => { if (!isOutOfStock) { addToCart.setProps((prev) => ({ ...prev, disabled: !valid })); }}, { eager: true });Handle out-of-stock clicks in the button handler
At the top of the CTA’s onClick handler, check isOutOfStock. When true, run your custom notify-me logic and return early so no cart logic executes.
onClick: async () => { if (isOutOfStock) { const values = pdpApi.getProductConfigurationValues(); // Replace with your logic: open modal, call back-in-stock API, emit custom event, etc. console.log('Notify Me', { sku: product?.sku, values }); return; }
// ... Add to Cart / Update in Cart logic}Subscribe to cart/data for update mode
Subscribe to cart/data with { eager: true }. When the cart data changes, determine whether the current product is already in the cart. If so, set isUpdateMode and call updatePrimaryCTA so the button shows “Update in Cart” instead of “Add to Cart”.
Why: The CTA text and behavior differ when the item is already in the cart. Cart data changes when items are added, updated, or removed.
events.on( 'cart/data', (data) => { // Determine if current product/variant is in cart... isUpdateMode = itemIsInCart; updatePrimaryCTA(addToCart, { isOutOfStock, isUpdateMode, labels }); }, { eager: true },);Reset the CTA after cart actions
After an add-to-cart or update-in-cart action completes (for example, in the finally block of your click handler), call updatePrimaryCTA to restore the correct button state.
finally { updatePrimaryCTA(addToCart, { isOutOfStock, isUpdateMode, labels }); addToCart.setProps((prev) => ({ ...prev, disabled: false, }));}