Any (webshop)

Clerk.js

Integrate Clerk.io into any frontend with a lightweight JS library.
Clerk.js

Overview #

Clerk.js is a JavaScript library that simplifies the integration of our API with the frontend. At just 37.7kb, it is a super lightweight solution.

There are three benefits to using Clerk.js:

  • It’s robust, as it’s loaded asynchronously. This means that the rest of the page is not dependent on an API response before loading.
  • It’s often faster, as your server can start rendering the page in parallel with Clerk.js making calls and rendering results.
  • Visitor- and click-tracking is handled automatically for any results shown by Clerk. This requires no cookies, as we generate a hashed value of the visitor’s IP and useragent, combined with a unique store salt that rotates every 30 days.

Clerk.js loads with an initialization script added to the header of the website:

<!-- Start of Clerk.io E-commerce Personalisation tool - www.clerk.io -->
<script type="text/javascript">
  (function(w,d){
    var e=d.createElement('script');e.type='text/javascript';e.async=true;
    e.src='https://cdn.clerk.io/clerk.js';
    var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(e,s);
    w.__clerk_q=w.__clerk_q||[];w.Clerk=w.Clerk||function(){ w.__clerk_q.push(arguments) };
  })(window,document);

  Clerk('config', {
    key: 'insert_api_key'
  });
</script>
<!-- End of Clerk.io E-commerce Personalisation tool - www.clerk.io -->

It loads the library from our CDN and lets you access its functionalities through the Clerk object, and configures Clerk.js with the API key so it already knows which Store it’s making API calls for.

Snippets #

When the page is loaded, Clerk.js scans it for any snippets with the class “clerk”.

It then uses the attributes from the snippet to build an API call while getting the API key from the config in the initialization script.

<span
  class="clerk"
  data-api="recommendations/popular"
  data-limit="10"
  data-template="@clerk-product-template">
</span>

The visuals are handled by the Design, which is also referenced by the snippet.

Clerk.js uses Liquid designs to render HTML with the data returned by the API. These are formatted as scripts, referenced by their ID in data-template in your snippet.

<span class="clerk"
     data-api="search/search"
     data-query="jedi"
     data-limit="20"
     data-template="#clerk-template">
</span>

<script type="text/x-template" id="clerk-template">
  <h1>Search result for {{ query }}.</h1>
  {% for product in products %}
    <div class="product">
      <h2>{{ product.name }}</h2>
      <img src="{{ product.image }}" />
      <a href="{{ product.url }}">Buy Now</a>
    </div>
  {% endfor %}

  <a href="javascript:Clerk('content', '#{{ content.id }}', 'more', 20);">Load More Results</a>
</script>

Snippets can also be simplified to just include a reference to a Content block, by using the syntax data-template="@content-block-id":

<span class="clerk"
     data-template="@product-page-alternatives"
     data-products="[12352]">
</span>

Designs are then handled with the Design Editor or with Liquid HTML code in a user-friendly way from my.clerk.io.

Your snippets will only need to contain the class clerk, any page-specific info like product ID’s, and a reference to the ID of a Content block in data-template.

Injection #

Injection is a feature that allows you to insert content snippets into your website without having to add it manually. Instead, you simply choose a CSS Selector to inject the snippet into, and Clerk.js will automatically add it on page load.

Read more about Injection here.

Configuration #

Clerk.js allows for a variety of configurations that change how it functions.

Visitor IDs #

By default, Clerk.js generates anonymous visitor IDs, used to track the sessions.

If customers agree to cookies, Clerk.js can be configured to place a persistent cookie with the visitor ID, which allows tracking over a longer period of time.

If you prefer managing session IDs manually, you can configure the visitor parameter that Clerk uses in API calls. Alternatively, you can turn off session tracking entirely by setting visitor to null.

// Persistent visitor ID
Clerk('config', {
  visitor: 'persistent'
});

// Custom visitor ID
Clerk('config', {
  visitor: 'ABC123'
});

// Disabling visitor tracking
Clerk('config', {
  visitor: null
});

Language #

Configures Clerk.js with the written language of the website. This is used for Clerk.io to properly handle grammar rules in Search, and for fetching the correct translations when you use multi-language feeds.

Clerk('config', {
  language: 'italian'
});

Design Functions #

Clerk.js supports adding Formatters and Globals, which can be used to create custom javascript functionality for your design scopes.

Formatters #

These are used to influence or change attributes. For example, you may only want to show the first 40 characters of a description, or you may need to calculate a specific discount percentage based on the type of customer who is logged in.

Globals #

These are meant to be used with frontend data that you want to access in designs. This could be examples like the remaining amount needed to achieve free shipping, the name of a logged-in customer, a currency symbol, or a conversion rate.

Below is an example of configuring formatters and globals.

