Skip to content

Instantly share code, notes, and snippets.

@rsolomakhin
Last active July 19, 2022 03:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rsolomakhin/eba91c185028899883d2c7f37f357d7c to your computer and use it in GitHub Desktop.
Save rsolomakhin/eba91c185028899883d2c7f37f357d7c to your computer and use it in GitHub Desktop.
Minimal UI Payment Handlers

Minimal UI Payment Handlers

Objective

Provide a golden path, low friction experience for users that are enrolled with payment handlers that support a minimal UI.

Overview

The following conditions must be satisfied to trigger the flow.

  1. The payment handler must register for minimal UI.
try {
  // Feature detection:
  if (registration.paymentManager.setMinimalUITriggerThreshold) {
    await registration.paymentManager.setMinimalUITriggerThreshold({"USD": "2.00", "JPY": "200"});
  }
} catch (e) {
  Sentry.captureException(e);  // Upload errors to the server for analysis.
}
  1. Merchant must request payment with certain properties.
    1. A single URL-based payment method.
    2. Payment handler’s currency.
    3. Value below the minimal UI trigger threshold and account balance.
    4. Only total specified.
    5. No shipping address or contact information requested.
    6. No promise for updated details passed into the show() method.
    7. show() triggered on user gesture.
try {
  const request = new PaymentRequest(
    [{supportedMethods: "https://paypal.com"}],
    {total: {label: "Payment", amount: {currency: "USD", value: "1.00"}}});
  const response = await request.show();
  await response.complete("success");
} catch (e) {
  Sentry.captureException(e);  // Upload errors to the server for analysis.
}
  1. The payment handler must handshake in the Can Make Payment event.
self.addEventListener("canmakepayment", (evt) => {
  // Feature detection:
  if (evt.respondWithMinimalUI && evt.currency) {
    return evt.respondWithMinimalUI({
      canMakePayment: true,
      readyForMinimalUI: (evt.currency === "USD" || evt.currency == "JPY")
                          && !userNeedsToReAuthenticate,
      accountBalance: "18.00",
    });
  } else {
    return evt.respondWith(true);
  }
});

The minimal UI flow then asks the user to scan their fingerprint or tap the Pay button on the screen, if the biometrics hardware is not available. The fingerprint scan is purely a confirmation step and its data is not shared with either payment handler or merchant.

User agent disables the openWindow() method in this flow, because the payment handler always responds with the payment details directly.

The account balance from the payment handler is not shared with the merchant.

Sample UI

Proposed Android minimal UI screenshot

@rsolomakhin
Copy link
Author

Absence of origin was a deliberate choice at the time, but we're up for discussion. Our reasoning was:

  1. Payment handler cannot display HTML content.
  2. Merchant must request payment directly through a single payment app.
  3. Two user gestures is required for payment: one to trigger the browser UI and another one to confirm payment.
  4. Biometric information is not passed to either merchant or payment handler.

@maxlgu
Copy link

maxlgu commented Sep 13, 2021

Chrome is deleting the Minimal UI implementation in https://chromium-review.googlesource.com/c/chromium/src/+/3150591

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