Shopify POS UI Extension: `shopify.cart.addLineItem` Performance Bottleneck

Hi @Victor_Chu, @Rune-Shopify & Shopify team,

I hope it’s ok to start a new thread about this issue. I still want to keep my other thread going to investigate cart transform issues, but I wanted to open a new issue related to shopify.cart.addLineItem(...), which both @Gunes and @derrick have both reported on.

We have been investigating add-to-cart performance in a Shopify POS UI extension and have found that shopify.cart.addLineItem(...) appears to be a major baseline bottleneck. We would appreciate guidance from Shopify on whether this latency is expected, and whether the POS cart APIs can be optimized for faster item creation.

Context

We have a POS UI extension for a cafe ordering workflow. The extension lets staff configure a product with modifiers, then adds the configured item to the Shopify POS cart with line item properties and cart properties.

The relevant APIs we tested are:


shopify.cart.addLineItem(variantId, quantity)

shopify.cart.addLineItemProperties(uuid, lineProperties)

shopify.cart.addCartProperties(cartProperties)

shopify.cart.bulkCartUpdate(cartUpdateInput)

Our original goal was to improve add-to-cart speed by moving from multiple sequential cart calls to bulkCartUpdate. After testing, we found that bulkCartUpdate is not faster for simple add-with-properties flows, but more importantly, the initial addLineItem(...) call itself consistently takes multiple seconds.

Test Environment

  • Surface: Shopify POS UI Extension

  • POS device: iPad running Shopify POS

  • Extension API package: @shopify/ui-extensions 2026.1.3

  • App type: Shopify app with embedded POS extension

  • Store/network/device kept consistent during the test runs

  • Timing captured inside the extension using performance.now()

  • Logs posted to a Gadget endpoint and streamed with ggt logs

Tested Add-To-Cart Strategies

We tested three strategies for adding a configured product with line item properties and cart properties.

1. Legacy Sequential


const uuid = await shopify.cart.addLineItem(variantId, quantity);

await shopify.cart.addLineItemProperties(uuid, lineProperties);

await shopify.cart.addCartProperties(cartProperties);

2. Bulk Cart Update


const uuid = await shopify.cart.addLineItem(variantId, quantity);

await waitForCartLineItem(uuid);

await shopify.cart.bulkCartUpdate({

lineItems,

properties: cartProperties,

cartDiscounts,

});

3. Parallel Property Calls


const uuid = await shopify.cart.addLineItem(variantId, quantity);

await waitForCartLineItem(uuid);

await Promise.all([

shopify.cart.addLineItemProperties(uuid, lineProperties),

shopify.cart.addCartProperties(cartProperties),

]);

Timing Results

Each strategy was tested repeatedly on the same device/store/network.


=== legacySequential ===

samples: 5

p50: 3049ms

p90: 3893ms

max: 3893ms

mean: 3244ms

=== bulkCartUpdate ===

samples: 5

p50: 4934ms

p90: 5728ms

max: 5728ms

mean: 4878.2ms

=== parallelProperties ===

samples: 4

p50: 2766ms

p90: 3431ms

max: 3431ms

mean: 2963.8ms

The fastest approach for our simple add-with-properties case was parallelProperties, but the total time was still usually around 2.7-3.4 seconds.

addLineItem Is a Major Baseline Cost

In a representative bulkCartUpdate run, the timing breakdown was:


addLineItemMs: 2623

waitForCartLineItemMs: 0

bulkCartUpdateMs: 2742

totalBlockingMs: 5367

strategy: bulk

This suggests that shopify.cart.addLineItem(...) alone took about 2.6 seconds.

The waitForCartLineItemMs value was 0ms in that run, which suggests the delay was not from our polling/wait helper. Instead, addLineItem(...) did not resolve until the POS cart line was already created and visible in shopify.cart.current.value.

So even after optimizing the property attachment step, the initial POS line creation remains a significant unavoidable delay.

Additional Observations

We found that bulkCartUpdate is useful for some existing-line mutation cases, but it is not a good fit for our simple add-with-properties flow.