Config #
Clerk('config', {
  formatters: {
    uppercase: function(string) {
        return string.toUpperCase();
    }
  },
  globals: {
    currency_symbol: '$'
  }
});
Design #
<div class="name">{{ product.name | uppercase }}</div>
<div class="price">{{ currency_symbol }}{{ product.price }}</div>
Output #
<div class="name">GREEN LIGHT SABER</div>
<div class="price">$1999.99</div>

Email Tracking #

Clerk.js can automatically collect emails in the customer’s session to be used for personalising email recommendations even if they haven’t placed an order yet.

This is done by configuring Clerk.js with collect_email: true as shown here:

<script type="text/javascript">
  Clerk('config', {
    key: 'insert_api_key',
    collect_email: true
  });
</script>

With this, Clerk.js will monitor all input fields on the website, and logs it with log/email when a visitor writes an email address into one of them:

https://api.clerk.io/v2/log/email?payload={"email":"test@test.com","key":"insert_api_key","visitor":"auto"}

Custom Rendering #

This is primarily used with Single Page Apps (SPA), Progressive Web Apps (PWA) and other applications that do not use traditional page loads.

Clerk.js renders any elements with the class clerk, but other classes can be used to customize the rendering as custom selectors.

By default, Clerk requires you to run Clerk("content", "SELECTOR") to render content every time it should be shown.

Adding auto_init_custom_selectors: true to the config, makes Clerk.js automatically initialise any custom selector elements as the DOM mutates, as long as they have already been rendered with Clerk("content", "SELECTOR") once.

This behaviour continues until a full page refresh happens.

Debugging #

Clerk.js has a built-in debug mode that will log various information to the console, depending on the level you choose. It’s configured directly in the URL:

https://yourwebsite.com/#clerkjs:debug.level=all&debug.enable=true

The debugger has 4 parameters:

ConfigFunctionType
levelDefines the log level. Can be either log warn or error. By default the level is warn.string
collectDefines if the logger should use the browsers storage, or use temporary storage to save log messages. Default is true.bool
enableEnables clerk debug messages to the browsers console. Default is true.bool
clearClears the log messages.bool

UI Kit #

Clerk.js includes a set of UI tools for important elements that can be used to enhance the user experience. These often save development time for custom setups.

A key part of a great e-commerce search experience is getting results immediately as you start typing. Our Instant Search UI component makes this user experience swift and easy to build.

Any Clerk.io content can theoretically be made into an Instant Search component, but it works best as a dropdown showing search results.

<span 
  class="clerk"
  
  data-api="search/predictive"
  data-limit="6"
  data-labels='["Instant Search"]'
      
  data-instant-search="INSERT_CSS_SELECTORS_HERE">
  
  <dl class="product-search-result-list">
    <dt>Products matching <i>{{ query }}</i></dt>
    
    {% for product in products %}
      <dd class="product clerk-instant-search-key-selectable">
        <h2 class="product-name">{{ product.name }}</h2> 
        <img src="{{ product.image }}" title="{{ product.name }}" />
        <div class="price">${{ product.price | money }}</div>
        <a href="{{ product.url }}">Buy Now</a>
      </dd>
    {% endfor %}
  </dl>
</span>

Read more about the Instant Search UI tool here.

Search Page #

A key part of a great e-commerce search experience is getting good search results. Our Search Page makes this user experience swift and easy to build.

The Search Page let’s you create a full page showing the best possible matches for any given query.

<span 
  class="clerk"
  
  data-api="search/search"
  data-limit="40"
  data-labels='["Search Page"]'
  data-query="INSERT_QUERY_HERE"
  data-orderby="INSERT_SORTING_ATTRIBUTE"
  data-order="asc_OR_desc">>
  
  <div class="product-search-result-list">
    <div>Products matching <i>{{ query }}</i></div>
    
    {% for product in products %}
      <div class="product">
        <h2 class="product-name">{{ product.name }}</h2> 
        <img src="{{ product.image }}" title="{{ product.name }}" />
        <div class="price">${{ product.price | money }}</div>
        <a href="{{ product.url }}">Buy Now</a>
      </div>
    {% endfor %}
    {% if count > products.length %}
        <div class="clerk-load-more-button" 
             onclick="Clerk('content', '#{{ content.id }}', 'more', 40);">
          		Show More Results
    		</div>
    {% endif %}
  </div>
</span>

Read more about the Search Page UI tool here.

Category Page #

A well structured category page is key to a successful eCommerce business. Our Category Page makes this user experience swift and easy to build. This let’s you create a full page showing the best possible results for any category.

