Apple pay gives an error InvalidAccessError: Must create a new ApplePaySession from a user gesture handler

Hi, we are using Square SDK to offer Card, Google Pay and Apple Pay payments but Apple Pay is not working each time i click on button it ends up saying InvalidAccessError: Must create a new ApplePaySession from a user gesture handler. I couldn’t find anything in the docs to deal with it. I have followed the documentation which worked great so far for Card and Google Pay methods but Apple Pay doesn’t work.

Can someone help us, getting rid of this error.

:wave: Is this only with an iOS 13 device? If so it looks like there’s some new behavior you need to be aware of with the device from this post. :slightly_smiling_face:

Hi thanks for your response, actually this is happening on safari browser of a Macbook running Mac OS Monterey. I checked the link you attached, it has something related to apple pay but not really anything on Square web SDK and how to solve it within it. What exactly i need to do apart from standard integration based on your documentation of apple pay.

Okay, thanks for clarifying where this is happening. Do you have the steps to reproduce and what’s your app ID? :slightly_smiling_face:

Our app id is sandbox-sq0idb-INHD8MywK2CrHHZLQLk4Gw and this is happening on the payment page when we click on Apple Pay button. This is how we initialise Apple Pay button. private async initializeApplePay(payments, amount) { const paymentRequest = this.buildPaymentRequest(payments, amount); // Note: You do not need toattach applePay. return await payments.applePay(paymentRequest); }

and we call it like this

const payments = window.Square.payments(environment.square.appId, environment.square.locationId);
    amount = amount.toFixed(2);

I have also attached the screenshot of the error for reference.

:wave: The error your getting is an error reported by Apple.
Are you not calling applePay.tokenize() from inside a user gesture handler such as onclick? Apple Pay can’t be triggered by a programmatic action alone. It has to be done directly from a handler triggered by a customer action. :slightly_smiling_face:

@Bryan we doing exactly same i have added our function which gets called on button click it gets called on click and then it calls apple tokenize function :

  async applePayClicked() {
        console.log('Apple Pay Click Handler');
  this.paymentMethod = 'Square-ApplePay';
    try {
      // disable the submit button as we await tokenization and make a
      // payment request.
      this.cardButton = true;
      // Create an instance of the loading spinner and pass the message we want this spinner to have
      this.processingSpinner = this.createLoadingSpinner(
        'Submitting Order<br>Please Wait...'
      );
      await (await this.processingSpinner).present();
      const token = await this.tokenize(this.paymentService.applePay);
      await this.placeOrder(token);
    } catch (e) {
      this.cardButton = false;
      //displayPaymentResults('FAILURE');
      console.error(e);
      this.displayPaymentError('ApplePay');
    }
  }

And then this function gets called from HTML like this :

   <div id="apple-pay-button" (click)="applePayClicked()"  #applePay></div>

What can be wrong in this. Can you please guide us.

A few things we need clarity on. First:

const token = await this.tokenize(this.paymentService.applePay);

what is this.tokenize and this.paymentService.applePay ?

Second:

<div id="apple-pay-button" (click)="applePayClicked()" #applePay></div>

Is that (click) an event handler definition? Also what framework are you using? :slightly_smiling_face:

Hi @Bryan-Square, sorry for delayed response, this click event is click event handler and we are using Angular 12. Also i have a good news, i was able to fix the issue myself. I just checked and found as soon as user clicks on apple pay button we were calling applePayClicked function which basically calls square SDK to create apple pay token using this function
const token = await this.tokenize(this.paymentService.applePay);
but i just realised we were also creating a progress bar to avoid any more clicks to the Apple Pay button before calling it and this statement was using await this statement was creating progress bar asynchronously and then only creating token.

I read somewhere (in a stack-overflow answer) that apple Pay Doesn’t like await after apple pay button is clicked. So i simply removed promise and continued to call tokenize function and it just worked.

So basically solution is to remove any async call in the click function of Apple Pay button, there should not be any kind of delay between clicking the function and calling token method of apple pay.

So as per my understanding, if there is time difference between Button click and token create statement then Apple Pay assume that this was not button click and hence it was behaving like this. I really suggest this should be added somewhere in Documentation (a warning or note) to inform other devs, so they can avoid this error as it is not clear at all.

Thanks for sharing your findings! :slightly_smiling_face: