The ability for an ecommerce business to accept payments online depends on the quality of the software that handles the transaction. A key way to create the best user experience in this area is with an embedded payments solution. It allows you to create a customized checkout experience where you have complete control over how the checkout works and how it integrates with your website's design and functionality. You'll also benefit from features of the solution, such as PCI compliance and data security, and support for a variety of payment methods and credit card types handled by your payment gateway.

In this article, you'll learn how to create a custom checkout experience using North's iFrame JavaScript SDK in a Vue.js application. While the SDK allows you to create an entirely custom checkout system from the ground up, North handles the sensitive payment information to ensure your solution is secure and PCI compliant.
Throughout this tutorial, you can follow along with this GitHub repo.
Prerequisites
Make sure you have Node.js v16.10.0 or newer installed. Start by creating a new project using Nuxi (the Nuxt CLI) and initiating the development server:
After running this code, when you open localhost:3000, you will see Nuxt project's default page. This means that the project has been successfully created and the dev server is running.
Setting Up a North Account
If you haven't already, start by creating a North account. Then check out the official iFrame JS SDK integration guide — especially the server security requirements you'll have to meet in your production environment.
To get test credentials, contact the North support team using the contact form.
Once you have access to your API keys, you need to securely add them to your project. Start by updating the nuxt.config.ts file, as follows:
This configuration ensures that you'll be able to access the test credentials through the Nuxt API. Variables placed within public will be available on both the front-end and back-end, while those outside will only be available on the back-end.
To provide values for the variables, place your credentials in the .env file:
Creating the Product Page
Now that you have access to the credentials, you can start creating the product page. Inside the app.vue file, add the following code:
HTML
The app.vue component serves as an entry to your Vue app, so it's a good place to set up global styles. In the template, make sure to include the NextPage component, which is responsible for rendering the current route.
Now, create a new component representing a new page in pages/product.vue:
HTML
The code above gives you a simple, styled page thanks to the included CSS. It contains an image of the product and most importantly, the payment button.
You can preview the product page at the localhost:3000/product/ route, which corresponds with the component's file name.
Next, you'll create the modal that the user should be presented with when they click the Purchase button. For this, create a separate file — components/payment-modal.vue — for a new component with the following code:
HTML
The modal contains a set of input fields and is controlled through the props. You can see that some fields have input elements while others are empty div elements. That's because the latter will be used for holding iframe elements provided and loaded by the SDK. That's also why you should keep the IDs of the elements in mind — they will be important later when you integrate with the iFrame SDK.
Also take note that submitting the form calls the submitPayment() function. However, it will remain empty until the SDK is integrated.
To add the PaymentsModal component to the page, you'll have to make a few edits to pages/product.vue:
HTML
Thanks to the script setup syntax, you only need to import a component to use it. You can then use it by binding its props and event handlers to specific values, like a newly created paymentModalOpened ref for the opened prop, to control the opening state of the modal. The ref() function, like many other functions and utilities provided by Vue.js or Nuxt, is auto-imported, which means you don't have to explicitly specify an import.
The modal is still missing some styling and most importantly, functionality. It's time to fix that with North's iFrame JS SDK.
Integrating the iFrame JS SDK
To start working with the iFrame JS SDK, you should first load the https://sdk.paymentshub.dev/pay-now.min.js module in your head element. To do so, use the useHead() composable provided by Nuxt. In pages/product.vue, add the following code inside the script setup block:
HTML
useHead() alters the content of the head element for the page it's used in. In the code above, it adds a custom title and script tag to load the SDK.
With the SDK loaded, you now have access to a PayNow global object.
Next, create a utils/sdk.js module in which you will place all the utility functions for interacting with the SDK:
The first one of these utility functions is initializeSDK, which, with proper credentials, will initialize the SDK along with all the sensitive fields like card number or CVV inputs. As you can see, it does so by referencing the container div elements from the payment modal by their IDs. On top of that, it allows you to style the iframe-based inputs using inline styles. This functionality is used to complete the design of the payment modal.
To call this function and initialize the SDK, back inside the components/payment-modal.vue file, add the following code inside the script setup block:
HTML
Nuxt auto-imports all the functions from the utils folder that it notices you use. This allows you to use initializeSDK() without any additional imports.
The SDK is initialized inside the onMounted() lifecycle hook, which is run after the UI, including the form fields, has already been mounted and rendered.
Also note the use of the useRuntimeConfig() composable. It gives you access to the credentials configured earlier, which means you can now easily access and forward the credentials to the initializeSDK(). Since you are accessing a public config property, you need to prefix it with .public — e.g., config.public.mid.
With the payments modal finished, the last step is submitting the form and handling it on the server. To implement this, create a new getToken() function in utils.sdk.js:
The getToken() function uses the SDK to tokenize the card number and CVV inputs. This gives you a single token to work with while the most sensitive payment data is handled by North to ensure PCI compliance.
On top of that, the function uses the #alert_message element to inform the user about the progress. Finally, it retrieves the street and ZIP inputs using the .getAVSFields() method, and combines all the data to send a request to the server. For this, a useful $fetch() utility function is used that provides an isomorphic (i.e., working in both browser and Node.js environments) Fetch API–like interface for making HTTP requests.
To create the API route (/api/submit), create a new file called server/api/submit.js with the following code:
The route makes two requests using the data from the request body and credentials from the config:
-
Authentication authenticates you with the API and provides a JWT token that's required to access the next endpoint.
-
Payment submission submits the payment for processing using all the details given, including the transaction's amount, and the previously generated card token.
The end response is a JSON object of the following shape:
Returning the object from the route makes it into a JSON response.
To use the getToken() callback function and the new API route, go back to components/payment-modal.vue and add proper handling to the submitPayment() function:
HTML
With that, the integration is ready.
How To Get Started
This article showed you how to integrate with North to embed payments into your Vue.js application. Thanks to the flexibility of the iFrame JS SDK and the modern features of JavaScript frameworks like Nuxt and Vue, the process is quick and relatively easy. Contact North's Sales Engineering team to learn more about how the iFrame JS SDK and other tools can meet your business needs.