Seven wood-pressed cooking oils that look the same in a list and behave very differently in a pan. The storefront's whole job is making that difference easy to see before you add to cart.
- Client
- The Soul Foods
- Platforms
- Headless Shopify · Web
- Timeline
- Live, with releases since
- Year
- 2026

7
Wood-pressed oils in the range
1L / 5L
Sizes across most of the range
₹999
Free shipping threshold, set in Shopify
The Soul Foods sells seven cold-pressed oils — sunflower, sesame, safflower, coconut, groundnut, mustard and avocado — and in a product list they are nearly indistinguishable. Same bottle, overlapping prices, one word of difference on the label. The real difference is what each oil is for: mustard oil at ₹427.50 belongs in pickles and North Indian cooking, avocado oil at ₹1,199 belongs on a salad or under a high-heat roast, and nobody buying their first bottle knows that. On top of that, every oil is discounted off a compare-at price, sits in two sizes, and the brand sells on a specific idea — a squeeze bottle you can portion with, instead of a tin you pour from. A stock Shopify theme flattens all of it into a grid of identical cards and a size dropdown. The brief was to build a storefront that explains the range while leaving Shopify in charge of money, stock and tax.
- 01
The storefront is its own Next.js App Router app on Vercel, reading products, collections and articles through Shopify's Storefront API. Nothing about the layout is decided by a theme, and the brand's product photography gets to run full width.
- 02
Shopify keeps the parts worth not rebuilding: inventory, orders, payments, taxes, discount codes and the hosted checkout. The compare-at pricing behind every bottle — coconut oil at ₹665 down from ₹850, sesame at ₹475 from ₹600, safflower at ₹465 from ₹800 — is Shopify's own pricing, read through the API, so a sale is a price change in the admin rather than a deploy.
- 03
The collection page carries a filter drawer, a sort control and a grid-density switch. The range fits on one screen, so the useful action is not paging through results but comparing them side by side: the density switch lets someone go wide to read labels or tighten the grid to see all seven at once.
- 04
Product pages lead with the bottle, then give the size switch for 1L and 5L, the discount against the compare-at price, and the smoke point. The smoke point is the fact that decides whether an oil survives what you are about to cook, so it sits on the page rather than three paragraphs into a description.
- 05
Each product carries short, plain-language tags — Nutrient-Dense, Cold-Pressed, Gut-Friendly — instead of a nutrition table. The tradeoff is accepted deliberately: a tag is less precise than a panel, but it is read, and the detail still lives in the accordions underneath.
- 06
Reviews run on Judge.me, with the rating shown on the product page and on the cards in the grid, and a write-a-review form that accepts photos. Review images upload to Supabase storage rather than being posted straight to a third party, so a failed submission is recoverable.
- 07
Customer accounts run on Supabase with email OTP: no password to set, lose or reset, which suits a store people buy from every few months. The account area covers profile, order history and saved addresses, with orders read back from Shopify so the admin stays the single source of truth.
- 08
Merchandising the brand changes often is read from Shopify rather than written in code — the ₹999 free-shipping announcement bar, the home page's featured collections, the newsletter sign-up and the trust strip. The founders edit those in the Shopify admin they already use; the cost is one more place to look when something on the page is wrong.
- 09
Writes go through Shopify's Admin API behind the app's own API routes, never from the browser, and Shopify webhooks all land on one HMAC-verified endpoint that busts the matching Next.js cache tag. One URL and one secret to configure means a price edit in the admin reaches the live page without waiting out a cache.
- 10
A scheduled reconcile job re-checks what a dropped webhook would have missed, and an admin page lists failed events so a sync problem is visible instead of silent. Upstash Redis rate-limits the public API routes, because contact, newsletter and review endpoints are the ones that get hammered.
- 11
The contact page is a real form rather than a mailto link: name, email, an enquiry category and up to five image attachments, which matters for a food product where the complaint is usually a photo of a bottle. It sits beside a WhatsApp link, the brand's phone number and its Telangana plant address, and the submission is stored through Shopify metaobjects so nothing depends on an inbox.
- 12
The blog is Shopify-backed, with a load-more endpoint instead of numbered pages, and carries the cooking and oil-guide posts the brand uses to bring people in from search. Every page's metadata is generated from the Shopify data, so a new product or article is indexable the day it is published.
- Discovery
Started from the question a first-time buyer actually asks: which of these seven do I need? That turned into the facts that had to be on the card and the top of the product page — what the oil is for, its smoke point, and the price in each size — rather than buried in a tab.
- Design
Built the storefront around the brand's own bottle photography, a warm palette and a rounded display face, with the squeeze bottle treated as a selling point rather than packaging. Product cards show the compare-at price struck through next to the live one, since the discount is part of how the range is sold.
- Build
Next.js App Router with Tailwind and Zustand for cart state, reading from Shopify's Storefront API and writing through the Admin API. The filter, sort and density controls, the size switch and the review form were the pieces that took the most iteration, because they are the ones people actually touch.
- Catalogue and content
Loaded the seven oils, their sizes, compare-at pricing, tags and the blog into Shopify with import scripts rather than by hand, so the catalogue can be rebuilt or extended without re-typing it. The announcement bar, featured collections and policy pages went in as Shopify content the founders can edit.
- Accounts and sync
Wired Supabase email OTP for login, mapped customers to their Shopify records, and put the webhook, reconcile job and failed-events page in place. The point of that last piece is boring and important: when a sync breaks, someone can see it.
- Where it is now
Live at thesoulfoods.in with the full range, accounts, reviews and the blog working end to end. What is still outstanding is content, not engineering — the home page hero and several product accordions carry placeholder copy the brand needs to replace.

The home page, led by the bottle rather than a banner

Coconut oil: the 1L and 5L switch, the discount, and the plain-language tags

The about page, with the brand's own timeline

The blog, pulled from Shopify
On a phone, where most of the traffic is


All seven oils are live at thesoulfoods.in in both sizes, selling through Shopify checkout, with filters and sorting on the collection page, Judge.me reviews on the products, OTP accounts with order history, and a blog. The founders set pricing, discounts, the ₹999 free-shipping rule and the announcement bar from the Shopify admin, and fulfil orders there too, so nothing routine needs a developer. The storefront itself is entirely the brand's own — the design is not bounded by a theme, and the oils are presented by what they are for rather than as seven rows of the same bottle.
Scope
Storefront design, Headless Shopify build, Filtering, sorting & grid density, Customer accounts, Reviews with photo uploads, Webhooks & reconcile job, Contact & enquiry handling, Catalogue migration, Blog & SEO
Stack
Next.js, React, Tailwind, Zustand, Shopify Storefront API, Shopify Admin API, Supabase, Judge.me, Upstash Redis, Vercel
Want results like this? Tell me about your project.
- Projects from $500
- Reply within one business day
- Free, no obligation
Next case study
Bookvy digital school