Example snippet:
export function ExampleTwo() {
if (navigation.currentEntry.url === "/scanner") {
return (
<s-page heading="Scanner page">
<ExampleScannerPage />
</s-page>
);
}
return (
<s-page heading="Default page">
<s-button onClick={() => navigation.navigate("/scanner")}>
Go to scanner page
</s-button>
</s-page>
);
}
function ExampleScannerPage() {
const [scannedValue, setScannedValue] = useState("");
useEffect(() => {
const unsubscribeScanner = shopify.scanner.scannerData.current.subscribe(
async ({ data }) => {
if (!data) return;
shopify.toast.show(`Scanned: "${data}"`);
setScannedValue(data);
}
);
return () => unsubscribeScanner();
}, []);
return <s-text>Scanned Value: {scannedValue}</s-text>;
}
To reproduce:
- Go to scanner page
- Scan with a physical scanner. I used Socket Mobile 2D.
After scanning, the scanner beeps, indicating an error - the same sound when the product’s barcode isn’t recognised in native POS. scannedValue remains blank.
Note that the physical scanner works from the initial page. To verify, replace navigation.currentEntry.url === "/scanner" with navigation.currentEntry.url === "/" and scan after loading the extension’s modal.
This was reproduced on version 2026-01, pos.home.modal.render target.
This works fine in production, version 2025-07.