Apple Pay with Elements

Add Apple Pay to your custom Elements-based checkout using the Express Checkout Element or Payment Element.

View as MarkdownInstall skills

VINR Elements is the component library for building a custom checkout UI inside your own page. Adding Apple Pay through Elements requires no Apple Pay JS API code — the Express Checkout Element and Payment Element handle eligibility detection, merchant validation, and button rendering automatically.

PrerequisitesAsk

  • Apple Pay enabled on your VINR account (Settings → Payment methods).
  • All domains that display the Apple Pay button registered under Settings → Payment method domains. See Register your domain.
  • VINR.js loaded on your page.

Integration optionsAsk

Two Elements support Apple Pay. Choose based on how much of the checkout UI you control:

ElementWhen to use
Express Checkout ElementYou want a wallet-button-only row (Apple Pay, Google Pay, etc.) alongside or above a card form. Best for express checkout flows.
Payment ElementYou want a single all-in-one payment UI that shows all enabled payment methods, including Apple Pay for eligible sessions.

Express Checkout ElementAsk

The Express Checkout Element renders a row of wallet buttons — Apple Pay on Safari, Google Pay on Chrome, and any other configured wallets — without any eligibility detection code on your side.

1. Initialize Elements

Obtain a clientSecret from a server-side payment or setup intent, then initialize Elements.

import { loadVinr } from '@vinr/sdk';

const vinr = await loadVinr('YOUR_VINR_PUBLISHABLE_KEY');
const elements = vinr.elements({ clientSecret: 'YOUR_CLIENT_SECRET' });

2. Mount the Express Checkout Element

const expressCheckoutElement = elements.create('expressCheckout', {
  // Optional: configure Apple Pay button appearance
  applePay: {
    buttonType: 'buy',      // 'buy' | 'check-out' | 'pay' | 'subscribe' | etc.
    buttonStyle: 'black',   // 'black' | 'white' | 'white-outline'
  },
});

expressCheckoutElement.mount('#express-checkout-element');
<div id="express-checkout-element"></div>

VINR calls canMakePayment() internally. The Apple Pay button renders only when the session is eligible — Safari with an active card in Wallet. No additional detection code is needed.

3. Handle the payment

Listen for the confirm event, which fires after the customer authenticates in the Apple Pay sheet.

expressCheckoutElement.on('confirm', async (event) => {
  const { error } = await vinr.confirmPayment({
    elements,
    confirmParams: {
      return_url: 'https://yoursite.com/order/complete',
    },
  });

  if (error) {
    // Show error to customer
    document.getElementById('error-message').textContent = error.message;
  }
  // On success, VINR redirects to return_url
});

VINR handles merchant validation and token decryption server-side. Call confirmPayment() only after the customer has authenticated — never before.

Payment ElementAsk

The Payment Element is a single component that renders all payment methods enabled on your account. Apple Pay appears automatically for eligible Safari sessions — no configuration required.

1. Initialize Elements

import { loadVinr } from '@vinr/sdk';

const vinr = await loadVinr('YOUR_VINR_PUBLISHABLE_KEY');
const elements = vinr.elements({ clientSecret: 'YOUR_CLIENT_SECRET' });

2. Mount the Payment Element

const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
<div id="payment-element"></div>

Apple Pay is included automatically. In Safari with a card in Wallet, the payment sheet appears at the top of the Payment Element before the card form.

3. Handle the payment

const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
  event.preventDefault();

  const { error } = await vinr.confirmPayment({
    elements,
    confirmParams: {
      return_url: 'https://yoursite.com/order/complete',
    },
  });

  if (error) {
    document.getElementById('error-message').textContent = error.message;
  }
});

Dynamic sheet updatesAsk

To update shipping options, line items, or totals while the Apple Pay sheet is open, use the shippingaddresschange, shippingoptionchange, and paymentmethodchange events on the Express Checkout Element. See Dynamic sheet updates for the full event reference.

Recurring payments and merchant tokensAsk

To request a merchant token (MPAN) for recurring, deferred, or automatic reload payments, pass the applePay object with the appropriate request type when creating the element:

const expressCheckoutElement = elements.create('expressCheckout', {
  applePay: {
    recurringPaymentRequest: {
      paymentDescription: 'Monthly subscription',
      managementURL: 'https://example.com/billing',
      regularBilling: {
        amount: 1000,
        label: 'Standard plan',
        recurringPaymentIntervalUnit: 'month',
        recurringPaymentIntervalCount: 1,
      },
    },
  },
});

See Merchant tokens for all MPAN request types and the full parameter reference.

Capability required — Recurring tier. MPAN requests require the apple_pay_recurring capability on your VINR account. Contact your VINR account manager to enable it.

iframesAsk

If you embed Elements in an iframe, the iframe origin must match the top-level page origin. For Safari 17+, you can use a cross-origin iframe if you add allow="payment" to the <iframe> element.

<!-- Same-origin: works on all supported Safari versions -->
<iframe src="https://yoursite.com/checkout"></iframe>

<!-- Cross-origin: Safari 17+ only -->
<iframe src="https://checkout.yoursite.com" allow="payment"></iframe>

Non-Safari browsersAsk

Elements degrades automatically — on Chrome, Firefox, Edge, and other non-Safari browsers, the Apple Pay button is hidden. In the Express Checkout Element, Google Pay (or other configured wallets) appear instead. No fallback code is needed on your side.

TestingAsk

Use your VINR sandbox publishable key. VINR intercepts the Apple Pay token in test mode and returns a successful result without charging the real card. Open your checkout page in Safari on a real device with any real card saved to Wallet.

See Test & go live for the full test scenario reference.

See alsoAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page