<span 
  class="clerk"
  
  data-api="recommendations/category/popular"
  data-limit="40"
  data-labels='["Category Page Grid"]'
  data-category="INSERT_CATEGORY_ID"
  data-orderby="INSERT_SORTING_ATTRIBUTE"
  data-order="asc_OR_desc">
  
  <div class="product-category-result-list">
    {% for product in products %}
      <div class="product">
        <h2 class="product-name">{{ product.name }}</h2> 
        <img src="{{ product.image }}" title="{{ product.name }}" />
        <div class="price">${{ product.price | money }}</div>
        <a href="{{ product.url }}">Buy Now</a>
      </div>
    {% endfor %}
    {% if count > products.length %}
        <div class="clerk-load-more-button" 
             onclick="Clerk('content', '#{{ content.id }}', 'more', 40);">
          		Show More Results
    		</div>
    {% endif %}
  </div>
</span>

Read more about the Category Page UI tool here.

Facets #

Clerk.js comes with built-in support for dynamic faceted navigation for both search and categories. Any product attributes you send to us can be used as facets.

Here’s an example of basic usage:

<div id="clerk-search-filters"></div>

<span 
  class="clerk" 
      
  data-template="@search-page" 
  data-query="shoes"
  
  data-facets-target="#clerk-search-filters" 
  data-facets-attributes='["price","categories","brand"]'
  data-facets-titles='{"price": "PRICE-TRANSLATION", "categories": "CATEGORIES-TRANSLATION", "brand": "BRAND-TRANSLATION"}'
  data-facets-price-prepend="€"
  data-facets-in-url="true"
  data-facets-view-more-text="View More"
  data-facets-searchbox-text="Search for "
  data-facets-design="133995">
</span>

Read more about the Facets UI tool here.

Exit Intent #

The exit intent popup reacts when a visitor tries to leave your site by hovering their mouse near the top of the browser window. It pops up and displays interesting products, possibly converting a leaving visitor to a buying customer.

Any Content block can be triggered upon a visitors intent to exit by adding the data-exit-intent="true" attribute to the snippet.

<span
  class="clerk"
  
  data-api="recommendations/visitor/complementary"
  data-limit="20"
  data-labels='["Exit Intent / Popup"]'
  
  data-exit-intent="true">
</span>

Read more about the Exit Intent UI tool here.

The UI Kit contains a simple popup library to easily create simple but user-friendly popups with any content. Any HTML element on your website with the class clerk-popup will be displayed as a popup.

<div id="my-popup" class="clerk-popup">Hello, world!</div>

<script type="text/javascript">
  var my_popup = Clerk('ui', 'popup', '#my-popup');
  
  // show popup
  my_popup.show(); 
  /* or */ 
  Clerk('ui', 'popup', '#my-popup', 'show');
  
  // hide popup
  my_popup.hide(); 
  /* or */ 
  Clerk('ui', 'popup', '#my-popup', 'hide');
</script>

Read more about the Popup UI tool here.

Excluding Products #

Clerk.js has two different ways of excluding products, depending on whether you want to exclude specific IDs or avoid showing duplicate products between different sliders.

Excluding Specific IDs #

Simply add the attribute data-exclude to the snippet. The content of data-exclude should be a list of the product IDs you don’t want to be shown i.e. the products in the customer’s shopping cart or a list of products they are not allowed to see.

<span class="clerk"
  data-template="@clerk-complementary"
  data-exclude="[45654, 3244, 12352]">
</span>

Avoiding Duplicates #

This is done by adding the data-exclude-from attribute on the Clerk Block wherever you want to remove the duplicate from. The value of the attribute should be a CSS selector for the other snippet(s)to prevent duplicates from.

In the example below, .clerk-2 excludes any product that is in .clerk-1, and .clerk-3 excludes any products that are in either .clerk-1 or .clerk-2.

<span class="clerk clerk-1"
  data-template="@clerk-banner-1">
</span>
 
<span class="clerk clerk-2"
  data-exclude-from=".clerk-1"
  data-template="@clerk-banner-2">
</span>
 
<span class="clerk clerk-3"
  data-exclude-from=".clerk-1,.clerk-2"
  data-template="@clerk-banner-3">
</span>

Read more about the Excluding Products UI tool here.

Events #

When building more customised setups you will often need to react to or modify the results from Clerk before rendering them. This is where Events are useful.

Events allow you to set up event listeners that run code at specific times before, during, or after Clerk.js renders its results.

A common example is to load custom prices for a logged-in customer in a B2B setup. An event can run immediately after Clerk’s API is finished rendering, allowing you fetch custom prices for a customer, and append them to the product elements:

var customer_id = INSERT_CUSTOMER_ID;
Clerk("on", "rendered", function(content, data){
  for (i = 0; i < data.product_data.length; i++) {
      var product = data.product_data[i];
        var custom_price = FETCH_PRICE_FROM_SERVER(product.id,customer_id);
        let price_container = document.querySelector(`[data-clerk-product-id='${product.id}'] .clerk-price`);
        price_container.innerText = custom_price;
    }
})

Read more about the Events here.