Display Klarna at checkout with the JavaScript SDK, then get authorization for the purchase.
During the checkout, your customers can see Klarna as a payment option, select it, and go ahead with the purchase. Everything on this page happens on the client side using Klarna's JavaScript SDK. To enable it, complete three steps:
Add the SDK by including the following script in the body section of your checkout page.
MARKUP
1
2
3
4
5
6
7
8
<script>
window.klarnaAsyncCallback = function () {
// This is where you start calling Klarna's JS SDK functions
//
// Klarna.Payments.init({....})
};
</script>
<script src="https://x.klarnacdn.net/kp/lib/v1/api.js" async></script>
A sample of Klarna's JavaScript SDK in the checkout page.
You do not need to install the JavaScript SDK beforehand. It's enough to include the previous script in the HTML file of your checkout page.
If your site sets security headers, make sure they allow Klarna. These settings apply to every integration — whether you load Klarna 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.
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.
Avoid Cross-Origin-Opener-Policy: same-origin. It severs the reference between your page and the Klarna pop-up that the 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.
You can load the Klarna SDK integration 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 Klarna feature available. Only use an iframe if your architecture requires it, and follow the iframe guidance closely.
Load the Klarna SDK integration directly in the top-level document of your checkout 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 Klarna feature available, including those that require the top-level context.
Only embed Klarna 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 checkout. If you load Klarna 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.
Keep the iframe's own origin for storage, cookies, and network calls
allow-popups
Open the Klarna pop-up window
allow-popups-to-escape-sandbox
Ensure the Klarna pop-up is not itself sandboxed
allow-forms
Submit the payment form
allow-modals
Show modal dialogs where needed
allow-storage-access-by-user-activation
Let Klarna access browser storage after a customer interaction
allow-top-navigation-by-user-activation
Navigate the top-level page to the Hosted Payment Page when the redirect-based flow is used
The allow attribute is separate from sandbox — it delegates a browser permission to the framed document.
allow directive
Why it's required
payment
Delegate 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 checkout 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 the Klarna SDK integration 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 checkout page, 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
constPARENT_ORIGIN = 'https://parent.example.com';
functionstartKlarnaFlow() {
// Ask the parent to expand the frame, then open the purchase flow.
window.parent.postMessage({ type: 'klarna:flow-open' }, PARENT_ORIGIN);
Klarna.Payments.authorize({}, { /* billing_address, shipping_address, ... */ }, function (res) {
// Restore the frame once the authorize() callback runs.
window.parent.postMessage({ type: 'klarna:flow-close' }, PARENT_ORIGIN);
console.debug(res);
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.
At checkout, your customers can choose to pay with Klarna. Then, a pop-up window opens where your customers log into their Klarna account and select their preferred Klarna payment option.
You need to use our JavaScript SDK to display Klarna in your checkout. This interaction is possible through the load() call happening on the client side.
The following information is applicable for both scenarios, one-time and recurring payments.
For a better customer experience, call load() when loading your checkout. In this way, you ensure that the container of Klarna payments loads immediately in a hidden container, and it's ready to appear when needed.
Don't forget to use the Klarna logo that you received in Step 1: Initiate a payment and add the payment option name. From the payload you received in Step 1, use:
identifier to dynamically load the payment option
name to display the correct and localized payment option title
After processing the load() call, the callback function runs. The JavaScript callback is an object containing the following parameters:
show_form, indicating if Klarna payments is available
error, containing details of potential error messages
The show_form boolean parameter is the response flag to the load() call. It tells your checkout whether the customer can pay with Klarna. Always listen to it so you can react when Klarna is unavailable.
There are two potential cases that you need to handle based on the response flag:
Success response: Your checkout offers Klarna payments.
Error response: Your checkout is not able to offer Klarna payments.
When your customer selects Klarna to pay, you need to use our JavaScript SDK to get authorization for the purchase.
In this step, you send all the necessary customer details for Klarna to assess and decide whether or not to accept this purchase. When the authorization is successful, you receive an authorization token as a response, useful for Step 3: Create an order.
The authorization is possible through the authorize() call happening on the client side. You should also implement the authorization callback so that you receive the authorization token on the server side and no authorization is missed.
The following information is useful for both scenarios, one-time and recurring payments.
Get authorization for the purchase by using the authorize() call. We recommend sending the following parameters in the data object of the authorize call:
billing_address, containing the customer's billing address.
shipping_address, containing the customer's shipping address. If you don't provide a shipping address, we copy the billing address and use it as the shipping address.
If no billing or shipping address is provided, new Klarna customers have to manually enter their full billing address on the Klarna payment page. Providing the billing address in the authorize() call enables Klarna to prefill the signup form for new customers.
We recommend avoiding any delays or asynchronous operations (for example, sending calls to your server) between the customer clicking the Buy button and you calling authorize(). Longer delays or asynchronous operations between the actual customer interaction and the authorize() call cause the browser to block the Klarna pop-up from opening.
If you load Klarna 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, we recommend the redirect-based flow (Hosted Payment Page) rather than the pop-up for the most reliable experience. To use it, create a Hosted Payment Page session and redirect the customer to Klarna instead of calling authorize() in the browser — see the Hosted Payment Page integration guide.
To update the Klarna session, provide all necessary information when calling authorize(). If you need to update your server-side session, we recommend doing so when the customer returns from Klarna's purchase flow.
In some cases, Klarna requires additional information about the customer and purchase. We recommend you send it in the authorize() call. For more information, see the Extra merchant data section.
For GDPR (General Data Protection Regulation) reasons, you shouldn't send customer data before the authorize() call.
Klarna uses all this information to make the fraud assessment. To see what data you need per market and how to format it, check the customer data requirements.
During the authorize() call and until you receive the callback, Klarna runs a purchase flow that includes a fraud assessment. You need to visually indicate to your customer that an ongoing process is happening. For a better customer experience, we suggest:
Avoiding another authorize() call (for example, disable the buy button)
Showing your customer that the order is in progress (for example, show a loading spinner)
Preventing your customer from changing the order or billing details (for example, lock the input fields on your page).
Implement the server-side authorization callback so you always receive the authorization_token and session_id, even when client-side communication fails. You need both values to create the order, so the callback keeps the checkout reliable if the customer's browser drops the response.
If the response of the authorize is not successful with show_form: true and an error object containing invalid_fields, something fixable is wrong and the customer needs to take action. An error message is displayed asking the customer to make corrections before you re-authorize the purchase. The error message points out which fields are incorrect.
It's also possible that the response is approved: false and show_form: true, but the callback doesn't include error. This means the customer has terminated a required interaction in the widget, such as authentication or sign-up flows. In this case, you should keep Klarna visible so that the customer can make another purchase attempt.
If the response is show_form: false, your checkout is not able to offer Klarna as a payment option. You should disable Klarna from your checkout, and your customer might select another payment option.
This negative response results from the pre-assessment that Klarna runs for the purchase.