POS UI Extension (Smart Grid Tile) — "App failed to load" on every tap, JS never executes

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 official shopify app generate extension template exactly

  • API version: 2025-04

  • POS app version: 11.1.1 on iPad

  • Package: @shopify/ui-extensions version 2025.10.13


What works

  • shopify app deploy succeeds — 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 export field in toml to specify named exports — same result

  • Downgrading @shopify/ui-extensions to 2024.1.0 — same result

  • Setting embedded = false in app toml — broke POS entirely

  • Adding a real OAuth backend (Vercel serverless function) to complete token exchange — OAuth works, tile still fails

  • Both 2025-04 and 2026-01 API versions — same result

  • Uninstalling and reinstalling the app multiple times — same result


Questions

  1. Is there a minimum POS app version required for UI extensions? Does 11.1.1 support them?

  2. Is there something specific about the app configuration (embedded app vs extension-only) that would cause this?

  3. Is there any way to debug a POS UI extension on iPad without a Mac/Safari Web Inspector?

  4. Are there any known issues with POS UI extensions and the current @shopify/ui-extensions version?

Any help appreciated — I’ve been stuck on this for a full day!

Hi! For POS extension troubleshooting, these debugging resources should help:

Also, can you confirm whether your extension is loading correctly in development on the device? If it is not appearing or not updating as expected, that will help narrow down whether this is a local development setup issue or an extension runtime issue.

Hi Victor,

Thanks for those links, I’ll check them out.

What do you mean by loading correctly ‘in development’. This is actually my first time trying to make one of these extensions, so you’ll have to forgive me if I need things explaining in simpler terms.

It is appearing, I can install it and add it as a tile on the Smart Grid. However, it just says ‘App Failed to Load’ every time, no matter what adjustments I’ve tried to make to date.

Ah I understand better what you meant by in development. I loaded the dev server in terminal, and used the dev console mobile QR code to load it onto the POS Tablet in development. It successfully does this, but the modal preview fails to load (Error loading extension) and the tile says app failed to load

Can you inspect the web view logs and see if theres any errors that are outputted? You will need to plug your device into the computer to do so. Below are the instructions for each OS:

That might be a difficulty. I don’t have a Mac I can use, and I only have an iPad tablet. I have Windows Laptop and iOS devices

Hey I checked again, this is almost certainly a framework / API version mismatch. POS uses two different rendering engines depending on the API version:

  • 2025-04 through 2025-07remote-ui, expects React (@shopify/ui-extensions-react)
  • 2025-10 and laterremote-dom, expects Preact + web components

You’re using Preact + web components but targeting 2025-04, so POS loads the wrong rendering engine. The extension script crashes before any of your code runs — which is why even a toast.show() at the entry point never fires.

Fix: set api_version = "2025-10" in your shopify.extension.toml and redeploy. Your POS version (11.1.1) supports it.

If you already tried 2026-01 and it still failed, make sure you redeployed afterward (shopify app deploy) — the CDN bundle URL changes per API version, so POS won’t pick up the new one until you do.

Hi victor,

thanks for your help. I think there were actually multiple issues at play but I managed to get it working. I went back to the tutorial and tried to run a purely scaffolded UI extension and even that didnt work.

Eventually, I went through the POS settings on the web app and added the tile to smart grid from there, that seemed to do the trick as it started working properly from then on, and I was able to implement the functionality I wanted.

Thank you