A wallet payment method, whose integration haunts many devs, especially devs with slightly different use-case. 😨 

Did you know you cannot use the ApplePay wallet button in an iframe? 😱 

But you actually can. 😥 

The Major Problem

While integrating the Apple Pay wallet in the Hyperswitch SDK, I came across a major problem , where ApplePaySession functions were returning an error saying ApplePay cannot run inside an iframe. 🤔 

This was a major issue because the SDK we provide is an iframe, which prevents integrating partner's client-side code from increasing. At first glance it was terrifying thinking we might need to change our entire architecture for the SDK 😭 😭 😭 , and any other solution would be hacky, but after a while of actually diving deep into the code, there was a solution. 

How would you solve it? 🤓 

The script that is used to import our SDK, runs on the main integrating partner's app. This code is responsible for mounting iframes, optimized API calls, cross communication between iframes and many more. If you were to run ApplePaySession here, then it's a valid call. 😲 

But running ApplePaySession actually requires a User Interaction, You cannot just programmatically trigger it. Now the Button is inside an iframe but the ApplePaySession code is on top, outside. What do you do? 

Well turns out, there is a window of time, in which if there is a user interaction, you can trigger an ApplePaySession. So sending a postMessage back from the iframe saying "Apple Pay Button was clicked" , and on receiving you immediately trigger the ApplePaySession , it registers! That's how we have been taking ApplePay payments ever since. 🤯 🤯 🤯 .

This also comes with its own drawbacks actually. The problem is the User Gesture handler part. The thing is for something to register as a user gesture, the post message has to be immediate. So if you have an async operation running simultaneously , then there is a code running all the time and doing some operation. In that case there is a delay as after the button is clicked, the call stack has some other operation on top which executes before you call the ApplePaySession.

That is where you will get an error saying ApplePaySession can only be triggered by a user gesture. A lot of times devs actually face this issue where they have an immediate call of the ApplePaySession but still they receive this error.

Some troubleshooting points

1. Check if you have any async code running throughout the life cycle of ApplePay payments. This could be an issue as I mentioned above, so for the ApplePay payment ensure you have everything in sync otherwise you will face this issue regardless of an iframe present or not. 

2. Ensure that you do not have any rouge event listeners running or mounted repeatedly. Ensure that you remove the event listener when you do not need it. If you have multiple event listeners of the same event then you could face an issue similar to what was mentioned above.

3. Ensure you do an abort of the ApplePay session. The latest version I believe does not need you to explicitly do that but if you have a complex use case like we did it might be beneficial to do so to avoid any intermittent runtime issues. 

An interesting update follows Safari 17.0, where you can open up ApplePay in a cross-origin iframe.
https://github.com/WebKit/WebKit/pull/11485

The pull request for the same does not seem to explain why this change was even there in the first place, but an educated guess would be that they wanted to add such restriction for security reasons but they felt there wasn’t any added advantage in doing so, as integrating in an unsafe (with many vulnerabilities) website will not cause a loss to Apple, but the merchant itself, which they would have faced regardless. 

However this change is out for Safari 17.0 September 18, 2023 and can be found in the release notes for the same.
https://developer.apple.com/documentation/safari-release-notes/safari-17-release-notes

We are still following ApplePay integration assuming they are not allowed to be opened up inside an iframe. Since this is a pretty recent change, its safe to assume some older versions of Safari, some iOS versions might still be expecting ApplePay to not run inside an iframe. Hopefully in the long run it becomes the norm to be able to run ApplePay inside an iframe without having to go through an extra step of development effort.

Apple Pay - Apple

All in all Apple Pay has been rather confusing for development and integration, and a lot of 'Why's may not be even covered in their documentation. It helps diving into Pull Requests raised on the topic similar to the issues you face as they cover up a lot of it and the conversations there make you feel like you are not alone with the issue you face 😂. 

Well, we resolve many such issues at Hyperswitch while working on our product.

Best part, the code is open source and is open for contributions. 

Here’s the repository link.