Klarna

One-step Express checkout

Add one-step Express checkout to your website, configure your page for the Klarna pop-up, and create an order.
Add one-step Express checkout to your website to give customers the fastest, lowest-friction purchase journey.
Not sure if the one-step checkout is right for your online store? Refer to the platform and PSP support article to choose the best checkout experience for your customers.
Creating a one-step Express checkout involves three steps:
  1. 1.
    Initialize and display Express checkout — load the library, configure your page, and render Express checkout.
  2. 2.
    Handle the authorization response — read the authorize() response and the authorization callback.
  3. 3.
    Create an order — use the authorization_token to create the order.

Initialize and display Express checkout

Load the Klarna payments JavaScript library on the cart page or a product detail page. Include the library only once to prevent conflicts.
HTML
1 2 3
<script defer src="https://x.klarnacdn.net/kp/lib/v1/api.js"> </script>
A sample script tag to load the Klarna payments library.

Configure your page for Express checkout

If your site sets security headers, make sure they allow Klarna. These settings apply to every integration — whether you load Express checkout at the top level or inside an iframe.
Content-Security-Policy. Allow Klarna's hosts. These directives extend your existing policy — if you use a default-src policy, make sure these hosts also appear in the corresponding directives. The img-src host lets the browser render the Klarna logo from the asset_urls on x.klarnacdn.net.
MARKUP
1 2 3 4
script-src https://x.klarnacdn.net https://js.klarna.com; connect-src https://*.klarna.com https://*.klarnaevt.com https://js.klarna.com https://x.klarnacdn.net; frame-src https://*.klarna.com https://x.klarnacdn.net; img-src https://x.klarnacdn.net;
Cross-Origin-Opener-Policy. If you set a Cross-Origin-Opener-Policy, use same-origin-allow-popups. Send it as an HTTP response header — browsers ignore Cross-Origin-Opener-Policy when it's set through a <meta> tag.
MARKUP
1
Cross-Origin-Opener-Policy: same-origin-allow-popups
Avoid Cross-Origin-Opener-Policy: same-origin. It severs the reference between your page and the Klarna pop-up that the purchase flow uses to re-focus the pop-up and to drive the recovery backdrop. same-origin-allow-popups keeps that reference while preserving the same isolation. If you set this header through a security middleware (for example, Helmet), use same-origin-allow-popups, or run the policy in report-only mode while you migrate.

Load Express checkout

You can load Express checkout in two ways: at the top level of your page (the first-party context) or inside an iframe. Load it at the top level whenever you can — this is Klarna's recommended approach, gives the most reliable customer experience, and keeps every Express checkout feature available. Only use an iframe if your architecture requires it, and follow the iframe guidance closely.

Load Express checkout in the first-party context

Load Express checkout directly in the top-level document of your page. The first-party context avoids the browser restrictions that apply to framed content, so pop-ups, storage access, and cross-origin windows work without extra configuration. It also keeps every Express checkout feature available, including those that require the top-level context.

Load Express checkout in an iframe

Only embed Express checkout in an iframe if your architecture requires it — loading at the top level avoids the browser restrictions that apply to framed content. If you must use an iframe, follow this guidance closely to keep the integration robust and deliver a best-in-class customer experience.
Klarna's purchase flow opens in a pop-up window on top of your page. If you load Express checkout inside an iframe and apply the sandbox attribute, include the tokens below and delegate the payment permission with allow, so the browser can open that pop-up and keep the reference between the pop-up and your page.
MARKUP
1 2 3 4 5
<iframe src="https://your-store.example.com/cart" sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-modals allow-storage-access-by-user-activation" allow="payment"> </iframe>
sandbox tokenWhy it's required
allow-scriptsRun the Klarna SDK integration
allow-same-originKeep the iframe's own origin for storage, cookies, and network calls
allow-popupsOpen the Klarna pop-up window
allow-popups-to-escape-sandboxEnsure the Klarna pop-up is not itself sandboxed
allow-formsSubmit the payment form
allow-modalsShow modal dialogs where needed
allow-storage-access-by-user-activationLet Klarna access browser storage after a customer interaction
The allow attribute is separate from sandbox — it delegates a browser permission to the framed document.
allow directiveWhy it's required
paymentDelegate the Payment Request API to the iframe. The permission defaults to the top-level document only, so a framed integration has to be granted it explicitly.
Where possible, host the iframe on the same origin as your page. It reduces the third-party-context storage and redirect issues involved in this class of failure. This is a reliability recommendation, not a security boundary — with allow-scripts and allow-same-origin a same-origin frame can reach its parent, so do not treat the sandbox as an isolation control.
Also, when loading inside an iframe:
  • Load Express checkout only once per page — loading it more than once can leave overlapping widgets and lock page scrolling.
  • Expand the iframe to full screen while the purchase flow is open — required so Klarna can render the recovery backdrop and, where pop-ups are not possible, the flow itself. A frame cannot resize itself, so the parent page must apply the resize: have the framed page notify the parent with postMessage when the flow opens and closes, and have the parent expand the frame to the full viewport and restore its inline size afterwards. Validate the origin on both sides — the framed page posts to the exact parent origin, and the parent checks event.origin before it resizes. The example below shows the handshake.
  • Some Klarna features are not available inside an iframe — pre-purchase personalization and conversion-boost placements require the top-level context. Use the top-level integration if you rely on them.
