Navigation api bricked with the new ios app update v10.19.x

hello there sailors!

we have a number of pos extensions that are using the navigation API. we’re currently on v 2024.07.x for both packages:

  "dependencies": {
    "react": "^18.0.0",
    "@shopify/ui-extensions": "2025.07.x",
    "@shopify/ui-extensions-react": "2025.07.x"
  },

And then in File A we use the api as:

const api = useApi<'pos.home.modal.render'>()
...
..
.

and then

<Screen
onReceiveParams={(params: { someParameter: boolean }) => params?.someParameter && setSomething(someParameter)}
>

Then File B, uses the same navitagion api to move back to File A screen:

const api = useApi<'pos.home.modal.render'>()
...
..
.
api.navigation.navigate('FileA', { someParameter: true })

BUT since the new ios shopify pos update with v10.19.x, this throw’s an error, saying that the

params are undefined.

Here’s the source code from the package itself:

export interface NavigationApiContent {
  /** Navigate to a route in current navigation tree.
   * Pushes the specified screen if it isn't present in the navigation tree, goes back to a created screen otherwise.
   * @param screenName the name of the screen you want to navigate to.
   * @param params the parameters you want to pass to that screen.
   */
  navigate(screenName: string, params?: any): void;

  /** Pops the currently shown screen */
  pop(): void;

  /** Dismisses the extension. */
  dismiss(): void;
}

You can clearly see that there are params and I’m not crazy :slight_smile:

Why break backwards compatibility? Or if you would have told us to migrate in a timely manner we would have (already planning to migrate to v2026.01), but as you can imagine every single piece of code needs to be touched.

react to preact and polaris components for everything instead of ui-extensions-react package.

1 Like

Hey @Gunes - thanks for flagging this. Just to confirm, you’re only seeing this pop up in iOS, not Android? Just want to see if we can isolate this to a specific OS. Happy to dig into this though.

Hey @Alan_G, yes I can confirm iOS, we do not have Android devices.

Hi @Gunes

Could you provide a screenshot/recording of the issue along with more code? This will help us to debug this more effectively. We’re currently not able to reproduce this issue on our side.

here’s two trimmed down components..

StartOrder.tsx :backhand_index_pointing_down:

import { useState } from 'react'

import type { ListRow } from '@shopify/ui-extensions-react/point-of-sale'
import { Screen, Stack, ScrollView, Button, List, useApi } from '@shopify/ui-extensions-react/point-of-sale'

export const StartOrderScreen = () => {
  const api = useApi<'pos.home.modal.render'>()

  const [visibleCollection, setVisibleCollection] = useState<ListRow[] | undefined>()

  const navigateToProductDetails = (productId: string) => {
    api.navigation.navigate('ProductDetails', { productId })
  }

  const testProduct = {
    title: 'title',
    id: 'id',
  }

  return (
    <Screen
      name="Start"
      title="Start Order"
      // reset the menu after adding an item to the cart
      onReceiveParams={(params: { resetView: boolean }) => params.resetView && setVisibleCollection(undefined)}
      secondaryAction={{
        onPress: () => api.navigation.dismiss(),
        text: 'Close',
        isEnabled: true,
      }}
    >
      <Button
        title={testProduct.title}
        onPress={() => {
          navigateToProductDetails(testProduct.id)
        }}
      />
      <ScrollView>
        <Stack>{visibleCollection && <List data={visibleCollection} imageDisplayStrategy="always" />}</Stack>
      </ScrollView>
    </Screen>
  )
}

ProductDetails.tsx :backhand_index_pointing_down:

import { useEffect, useState } from 'react'
import { Screen, Stack, ScrollView, Text, useApi, Button, Stepper } from '@shopify/ui-extensions-react/point-of-sale'
import type { ProductVariant, Product } from '@shopify/ui-extensions/point-of-sale'

export const ProductDetailsScreen = () => {
  const api = useApi<'pos.home.modal.render'>()

  const [productId, setProductId] = useState<string | undefined>()
  const [productInfo, setProductInfo] = useState<Product | undefined>()
  const [variant, setVariant] = useState<ProductVariant | undefined>()
  const [loading, setLoading] = useState(false)
  const [quantity, setQuantity] = useState(1)

  const getIdNumber = (id: string): number => Number(id.match(/\d+$/)[0])

  const fetchProductInfo = async (id: string) => {
    setLoading(true)
    const product = await api.productSearch.fetchProductWithId(getIdNumber(id))
    setLoading(false)
    setProductInfo(product)
    const [mainVariant] = product.variants
    setVariant(mainVariant)
  }

  const addToCart = async (variant: ProductVariant, shouldFinish?: boolean) => {
    api.cart.addLineItem(variant.id, quantity)
    setQuantity(1)
    api.toast.show(`${productInfo.title} added to Cart!`)

    return shouldFinish ? api.navigation.dismiss() : api.navigation.navigate('Start', { resetView: true })
  }

  useEffect(() => {
    productId && fetchProductInfo(productId)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [productId])

  return (
    <Screen
      name="ProductDetails"
      title="Select Options"
      onReceiveParams={(params: { productId: string }) => setProductId(params.productId)}
      isLoading={loading}
      secondaryAction={{
        onPress: () => api.navigation.dismiss(),
        text: 'Close',
        isEnabled: true,
      }}
    >
      <ScrollView>
        <Stack direction="block" gap="200" paddingInline="100">
          {productInfo && (
            <Stack>
              <Stack direction="inline" gap="400">
                <Text variant="display">{productInfo.title}</Text>
                <Text variant="display">- €{variant?.price || productInfo.minVariantPrice}</Text>
              </Stack>
            </Stack>
          )}
        </Stack>
        <Stack direction="block" paddingBlock="400" paddingInline="100" gap="400">
          <Stepper initialValue={quantity} onValueChanged={setQuantity} />
          <Stack direction="inline" flexChildren gap="400">
            <Button title="Add and View Cart" onPress={() => addToCart(variant, true)} type="primary" />
          </Stack>
        </Stack>
      </ScrollView>
    </Screen>
  )
}

StartOrder.tsx => you find/select a product, navigate to the ProductDetails.tsx with the productId, where you fetch the product details with that id. The ID is passed as a param from the navigation api.

But, I mean also, we have all managed devices and they are currently locked in @ v10.15.x.

Now we have to do a huge migration and we can’t even go from 2025-07 to 2025-10 because most of the components that we currently use are not even available on 2025-10 but 2026-01.

And if we move to 2026-01 this version does not run on iOS v10.15.x. And if we update to v10.19.x the apps are bricked. :melting_face:

It’s a huge letdown in terms of backwards compatibility and non-communication from your side.

Idk if you’re investigating still but if you are, it’s gonna be for other people, I’ve done the migration from 2025-07 to 2026-01, couldn’t do the migration before to 2025-10 as it did not include key components that we use in our extensions.

Screenshot 2026-02-06 at 16.12.04

I like how you guys went:

“Let’s change from react to preact AND remove the dependency to our react library at the same time and switch to polaris components AND change every single API source” :smiley:

Literally every single line had to be touched. It’s kind of unbelievable.