Signal

Apple Pay version probe

Descends ApplePaySession.supportsVersion from 15 down to 1 on HTTPS Safari and hashes the highest supported version. Strong Apple-device proxy with an iOS / Safari major-version hint.

Reviewed

Tier 1 engine

What it measures

ApplePaySession.supportsVersion(N) returns whether the running Safari supports Apple Pay protocol version N. Apple raises the version with each major iOS / Safari release: v12 with iOS 15, v13 to v14 with iOS 16, v15 with iOS 17+. The highest supported version is therefore a coarse Safari major-version probe in addition to confirming the browser is Safari (no other browser exposes the API).

The signal is engine-bound. Safari on a Mac exposes the API; Chrome and Firefox on the same Mac do not. Including it in the hardware signal set would break cross-browser stability, which is why it's classified as engine-bound.

How it is collected

The collector first checks two gates: ApplePaySession must exist on globalThis and globalThis.isSecureContext must not be explicitly false. Either gate failing returns absent immediately. On a secure context with the API present, the collector loops from version 15 down to 1, calling supportsVersion(v) inside a try/catch. The first truthy return becomes the hashed value; if every probe throws (which can happen inside cross-origin iframes or under feature-policy blocks) the result is absent.

Descending rather than ascending lets modern Safari short-circuit on the very first probe. Most current installs satisfy v14 or v15 immediately.

Confidence rules

ConfidenceTriggervalue.reason when absent
normalHighest supported version found (1 to 15)n/a (value is { version })
absentApplePaySession not present or supportsVersion not a functionapi_missing
absentisSecureContext is explicitly falseinsecure_context
absentEvery probe from 15 to 1 threw or returned falsyno_supported_version

Why HTTPS-only

Apple gates ApplePaySession on secure contexts. The constructor is not exposed on plain HTTP origins in iOS Safari, and on macOS Safari supportsVersion throws InvalidAccessError. The most common reason for absent on a known-Safari install is testing test-ui.html over plain HTTP from a LAN dev server. Switching to HTTPS (e.g., with a self-signed cert from openssl) restores the signal.

iOS Safari Private Browsing also hides ApplePaySession. In-app WKWebView (the browser used inside Slack, Twitter, Mail link previews) does not expose it either.

Things worth knowing

  • 'Apple Pay not enabled in Wallet' does NOT matter for this signal. supportsVersion() is a pure capability check: it returns true even when the user has zero cards configured. The richer canMakePayments() method does depend on Wallet state but is not called by this collector.
  • Brave on macOS is Chromium under the hood and does NOT expose ApplePaySession; it returns absent with reason 'api_missing'.
  • Safari 17+ shipped Apple Pay protocol v15 alongside iOS 17. Observing v15 confirms iOS 17 / Safari 17 or later.
  • No farbling defence needed: no known privacy browser noises or modifies ApplePaySession output.
  • Real-device validation: this signal returned { version: 15 } on a Safari iPhone 12 Pro Max over HTTPS during the 1.5.0 release.

Last reviewed 2026-06-04