In Checkout extension multiple apis are getting called for different targetsCheckout UI extensions: Shared hook calling backend API multiple times across targets (cart-line + reductions) — how to avoid duplicate calls?

  • I have a shared useSimulation.js hook used by two targets:

    • purchase.checkout.reductions.render-before

    • purchase.checkout.cart-line-item.render-after .

  • I see my backend simulation API getting called multiple times (once per line) when I expected one call per checkout.

    I’m building a Checkout UI extension that uses multiple targets and a shared hook to call my backend “simulation” API (loyalty/points calculation).

    Setup

    I have a single extension bundle with two targets:

    1. purchase.checkout.reductions.render-before

      • File: earnbox.jsx

      • Used to show an order-level message like “Earn up to X points on this order”.

    2. purchase.checkout.cart-line-item.render-after

      • File: checkout.jsx

      • Used to show per-line +Y pts for each cart line.

    Both targets import and use a common hook: useSimulation(api, opts) from useSimulation.js.

    api is getting triggered 4 times 1 times for purchase.checkout.reductions.render-before target file, 3(if 3 items in checkout page ) times for purchase.checkout.cart-line-item.render-after taget file , both files use useSimulation its response is only used to render the reponse in these two targets

    what to do , should I use caching? I want api to be called once and used by all targets in checjout UI

Hey @Ammaar_Farhan_Syed :wave: thanks for reaching out, this is a great question. Hopefully I’m understanding correctly, but you’re using network access to make those API calls to your backend?

If so , the reason you’re seeing multiple API calls is that each extension target runs in its own Web Worker, so there’s no shared state between your reductions target and your
cart-line-item target. Essentially, purchase.checkout.cart-line-item.render-after fires a separate render call per line item in the cart, so your useSimulation hook ends up executing N+1 times total (1 for reductions + 1 per cart line).

That’s by design with how the extension runtime works currently, but I definitely get it’s not ideal when you just need the same data everywhere.

The good news is that all the cart-line-item render calls share the same worker, which means a module-level promise cache in your hook should collapse those multiple calls into 1. Something like a let cachedPromise that stores the fetch promise on first call, then returns it for every subsequent render. That gets you down to 2 calls total (1 from reductions, 1 shared across all cart lines).

To get it down even further, the recommended approach would be to pre-compute your data ahead of checkout rather than calling your backend at render time. You’d listen for something like the carts/update webhook, run your logic there in the backend, and store the results as metafields via the Admin API. Then both targets should be able to just read from metafields at checkout with zero network calls way faster and no duplication at all.

Hope this helps — let me know if I can clarify anything on our end here!