Implementing a Components checkout

Acquire a basic understanding of how to integrate components

Components are a low-code checkout option that consist of UI building blocks. They allow you to create customized checkout flows that connect to Digital River's address validation, logistics, local pricing, payment processing, subscription, fraud detection, tax computation, and compliance services.

Components make it even easier to integrate with Digital River, reducing the amount of time you spend launching and managing your solution.

You can use all of the available components together to create traditional checkout flows. Alternatively, you might decide to use them selectively to construct specialized flows. For example, by pairing the wallet component with the compliance component, you can offer customers an expedited checkout experience.

On this page, you'll find information on:

After customers successfully complete the checkout process, your application also needs to handle completed checkout-sessions.

Building a cart and initiating checkout

During the early stages of an e-commerce transaction, customers land on your storefront, review products and build a cart. Unless you're engaging our local pricing service, Digital River is typically not involved in these pre-checkout interactions. However, once customers initiate checkout, you'll need to start interacting with components.

Designing the checkout experience

For each component that you implement, your DOM needs to contain a unique HTML element to display it.

...
<div id="address-container" style="display: block"></div>
<div id="shipping-container" style="display: block"></div>
<div id="tax-identifier-container" style="display: block"></div>
<div id="payment-container" style="display: block"></div>
<div id="wallet-container" style="display: block"></div>
<div id="compliance-container" style="display: block"></div>
<div id="order-summary-container" style="display: block"></div>
<div>
    <div>
        <button id="previousButton" onclick="onPreviousButtonClick()">Previous</button>
    </div>
    <div>
        <button id="nextButton" onclick="onNextButtonClick()">Next</button>
    </div>
</div>
<div id="order-confirmation-container" style="display: none"></div>
...

The following example uses all of the available components, but how you design your experience is highly customizable.

If you implement multiple components that accept customer input, such as address, shipping, and payment, your experience should also contain buttons, or some other type of navigational control, that allows customers to move the checkout process forward and backward. These button's click events should activate your checkout flow control functionality.

Executing a components checkout

On your checkout page, you should:

Add scripts and style sheets

In the head of your html, add the DigitalRiverCheckout.js script. If you'd like, you can also include a link to the DigitalRiver.css style sheet.

<head>
    <title>Checkout Page</title>
    <script defer="defer" src="https://checkout.digitalriverws.com/v1/DigitalRiverCheckout.js"></script>
    <link rel="stylesheet" href="https://js.digitalriverws.com/v1/css/DigitalRiver.css" type="text/css"/>
</head>

Create a Digital River Checkout object

Use your public API key to create a DigitalCheckoutRiver object.

let digitalRiverCheckout = new DigitalRiverCheckout("YOUR_PUBLIC_API_KEY");

Initialize components

When your checkout page loads, invoke an asynchronous function that initializes components.

...
initializeComponents();
...

The async function you implement should:

async function initializeComponents() {
    //Build a configuration object
    const configuration = {
        checkoutSessionId: await createComponentsCheckoutSession(),
        onReady: function (data) {
            //Handle event
        },
        onChange: function (data) {
            //Handle event
        },
        onSuccess: function (data) {
            //Handle event
        }
    }
    //Create components
    let components;
    components = digitalRiverCheckout.components(configuration);
    
    //Create the individual components
    paymentComponent = components.createComponent('payment');
    shippingComponent = components.createComponent('shipping');
    addressComponent = components.createComponent('address');
    walletComponent = components.createComponent('wallet');
    thankYouComponent = components.createComponent('thankyou');
    complianceComponent = components.createComponent('compliance');
    orderSummaryComponent = components.createComponent('ordersummary');
    
    //Mount the individual components
    paymentComponent.mount('payment-container');
    shippingComponent.mount('shipping-container');
    addressComponent.mount('address-container');
    walletComponent.mount('wallet-container');
    thankYouComponent.mount('order-confirmation-container');
    complianceComponent.mount('compliance-container');
    orderSummaryComponent.mount('order-summary-container');
}

Build a configuration object

To set checkoutSessionId in the components configuration object, you should invoke an asynchronous function, wrapped by your initialize components function, that defines a checkout-session on your front-end and then passes that data to your server so that it can submit the create request.

Alternatively, before loading your checkout page, you could define and create a checkout-session completely server-side.

In either case, the function you implement needs to return the checkout-session's id.

function createComponentsCheckoutSession() {
  //Creates checkout-session
  //Returns checkout-session identifier
}

In the configuration object, you'll also need to define how you want to handle callback methods.

async function initializeComponents() {
    //Build a configuration object
    const configuration = {
        checkoutSessionId: await createComponentsCheckoutSession(),
        onReady: function (data) {
            //Handle event
        },
        onChange: function (data) {
            //Handle event
        },
        onSuccess: function (data) {
            //Handle event
        }
    }
    ...
}