For simple new-item adds:

  • bulkCartUpdate was slower than dedicated property APIs.

  • Resending the full cart payload is expensive.

  • Using bulkCartUpdate for duplicate quantity increments caused a serious issue where cart line prices changed to $0.00 on-device. We avoided this by no longer using bulkCartUpdate for duplicate adds.

Our current fastest safe path is:


const uuid = await shopify.cart.addLineItem(variantId, quantity);

await Promise.all([

shopify.cart.addLineItemProperties(uuid, lineProperties),

shopify.cart.addCartProperties(cartProperties),

]);

Even with that optimized path, addLineItem(...) itself remains a multi-second bottleneck.

Questions For Shopify

  1. Is a 2-3 second duration for shopify.cart.addLineItem(...) expected in Shopify POS UI extensions?

  2. Are there known performance limitations in POS cart line creation that extension developers should account for?

  3. Is Shopify planning any optimization work for addLineItem(...) latency?

  4. Is there a faster supported API for adding a variant line with initial line item properties in one operation?

  5. Could addLineItem(...) accept optional initial line item properties/cart properties in the future, so POS does not require separate calls after UUID creation?

  6. Are there recommended profiling steps or diagnostic data Shopify would like us to capture to help investigate?

Ideal API Shape

For POS ordering workflows, the ideal API would allow a configured line to be created with properties in one call:


await shopify.cart.addLineItem({

variantId,

quantity,

properties: lineProperties,

cartProperties,

});

This would avoid requiring developers to:

  • wait for a UUID before attaching properties

  • issue separate line-property/cart-property calls

  • use bulkCartUpdate as a workaround

  • risk full-cart rewrite side effects

Request

Could the Shopify POS team please investigate the performance of shopify.cart.addLineItem(...) in POS UI extensions, especially for workflows where staff need to add configured products quickly during checkout?

For cafe/restaurant POS use cases, an add-to-cart operation taking 2-3+ seconds creates a noticeable delay for staff during order entry. Any improvement to the baseline addLineItem(...) latency, or a new API for creating a line with initial properties, would make a significant difference.

Happy to provide more logs, timing breakdowns, or reproduction details if helpful.

Hey Adam,

Thanks for the writeup. The timings, the three strategies side by side, and the $0.00 repro on duplicate adds give us a lot to work with.

I’ll follow up here once we have a concrete read on root cause, what’s fixable short term, and whether the right longer-term answer needs an API change. No ETA yet, but we’ll keep you posted.

Victor

Hey @Victor_Chu , thank you very, very much for your time and help with this, it is very much appreciated :folded_hands:t5:

I noticed this as well. When adding a line item before closing my modal there was a significant delay. As a workaround I’ve handed that off to Tile, so the Modal closes quickly and the addLineItem runs whilst that is happening, so by the time the user returns to the cart it’s done - but without any noticeable delay.

Obviously a faster insert would be great, but this is not a bad workaround.

As @adamwooding says, being able to insert a line item and add a property in a single call would be very useful. That said, ideally this should not be implemented under the hood as an insert followed by the properties since that generates 2 cart updates which can fire off a lot of additional functions.

What would be great is a transaction. ie. something like this:

startCartTransaction()
insertLineItem()
addCart Property()
removeCart Property()
commitTransaction()

The end result being all changes are applied before a single cartUpdate event is generated. This could avoid a lot of churn due to subscribers processing partial changes.

Hey @Ian_Bale and @Victor_Chu,

Ian, thank you for your reply and the suggestion about handing the cart mutation off to the Tile. I think that is a really good workaround for improving perceived performance, especially when the delay is only a couple of seconds.

In our case, though, we have had a large number of merchants report that the addLineItem process can take up to 10-15 seconds. In those situations, even handing the work off to the Tile could still cause issues, because the cart mutation is still running for a long time in the background and we need to manage pending state, duplicate taps, failures, and cart reconciliation.

We have tried to find a common thread among those affected merchants, and so far it seems to be either older iPad hardware, weaker internet/Wi-Fi, or both. That makes me think there is an underlying issue with the current addLineItem flow, especially because extension developers have to wait for the POS-issued UUID before we can safely attach required line item properties.

