Skip to content

Apple Pay: "Contact" section missing and fails with "update shipping contact" for authenticated cart with buyerIdentity #381

Closed
Shopify/checkout-sheet-kit-swift
#522

Description

@etabard

What area is the issue related to?

Checkout Sheet Kit

What platform does the issue affect?

iOS

What version of @shopify/checkout-sheet-kit are you using?

3.4.0

Do you have reproducible example code?

We don't have a minimal reproducible example, but the issue is behavior-dependent based on whether buyerIdentity is provided when creating the cart.

Here the provider's config:

{
  "colorScheme": "web_default",
  "colors": {
    "ios": {
      "backgroundColor": "#FFFFFF",
      "tintColor": "#000000",
      "closeButtonColor": "#333333"
    },
    "android": {
      "backgroundColor": "#FFFFFF",
      "progressIndicator": "#000000",
      "headerBackgroundColor": "#FFFFFF",
      "headerTextColor": "#000000"
    }
  },
  "acceleratedCheckouts": {
    "storefrontDomain": "xxx.myshopify.com",
    "storefrontAccessToken": "xxx",
    "wallets": {
      "applePay": {
        "contactFields": [
          "email",
          "phone"
        ],
        "merchantIdentifier": "xxx"
      }
    }
  },
  "title": "My order"
}

Steps to Reproduce

  • Set up the ShopifyProvider and ShopifyCheckoutSheet.
  • Ensure Apple Pay is configured for the store and the test device with required phone contact.
  • Create a Shopify cart, passing a valid buyerIdentity with customerAccessToken.
  • Add a physical product requiring shipping to this cart.
  • Tap the "Apple Pay" accelerated checkout button on the cart screen.
  • The native Apple Pay payment sheet slides up.
  • Observe: The "Contact" section (which normally shows email/phone) is completely missing.
  • Try to authenticate and confirm the payment (e.g., with Face ID or passcode).
  • Observe: The payment fails, and an error related to "update shipping contact" is displayed on the sheet.

Expected Behavior

When the Apple Pay sheet is presented for an authenticated user (buyerIdentity present), it should either:

  • Automatically use the contact information (especially the phone number) associated with the buyerIdentity to satisfy Apple Pay's requirements.
  • Or, still display the "Contact" section, allowing the user to select their contact info from their Apple Wallet, just as it does for an anonymous cart.

The payment should be validatable without an error.

Actual Behavior

  1. When the cart is authenticated (Case 1):
  • The Apple Pay sheet opens, but the "Contact" section is missing. (See Screenshot 1 description below).
  • Because the phone number is missing and cannot be added (due to the missing section), the payment validation fails with an "update shipping contact" error.
  1. When the cart is anonymous (Case 2):
  • The Apple Pay sheet opens, and the "Contact" section is visible. (See Screenshot 2 description below).
  • The user can select their contact info, and the payment can be validated successfully.

Notes: We also tried conditionally passing the customer prop to the . This did not change the behavior; the issue seems directly tied to the buyerIdentity on the cart itself.

Storefront domain

easy-clothes-europe.myshopify.com

Screenshots/Videos/Log output

Screenshot 1: Authenticated Cart (Bug)
The "Contact" section is missing.

Authenticated cart (Bug)
Screenshot 2: Anonymous Cart (Working)
The "Contact" section is visible.

Anonymous cart (Working)

