The future of E-Commerce is headless: how we use Sanity to elevate the customer experience
We cover why a headless approach is foundational to Nightjar builds.
Nightjar recently partnered with Redsbaby – one of Australia’s leading premium pram companies, on their new E-Commerce website. As Redsbaby sells exclusively online, the website is the main touch point for customers and has to convey the premium nature of the brand at every turn. However, traditional E-Commerce platforms just aren’t flexible enough for the kinds of features and highly curated editorial design that we demand for our clients, to create a truly unique experience. This is why a headless approach is foundational to Nightjar builds.
For those playing along at home, headless E-Commerce is the development approach of separating the front-end of a website from a ‘monolithic’ backend such as Shopify, BigCommerce or Magento. Using the platform’s APIs, we’re able to leverage their E-Commerce functionality but enhance it with the best-in-class content editing features from a headless CMS like Sanity, allowing each platform to focus on what it does best. This headless architecture also allows us the flexibility to streamline development of custom integrations and features, like the ones we’ll go into more detail later in this article. All this combined allows for some truly bespoke E-Commerce experiences that effectively convey the story and editorial direction of our clients’ products.
In this article we’ll go over some of the key learnings we discovered and problems we solved while developing Redsbaby’s new website. Powered by BigCommerce Enterprise, Sanity, Next.js and Vercel.
The foundational layer of all of our headless E-Commerce builds is the product sync. This is a serverless function that gets triggered by webhook, and copies all the product and categories data from BigCommerce into Sanity in near real-time. Now that the product data is in Sanity we can extend the products with whatever custom fields we like while having ease of access to the raw product data for things like: pricing, variants, and inventory. Shopify has an official integration for this that includes a readymade sync, also Kevin Green’s sync, and Nick DiMatteo’s Hull starter are good places to start. We developed our own sync function to work with the BigCommerce API for Redsbaby, since that’s the platform we were using, and this also allowed us to build our more advanced features like bundles - which were a core focus of the Redsbaby business, and a key driver of increasing basket size.
We developed our own sync function to work with the BigCommerce API for Redsbaby which allowed us to build advanced features like bundles - which were a core focus of the Redsbaby business, and a key driver of increasing basket size.
Max Celima, Full Stack Engineer NIGHTJAR
In our builds, pretty much everything on each page (except the header and footer) consists of reusable modules we call “slices”. This allows us, or our clients, to build unique pages without having the rigidity of templates, but while also keeping the overall design cohesive. In the Next.js front-end, we have an index slices component which takes in the entire array of slices from Sanity and automatically imports and renders the correct corresponding components.
It also passes through the entire page’s data and a global settings object from Sanity. This is helpful for slices like a product hero for example, where the product data is stored at the root of the page document in Sanity. Slices don’t necessarily have to render UI either, we’ve also used slices to mark changes in page background colour at set points on the page, and to create anchor links that scroll to specific sections.
We hit a bit of a wall when starting to develop bundle functionality for Redsbaby, as we quickly realised that this wasn’t supported by BigCommerce natively. However, using headless and Sanity we were able to develop our own custom solution for this. The first step was to create new products in BigCommerce that would act as the purchasables for the bundle, then using custom fields on the bundle product we added all the variant SKUs of the products to be included in the bundle. In our product sync we automatically detect that this is a bundle product and handle it differently. We import them as bundle documents in Sanity, and using GROQ, match up the variant SKUs from the custom fields with references to the actual product documents in Sanity.
This allows us to access all the product data of the products included in the bundle. Meaning there is zero extra setup for variants, product images, descriptions, etc. We also calculate the overall inventory level of the bundle and delivery date based on the configuration the user has selected using the data from the sub-products. When a bundle product is added to cart, we store the chosen variant SKUs as modifier fields on the line item and this is parsed by Fishbowl (the inventory management software, not the delicious poke bowl provider) which will automatically recalculate the inventory levels for all the included SKUs on the backend.
Our approach kept the relationship between products centralised and removed the content duplication.
Lachie Golledge, Front End Engineer NIGHTJAR
Another unique use-case for Redsbaby was that they had several products that had two versions, a regular and a premium edition, and we wanted a way to group these throughout the website. Using Sanity, we were able to create a grouping system that allowed them to tie these products together. We created a new document type in Sanity cleverly called “product groupings”, which had an array of product references. In the GROQ query for the product on the front-end, we check if the product is contained within one of the groups, and if so, we also join the other products, allowing us to present a UI for this on the front-end. This approach kept the relationship between products centralised and removed the content duplication that would’ve been required for the site editors otherwise.
We were able to reuse this product grouping functionality for bundles as well, which was a real win. Some of the products included in bundles on Redsbaby had different pricing, depending on the selected variant, and because the bundle’s purchasable entity has a fixed price, we were able to link two bundles together to seamlessly switch between them depending on which variant the customer chose.
Estimated Delivery Dates
For expecting Mums, it’s crucial to know the delivery date of the products. Redsbaby’s entire inventory system is managed by Fishbowl, which updates the inventory levels in BigCommerce automatically and adds the estimated delivery date to products at a variant level via metafields in BigCommerce. This is also picked up as part of our product sync into Sanity so we can present it on the front-end. For bundles, it calculates whichever date is furthest in the future across all the sub-products and then presents that as the overall estimated delivery date for the bundle and presents this to the user on the front end
T1, T2, and T3 Products
In Sanity and Next.js we were able to accommodate the varying kinds of products Redsbaby offered, and tailor the customer experience accordingly. The T1 (flagship products) have a dedicated product page with immersive imagery, as well as subpages for more product details such as specs, demos, and reviews. T2 Products have fewer subpages and less overall content, and T3 (Accessories) products opened the buy dialog directly. We created ‘document actions’ in Sanity that allowed content authors to quickly generate any of the three document types, and fill in the required fields with placeholder information or common information.
Buy Dialog and Cross-sells
In Next.js we were able to dynamically extend the page routing for all products to create route-able dialogs for the add to cart experience. For the more complicated flagship products this houses the variant selection UI, and for the more basic accessory products this dialog acts as the main product page since they have less content. This dialog is customisable on a per-product basis and we also built custom functionality for cross-sells that let the content authors select compatible accessories or other products that compliments the purchase. To achieve this we create a temporary cart for the dialog session, allowing customers to add and remove multiple products, which also re-calculates the overall total, and then adds everything to the cart once the user clicks “add to cart”.
The reference is fully editable from anywhere in the CMS. So, if the CMS user decides to change the name of one of the fields from any referenced instance, it will be instantly updated CMS wide.
Samuel Surgeon, Full Stack Engineer NIGHTJAR
The purchase of a pram is a big decision to make, and we knew that it was important for potential buyers to compare product features to find one that suits their needs. Redsbaby’s product line presented an opportunity for us to build a “Comparison” component that allowed customers to do just that. The products are pulled in from the BigCommerce datasync into Sanity, then displayed in a dropdown that the CMS user can select from. Any product available in the BigCommerce inventory can be compared with any other product. This level of freedom is only made possible by creating a single origin point for the list of fields that the “Comparison” component can compare.
This list exists in the global settings section of the Sanity backend. It is an array of type “field” - a unique custom object that can be referenced anywhere in the CMS. The reference is fully editable from anywhere in the CMS too. So, if the CMS user decides to change the name of one of the fields from any referenced instance in the CMS, it will be instantly updated CMS wide.
The list of these unique fields contains what items the “Comparison” component will check for when creating its table layout. If the field exists on the product it will create a row for it on the front-end. This process will occur for each product that the “Comparison” component references, until a fleshed out list of rows and columns is rendered on the front-end.
The content that each field can contain varies greatly. In aligning to the brand concept and design of the site, some of the fields can contain text, bold headings, small text, icons, text and icons, images and more. There’s a huge degree of variance for formatting the content too. Some of the icons can be centred, some can be left aligned - and all of this depends on a dynamic set of values set in the CMS. To sort and render such a diverse set of data we reached for Sanity’s Portable Text. The Portable Text component in Sanity is a WYSIWYG editor that, under the hood, is made up of a collection of “blocks”.
These “blocks” are built in by standard as arrangements of text, but Sanity also gives you the option to make custom “blocks” that can be any data type required. We created a block for each of the unique types of data that we needed to support. When the CMS user has filled out the WYSIWYG editor with a list of these “blocks”, this data is then handed to the front-end. On the front-end, using a recursive sort, we comb through the data and interpret what type of data each block is and what its layout properties are.
There was one final layer of abstraction that was brought into this unique engineering problem. Each of these Comparison Tables could be placed on top of each other in a “tab” system. The CMS editor could have any number of tables they liked in one section of the site, and these tables would stack on top of each other and display a row of “tabs” that the user could click on to be taken to the desired table. These collections could contain any product they desired, and the “tabs” could be named anything they wanted.
We were able to enhance both the front-end and the content editing experience with the official Hotspot Array Sanity plugin.
Lachie Golledge, Front End Engineer NIGHTJAR
It was really important for the Redsbaby target audiences to see not just the product images, but how this product would fit with their lifestyle, and help them keep their pre-baby sense of style. We were able to enhance both the front-end and the content editing experience with the official Hotspot Array Sanity plugin. This lets content authors click and drag around points on an image to create hotspots that would swap out an image for a product lifestyle shot or link to a specific product from a blog post for example. All without manually entering X, Y coordinates which can be an arduous process!
Tab groups are a collection of user-defined links. These links are defined in the global settings of the Sanity backend and can link to any internal page in the CMS or an external link. The links are then consumed in a React component that displays them in a standard tab format, not unlike the tabs used in a web browser. When this component is present on a page and a tab group from the CMS is fed into it will handle a lot of things automatically.
Such as creating routes between all the pages, so as you click through each of the links (that link to internal links) you will be instantly redirected to the selected page. These pages have also been pre-rendered with the Next Link component so they load instantly creating the illusion that you haven’t been redirected to another page.
Another advantage of doing things this way is that the content between the tabs in the Tab group have no limitations on what they can be. Any content that can be rendered on a page in Next can be used, and each tab can be completely different from the one before. You also get page transitions for free between the tabs if you choose to use them.
In our Sanity backend each product pulled from BigCommerce has a type of “product”. This “product” type is unique in that it only contains information related to that specific product but is also accessible on the front-end as a page. So each instance of “product” exists as a datastore and also a page that corresponds to front-end components defined on that product.
Doing things this way allowed us to organise and couple related information into a larger pool that made it easier for us to build and organise front-end components to manage the abundance of product information in an E-Commerce environment.
Each “product” page contains a collection of “slices” that hold a React component which will render on the front-end. In this way looking at the “slices” that are present on a “product” describes what the content of the page will be from top to bottom. Organising things in this way allowed us to extend this system even further by allowing a “product” to have subpages.
A “subpage” would be a mini version of a “product”, in that it contained the array of “slices” that described the page contents but without the datastore. Routing logic on the front-end then looks for any subpages on a “product” and creates URL routes to make them accessible to the user and populates each of the subpages with the slices that belong to that subpage.
By default, Sanity has support for an icon on each document or object in the Sanity Studio. However, some of the icon packs that can be added to Sanity weren’t giving the level of personality and approachability we were looking for, so we decided to extend what icons could be used in this section by adding native Emoji support.
In the schema of Sanity, we created a reusable Emoji component that is a text field wrapped in a React component. This React component is then imported and implemented into the appropriate object or document schema, giving the Sanity Studio a burst of colour and context.
Using the preview mode feature in Next.js and the official Sanity production preview plugin we’re able offer clients a live preview of the site as they edit it in Sanity. This is a highly requested feature from clients and can be a challenge with other headless setups. Not so with Sanity!
Multi-site / Multi-store
On another Nightjar E-Commerce project, Armadillo, we were able to manage multiple localised sites for Australian and International customers all within Sanity. We customised our product sync to allow for multiple BigCommerce stores to import into Sanity, and we then customised the desk structure of Sanity to allow clear separation between the sites. Having both the product data and content headless allows us to use different currencies, inventory, shipping methods on the product side, and different spelling, units, and localised content on the content side.
Using a headless approach we are able to move quickly on our feet to deliver bespoke E-Commerce features that enhance the customer and content author experience. Instead of relying on limited and expensive plugins and apps, headless allows us to look at the problems our clients face head on, solve them with code, while also creating beautiful editorial experiences in the process.
In the future, we’re excited to perfect subscriptions, and explore new and upcoming platforms such as swell.is.