For configured-product workflows, the current flow can require several separate cart mutations:

  1. Add the base product line with addLineItem.
  2. Shopify POS creates, validates, prices, and materializes that line before returning the POS-issued UUID.
  3. Use that UUID to attach the line item properties that describe the configured item, creating another cart update.
  4. Add/update cart properties, creating another cart update.
  5. Optionally apply discounts, creating another cart update.

In our app, we also use Cart Transform. The Cart Transform logic depends on the line item properties added after addLineItem, so the meaningful transform work likely happens after the property mutation rather than during the initial bare line insert.

That means the current API flow can create an intermediate cart state where the product line exists, but the metadata required to interpret it has not been attached yet. If Cart Transform functions, subscribers, or other cart update processing run after each mutation, a single configured item can cause multiple rounds of cart processing before the final cart state is ready.

When step 1 takes several seconds, everything else is blocked behind it.

@Ian_Bale - I also really like your transaction suggestion. I think that would be the ideal API shape, rather than Shopify simply adding a convenience wrapper that internally performs multiple cart mutations. Something like:


const transaction = await shopify.cart.startTransaction();

transaction.addLineItem({

variantId,

quantity,

properties: lineProperties,

});

transaction.addCartProperties(cartProperties);

await transaction.commit();

The important part would be that Shopify POS applies all changes as one atomic cart operation and emits one final cart update event, rather than exposing intermediate states or firing multiple cart updates/functions/subscribers.

That would help with a few things:

  • Avoid waiting for a UUID before attaching required properties.
  • Reduce partial cart states.
  • Avoid multiple cart update events for a single configured item.
  • Reduce cart transform / subscriber churn.
  • Improve reliability on older devices or weaker networks.
  • Give extension developers a safer way to create fully configured cart lines.

So I think there are two related asks here:

  1. Improve the baseline performance of shopify.cart.addLineItem(...), especially on older iPads or slower networks.
  2. Consider a transaction/batched cart API so extensions can create a configured cart line with properties and cart attributes in one atomic operation.

Happy to provide timing logs or reproduction details if useful.

Thank you so much,
Adam

Hi everyone,

Adding some more info here from my own testing (originally posted here).

We have been using the bulkCartUpdate method for some time now along with a cart transform and whilst it does provide a more consistent delay, it still adds a decent amount of time to the operation. Which in some contexts is undesirable, some merchants are not tolerant of this amount of delay.

I did some testing some time ago which I provided in an issue on the Shopify/ui-extensions repo, looks like issues have since been disabled so I can’t reference it anymore but here are the results I had:

Numbers for the bulkCartUpdate I got today:

Screenshot 2026-05-13 at 08.47.24

It seems to take around 2.5s, these were with a varying number of line items and a cart transform.

addLineItem (also from today) appears to take a similar amount of time:

Screenshot 2026-05-13 at 09.00.29

Screenshot 2026-05-13 at 09.00.29710×220 11.3 KB

Ignore the 5s+ one that one was out of stock :slightly_smiling_face:

If nothing has changed since my initial tests over a year ago then it looks like the cart transform adds another second to the latency.

It would be nice to be able to kick the bulkCartUpdate or addLineItem off from within an extension and have it queued (FIFO) to mutate the cart asynchronously rather than have us wait for the return result.

That way we could carry on doing whatever it is we want to do, e.g. dismiss the extension or navigate elsewhere, and be assured that the cart update was happening in the background. The cart update mutation could be indicated to the user via a loading spinner or skeleton text?

Would also be nice if you could add line item properties at the same time as adding a line item via addLineItem :slightly_smiling_face:

Hey @Victor_Chu ,

I just wanted to check in to see if you’ve had a chance to have a look at this issue?

Thank you so much,
Adam

Hi,

I’d like to point out another point in this discussion.

In my case, I created a POS app to customize a product using the lineItem properties. While testing this feature, I noticed that if I try to add the same variant of the product to the cart more than once, the cart merges it with the existing lineItem and returns its ID.
So, using addCartProperties, I’m overwriting the properties of the old one, making a mess.

We should be able to add a product to the cart with certain properties atomically to avoid this behavior.

Thanks!
Francesco