From the framed page that hosts Express checkout, tell the parent when Klarna's flow opens and closes. Post to the exact parent origin — never *.
JAVASCRIPT
1 2 3 4 5 6 7 8 9 10
const PARENT_ORIGIN = 'https://parent.example.com'; // Wire this into the button's on_click handler. function onKlarnaClick(authorize) { // Ask the parent to expand the frame, then start the flow. window.parent.postMessage({ type: 'klarna:flow-open' }, PARENT_ORIGIN); authorize({ auto_finalize: true, collect_shipping_address: true }, orderPayload, (result) => { // Restore the frame once the authorize() callback runs. window.parent.postMessage({ type: 'klarna:flow-close' }, PARENT_ORIGIN);
The framed page signals the parent around the purchase flow.
From the parent page, expand the iframe to the full viewport while the flow is open, then restore its inline size. Validate event.origin before acting on any message.
JAVASCRIPT
1 2 3 4 5 6 7 8 9 10
const FRAME_ORIGIN = 'https://your-store.example.com'; const frame = document.getElementById('klarna-frame'); const inlineStyle = frame.getAttribute('style') || ''; window.addEventListener('message', function (event) { if (event.origin !== FRAME_ORIGIN) return; if (event.data && event.data.type === 'klarna:flow-open') { frame.style.cssText = 'position:fixed;inset:0;width:100vw;height:100vh;border:0;z-index:2147483647;';
The parent resizes the iframe when the framed page signals.

Initialize Express checkout

Implement the klarnaAsyncCallback function to initialize Express checkout. Implement klarnaAsyncCallback before you load the library, so it runs when the library is ready. Within klarnaAsyncCallback, include the logic to:
  1. 1.
    Initialize Klarna's JavaScript SDK with your client identifier as client_id. Get your client_id from the Klarna Partner Portal. You must also allowlist your integration's origin in the Klarna Partner Portal under Payment settingsClient Identifiers, otherwise the customer sees a "We couldn't load the next screen" error. Refer to the platform and PSP support article for instructions.
  2. 2.
    Load Express checkout in a chosen container with the load() function. To debug issues when it loads, handle the result in the load() callback.
  3. 3.
    Handle the on_click event, where you start the payment authorization by calling the authorize() function. Keep these best practices in mind:
    • 3.1.
      Make sure the format of the orderPayload matches the body of the request to create a Klarna payments sessionAPI.
    • 3.2.
      Always invoke the authorize() callback that you receive in on_click.
    • 3.3.
      Avoid delays or nested asynchronous calls between the customer clicking Express checkout and calling authorize(), because longer delays cause the browser to block the Klarna pop-up.
The orderPayload object can contain all information allowed in the Klarna payments APIAPI, for example, merchant references, merchant URLs, and extra merchant data.
HTML
1 2 3 4 5 6 7 8 9 10
<script defer src="https://x.klarnacdn.net/kp/lib/v1/api.js"> </script> <script> window.klarnaAsyncCallback = function () { window.Klarna.Payments.Buttons.init({ client_id: 'klarna_client_test...', }).load( {
A sample that initializes the library and renders Express checkout.
The following table lists the attributes of the load() function's configuration object.
AttributeRequiredDescription
containerYesThe location where you want Express checkout to be displayed. You can specify either a CSS selector, for example, #my-component-id or .my-component-class, or an element-type object directly, for example, document.createElement('div').
on_clickYesThe function that runs when the customer clicks Express checkout. It receives the authorize() function, which you must invoke to start the Express checkout flow. The authorize() function acts like authorize() in a standard Klarna payments integration.
themeNoThe color theme of the button. The possible values are default, light, and dark. If the value isn't specified, default is used.
shapeNoThe shape of the button. The possible values are default, rect, and pill. If the value isn't specified, default is used.
localeNoThe language of the button text. If not specified, the browser's language is used.
The value of locale passed in the authorize() function's configuration object defines the language of the button text. The value of localeAPI passed to authorize() inside the orderPayload defines the language of the purchase flow. Learn more about locale formatsAPI in Klarna APIs.
The following table lists the attributes for the authorize() function's configuration object.
AttributeRequiredDescription
collect_shipping_addressNoInforms Express checkout whether you need the customer's shipping address from Klarna. The default value is false; set it to true when you need Klarna to return the customer's shipping address.
auto_finalizeNoSpecifies whether the authorization is automatically finalized when the customer clicks Express checkout. In one-step Express checkout, set auto_finalize to true so the purchase is authorized automatically. The default value is true.
If you load Express checkout inside an iframe, expand the iframe to fill the full viewport while the purchase flow is open. This lets Klarna render its backdrop — the recovery mechanism that lets the customer reopen or locate the Klarna pop-up if the browser blocked it or the pop-up was lost among their other tabs — and, on surfaces where a pop-up is not possible (such as a WebView), render the purchase flow inside the iframe. If the iframe stays at its inline size, neither recovery path can display and customers who lose the pop-up drop out of the checkout.
On mobile browsers, where pop-ups and cross-origin windows are the most restricted, Klarna's JavaScript SDK works within the browser's restrictions to open the purchase flow. Express checkout has no redirect-based fallback.
We recommend creating the payment session on your server. Server-side session creation keeps your Klarna API credentials and session setup off the client, which is more secure and reliable. Creating the session client-side — initializing with your client_id and passing the orderPayload to authorize(), as shown above — remains a supported alternative if it better fits your architecture.
To create the payment session on your server, follow these steps:
  1. 1.
    Create a new payment session.
  2. 2.
    Pass the client_token from the create session responseAPI to the Klarna.Payments.Buttons.init function.
  3. 3.
    Omit the order details in the authorize() function.
  4. 4.
    Keep the rest of the implementation the same.
HTML
1 2 3 4 5 6 7 8 9 10
<script> window.klarnaAsyncCallback = function () { window.Klarna.Payments.Buttons.init({ client_token: '<client_token>', }).load( { container: '#container', theme: 'default', shape: 'default', locale: 'es-ES',
A sample that initializes Express checkout with a client_token created on your server.

Render your own button (optional)

Render your own button to align with your other Express checkout buttons, then start the purchase flow programmatically. Use the same orderPayload object described above — it matches the body of the request to create a Klarna payments sessionAPI. Call authorize() from your button's click handler, not at load, otherwise the browser blocks the Klarna pop-up.
JAVASCRIPT
1 2 3 4 5 6 7 8 9 10
window.klarnaAsyncCallback = function () { // Initialize once when the library is ready. const button = window.Klarna.Payments.Buttons.init({ client_id: '<client_id>', }); // Start the purchase flow from the click handler of your own button. document.getElementById('my-express-button').addEventListener('click', () => { button.authorize( {
A sample that starts the purchase flow from your own button's click handler.

Handle the authorization response

If the authorization is successful, you receive the authorization_token from the client-side authorize() response, in the authorization callback, or by getting the payment details from the Klarna payments APIAPI.
If collect_shipping_address is true, the response includes collected_shipping_address. Any merchant_reference1 and merchant_reference2 values you provided are echoed back.
JSON
1 2 3 4 5 6 7 8 9 10
{ "show_form": true, "approved": true, "finalize_required": false, "authorization_token": "1eddf502-f3a0-45bf-b1fd-f2e3a2758200", "session_id": "e4b81ca2-0aae-4c16-bcb2-29a0a088a35b", "collected_shipping_address": { "attention": "Attn", "city": "London", "country": "GB",
A sample response from the client-side authorize() call.
JSON
1 2 3 4 5 6
{ "authorization_token": "1eddf502-f3a0-45bf-b1fd-f2e3a2758200", "session_id": "e4b81ca2-0aae-4c16-bcb2-29a0a088a35b", "merchant_reference1": "order-1234", "merchant_reference2": "customer-5678" }
A sample response from the authorization callback.

Create an order

Once you have the authorization_token, create an orderAPI. When you create the order, make sure the shipping address in the API request matches the collected shipping address returned alongside the authorization_token.