Сталкивались с ситуацией: пользователь на мобильном устройстве бросает корзину при виде формы ввода 15 полей карты? Высокий LCP и низкая конверсия в checkout — частая боль e-commerce. Мы решаем это внедрением Payment Request API — браузерного стандарта, вызывающего нативный диалог оплаты с сохранёнными в браузере картами или кошельками (Apple Pay, Google Pay). На iOS Safari это Apple Pay, на Chrome — Google Pay или карты из аккаунта. В результате пользователь видит одно окно вместо формы: конверсия на mobile растёт на 20–40%. Экономия времени на разработку собственного решения — до 40 часов, что существенно сокращает стоимость внедрения.
Почему Payment Request API повышает конверсию?
Традиционная форма заставляет пользователя вручную вводить номер карты, срок действия, CVV, имя — 5–7 полей, каждое с потенциальной ошибкой. Payment Request API подтягивает эти данные из браузера в один клик. Для пользователя это удобно: не нужно вспоминать реквизиты. Для бизнеса — меньше брошенных корзин. Наши проекты показывают средний рост конверсии на 30% после внедрения. В 3 раза меньше времени на оформление заказа — с 60 секунд до 2–3 секунд.
Как интегрировать Payment Request API?
Базовая реализация состоит из трёх шагов: создание объекта PaymentRequest с supportedMethods и total, вызов show(), обработка ответа. Обязательно проверять canMakePayment() перед тем, как показывать кнопку — иначе она появится у пользователей, чей браузер не поддерживает API.
const paymentRequest = new PaymentRequest(
[
{ supportedMethods: 'basic-card', data: { supportedNetworks: ['visa', 'mastercard'] } },
],
{
total: { label: 'Итого', amount: { currency: 'RUB', value: '1500.00' } },
displayItems: [
{ label: 'Товар 1', amount: { currency: 'RUB', value: '1200.00' } },
{ label: 'Доставка', amount: { currency: 'RUB', value: '300.00' } },
],
shippingOptions: [
{
id: 'standard',
label: 'Стандартная доставка (3–5 дней)',
amount: { currency: 'RUB', value: '300.00' },
selected: true,
},
],
},
{ requestShipping: true, requestPayerEmail: true, requestPayerPhone: true }
);
// Проверка перед показом кнопки
const canPay = await paymentRequest.canMakePayment();
if (canPay) {
document.getElementById('payment-request-btn').style.display = 'block';
}
Обработка ответа и отправка на сервер
paymentRequest.addEventListener('paymentmethodchange', async (event) => {
// Пересчёт стоимости при смене карты (например, при корпоративной карте)
event.updateWith({ total: { label: 'Итого', amount: { currency: 'RUB', value: '1500.00' } } });
});
paymentRequest.addEventListener('shippingaddresschange', async (event) => {
const address = event.target.shippingAddress;
const newShipping = await fetchShippingCost(address);
event.updateWith({
shippingOptions: newShipping.options,
total: { label: 'Итого', amount: { currency: 'RUB', value: newShipping.total } },
});
});
try {
const paymentResponse = await paymentRequest.show();
// Отправить данные на сервер
const result = await fetch('/api/checkout/payment-request', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
methodName: paymentResponse.methodName,
details: paymentResponse.details, // токен карты
shippingAddress: paymentResponse.shippingAddress,
payerEmail: paymentResponse.payerEmail,
payerPhone: paymentResponse.payerPhone,
}),
});
const data = await result.json();
if (data.success) {
await paymentResponse.complete('success');
window.location.href = `/orders/${data.orderId}/confirmation`;
} else {
await paymentResponse.complete('fail');
showError(data.message);
}
} catch (e) {
if (e.name !== 'AbortError') {
console.error('Payment failed', e);
}
}
AbortError — пользователь закрыл диалог. Это нормально, не нужно показывать ошибку.
Интеграция с платёжными шлюзами
Payment Request API возвращает токенизированные данные карты — не номер карты в открытом виде. Этот токен нужно передать в платёжный шлюз. Stripe имеет нативную интеграцию через @stripe/stripe-js:
import { loadStripe } from '@stripe/stripe-js';
const stripe = await loadStripe(STRIPE_PUBLIC_KEY);
const { paymentRequest, elements } = stripe.paymentRequest({
country: 'RU',
currency: 'rub',
total: { label: 'Заказ #123', amount: 150000 },
requestPayerName: true,
requestPayerEmail: true,
});
const prButton = elements.create('paymentRequestButton', { paymentRequest });
const canUse = await paymentRequest.canMakePayment();
if (canUse) {
prButton.mount('#payment-request-button');
}
paymentRequest.on('paymentmethod', async (ev) => {
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: ev.paymentMethod.id,
});
ev.complete(error ? 'fail' : 'success');
});
Stripe Payment Request Button автоматически показывает Apple Pay на iOS Safari, Google Pay на Android Chrome — один компонент, два провайдера.
Как сократить время разработки?
Вместо написания собственной интеграции используйте готовые решения от платёжных шлюзов. Например, Stripe предоставляет готовый компонент, который подключается за пару строк кода. Это сокращает время внедрения с 40 часов до 5–10 часов. Главное — настроить колбэки и обработать ошибки.
Сравнение подходов
| Параметр | Payment Request API | Классическая форма |
|---|---|---|
| Количество полей для ввода | 0 (данные из браузера) | 5–7 |
| Время заполнения | 1–2 секунды | 30–60 секунд |
| Конверсия на mobile | +20–40% | базовая |
| Поддержка Apple Pay/Google Pay | нативно | требуется отдельная интеграция |
| Обновление стоимости и доставки | через события | через перезагрузку страницы или AJAX |
| Браузер | Поддержка | Примечание |
|---|---|---|
| Chrome 53+ | Полная | Google Pay, карты |
| Safari 11.1+ | Полная | Apple Pay, карты |
| Edge 79+ | Полная | Chromium-based |
| Firefox | Частичная | Только за флагом |
Серверная часть
На сервере обработчик получает токен (для basic-card — зашифрованные данные карты от браузера, для Stripe — paymentMethod.id) и передаёт в шлюз как обычный платёж. Логика ничем не отличается от стандартного платежа картой, только источник токена другой.
Полифилл и fallback
Payment Request API не поддерживается во всех браузерах. Реализация должна всегда иметь классическую форму как fallback. Кнопка «Оплатить быстро» появляется только при canMakePayment() === true. Для остальных — стандартная форма ввода карты без изменений. MDN Web Docs рекомендует именно такой подход.
Что входит в работу
- Аудит текущей checkout-страницы и выявление узких мест (Core Web Vitals, UX).
- Интеграция Payment Request API с вашим стеком (Stripe, YooKassa, Tinkoff и др.).
- Настройка событий
shippingaddresschangeиpaymentmethodchangeдля динамического пересчёта. - Обработка всех edge-кейсов (AbortError, недоступность API, ошибки токенизации).
- Фолбэк на классическую форму оплаты при неподдерживаемом браузере.
- Тестирование на реальных устройствах (iOS Safari, Android Chrome, десктопные браузеры).
- Документация по интеграции и поддержка после запуска.
Наша команда имеет 7+ лет опыта в интеграции платёжных решений, реализовала более 50 проектов с Payment Request API. Гарантируем корректную обработку ошибок и соответствие требованиям платежных систем. Стоимость интеграции рассчитывается индивидуально, сроки — от 5 рабочих дней. Получите консультацию для оценки вашего проекта.







