Multiple Checkout Items

In the previous guide, we showed the basic SDK code to send product and payment confirmation events on a single product.

In reality, users usually purchase multiple products, or multiple items of the same product.

There are two distinct use-cases for multiple checkout items.

  1. A user purchased several identical items. For example, 5 iPhone X covers.
  2. A user purchased several items of different kinds. For example, 2 iPhone X covers, and 3 iPhone X chargers.

In both use-cases, you should first decide whether each sold item should be considered as an individual conversion, or should any number of identical item sales are considered a single conversion.

Important

Each call to QL.sendConfirmationEvent creates a single conversion event in QL's BI database, and is treated as a single unit of sale. Units of sale are used to calculate conversion rate and aggregated number of sales across QL's UI.

Multiple checkout items - Distinct conversion events

When a user purchased several items and we want to count each item as a distinct conversion event, we create an array of sold products, and add each sale to that array, along with its sale price.

app/controllers/checkout_controller.rb

class CheckoutController < ApplicationController
 
  # GET /checkout/finish - renders successful checkout
  def finish
    checkoutProducts = session[:checkoutProducts] # read checked out products from session
    @soldProducts = []
    checkoutProducts.each do |product|
      # product is a hash table: {id: productId, salePrice: salePrice}
      productFromDB = Product.find(product[:id])
      productId = productFromDB.ean # use product ean as productId
      # push product to soldProducts      
      @soldProducts.push({
        id: productId,
        salePrice: product[:salePrice]
      })
    end
    @clientKey = 'myvirtualstore'
    
    render('finish') # explicit call to render the payment confirmation view
  end
 
end

Sale price

In reality sale prices can be different event when the same item is sold multiple times. For example Buy 2 and get the 3rd one free. You should set the sale price of each item to the actual price it was purchased in.

Multiple checkout items - Summed conversion events

When a user purchased several items and we want to count all items of the same kind (product ID) as a single conversion event, we create an array of sold products, and add an entry for each product kind (product ID), along with its sale price multiplied by the number of sold items.

app/controllers/checkout_controller.rb

class CheckoutController < ApplicationController
 
  # GET /checkout/finish - renders successful checkout
  def finish
    checkoutProducts = session[:checkoutProducts] # read checked out products from session
    @soldProducts = []
    checkoutProducts.each do |product|
      # product is a hash table: {id: productId, salePrice: salePrice, soldItems: soldItems}
      productFromDB = Product.find(product[:id])
      productId = productFromDB.ean # use product ean as productId
      # push product to soldProducts      
      @soldProducts.push({
        id: productId,
        salePrice: product[:salePrice] * product[:soldItems]
      })
    end
    @clientKey = 'myvirtualstore'
    
    render('finish') # explicit call to render the payment confirmation view
  end
 
end

Note

As with the previous example, we save the sale information in the user's session for simplicity. In reality you might save this information in your DB or a cache layer like Redis.

Sending events with the SDK

With our controller code in place, we can now modify our payment confirmation view to send multiple items to QL using the SDK.

Note that the @soldProducts array is serialized into JSON, and then iterated over, calling the QL.sendConfirmationEvent method for each product in the array.

app/views/checkout/finish.erb

<div>
  <p>Your payment has been received!</p>
  <!-- rest of HTML is redacted for simplicity --> 
</div>
<!-- ADD QL's SDK at the bottom of the page template -->
<script>
  window.QLAsync = function(QL){
    var clientKey  = '<%= @clientKey %>',
        soldProducts  = JSON.parse('<%= @soldProducts.to_json %>');
    QL.init(clientKey);
    
    // iterate over soldProducts and send each one to QL using the SDK
    soldProducts.forEach(function(product) {
      QL.sendConfirmationEvent(product.productId, parseFloat(product.salePrice, 10));
    });    
  }
</script>
<script src="//d3jdlwnuo8nsnr.cloudfront.net/sdk/v2.1/ql.js"></script>

Google Tag Manager

The above example can be modified to work on Google Tag Manager by pushing the @soldProducts array into GTM's dataLayer.

app/views/checkout/finish.erb

<div>
  <p>Your payment has been received!</p>
  <!-- rest of HTML is redacted for simplicity --> 
</div>
<!-- initialize GTM dataLayer -->
<script>
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    'clientKey':  '<%= @clientKey %>',
    'soldProducts': '<%= @soldProducts.to_json %>'
  }]);
</script>

Modify your GTM embed code for the Payment Confirmation Page as follows:

<script>
  window.QLAsync = function(QL){
    var clientKey  = '{{ clientKey }}',
        soldProducts  = JSON.parse('{{ soldProducts }}');
    QL.init(clientKey);
    
    // iterate over soldProducts and send each one to QL using the SDK
    soldProducts.forEach(function(product) {
      QL.sendConfirmationEvent(product.productId, parseFloat(product.salePrice, 10));
    });    
  }
</script>
<script src="//d3jdlwnuo8nsnr.cloudfront.net/sdk/v2.1/ql.js"></script>