Sticky mobile checkout bar with a collapsed promo field
Keep the Pay button visible on mobile checkout by pinning a sticky order bar and collapsing the promo-code field behind a link.
Design
If the Pay button stays visible on mobile checkout instead of being pushed below the fold by the promo-code field, then purchase_completed will recover on mobile web, because shoppers keep sight of the primary action through payment.
Control
Current mobile checkout: the promo-code field is expanded above the Pay button, pushing it below the fold on most phones.
Treatment
Promo field collapses behind a "Have a code?" link; a sticky bottom bar shows the order total and a full-width Pay button that stays visible as the page scrolls.
Code changes (2 files)
Touches files that look higher-stakes, worth a closer review before merging: src/components/checkout/MobileCheckoutBar.tsx, src/app/checkout/CheckoutForm.tsx
+ 'use client'++ import { formatPrice } from '@/lib/format'+ import { usePlaceOrder } from '@/lib/checkout'++ // Pinned to the bottom of the mobile checkout viewport so the primary action+ // stays visible regardless of scroll position. Rendered only on mobile web;+ // desktop and the iOS app keep their existing layouts.+ export function MobileCheckoutBar({ total }: { total: number }) {+ const { placeOrder, submitting } = usePlaceOrder()++ return (+ <div className="fixed inset-x-0 bottom-0 border-t bg-white px-4 py-3 shadow-[0_-1px_8px_rgba(0,0,0,0.06)]">+ <div className="flex items-center justify-between gap-3">+ <span className="text-sm text-neutral-500">Total</span>+ <span className="text-base font-semibold">{formatPrice(total)}</span>+ </div>+ <button+ onClick={placeOrder}+ disabled={submitting}+ className="mt-2 w-full rounded-xl bg-emerald-700 py-3 font-semibold text-white disabled:opacity-60"+ >+ {submitting ? 'Placing order…' : 'Pay now'}+ </button>+ </div>+ )+ }+
Primary metric
purchase_completed
Rollout
50%
Guardrail metrics
checkout_started
add_to_cart
average_order_value