Issue Summary
Our POS extension experiences severe performance degradation during peak hours. Add-to-cart operations that normally take 1-2 seconds increase to 5-8 seconds during busy periods. Force-closing and restarting the Shopify POS app temporarily restores normal performance.
Performance Comparison
- Off-peak: 1-2 seconds per add-to-cart
- Peak hours: 5-8 seconds per add-to-cart (and sometimes up to 15 seconds)
- After POS app restart: Returns to 1-2 seconds (then degrades again)
Supporting Evidence
Please see the following screen recordings demonstrating:
Normal performance
(1-2s, 3 API calls completing quickly) during off-peak hours
Degraded performance
(5-8s, each API call taking longer) during peak hours - these are from two different merchants:
Example 01:
Example 02:
Current Implementation: Sequential API Calls
We currently use the standard sequential approach for adding items to the cart:
// Step 1: Add the line item
const uuid = await shopify.cart.addLineItem(
Number(variantId),
quantity
);
// Step 2: Add line item properties
await shopify.cart.addLineItemProperties(
uuid,
lineProperties // includes _modifierVariants, _order_type, etc.
);
// Step 3: Update cart properties
await shopify.cart.addCartProperties(mergedCartProperties);
Current Approach Characteristics
- 3 sequential API calls per add-to-cart operation
- 2-3 Cart Transform executions (triggered after each cart mutation)
- Race condition potential between calls (properties added after initial line item)
- Each API call must complete before the next begins
Optimized Cart Transform Function
Our Rust Cart Transform function is optimized with:
- Early exits to skip unnecessary processing
- Pre-allocated vectors with capacity hints
- Cached attribute lookups to avoid repeated HashMap access
- Minimal string allocations using
Cow<str>
// Early exit if no processing needed
fn should_process(cart: &input::InputCart) -> bool {
let referrer = cart.referrer.as_ref().and_then(|a| a.value.as_ref());
referrer.is_some()
}
// Parse modifiers with early returns
fn parse_modifier_variants(line: &input::InputCartLines) -> Vec<ModifierVariant> {
let value = match line.modifier_variants
.as_ref()
.and_then(|attr| attr.value.as_ref()) {
Some(v) => v,
None => return vec![],
};
if value.is_empty() {
return vec![];
}
serde_json::from_str::<Vec<ModifierVariant>>(value).unwrap_or_default()
}
Key Observations
- Time-based pattern: Fast in morning, degrades throughout the day during peak hours
- Affects all locations and devices (multiple iPads at different sites)
- App restart fixes it temporarily: Suggests memory/state accumulation in POS app
- General Shopify POS sluggishness: Users report overall Shopify POS slowness during same periods (not just our extension)
- Same code, different performance: Identical code runs fast off-peak, slow during peak
- Multiple Transform executions: Each of our 3 API calls may trigger a Cart Transform, compounding latency
Performance Breakdown
Off-Peak (Normal)
- Total: 1-2 seconds
addLineItem: ~400-600msaddLineItemProperties: ~400-600msaddCartProperties: ~200-400ms- Cart Transform (2-3x): Unknown execution time
Peak Hours (Degraded)
- Total: 5-8 seconds
- Each API call appears significantly slower
- Cart Transform executions may also be slower
- Compounding effect with sequential calls
Business Impact
- Peak hours = 60-70% of daily revenue
- Staff must wait 5-8 seconds per item during lunch/dinner rush
- Each add-to-cart requires 3 sequential API calls + multiple Cart Transform executions
- Reduced order throughput during critical business periods
- Staff resorting to app restarts multiple times per shift
- Customer satisfaction impacted by slow service
What We Need
Immediate Questions
- Is this a platform-level performance issue during peak load?
- Is this a POS app memory/state management issue?
Guidance Requested
- Recommendations for improving performance with our current approach
- Best practices for Cart API usage during high-load scenarios
- Whether atomic cart updates would be more resilient during peak periods
Context: Why We Use This Approach
We currently use the sequential approach because:
- It’s the documented standard pattern for adding line items with properties
- We need to attach custom properties (including
_modifierVariantsJSON for Cart Transform)
We’re open to refactoring if a different approach would solve the peak-hour performance issue.
Technical Details
- Platform: Shopify POS (iOS/iPad)
- Extension Type: POS UI Extension (Preact) + Cart Transform Function (Rust)
- API Version:
2025.10.x - Cart Transform: Expands line items based on
_modifierVariantsproperty - Current Pattern:
addLineItem→addLineItemProperties→addCartProperties