Create the components object

Pass your configuration object to components().

async function initializeComponents() {
    ...
    //Create components
    let components;
    components = digitalRiverCheckout.components(configuration);
    ...
}

Create individual components

Use the object returned by components() to create the individual components that you want customers to interact with.

async function initializeComponents() {
    ...
    //Create the individual components
    paymentComponent = components.createComponent('payment');
    shippingComponent = components.createComponent('shipping');
    addressComponent = components.createComponent('address');
    walletComponent = components.createComponent('wallet');
    thankYouComponent = components.createComponent('thankyou');
    complianceComponent = components.createComponent('compliance');
    orderSummaryComponent = components.createComponent('ordersummary');
    ...
}

Mount individual components

For each component, pass the id of its HTML container to mount().

async function initializeComponents() {
    ...
    //Mount the individual components
    paymentComponent.mount('payment-container');
    shippingComponent.mount('shipping-container');
    addressComponent.mount('address-container');
    walletComponent.mount('wallet-container');
    thankYouComponent.mount('order-confirmation-container');
    complianceComponent.mount('compliance-container');
    orderSummaryComponent.mount('order-summary-container');
}

Handling front-end events

Ensure you define how you'd like to handle the ready, change, and success callback functions.

Ready events

Some of the ways you might handle onReady is by:

...
onReady: function (data) {
  if (data.requiresShipping === false) { 
    //Update the variable that controls whether to display the shipping component
  }
  if (data.showTaxIdentifiers === false) {
    //Update the variable that controls whether to display the tax identifier component
  }
  //Call a function that determines the correct component(s) to display
},
...

Change events

If you're using the tax identifier component, handle onChange by determining whether optionalTaxIdentifiers[] or requiredTaxIdentifiers[] exists in the returned data. If either does, set a variable that controls whether that component is displayed during the checkout process.

onChange: function (data) {
    ...
    if (('optionalTaxIdentifiers' in data) || ('requiredTaxIdentifiers' in data)){
      //Set a display tax identifier component boolean variable to true
      //At some point in the checkout process, display the tax identifier component
    };
},
...

If, for whatever reason, you decide not to use the order summary component, you can also use onChange to update your custom-built order summary section. There are a variety of ways to do this.

The example below retrieves locale, currency, totalAmount, totalShipping, totalTax, and subTotal, along with each items[].amount, from the data returned by onChange and then constructs JavaScript Int.NumberFormat objects which are then used to set the innerText of the appropriate HTML element.

In this example, the sku.image and sku.name of each items[] is also displayed.

  ...
  onChange: function (data) {
    const locale = data.locale.replace('_', '-');
    document.getElementById('total').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalAmount);
    document.getElementById('shipping').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalShipping);
    document.getElementById('tax').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalTax);
    document.getElementById('subtotal').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.subtotal);
    document.getElementById('items').innerHTML = data.items.map( i => {
      return <div>
        <img style="height: 30px; width: 30px" src="${i.sku.image}"/> ${i.sku.name} - ${new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(i.amount)}
      </div>
    });
  },
  ...

Success events

One way to handle onSuccess is by passing an argument to your control checkout flow function, instructing it to display the thank you component.

Alternatively, you could retrieve order.id (and whatever else you need) from data and use it to build your custom order confirmation page.

  ...
  onSuccess: function (data) {
    // Display the thank you component or a customized order confirmation page
  },
  ...

Controlling the checkout flow

To control the flow of the checkout experience, you'll need to implement asynchronous functionality.

One possible approach is to define a function that checks a position enumeration, each value of which corresponds to a stage in the checkout process, and then, depending on the value, uses document to access each HTML element in your experience that holds a component, displaying and hiding the appropriate ones.

As you progress through the various checkout stages, make sure you also call done() to ensure that the customer's inputs are submitted and valid. For details, refer to Submitting components.

Submitting components

Some of the available components collect data from customers. For a subset of these, Digital River handles submitting that data. For others, you must initiate the process.

For example, in the payment component, DigitalRiver.js handles the button click event by sending a create source request, performing any required SCA or redirects to the payment provider, and then, assuming those processes are successful, requesting that the payment object be added to the checkout-session's sources[].

On the other hand, the address, shipping, tax identifier, and invoice components require that you invoke a function that submits the data they collect and determines whether it's valid. Specifically, these components require that, inside of an async function, you call done() using the await operator and then check the returned value to determine whether the checkout should advance to the next stage.

...
const addressComponentStatus = await addressComponent.done();
if (!addressComponentStatus) {
  //Do not advance checkout to the next stage
  return;
} else {
  //Advance checkout to the next stage
}
...

For details, refer to:

Last updated