Highnote's card viewer SDK allows you to embed sensitive card data into your UI using iframes. This prevents PCI-scoped data from flowing through your servers or being accessible to scripts running on your page.
This guide provides an overview of requirements, installation steps, and usage guidelines for the card viewer SDK.
You can install the card viewer SDK using JavaScript package managers or CDN. For more installation information, see the SDK Installation guide.
To render card details in your UI, you must set up elements to hold each field. This involves the following steps:
To use the card viewer SDK, you must provide elements for each field you want to render iframes for. The following example uses:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Payment Card</title> </head> <body> <p>Card Number</p> <div id="cardNumber"> <!-- An iframe will be injected here --> </div> <p>CVV</p> <div id="cvv"> <!-- An iframe will be injected here --> </div> <p>Expiration Date</p> <div id="expirationDate"> <!-- An iframe will be injected here --> </div> </body> </html>
To obtain a client token from your server for the card viewer SDK, use the generatePaymentCardClientToken
mutation.
Refer to the following guidelines when generating a payment card client token:
paymentCardId
of the payment card you are rendering.Use the following mutation to generate a payment card client token:
xxxxxxxxxx
mutation GeneratePaymentCardClientToken(
$input: GeneratePaymentCardClientTokenInput!
) {
generatePaymentCardClientToken(input: $input) {
... on ClientToken {
value
expirationDate
}
}
}
The card viewer library works by injecting an iframe into each provided element to render the appropriate data. You can style the content inside each iframe by passing any combination of styling options.
You can initialize the card viewer by using a renderFields
function. This returns a Promise that contains a reference to the cardViewer
instance. This is useful for lifecycle management and interactions such as card number masking.
The following example shows how to initialize the card viewer:
import { renderFields } from "@highnoteplatform/card-viewer"; const { unmount } = await renderFields({ clientToken: "client token from server", // This is the same paymentCardId used to generate the token paymentCardId: "PAYMENT_CARD_ID", onError: (error) => { // Handle errors }, onReady: () => { // Called after data has been fetched and sdk is ready to display information // For eg, can be used to show a custom loading indicator document.querySelector(".loading").classList.add("hidden"); document.querySelector(".cardFields").classList.remove("hidden"); }, // Specify the individual fields to render data into elements: { cardNumber: { selector: "#cardNumber", }, cvv: { selector: "#cvv", }, expirationDate: { selector: "#expirationDate", }, }, });
Note: The card viewer doesn’t render error messages or update your UI inside iframes when errors occur. You must introspect and handle errors accordingly.
When initializing the card viewer, you can pass an onError
handler to the renderFields
function. This callback is invoked whenever an error is raised from the integration.
The following error types are supported for the card viewer SDK:
Error | Description |
---|---|
InvalidCredentialError | Occurs when the provided client token is invalid or expired. The payload will contain the requestId which can be used for support and debugging. |
CardViewerRequestError | Represents errors encountered when communicating with the Highnote API. The payload will contain the requestId which can be used for support and debugging. |
CardViewerFieldsInputError | Raised when an invalid configuration is provided at runtime. |
CopyToClipboardError | Raised when there is an issue copying a field value to a user's clipboard. |
CardViewerError | A generic catchall error. |
import { renderFields } from "@highnoteplatform/card-viewer"; const handleError = ( error: HighnoteRequestError | HighnoteConfigError | Error ) => { switch (error.name) { case "InvalidCredential": // Handle invalid/expired credential // Unmount fields, fetch new client token, re-initialize console.error(error.context.requestId); // "some-request-id" break; case "CardViewerRequestError": console.error(error.context.requestId); // some-request-id break; case "CardViewerFieldsInputError": console.error(error.message); // "Invalid Payment Card ID" break; default: console.error(error); } }; const { unmount } = await renderFields({ clientToken: "client token from server", // This is the same paymentCardId used to generate the token paymentCardId: "PAYMENT_CARD_ID", onError: (error) => { // Handle errors }, onReady: () => { // Called after data has been fetched and sdk is ready to display information }, // Specify the individual fields to render data into elements: { cardNumber: { selector: "#cardNumber", }, cvv: { selector: "#cvv", }, expirationDate: { selector: "#expirationDate", }, }, });
The following styling options are available for use in elements for your card viewer:
Property | Examples | Docs |
---|---|---|
color | #55f5a3 , rgba(85,245,163,1) , #springgreen | MDN Docs |
cursor | pointer , none | MDN Docs |
fontFamily | sans-serif , serif , monospace System fonts only | MDN Docs |
fontSize | 12px , 1em , 1.1rem | MDN Docs |
fontWeight | bold , normal | MDN Docs |
letterSpacing | normal , .2rem | MDN Docs |
lineHeight | normal , 150% | MDN Docs |
userSelect | none , auto , inherit | MDN Docs |
Highnote injects card viewer iframes with the following defaults. Your CSS styling can override each of these:
border: none
width: 300px
(browser default)height: 150px
(browser default)The document and body inside the frame will have transparent backgrounds and default to margin: 0
, padding: 0
.
The layout of payment card fields in the card viewer is customizable. Highnote injects iframes into the provided container elements, which will inherit the width of the container.
You can customize the width and height of the container to accommodate your UI as needed.
The following code sample provides an example of custom layout styling:
#cardNumber { margin: 1em; } /* You can target the iframe with a child combinator. */ #cardNumber > iframe { height: 140px; }
By default, the card viewer library will make requests against the test environment. When you are ready to switch to the live environment, set the environment
configuration option using the following function call:
const { unmount } = await renderFields({ clientToken: "client token from server", paymentCardId: "PAYMENT_CARD_ID", // Set this to `live` environemnt: 'live', onError: handleError, elements })
The card viewer SDK has a lifecycle that consists of a loading state, which resolves with payment card details. You can also unmount payment card details as needed.
When rendering card viewer fields, the library writes the required iframes into your UI and renders them in a loading state. While in the loading state, the fields will be populated with placeholder characters:
•••• •••• •••• ••••
•••
••/••
You can't change these values. Once the configuration has been validated and the fields rendered, the library will request the card details from the Highnote API and replace the loading values with the corresponding data.
If you need to unmount payment card fields, use the unmount
method on the returned reference. This is useful when you need to “restart” the integration, or navigate to a new view client-side. Using this will ensure the cleanup of any DOM and event handlers.
The following code sample provides an example function to unmount fields:
import { renderFields } from "@highnoteplatform/card-viewer"; const { unmount } = await renderFields({ // ...config }); // Later...unmount await unmount()
The card viewer SDK supports the following end-user interactions:
By default, the payment card number will be masked (•••• •••• •••• ••••
). Only the last four digits will be shown when the card number is available.
You can toggle the masking on and off using the toggleCardNumberMask
method on the returned card viewer reference.
The following code sample is an example of a card number masking configuration:
import { renderFields } from "@highnoteplatform/card-viewer"; const { toggleCardNumberMask } = await renderFields({ // ...config }); // Toggle card number mask const err = toggleCardNumberMask() if (err) { console.log(err); // { name: "CardViewerToggleMaskError", message: "Unable to toggle card number mask." } }
By default, users can select and copy payment card detail values to their clipboard. You can use the enableClipboard
configuration property to toggle the "copy to clipboard" feature on or off.
When enabled, clicking the card number, expiration date, or CVV field will copy the underlying value to the account holder's clipboard. This results in a copy event.
In addition to the copy event, two callback functions allow customization when a user copies or fails to copy a value:
callback | description |
---|---|
onCopyToClipboardSuccess | Invoked when an account holder successfully copies a value to their clipboard. This function will also receive an object with the property field and a property __typename of COPY_TO_CLIPBOARD_SUCCESS |
onError | invoked with an error of type COPY_TO_CLIPBOARD_ERROR in the event this functionality fails. |
The following code sample is an example of a copy to clipboard configuration:
import { renderFields } from "@highnoteplatform/card-viewer"; const { unmount } = await renderFields({ clientToken: "client token from server", // This is the same paymentCardId used to generate the token paymentCardId: "PAYMENT_CARD_ID", // This allows a user to click and copy the value of a field. Enabled by default enableClipboard: true, // Only needed is clipboard is enabled onCopyToClipboardSuccess: ({ field }) => { console.log(`${field} value copied!`); // cardNumber value copied! }, onError: (error) => { // Handle errors }, onReady: () => { // Called after data has been fetched and sdk is ready to display information }, // Specify the individual fields to render data into elements: { cardNumber: { selector: "#cardNumber", }, cvv: { selector: "#cvv", }, expirationDate: { selector: "#expirationDate", }, }, });
If your application enforces a content security policy, you must set the frame-src
header to allow iframes from the Highnote domain:
Content-Security-Policy: frame-src https://cdn.highnote.com