> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Apple Pay and Google Pay

> Enable and configure Apple Pay and Google Pay on your checkout (NMI or Stripe)

Apple Pay and Google Pay are payment options on your checkout. They work with both **NMI** and **Stripe** merchants. No separate merchant account is required. Card checkout remains available if a wallet is not shown or the customer cancels.

## Overview

* **Apple Pay** - Appears on **Safari** (macOS and iOS) when the customer has Apple Pay set up. Setup depends on your gateway (see below).
* **Google Pay** - Appears on supported browsers when a Google Pay wallet is available. With NMI it appears on **Android devices** only. With Stripe it can also appear on **desktop Chrome**.
* Both options appear on the **checkout page** only. By default they render above the card fields inside `<checkout-cc-panel>`, or you can place them separately with `<checkout-wallet />` or `<checkout-apple-pay />`.

## How to configure / enable

Setup differs by gateway. Choose your gateway below.

***

### Stripe

#### Google Pay (Stripe)

No configuration is required beyond domain registration (see Apple Pay step below). Google Pay appears automatically on checkout when the customer has a Google Pay wallet. With Stripe, Google Pay can appear on **desktop Chrome** in addition to Android devices.

#### Apple Pay (Stripe)

Stripe handles Apple's merchant validation behind the scenes. You do **not** need to create an Apple Merchant ID, CSR, or host a `.well-known` verification file. Follow these steps:

**Step 1: Make sure your Stripe account is in live mode**

<Warning>
  Apple Pay **only works with live Stripe API keys**. If your Stripe merchant is using test-mode keys, Apple Pay will not appear - `canMakePayment()` returns `null` and the button is silently hidden. Switch to **live mode** in the Stripe Dashboard and use your live publishable key on the checkout domain.
</Warning>

**Step 2: Register your checkout domain(s) with Stripe**

