Aug 11, 2026
12 min read
Kombucha Subscription Tech Stack for Batch Tracking and Cold Chain Scheduling
Selling a perishable product on a subscription?
If your batch logic still lives in a brew-day spreadsheet, it's not a process you can run in a crisis. We build the batch-traceability and rotation layer your commerce platform was never designed to hold.
See How We BuildThe email says this month’s Ginger tastes different from last month’s.
She is right. It does.
Someone in ops opens the order to work out which batch she received. The line item says “Ginger.” Quantity one, fulfilled on the 14th. That is the entire record.
There is a brew log that could answer her, sitting in a spreadsheet, if anyone can match a ship date to a bottling date and trust that the warehouse picked in the order they were meant to. Nobody has that kind of afternoon, so the reply says sorry, here is a replacement, and the question goes unanswered.
The ticket costs twenty minutes. What it exposes costs considerably more, because the day a genuine recall lands, that same lookup has to run across every subscriber, every past order, and every renewal already scheduled to ship.
A kombucha subscription ships a living product whose identity is the batch, not the SKU. That sentence sounds like a detail. It is the reason three separate parts of your operation keep failing in ways that look unrelated.
The five layers, and the one thing none of them holds
Pull apart any kombucha subscription and you find the same five layers, usually from five different vendors.
Product data holds your catalogue and stock. Scheduling decides who gets billed and when. Selection works out which flavors go in which box. Fulfilment picks and ships. Traceability answers what went where, and in most stacks that layer does not exist at all.
Each one is competent. Each one models a SKU.
| Layer | What it does | What it thinks it ships | What you actually ship |
|---|---|---|---|
| Product data | Catalogue and stock counts | Ginger, 12oz | Ginger, batch 247, bottled 3 Aug |
| Scheduling | Billing and ship dates | A recurring line item | A commitment against unbrewed stock |
| Selection | Flavors per cycle | Preferences against a catalogue | Preferences against actual yields |
| Fulfilment | Pick, pack, ship | A list of SKUs | Bottles of five different ages |
| Traceability | Batch to customer history | Usually absent | The thing a recall needs |
Five layers, five copies of the same assumption.
Read down the last two columns and the gap is the whole article. Nothing in the third column is wrong, exactly. It is just a shorter description of the thing than the product requires, and every layer inherits the same shortfall from the one before it.
Layer one, product data: a SKU is not a thing you can ship
A SKU is a name that stays still. That is its entire purpose, and for most products it is exactly right.
A batch does not stay still. It has a brew date, a carbonation curve, and an alcohol content that keeps moving after it leaves you.
Two bottles of the same SKU brewed three weeks apart are different products to the person drinking one. Your catalogue cannot express that, because Shopify has no native lot or batch field to put it in.
An entire app category exists to fill that gap. Batchly, Freshly Batch Inventory, and Batch ExpiryPro all add lot numbers, expiry dates, and batch-level allocation, and they do it properly for the case they were built for.
Worth understanding the allocation choice they offer, because it is not cosmetic. FIFO ships the oldest stock first. FEFO ships whatever expires soonest first. Those sound identical and they are not, because your best-by window differs by flavor: a high-acid citrus batch and a low-acid ginger batch bottled the same day do not die on the same day.
Pick the wrong rule and you ship a flat bottle and a fizzing one in the same box, to the same subscriber, in the same week.
Batch tracking on a Shopify subscription also has to survive contact with your warehouse. An app can allocate lot 247 to an order perfectly and still be wrong, because the picker took the case nearest the door. Allocation is a claim about what should have happened. Traceability is a record of what did.
Closing that gap means the batch number gets captured at pick and written back, not assumed at allocation. Most stacks never close it, which is why the batch field in the admin and the bottle in the box drift apart over a season.
That is a solvable problem for a store selling one-time orders. It gets harder one layer up.
Layer two, scheduling: the batch that ships on renewal day hasn’t been brewed yet
Every batch app on the App Store allocates at order time. Someone buys, the app assigns a lot, stock decrements, done.
That logic is sound because a one-time order ships from stock that already exists.
A subscription is not an order. It is a promise about the future.
On the 1st you commit to shipping on the 15th. The batch that will fill that box goes into a tank on the 6th, finishes conditioning around the 12th, and gets its final yield count on the 13th. On the 1st, when your system made the promise, the product did not exist in any form.
So you cannot pre-assign a batch. You cannot honour FEFO against stock that has not been brewed. You cannot tell a subscriber what is coming, because nobody knows yet.
The move that fixes it is unglamorous. Batch allocation has to run as a scheduled job between brew completion and pick, rather than at checkout, which means your commerce platform is no longer the system that decides what ships.
Underneath that sit five dates, and almost nobody has them in one place.
| Date | Set by | Lives in | Changes when |
|---|---|---|---|
| Brew date | Production | Brew log or spreadsheet | Tank availability shifts |
| Conditioning window | The batch itself | Nowhere queryable | Fermentation runs fast or slow |
| Ship-by date | Ops judgement | Nowhere queryable | Yields come in short |
| Renewal date | Subscription app | Recharge, Appstle, Skio | Subscriber pauses or swaps |
| Carrier cutoff | 3PL and carrier | 3PL portal | Holidays, weather, volume |
Four systems, five dates, and only two of them sit anywhere a query can reach.
The two that live nowhere are the two that move most. Conditioning finishes when the batch decides it has finished, and the ship-by date follows from that. Both get held in a production manager’s judgement, communicated verbally on brew day, and never written to a system that scheduling can read.
So the reconciliation happens in someone’s head, and it works right up until that person takes a holiday. This is the layer where perishable subscription batch allocation actually lives, and it is the one nobody buys software for.
Layer three, selection: flavor rotation is a constraint solver
Rotation reads like a merchandising feature. Build one and you discover it is a constraint problem with a marketing name.
Every rotation rule is a promise that narrows what you are allowed to ship. No repeat within three cycles. Always one citrus. Never two gingers in a box. Honour her stated dislike of hibiscus, permanently.
Four rules, and the set of valid boxes for any given subscriber has already collapsed to a handful.
Then comes the collision. Rotation rules assume availability, and fermentation does not care about your rotation plan. You get the yields you get. A batch comes in under target and a rule that was satisfiable on Monday is not satisfiable on Thursday.
The swap window is where this gets sharp. Subscribers need a period before renewal to change their selection, and that window has to close before pick. Which means it closes before you know your final yields.
You are asking people to choose from a menu you cannot yet guarantee.
We solved a version of this with a custom flavor-select box on a 14-day cycle, with a 48-hour pre-renewal swap window layered onto Recharge. Recharge handled billing and the schedule properly. What it had no way to express was a selection interface governed by rotation rules, closing on a deadline tied to a brew calendar rather than a billing date.
That is the shape of most work in this category. Not replacing the subscription platform, but building the layer it was never designed to hold.
Layer four, fulfilment: where scheduling hands off to physics
There is one moment where your software stops mattering.
Your system picks a ship date, the pallet leaves, and from then on the product is in the hands of a carrier who has never heard of your brand.
Three things the fulfilment layer needs to be told, and usually is not. Which batch is in the box. How old that batch is on the day it ships. How many days of transit it can absorb before it stops being the thing you sold.
Most stacks pass none of these, because the pick list is a list of SKUs and a SKU has no age.
Here is the arrow that points the wrong way in nearly every kombucha operation. Carrier cutoffs and transit times get treated as a downstream consequence of the renewal date. They are an input to it.
If a subscriber in a three-day transit zone renews on a Thursday, the box misses Friday’s cutoff and sits over a weekend, and no amount of good packaging fixes a date chosen without reference to geography.
Cold chain scheduling in ecommerce is mostly this. Not refrigeration, but deciding which days a given postcode may renew on, and enforcing that at the point the subscription is created rather than apologising for it later.
What actually happens to a bottle across those extra days is a longer story, and we covered it in detail in our post on kombucha subscription fulfilment.
Layer five, traceability: what a recall asks of your data
A recall is the batch question asked under time pressure, with a regulator waiting.
It needs three lookups. Which orders contained batch 247. Which subscribers received it. Which scheduled future orders are still allocated to it.
The first two are what batch apps are built for. The third is unique to subscription, and nothing off the shelf handles it, because a future order is not an order yet.
Run the reverse direction too. A subscriber calls with a complaint, and you need to go from her order to the batch, not from a batch to a list of orders. Systems that can answer one direction frequently cannot answer the other.
There is a quieter use for the same data. Kombucha DTC operations that hold batch-to-subscriber history can answer questions nobody thinks to ask of a support system: whether complaints cluster on one tank, whether a flavor reformulation moved churn, whether a slow transit lane produces more refunds. That history is worth building before a recall forces you to build it badly.
The uncomfortable test is simple. Pick a batch from four months ago and try to name every subscriber who received it, including anyone whose next box is already scheduled from what remains. If that takes more than a few minutes, it is not a process you can run in a crisis.
A brief compliance note
Kombucha has a regulatory quirk that most beverage categories do not.
Under TTB rules, kombucha at or above 0.5% ABV at any point is an alcohol beverage. That includes product measuring under the line at bottling which keeps fermenting past it afterwards. Crossing 0.5% brings TTB-qualified premises, labelling requirements, and the ABLA health warning with it.
This is not theoretical. A 2021 study in the Journal of Food Protection tested 84 commercially labelled non-alcoholic kombucha products in British Columbia and found mean ethanol of 0.77% ABV, with the highest sample at 3.62% and over 31% above the Canadian limit.
The engineering consequence is narrow. Time and temperature drive that drift, and your subscription schedule sets both, so days in transit is a regulatory input and not only a quality one. Batch ABV at bottling belongs in your data model rather than in a lab report nobody queries. None of this is legal advice.
When this becomes a build
Batch apps, Recharge, Appstle, and Skio each do their own job well. Most kombucha brands should run all three and build nothing, and we tell people that regularly.
The threshold is not size. It is whether batch identity has to travel.
You have crossed it when batch identity needs to survive from brew tank to subscriber record, when rotation logic has to respect real yields rather than a planned catalogue, and when a recall has to reach orders that have not been placed yet. Those are the same class of problem as subscription logic no app can express, and they share a cause: the platform models a product, and you sell a relationship with something alive.
The diagnostic is your brew-day spreadsheet. If it decides who gets which flavor, and no system reads it, the spreadsheet is your selection layer, and your kombucha subscription software is doing bookkeeping around a decision made in Excel.
Your subscriber can taste the batch. Build a stack that can name it.
Frequently Asked Questions
Does Shopify support batch or lot tracking?
Not natively. Shopify has no built-in lot number or expiry field, which is why a dedicated app category exists to add batch tracking, FIFO or FEFO allocation, and recall traceability on top of standard inventory.
How do you assign batches to subscription orders?
Not at checkout. The batch usually does not exist when the renewal is committed, so allocation has to run as a scheduled job between brew completion and pick, reconciling actual yields against the orders already promised for that ship date.
What is the difference between FIFO and FEFO for live products?
FIFO ships the oldest stock first. FEFO ships whatever expires soonest. They diverge for kombucha because best-by windows vary by flavor, so two batches bottled the same day can reach end of life weeks apart.
Is kombucha regulated as alcohol?
It is if it reaches 0.5% ABV or more at any point, including after bottling through continued fermentation. That triggers TTB regulation, qualified premises requirements, and the ABLA health warning, even for a product labelled non-alcoholic at bottling.
How should a flavor rotation swap window work?
It has to close before pick, which usually means before final batch yields are known. Build it to validate selections against rotation rules at swap time, then revalidate against actual availability once yields are counted.
Tell us what your stack needs to do
Batch identity has to travel from brew tank to subscriber record — most stacks were never built to let it. Let's talk about what yours needs.