Migrate to Headless Checkout
Use Headless Checkout when you want to replace Widget V3 with a custom checkout UI and keep control over the flow.
Choose Headless if
- you want to own the full checkout layout
- you need custom method selection screens
- you want to handle split payments or secondary methods in your own UI
- you need more control than Drop-in exposes
What changes from Widget V3
| Widget V3 | Headless Checkout |
|---|---|
WidgetManager + createWidget() | createHeadlessCheckout(session) |
| built-in widget layouts | your own UI around reactive stores |
| widget config for assets and translations | your app handles presentation |
| widget lifecycle and navigation | your app controls the flow |
| widget-owned pay flow | your app wires its button to isPaymentFulfilled + submitPayment() |
Migration steps
- Keep the client session flow and pass
clientSession.widget.datato the SDK. - Replace each Widget V3 screen with your own UI.
- Render available payment methods from
paymentMethods.subscribe(). - Mount the selected method with
getPaymentElement()into your container. - Use
isPaymentFulfilledto control your pay button. - Call
submitPayment()from that button when the customer confirms payment.
const checkout = await Purse.createHeadlessCheckout(clientSession.widget.data);
const methodsList = document.getElementById('methods');
const form = document.getElementById('form');
const payButton = document.getElementById('pay-button');
checkout.paymentMethods.subscribe((methods) => {
renderMethodList(methods);
});
function renderMethodList(methods) {
methodsList.innerHTML = '';
methods.forEach((method) => {
const item = document.createElement('button');
item.type = 'button';
item.textContent = `${method.partner} - ${method.method}`;
item.addEventListener('click', () => selectMethod(method));
methodsList.appendChild(item);
});
}
function selectMethod(method) {
form.innerHTML = '';
const element = method.getPaymentElement();
element.appendTo(form);
}
checkout.isPaymentFulfilled.subscribe((isFulfilled) => {
payButton.disabled = !isFulfilled;
});
payButton.addEventListener('click', async () => {
await checkout.submitPayment();
});
What you may need to rebuild
- method cards, tabs, accordions, or custom filters
- payment summary blocks
- split-payment UI
- custom loading and error states
- any widget-specific navigation
If you use split payments
Headless Checkout is the right path when Widget V3 used vouchers, gift cards, or other secondary methods that need custom UI treatment.
Next steps
- Read the Headless Checkout guide.
- Review the Headless Checkout getting started guide.