Any (webshop)

Clerk.js

Overview #

Clerk.js is a JavaScript library that simplifies the integration of our API with your frontend. 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 is loaded with a lightweight tracking 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 -->

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

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 initialisation script.

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

The visual representation is handled by the design, which is also referenced by the snippet.

Clerk.js uses Liquid designs, known from Shopify, to render HTML with the data returned by the API. These should be formatted as scripts, with an ID that you can reference in “data-template” of 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 only include a reference to a Content within my.clerk.io.

Designs are then handled with a visual editor or with Liquid HTML code just like in the frontend.

With this approach, most of the configuration is done in a user-friendly way from the admin panel. 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”.

<span class="clerk"
     data-template="@product-page-alternatives"
     data-products="[12352]">
</span>
Screenshot 2023-06-13 at 11.49.01

Configuration #

Clerk.js allows for a variety of configurations.

As mentioned earlier, 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.

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

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

You can add Formatters and Globals to your design scope.

Formatters 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 are meant to be used with frontend data that you want to access in designs. This could include the remaining amount needed to achieve free shipping, the name of a logged-in customer, a currency symbol, or a conversion rate, among other things.

// Config
<script>
Clerk('config', {
  formatters: {
    uppercase: function(string) {
        return string.toUpperCase();
    }
  },
  globals: {
    currency_symbol: '$'
  }
});
</script>

// Use in Design

<div class="clerk-product-name">{{ product.name | uppercase }}</div>
<div class="clerk-product-price"> {{ currency_symbol }}{{ product.price }}</div>

Tracking visitor emails automatically #

Clerk.js can automatically collect emails i n the customer’s browsing session to be used for Abandoned Basket emails and other email campaigns.

Simply configure Clerk.js with collect_email: true as shown here:

HTML

<!-- 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',
    collect_email: true
  });
</script>
<!-- End of Clerk.io E-commerce Personalisation tool - www.clerk.io -->

UI Kit #

Clerk.js includes a set of UI tools for important elements like the search dropdown and facets on a search page.

For example the search dropdown kit enables you to create a snippet that monitors the input field through a CSS selector and displays a dropdown with content matching a visitor’s search.

<span
  class="clerk"

  data-api="search/predictive"
  data-limit="6"

  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>

Facets let you extend your existing search page snippet to include filters for products on the search page.

<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": "YOUR-PRICE-LABEL-TRANSLATION-GOES-HERE", "categories": "YOUR-CATEGORIES-LABEL-TRANSLATION-GOES-HERE", "brand": "YOUR-BRAND-LABEL-TRANSLATION-GOES-HERE"}'
  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>

Events #

When building more customised setups, such as for B2B businesses, 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 use-case is when you need to check which user is logged in and fetch specific prices for their customer group or remove products they are not allowed to see.

For example, an event can run immediately after Clerk’s API responds, allowing you to call your pricing database with the ID of the customer and the products returned by Clerk to fetch the correct prices before Clerk.js renders the results.

Clerk("on", "response", function(content, data) {
    let products = data['product_data'];
    const product_ids = data['result'];
    const customer_prices = getUniquePrices(customer_group, product_ids); // {"27746": 310.25, "26994": 124.50}
    products.forEach(product =>
      product['price'] = customer_prices[product['id']]) // Add customer price based on product ID;
  })