Activity

  1. kieran-osgood-shopify commented on Nov 12, 2025

    @kieran-osgood-shopify
    Contributor

    Hi @etabard!

    I want to confirm some details to get to the bottom of this with you

    1. Are you using Legacy Customer accounts or new customer accounts?
    2. Can you share the values in the customer account email and phone number? I want to see whether they're somehow defined but not valid in the submission requests
    3. I see you attempted to workaround this by conditionally applying the customer, can you try conditionally requesting the contactFields, we have an example in our sample
    4. I can search on our platform if you share a x-request-id header, you can find this in the response headers for the graphql requests that happen when you submit the payment
    5. Networking logs would also be helpful (showing both the request body and response body), specifically go through the requests that happen after you press submit, and search through them for a phone number violation if you use Expo then the JS Debugger has a network debugger, but other proxy based ones include: Proxyman and Charles Proxy

    I haven't had a chance to debug this just yet, but I feel like theres the possibility of a configuration gotcha so it'd be good to determine the exact state of the customer account you're using

  2. etabard commented on Nov 12, 2025

    @etabard
    Author

    Hi @kieran-osgood-shopify, thanks for getting back to us. Here are the details you requested:

    1. Account Type & Settings:

      • We are using Legacy customer accounts.
      • Our checkout settings are:
        • Customer contact method: Email
        • Shipping address phone number: Required
    2. Customer Account Details:

      • I cannot share the specific customer details publicly. Is there a private or secure channel where we could provide this?
      • However, I can confirm the data is valid. The email is a standard name@company.com format, and the phone number is a valid E.164 format (e.g., +33612345678). The customer account does have a valid phone number associated with it.
    3. Conditional contactFields:

      • Thank you for pointing that out, we had missed that subtlety.
      • We have just adapted our code to conditionally request contactFields (email and phone) as shown in the example.
      • Unfortunately, this did not solve the issue. We still receive the "Update shipping contact" error when the "Contact" section is missing from the Apple Pay sheet for an authenticated user.
    4. Network Logs (x-request-id):

      • I am having trouble capturing these logs. The Expo network debugger doesn't seem to include requests made natively outside of the JS thread.
      • I don't see any GraphQL requests in the JS debugger when ShopifyCheckout.present(cart.checkoutUrl) is called, nor when I tap the "Apple Pay" button. This suggests the payment sheet communication is happening purely on the native side.
      • I will investigate using a proxy tool like Proxyman or Charles as you suggested, but I wanted to share the information I have so far.
  3. kieran-osgood-shopify commented on Nov 13, 2025

    @kieran-osgood-shopify
    Contributor
    1. Legacy customer accounts will become deprecated at some stage in the future (no dates given) so generally we do recommend moving to New Customer Accounts for all possible bug fixes (features are tested against New Customer accounts more than Legacy)
    2. I understand not sharing the specific customer data - if I were to plug in the phone number you provided +33612345678 would I see the error?
    3. Ah that does make sense, I forget what level the expo debugger runs at, yes all of the networking occurs in the native SDK. Personally I typically run proxyman to see all of the traffic going so let me know if you do manage to find anything and I'll dig in further
  4. etabard commented on Nov 13, 2025

    @etabard
    Author

    Hi, thanks for the quick reply.

    1. Legacy Accounts: Thanks for the context on Legacy vs. New Customer accounts. We understand the recommendation and will discuss the migration with our client. For now, we are hoping to resolve this issue on the current Legacy implementation.

    2. Phone Number: Yes, I can confirm that the error is reproducible with a valid customer account that has a phone number in that E.164 format (e.g., +33612345678).

    3. Network Logs: Understood. I am actively working on setting up Proxyman to capture the native network traffic. I will post the relevant logs (x-request-id or request/response bodies) here as soon as I successfully reproduce and capture the error.

  5. etabard commented on Nov 14, 2025

    @etabard
    Author

    Hi @kieran-osgood-shopify , I've run the tests with Proxyman.

    Step 1: Create Cart

    I created the cart via the API, specifying the buyerIdentity (accessToken, email, phone).

    Step 2: Click Apple Pay

    I clicked the accelerated checkout Apple Pay button.

    Here is the sequence executed by the Shopify SDK:


    GetCart

    Response :

    "buyerIdentity": {
        "email": "name@company.com",
        "phone": "+33612345678",
        "customer": {
            "email": "name@company.com",
            "phone": "+33612345678"
        }
    },
    "deliveryGroups": {
        "nodes": []
    },
    "delivery": {
        "addresses": []
    },

    CartSelectedDeliveryOptionsUpdate

    Response :

    "buyerIdentity": {
        "email": "name@company.com",
        "phone": "+33612345678",
        "customer": {
            "email": "name@company.com",
            "phone": "+33612345678"
        }
    },
    "deliveryGroups": {
        "nodes": [
            // delivery options are now populated
        ]
    },
    "delivery": {
        "addresses": [
            {
             // address is set but it's incomplete
              "id": "gid://shopify/CartSelectableAddress/f4a54249-0157-4e71-a89e-b343dc8dfead",
              "selected": true,
              "address": {
                "address1": "",
                "address2": null,
                "city": "Bordeaux",
                "countryCode": "FR",
                "firstName": null,
                "lastName": "",
                "phone": null,
                "provinceCode": null,
                "zip": "33000"
              }
            }
        ]
    },

    CartPrepareForCompletion

    Response :

    //...
    "__typename": "CartStatusReady",
    //...
    "buyerIdentity": {
        "email": "name@company.com",
        "phone": "+33612345678",
        "customer": {
            "email": "name@company.com",
            "phone": "+33612345678"
        }
    },
    "deliveryGroups": {
        "nodes": [
            {
                // delivery options are now populated
            }
        ]
    },
    "delivery": {
        "addresses": [
            {
             // address is set but it's incomplete
              "id": "gid://shopify/CartSelectableAddress/f4a54249-0157-4e71-a89e-b343dc8dfead",
              "selected": true,
              "address": {
                "address1": "",
                "address2": null,
                "city": "Bordeaux",
                "countryCode": "FR",
                "firstName": null,
                "lastName": "",
                "phone": null,
                "provinceCode": null,
                "zip": "33000"
              }
            }
        ]
    },

    CartDeliveryAddressesAdd

    The variables show it's resetting the address but it's incomplete:

        // it's resetting the address but incomplete
        "variables": {
          "addresses": [
            {
              "validationStrategy": "COUNTRY_CODE_ONLY",
              "selected": true,
              "address": {
                "deliveryAddress": {
                  "city": "Bordeaux",
                  "countryCode": "FR",
                  "firstName": "",
                  "zip": "33000",
                  "lastName": ""
                }
              }
            }
          ],
          "cartId": "xxx"
        },

    The response shows nothing changed, the address is still incomplete:

    "buyerIdentity": {
        "email": "name@company.com",
        "phone": "+33612345678",
        "customer": {
            "email": "name@company.com",
            "phone": "+33612345678"
        }
    },
    "deliveryGroups": {
        "nodes": [
            {
                // delivery options are now populated
            }
        ]
    },
    "delivery": {
        "addresses": [
            {
             //nothing changed
              "id": "gid://shopify/CartSelectableAddress/f4a54249-0157-4e71-a89e-b343dc8dfead",
              "selected": true,
              "address": {
                "address1": "",
                "address2": null,
                "city": "Bordeaux",
                "countryCode": "FR",
                "firstName": null,
                "lastName": "",
                "phone": null,
                "provinceCode": null,
                "zip": "33000"
              }
            }
        ]
    },

    CartPrepareForCompletion

    No changes

    Clicking the 'Pay' Button

    It runs a sequence of requests again:

    • CartBuyerIdentityUpdate --> no change
    • CartPrepareForCompletion --> no change
    • CartDeliveryAddressesRemove --> delivery groups and addresses are removed
    • CartDeliveryAddressesAdd --> This mutation is called to add the full, complete address from Apple Pay.

    Here are the variables sent in this final CartDeliveryAddressesAdd mutation:

    "variables": {
        "addresses": [
          {
            "address": {
              "deliveryAddress": {
                "address1": "16 street name",
                "city": "Bordeaux",
                "firstName": "Billy",
                "countryCode": "FR",
                "zip": "33000",
                "lastName": "Bob"
              }
            },
            "validationStrategy": "STRICT",
            "selected": true
          }
        ],
        "cartId": "xxx"
    }

    And here is the error response to that mutation. The deliveryAddress object was missing the phone number, which is required by our store settings.

    "buyerIdentity": {
        "email": "name@company.com",
        "phone": "+33612345678",
        "customer": {
            "email": "name@company.com",
            "phone": "+33612345678"
        }
    },
    "deliveryGroups": {
        "nodes": []
    },
    "delivery": {
        "addresses": []
    },
    // ...
    "userErrors": [
        {
            "code": "ADDRESS_FIELD_IS_REQUIRED",
            "message": "Shop configuration specifies that the phone number is required in order to continue.",
            "field": [
            "addresses",
            "0",
            "address",
            "deliveryAddress",
            "phone"
            ]
        }
    ]

    Conclusion

    Thanks to the Proxyman logs, it's clear the buyerIdentity (with the correct email and phone) is present in the requests.

    The issue seems to stem from the delivery.address object itself:

    1. Mysterious Partial Address: As soon as the Apple Pay sheet opens, the SDK populates the cart with a very incomplete address (as seen in CartSelectedDeliveryOptionsUpdate), which has phone: null. What's confusing is that this partial address doesn't exist in my Apple Pay wallet or my Shopify customer account, so I'm not sure where the SDK is pulling this data from.

    2. Final Address is Missing Phone: When I confirm the payment, the final CartDeliveryAddressesAdd mutation sends the complete address from my Apple Pay wallet (e.g., "16 street name", "Billy Bob"), but the deliveryAddress object is still missing the phone field.

    This missing phone field is the direct cause of the ADDRESS_FIELD_IS_REQUIRED error, as our store requires a phone number for shipping.

  6. etabard commented on Nov 14, 2025

    @etabard
    Author

    Hi, I have a quick update on my debugging.

    I wanted to test if the issue was caused by not having a default address in the cart.

    I re-ran all the tests, but this time I set a complete, default shipping address on the cart (before hitting the Apple Pay button).

    This did not change the outcome of the bug.

    As soon as I click the "Apple Pay" accelerated checkout button inside the sheet, the Proxyman logs show that the Shopify SDK overwrites the default address I had set. It replaces it with a partial address (I can confirm I have a correct and complete address set up in my Apple Pay wallet).

    The SDK is still populating the delivery.addresses object with this same incomplete data:

    "delivery": {
        "addresses": [
          {
            "id": "gid://shopify/CartSelectableAddress/a2460431-394f-496b-a957-bea05ed554b9",
            "selected": true,
            "address": {
              "address1": "",
              "address2": null,
              "city": "Bordeaux",
              "countryCode": "FR",
              "firstName": null,
              "lastName": "",
              "phone": null,
              "provinceCode": null,
              "zip": "33100"
            }
          }
        ]
    }

    This confirms that the SDK is setting up an incorrect and incomplete address in the cart. It's also not merging the phone from the buyerIdentity into the delivery.address object, which is what causes the validation to fail.

    I wanted to clarify another important point. If I go to the checkout and click on the Apple Pay button, it works perfectly. So this doesn't seem to be an issue with Apple Pay itself, but rather an issue with the SDK or the configuration (but I don't see what we could have missed)

  7. etabard commented on Nov 21, 2025

    @etabard
    Author

    Hi @kieran-osgood-shopify,

    I hope you're doing well. Do you have any news on that issue? My client is eager to provide Apple Pay to customers :-)

    Thanks for your help!

  8. kieran-osgood-shopify commented on Nov 21, 2025

    @kieran-osgood-shopify
    Contributor

    Hey @etabard,

    I appreciate the comprehensive debugging steps you've been able to provide and it should be useful when someone is able to look into this

    This ticket has been triaged as a bug and will be looked into, but I can't provide a timeline as to when that will be complete

    Leaving some notes here for future reference:

    • Regarding the partial addresses being saved, this is expected during apple pay as they only expose partial information until the user authorises the payment with biometrics/pin after pressing pay now, at which point we update with the full address
    • The fact you're getting an address you don't have in your address book or wallet is peculiar, we just use the data that Apple provides us to perform that update, see this code it must be within the wallet somewhere I'd assume
    • I think the PKEncoder is (correctly) filtering the contactfields because it detects a phone number correctly in the customer account and we dont attach that to addresses in the CartDeliveryAddressInput

    Unresolved question: Why is it that guests can checkout successfully, because the phone number still wouldn't be applied to the deliveryAddress

  9. github-actions commented on Dec 22, 2025

    @github-actions

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs in 30 days. Thank you for your contributions.

  10. etabard commented on Dec 22, 2025

    @etabard
    Author

    Hi @kieran-osgood-shopify, this issue is still relevant and not stale. Any news on a resolution? Thanks for your help.

  11. kieran-osgood-shopify commented on Jan 5, 2026

    @kieran-osgood-shopify
    Contributor

    Hey @etabard

    The stale tag has been removed and I've added the never-stale until we get a chance to look at it
    I don't have any update on a time frame at the moment which I appreciate isn't ideal, but will report back on this thread when it has been looked into!

    Thank you for your patience

  12. kieran-osgood-shopify commented on Jan 22, 2026

    @kieran-osgood-shopify
    Contributor

    @etabard Just keeping you in the loop - I've been able to take a look and reproduce the issue
    I've got a pretty straight forwards fix that I will aim to draft a PR for tomorrow

    Again - appreciate the patience and all the information supplied it was useful

  13. lustsazeus-lab commented on Feb 24, 2026

    @lustsazeus-lab

    Thanks for reporting — happy to help triage this.

    A few quick clarifying questions that would let me narrow it down fast:

    • checkout-sheet-kit-react-native version + iOS version/device
    • Apple Pay env (sandbox vs prod) + whether Customer Accounts/authenticated cart is involved (buyerIdentity)
    • any logs / error payload around the "update shipping contact" failure (even a redacted snippet is fine)

    If this is still affecting production, I can put together a concrete fix plan (scope + test plan + ETA) and ship a fast-track PR/workaround within 48h once I have the above details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions