Since POS update 11.6.1, we have identified three breaking changes affecting POS UI Extensions that use the scanner and modal APIs:
shopify.scanner.hideCameraScanner() no longer works. Calling the method executes without error (confirmed via logs), but the camera scanner overlay remains on screen and does not dismiss. The only way to close it is for the user to manually press the X button. This is confirmed via setTimeout testing, the function fires correctly but has no effect on the native camera overlay.
window.close() no longer reliably closes the extension modal when called from an async context. Calling window.close() from within a chain of awaited Shopify API calls (e.g. after cart.addCartCodeDiscount) does not dismiss the modal in production. The same call works correctly when triggered directly from a user interaction (button press). This may share a root cause with the hideCameraScanner() issue, both are commands sent from the extension to dismiss a native overlay, and both stopped working in 11.6.1. It appears POS 11.6.1 may have changed or broken how the native layer handles dismissal signals originating from async extension code.
The camera scanner now renders full-screen within the modal. Prior to 11.6.1, the camera scanner rendered as a partial overlay within the modal view. It now takes up the full modal screen, which is a breaking UI change for extensions that display UI alongside the scanner.
All three issues are reproducible on production devices running POS 11.6.1 and were not present on earlier versions.
I upgraded the API version from 2026-01 to 2026-04, but I’m still experiencing the same issue: the camera overlay remains open even after calling shopify.scanner.hideCameraScanner().
Has the rollback already been deployed, and if so, is it expected to resolve this issue?
@JS_Goupil Hi! Checking back in here - I am trying to upgrade our app the the latest version and this bug would be a blocker in us being able to do so. Are there any updates on the status of fixing the inability to close the camer scanner? Or should we be using an older version?
Hey all, just catching up. @Adif The rollback was for a separate issue where the new UX for the scanner (full screen) was leaked to 2026-01. We fixed that. As of 2026-04, full screen is the default.
That said, it should definitely be closing when calling hideCameraScanner(). Was this a regression with a POS version? I’ll take a look at this today
Edit: It appears to be a regression in POS 11.9.x, I’m going to see if we can get a fix in ASAP
Thanks so much! Please let me know if you need any additional information from our side - yes, it was specific to hideCameraScanner() but all other components appeared to be working as normal!
@Tiago_Ramalho We have a partial fix going out shortly. There’s still a weird edge case where if the merchant taps the x button before you call dismiss, it could be a double dismissal, but we’ll get to that next week. This is at least mostly functional.
Hey JS,
I think there’s another bug here, where if the user closes the camera by clicking the X, and then call hideCameraScanner it crashes the POS extension
Hi @JS_Goupil, thanks for the partial fix,hideCameraScanner() does dismiss the camera again on our devices. However, we’re now seeing a new issue with it, and I want to flag it because it doesn’t match the edge case you described (merchant taps X before we call dismiss).
Since the partial fix, calling hideCameraScanner() programmatically dismisses both the camera scanner AND the extension modal, with no X tap involved.
const unsubscribe = shopify.scanner.scannerData.current.subscribe((result) => {
if (!result.data) return;
shopify.scanner.hideCameraScanner(); // hide camera, stay in the modal
lookupProduct(result.data); // renders a form in the same modal
});
2. Scan any barcode.
3. Expected: camera overlay closes, extension modal stays open showing our form.
4. Actual: camera closes and the extension modal is dismissed with it, the user is dropped back to the smart grid. It looks like the single programmatic dismissal is applied to the whole native stack (camera overlay + parent modal).
Could you confirm whether this week’s full fix covers this programmatic path as well, and not only the X-tap-before-dismiss ordering?
Thanks! We dug a bit deeper and noticed something we don’t fully understand: it looks
like multiple instances of our extension are running at the same time, after one
single camera scan, our backend receives three identical requests. Each instance also
calls hideCameraScanner(), so the hide effectively fires multiple times, and that
seems to be what closes the whole modal (no X tap involved).
Is it expected that multiple instances run and receive scans at the same time? And
would the fix you mentioned also cover this case?
@Tiago_Ramalho As of API version 2025-10, each screen in your navigator is running a separate instance. So if you’re subscribed globally to the scanner in each instance (not conditionally, like in a component that you know will be mounted), it will be listening in each instance. Kind of similar to how native UIViewControllers work in iOS - they’re still alive underneath, you need to make sure to clean them up. The best practice is to only subscribe if your component gets mounted, but alternatively you can listen to navigation.currentEntry to sub/unsub as well.
Alright, I understand. That said, we migrated the extension to API version 2026-04 a long time ago and this wasn’t happening before, so it does seem to be a side effect of your recent changes/fixes. Either way, we’ll try to work on our end to fix this behaviour.
I just ran into the window.close() not firing after running await’d code in my extension. Was working fine for months and then after publishing a new version of my extension today this started happening. I even tried reverting my changes but the issue is still present.
I’m seeing this in API version 2026-01 and POS versions 11.9.1 & 11.10.0