1. In the [Stripe Dashboard](https://dashboard.stripe.com), make sure you are in **live mode** (toggle at the top of the dashboard).
2. Go to **Settings** → [**Payment method domains**](https://dashboard.stripe.com/settings/payment_method_domains).
3. Click **Add a new domain**.
4. Enter the exact domain customers use at checkout (e.g. `checkout.yourstore.com`).
5. Click **Save and continue**.
6. Repeat for any additional domains or subdomains (including `www`).

<Note>
  Domains registered in **live mode** are automatically available in sandbox/test mode as well. For local testing, use a tool like [ngrok](https://ngrok.com/) to get an HTTPS domain and register that. However, Apple Pay itself still requires live keys to appear on supported devices.
</Note>

After registering with live keys, Apple Pay appears on checkout when the customer uses Safari on macOS or iOS and has Apple Pay configured. No verification file is needed - Stripe takes care of it.

For more details, see [Stripe's domain registration guide](https://docs.stripe.com/payments/payment-methods/pmd-registration) and [Apple Pay on the web](https://docs.stripe.com/apple-pay?platform=web).

***

### NMI

#### Google Pay (NMI)

No configuration is required.

1. Ensure the domain uses an **NMI** merchant.
2. Ensure that merchant uses **tokenization** (Collect.js): in the merchant settings, tokenization mode should be **Collect.js** and the **public / tokenization key** should be set.
3. Assign that NMI merchant to your checkout domain under **Settings** → **Domains** → **Edit Domain** → **Merchant**.

Google Pay appears automatically on checkout when the customer is on an **Android device** with a supported browser (Chrome). It does not appear on desktop browsers.

#### Apple Pay (NMI)

**Prerequisites:** NMI merchant with tokenization (Collect.js), and the checkout domain linked to that merchant (as above).

**Step 1: Enable Apple Pay in NMI**

1. Log in to the [NMI Merchant Portal](https://secure.nmi.com/merchants/).
2. Go to **Settings** → **Apple Pay**.
3. Enable Apple Pay for your account (if your processor supports it).

**Step 2: Register your checkout domain(s) with NMI**

NMI must have a list of domains that are allowed to show Apple Pay. Use the same domain(s) that serve your checkout in ElasticFunnels (e.g. the domain you set under **Settings** → **Domains**).

* In the NMI Merchant Portal, add your checkout domain(s) to the Apple Pay allowed list (see NMI's Apple Pay / domain registration section).
* If ElasticFunnels later adds an in-app "Register domains" action for your NMI merchant, you can use that to sync your linked domains; otherwise configure the list in NMI's portal.

**Step 3: Apple domain verification**

Apple requires a verification file on your checkout domain. NMI provides this file.

1. Download the **domain verification file** from NMI (in the NMI Merchant Portal under the Apple Pay settings, or from Apple's developer resources as NMI directs you).
2. Host it at:\
   `https://<your-checkout-domain>/.well-known/apple-developer-merchantid-domain-association`\
   Replace `<your-checkout-domain>` with the exact domain customers use at checkout (e.g. `checkout.yourstore.com`).
3. Ensure the file is publicly accessible over HTTPS. **Recommended:** In the app, go to **Domains** → edit the checkout domain → **Apple Pay** tab, and paste the exact contents of the verification file. The offer site will then serve it at `/.well-known/apple-developer-merchantid-domain-association` for that domain. Alternatively, you can set the env var **`APPLE_PAY_DOMAIN_VERIFICATION_CONTENT`** on the offer server as a fallback (same content for all domains on that server). If neither is set, the path returns 404 and you must host the file elsewhere.

After all three steps, Apple Pay can appear on checkout when the customer uses Safari on macOS or iOS and has Apple Pay configured.

## Placement options

There are three ways to include Apple Pay / Google Pay on your checkout page:

### Default - wallet buttons inside the card panel

```html theme={null}
<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover"></checkout-cc-panel>
```

Apple Pay and Google Pay buttons appear above the card fields with an "or pay with card" divider. This is the simplest setup.

### Standalone Apple Pay - separate from the card panel

Use `<checkout-apple-pay />` to place the Apple Pay button anywhere on the page, and disable it inside the card panel with `data-applepay="false"`:

```html theme={null}
<!-- Apple Pay at the top of the checkout, before the form -->
<checkout-apple-pay />

<!-- Card-only panel below -->
<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover" data-applepay="false"></checkout-cc-panel>
```

This lets you position Apple Pay prominently (e.g. above the personal details form) while keeping the card panel card-only.

### Separated - Apple Pay above with divider

Use `data-applepay-layout="separated"` to render Apple Pay above the card panel with an "OR PAY ANOTHER WAY" divider between them. This gives Apple Pay top-level prominence without needing a separate `<checkout-apple-pay />` element:

```html theme={null}
<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover"
                   data-applepay-layout="separated"></checkout-cc-panel>
```

The Apple Pay button appears above the panel. When the customer's device doesn't support Apple Pay, the button and divider are hidden and the card panel shows normally.

### Disable wallet buttons entirely

```html theme={null}
<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover" data-applepay="false"></checkout-cc-panel>
```

No Apple Pay or Google Pay buttons are shown. Customers can only pay with card (and PayPal/Klarna if configured).

## Conditional display with `checkout.wallet_available`

After the payment form loads, the scope variable `checkout.wallet_available` is updated with:

```json theme={null}
{ "applePay": true, "googlePay": false }
```

Use this to conditionally show or hide parts of your checkout layout based on wallet availability:

```html theme={null}
<!-- Show the personal details form only when Apple Pay is NOT available,
     or after the customer chooses to pay with card instead -->
<template-if data-condition="!checkout.wallet_available.applePay">
  <checkout-personal-details>
    <!-- name, email, address fields -->
  </checkout-personal-details>
</template-if>

<!-- Apple Pay section - always visible, button appears when supported -->
<checkout-apple-pay />

<!-- Divider when both options are available -->
<template-if data-condition="checkout.wallet_available.applePay">
  <div class="or-divider">or fill out the form below</div>
</template-if>

<!-- Card panel (no inline wallet) -->
<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover" data-applepay="false"></checkout-cc-panel>
```

<Note>
  `checkout.wallet_available` is set after the payment library loads and detects wallet support (NMI Collect.js or Stripe.js). It may take 1-2 seconds after page load before the values update. Use `template-if` conditions so the UI adjusts automatically once the value is available.
</Note>

### Example: wallet-first checkout

This layout shows Apple Pay prominently at the top. When Apple Pay is available, the form fields are hidden until the customer scrolls past or chooses card. When Apple Pay is not available, the standard form shows immediately:

```html theme={null}
<template-if data-condition="checkout.wallet_available.applePay">
  <div style="text-align:center; padding: 24px 0;">
    <h3>Quick checkout</h3>
    <checkout-apple-pay />
    <p style="margin-top: 12px; color: #6b7280; font-size: 14px;">
      Or scroll down to pay with card
    </p>
  </div>
</template-if>

<checkout-personal-details>
  <!-- name, email, address fields -->
</checkout-personal-details>

<checkout-cc-panel data-accepted-cards="visa,mastercard,amex,discover" data-applepay="false"></checkout-cc-panel>

<button type="submit" data-checkout-submit>Pay now</button>
```

## How wallet payment works

When a customer taps the Apple Pay or Google Pay button:

1. The native wallet sheet appears (Face ID / Touch ID for Apple Pay, or Google Pay authentication).
2. The wallet provides the payment token **and** contact data (name, address, email, phone).
3. The system automatically fills the checkout form fields with the wallet data.
4. The form auto-submits. No further action from the customer.

This means the customer can skip filling out the checkout form entirely. The wallet provides everything needed for the payment. Personal and shipping fields are only filled if they are currently empty; billing fields are always overwritten with the wallet data for AVS accuracy.

## Wallet contact field auto-detection

The wallet (Apple Pay / Google Pay) automatically detects which contact fields to request based on which checkout fields are on the page. No explicit configuration is needed.

| Page has                                                          | Wallet requests                        |
| ----------------------------------------------------------------- | -------------------------------------- |
| Shipping address fields (`shipping_address`, `shipping_country`)  | Shipping postal address                |
| Billing address fields (`billing_address`, `billing_country`)     | Billing postal address                 |
| Name fields (`first_name`, `last_name`, or `shipping_first_name`) | Name                                   |
| `email` field                                                     | Email                                  |
| `phone` field                                                     | Phone                                  |
| None of the above                                                 | No contact fields - payment token only |

**Digital product example:** A checkout page with only email and a payment panel (no name or address fields) causes Apple Pay to request only the customer's email. This is ideal for digital goods where shipping details are unnecessary.

```html theme={null}
<div class="floating-label-group">
  <input type="email" name="email" data-template-value="checkout.customer.email" />
</div>
<checkout-cc-panel data-applepay-layout="separated"></checkout-cc-panel>
<button type="submit" data-checkout-submit>Purchase</button>
```

## Subscriptions and recurring payments

When a customer purchases a **subscription** using Apple Pay or Google Pay, the system stores the payment method for future use:

* **NMI:** A **customer vault entry** is created during the initial charge. All subsequent subscription charges (renewals, rebills) use this vault entry server-to-server.
* **Stripe:** The **PaymentMethod** is saved to the Stripe customer with `setup_future_usage: 'off_session'`. All subsequent charges use this stored payment method server-to-server.

No additional customer interaction is needed for renewals. The subscription billing schedule is managed entirely on the server. The wallet token is consumed on the first charge, and the stored method handles everything after that.

## One-click upsells

When a customer pays with Apple Pay or Google Pay on the main checkout, the payment method is stored for reuse. Subsequent **one-click upsell** charges on the same funnel use this stored method server-to-server. No additional customer interaction is needed. The customer sees upsell pages and clicks "Yes, add this" as usual; the charge happens instantly.

This works the same as card-based one-click upsells for both NMI and Stripe.

## Billing address handling

When a customer pays with Apple Pay or Google Pay, the wallet provides the **correct billing address** associated with the card. The system uses this wallet billing address automatically for payment verification (AVS), regardless of what the customer entered in the checkout form's billing fields. This prevents address verification mismatches and declined payments.

No configuration is needed. This is handled automatically.

<Note>
  For non-US addresses, Apple Pay may not return a state/region value (many countries don't use states in their address format). The checkout validation automatically skips state validation for wallet payments, so this does not cause errors.
</Note>

## Troubleshooting

### Apple Pay button does not show

**Stripe:**

* **Confirm you are using live API keys.** Apple Pay does not appear when the Stripe merchant is in test mode. This is the most common cause of Apple Pay not showing with Stripe. Switch to live mode in the Stripe Dashboard and ensure your checkout domain is using the **live publishable key**.
* Confirm the domain is registered in the Stripe Dashboard under [Payment method domains](https://dashboard.stripe.com/settings/payment_method_domains) and shows as **Enabled**. Make sure you registered the domain in **live mode**.
* Check that the customer is on **Safari** (macOS or iOS) and the page is served over **HTTPS**.
* No `.well-known` verification file is needed for Stripe. Stripe handles merchant validation. If you previously used NMI and have a verification file on the domain, it does not interfere.
* If using `<checkout-wallet />` or `<checkout-apple-pay />`, make sure the tag is on the page.

**NMI:**

* Confirm the domain uses an NMI merchant with **Collect.js** (tokenization) and a public/tokenization key.
* Check that the customer is on **Safari** (macOS or iOS) and the page is served over **HTTPS**.
* Confirm the domain is registered with NMI for Apple Pay and that the Apple verification file is reachable at `https://<your-checkout-domain>/.well-known/apple-developer-merchantid-domain-association`.
* If using `<checkout-apple-pay />`, make sure the tag is on the page (it renders a container; the button appears inside it when supported).

### Google Pay button does not show

* **NMI:** Google Pay only appears on **Android devices**. It does not show on desktop Chrome or other desktop browsers. Confirm the domain uses an NMI merchant with **Collect.js** (tokenization) and a public/tokenization key.
* **Stripe:** Google Pay can appear on desktop Chrome as well as Android. Confirm the domain is registered under [Payment method domains](https://dashboard.stripe.com/settings/payment_method_domains).

### Verification file not found (NMI / Apple Pay)

* Ensure the file is at the exact `.well-known` path and that the domain matches the one used at checkout.
* If you use a subdomain for checkout, that subdomain must be the one registered with NMI and Apple and must serve the verification file.
* **This does not apply to Stripe** - Stripe handles verification without a hosted file.

### Other issues

* **Wallet payment cancelled or failed** - The customer can pay with card instead; the card form remains available. No page reload is required.
* **State/region error on wallet payment** - This should be handled automatically. If you see state validation errors after a wallet payment, ensure you are on the latest version of the checkout plugin.
* **Subscription charges fail after initial wallet purchase** - Verify the payment created a stored payment method. For NMI, check the transaction record for a `customer_vault_id`. For Stripe, check for a stored `payment_method` on the customer.
* **One-click upsell charges fail after wallet payment** - Same as above - ensure the payment method was stored during the initial charge.

For more on NMI and Apple Pay, see [NMI's documentation](https://docs.nmi.com/docs/collectjs) and [Digital Wallet Setup](https://docs.nmi.com/docs/digital-wallet-setup). For Stripe, see [Stripe's Apple Pay guide](https://docs.stripe.com/apple-pay?platform=web) and [domain registration](https://docs.stripe.com/payments/payment-methods/pmd-registration).
