Hey @Lachezar_Stanev, thanks for the follow-up and sorry for the delay.
This is a known pattern issue with StatefulRemoteSubscribable in checkout extensions — the subscription callback can fire with stale data briefly after a cart mutation, before the updated state has fully propagated. Here’s what’s likely happening:
- Your extension detects a product with an age-restricted tag via the subscription
- You show the modal, the buyer confirms, and you call
applyAttributeChange to set an “age verified” attribute
- The
applyAttributeChange promise resolves, but the attributes subscription fires again with the previous cart state before the updated attributes have landed — so your modal logic sees the old data and re-triggers
A few approaches to fix this:
1. Gate on the mutation result, not just the subscription
After calling applyAttributeChange (or applyCartLinesChange for removing products), await the result and check that it returned { type: 'success' } before relying on subscription data again. Use local state (e.g., a useState flag) to track that the mutation is in-flight and suppress the modal during that window:
const [isUpdating, setIsUpdating] = useState(false);
// When verifying age:
setIsUpdating(true);
const result = await applyAttributeChange({
type: 'updateAttribute',
key: 'age_verified',
value: 'true',
});
// Don't clear isUpdating here — wait for the subscription to deliver the updated value
Then in your subscription handler / render logic:
if (isUpdating) return; // skip stale intermediate updates
const attributes = useAttributeValues(['age_verified']);
// Only check attributes once isUpdating is false and value has landed
2. Use useAttributeValues (React) instead of raw .subscribe()
If you’re using the React hooks API (@shopify/ui-extensions-react/checkout), useAttributeValues gives you a cleaner reactive binding that integrates with React’s render cycle, reducing the chance of acting on stale intermediate values.
3. Debounce the modal trigger
If the issue is intermittent (which you mentioned), it could be that the subscription fires multiple times in quick succession during a cart update. Adding a short debounce (e.g., 200-300ms) before evaluating whether to show the modal can help filter out transient stale states.
A note on applyCartLinesChange for removing products: the same pattern applies — await the result, and don’t re-evaluate cart lines until the subscription delivers the updated lines value. The promise resolving means the change was accepted, but the subscription may deliver one more stale snapshot before the updated one arrives.
Docs references:
If you could share a simplified version of your subscription + modal logic, I can give you a more targeted fix. Happy to take a closer look!