Hi all,
I’ve built (with help from Claude) a POS UI Extension (smart grid tile + modal) that builds and deploys successfully, installs on the store, appears in POS, but always shows “app failed to load” when tapped. No JavaScript ever executes.
Setup
-
App type: Extension-only app (no Remix/React Router backend)
-
Extension type: POS smart grid (
pos.home.tile.render+pos.home.modal.render) -
Framework: Preact + Shopify web components (
s-tile,s-page, etc.) — matches the officialshopify app generate extensiontemplate exactly -
API version:
2025-04 -
POS app version: 11.1.1 on iPad
-
Package:
@shopify/ui-extensionsversion2025.10.13
What works
-
shopify app deploysucceeds — both targets build cleanly -
App installs on store and OAuth completes successfully
-
Tile appears in POS smart grid editor and can be added to the grid
-
Tapping “Open” in POS Settings → Apps loads the app (redirects to Shopify admin)
-
Dev Dashboard shows the extension listed correctly under the active version
What doesn’t work
-
Tapping the tile always shows “loading…” then “app failed to load”
-
No JavaScript ever executes — added
shopify.toast.show()calls at the very top of the default export, none fire -
No errors appear in Dev Dashboard logs (expected for client-side extensions)
-
Tested on both a dev store and the main production store — same result
Extension files
shopify.extension.toml:
toml
api_version = "2025-04"
[[extensions]]
type = "ui_extension"
name = "t:name"
uid = "149c1d23-b280-f51c-42ee-3a558fd9cf8a2b8ba0cd"
handle = "pos-smart-grid"
description = "A preact POS UI extension"
[[extensions.targeting]]
module = "./src/Tile.jsx"
target = "pos.home.tile.render"
[[extensions.targeting]]
module = "./src/Modal.jsx"
target = "pos.home.modal.render"
Tile.jsx:
jsx
import "@shopify/ui-extensions/preact";
import {render} from 'preact';
export default async () => {
try {
shopify.toast.show('Tile loading...');
render(<Extension />, document.body);
shopify.toast.show('Tile rendered OK');
} catch(e) {
shopify.toast.show('Tile error: ' + e.message);
}
}
function Extension() {
return (
<s-tile
heading="40% Off MSRP"
subheading="Tap to apply"
onClick={() => {
shopify.toast.show('Tile tapped');
shopify.action.presentModal();
}}
/>
);
}
What I’ve already tried
-
Using
extension()API from@shopify/ui-extensions/point-of-sale— same result -
Using separate files vs single file for tile/modal targets — same result
-
Using
exportfield in toml to specify named exports — same result -
Downgrading
@shopify/ui-extensionsto2024.1.0— same result -
Setting
embedded = falsein app toml — broke POS entirely -
Adding a real OAuth backend (Vercel serverless function) to complete token exchange — OAuth works, tile still fails
-
Both
2025-04and2026-01API versions — same result -
Uninstalling and reinstalling the app multiple times — same result
Questions
-
Is there a minimum POS app version required for UI extensions? Does 11.1.1 support them?
-
Is there something specific about the app configuration (embedded app vs extension-only) that would cause this?
-
Is there any way to debug a POS UI extension on iPad without a Mac/Safari Web Inspector?
-
Are there any known issues with POS UI extensions and the current
@shopify/ui-extensionsversion?
Any help appreciated — I’ve been stuck on this for a full day!