What area is the issue related to?
Checkout Sheet Kit
What platform does the issue affect?
All platforms
What version of @shopify/checkout-sheet-kit are you using?
@shopify/checkout-sheet-kit (React Native) 3.8.0 → iOS SDK 3.8.0, Android SDK 3.5.3 - iOS: device on iOS 26 - Android: device on Android 16 - Payment method: PayPo (BNPL via Przelewy24, Shopify Payments, Poland)
Do you have reproducible example code?
No response
Steps to Reproduce
- Use a Shopify Payments store with Przelewy24 enabled and PayPo available (PL market).
- Present checkout with
present(checkoutUrl) for a cart whose total qualifies for PayPo.
- Choose PayPo as the payment method and continue (Przelewy24 → Inne systemy ratalne i odroczone → PayPo).
- Checkout redirects through:
{shop}.myshopify.com/cart/c/… → secure.przelewy24.pl/trnRequest/… → process.paypo.pl/smartplan/{uuid}
- Observe the checkout fail / sheet dismiss instead of the PayPo page loading.
Expected Behavior
HTTP status-code error handling should be scoped to the merchant's own checkout origin.
A third-party payment page reached via redirect should be allowed to load/render exactly as a
browser would — including a page that returns a non-2xx status but serves a renderable body.
process.paypo.pl is a client-side-routed SPA on S3/CloudFront. The deep path isn't a real S3
object, so it responds HTTP 404 (x-amz-error-code: NoSuchKey) but serves the SPA
index.html as the body. Every real browser (Safari, Chrome — including with the SDK's exact
User-Agent) renders that body, the SPA boots, reads the UUID, and PayPo completes normally.
Actual Behavior
The kit treats the third-party 404 as a fatal checkout error and tears down the sheet, so PayPo
is unusable in-app on both platforms. It polices HTTP status codes on external
payment-provider domains, which it should not – providers legitimately serve non-2xx
responses with renderable bodies.
Root cause per platform:
- iOS (
ShopifyCheckoutSheetKit 3.8.0): CheckoutWebView.handleResponse cancels any
response with statusCode >= 400 and emits CheckoutHTTPError. The isCheckout(url:) guard
is self.url == url, and self.url follows redirects onto process.paypo.pl, so checkout
error handling is applied to a third-party page.
- Android (
com.shopify:checkout-sheet-kit, incl. main): BaseWebView.onReceivedHttpError
→ handleError fires a non-recoverable HttpException for any main-frame HTTP error, with
no host/origin check at all. CheckoutDialog then dismisses the sheet.
Storefront domain
wasalaa.myshopify.com
Screenshots/Videos/Log output
Started provisional navigation - url:https://{shop}.myshopify.com/cart/c/…
Started provisional navigation - url:https://secure.przelewy24.pl/trnRequest/…
Started provisional navigation - url:https://process.paypo.pl/smartplan/…
Handling response for URL: https://process.paypo.pl/smartplan/…, status code: 404
Not found (404)
Failed provisional navigation with error: Frame load interrupted
404 response (the redirect target that the kit aborts on):
HTTP/1.1 404 Not Found
Server: CloudFront
x-amz-error-code: NoSuchKey
x-amz-error-message: The specified key does not exist.
Body = PayPo SPA index.html (<div id="application"></div> + module scripts) — fully
renderable; a browser ignores the 404 status on a top-level navigation and runs the SPA.
What area is the issue related to?
Checkout Sheet Kit
What platform does the issue affect?
All platforms
What version of
@shopify/checkout-sheet-kitare you using?@shopify/checkout-sheet-kit(React Native) 3.8.0 → iOS SDK 3.8.0, Android SDK 3.5.3 - iOS: device on iOS 26 - Android: device on Android 16 - Payment method: PayPo (BNPL via Przelewy24, Shopify Payments, Poland)Do you have reproducible example code?
No response
Steps to Reproduce
present(checkoutUrl)for a cart whose total qualifies for PayPo.Expected Behavior
HTTP status-code error handling should be scoped to the merchant's own checkout origin.
A third-party payment page reached via redirect should be allowed to load/render exactly as a
browser would — including a page that returns a non-2xx status but serves a renderable body.
process.paypo.plis a client-side-routed SPA on S3/CloudFront. The deep path isn't a real S3object, so it responds HTTP 404 (
x-amz-error-code: NoSuchKey) but serves the SPAindex.htmlas the body. Every real browser (Safari, Chrome — including with the SDK's exactUser-Agent) renders that body, the SPA boots, reads the UUID, and PayPo completes normally.
Actual Behavior
The kit treats the third-party 404 as a fatal checkout error and tears down the sheet, so PayPo
is unusable in-app on both platforms. It polices HTTP status codes on external
payment-provider domains, which it should not – providers legitimately serve non-2xx
responses with renderable bodies.
Root cause per platform:
ShopifyCheckoutSheetKit3.8.0):CheckoutWebView.handleResponsecancels anyresponse with
statusCode >= 400and emitsCheckoutHTTPError. TheisCheckout(url:)guardis
self.url == url, andself.urlfollows redirects ontoprocess.paypo.pl, so checkouterror handling is applied to a third-party page.
com.shopify:checkout-sheet-kit, incl.main):BaseWebView.onReceivedHttpError→
handleErrorfires a non-recoverableHttpExceptionfor any main-frame HTTP error, withno host/origin check at all.
CheckoutDialogthen dismisses the sheet.Storefront domain
wasalaa.myshopify.com
Screenshots/Videos/Log output
404 response (the redirect target that the kit aborts on):
Body = PayPo SPA
index.html(<div id="application"></div>+ module scripts) — fullyrenderable; a browser ignores the 404 status on a top-level navigation and runs the SPA.