@cartbase/storefront
v0.42.1
Published
Storefront SDK + UI component library for Cartbase stores: typed API client, checkout orchestration, cart drawer, product/catalog components, tracking. Source-shipped TypeScript — add it to transpilePackages.
Readme
@cartbase/storefront
The storefront kit for the Cartbase commerce platform: a fully-typed API client for every store endpoint, checkout orchestration, a production-grade cart drawer, product and catalog components, and consent-gated tracking — everything a storefront needs between your pages and your store.
npm create cartbase my-store # scaffold with everything prewired
# or add to an existing Next.js app:
npm install @cartbase/storefrontSetup
The package is source-shipped TypeScript — tell Next.js to compile it:
// next.config.js
module.exports = {
transpilePackages: ["@cartbase/storefront"],
}One environment value wires it to your store: the publishable key your Cartbase admin hands out on the Storefront page.
NEXT_PUBLIC_CARTBASE_PUBLISHABLE_KEY= # your store's key: names the store, scopes the catalog
NEXT_PUBLIC_CARTBASE_URL= # optional: only to point at a local or staging platformWhat's inside
| Import | What you get |
|---|---|
| @cartbase/storefront/api | Typed client for the whole store API — products, carts, checkout, orders, customers, auth, content, search, reviews, and a custom app's public records (api/apps) |
| @cartbase/storefront/checkout | The complete checkout: the orchestration hook, address forms, shipping/payment method lists, Stripe wrapper, carrier pickers |
| @cartbase/storefront/checkout/use-checkout-* | The checkout's nine concerns, each its own import: use-checkout-cart, use-cart-notes, use-checkout-address, use-checkout-delivery, use-checkout-tender, use-checkout-totals, use-checkout-buy (the money path, locked), use-checkout-error-log, use-checkout-feed. useCheckoutOrchestration is their composition; compose your own checkout from the pieces you keep |
| @cartbase/storefront/cart-drawer | Slide-out cart with upsells, tiers, gift options, notes |
| @cartbase/storefront/products | PDP building blocks: gallery, options, prices, actions |
| @cartbase/storefront/store | Listing pages: pagination, sorting, collection/category/search templates, and the search box that shows products and pages while the shopper types (usePredictiveSearch, PredictiveSearch, PredictiveSearchResults) |
| @cartbase/storefront/order | Order confirmation surfaces |
| @cartbase/storefront/account | The customer's side: who is signed in, the sign-in with an emailed code, the account page with the orders and the profile, and Sign out |
| @cartbase/storefront/tracking | Consent banner and Consent Mode v2, every marketing tag the store configured mounted from its own config (Meta Pixel, TikTok, Google Analytics 4 and Google Ads on one tag, Google Tag Manager), and one call per commerce moment that fires all of them |
| @cartbase/storefront/locales | English built in; Spanish and Bulgarian as typed packs. One provider mounts the language for every client component; the server-rendered templates take their area of the pack as a required prop |
| @cartbase/storefront/experiments | The store's A/B tests: ExperimentsProvider once in the layout, useExperiment(key) in any component, getExperimentVariant on the server; the visitor's variant computed with the platform's own assignment, and what each visitor was shown reported once |
| @cartbase/storefront/theme | The design system: token names plus a filled default set of values (Tailwind 4, CSS-first) |
The checkout page is static
Mount CheckoutClient with the transport alone and the page needs no server
read: the form is in the prerendered HTML and paints with your header, and
the client reads the shopper's cart, the delivery methods and the tenders
from the browser in one round after the paint, through your same-origin
/api/store rewrite. Until the cart lands the summary marks where its
numbers go; a listing that fails says so in its own section with a Try
again; no cart, an empty cart or one completed elsewhere shows the empty
notice with the way back. A store that reads any of the three on its server
hands it in as the value, or as a promise wrapped with settleFeed() so it
settles into a result and never rejects (checkout/checkout-feed). The cart
is re-read once when the tab comes back into view; nothing here ever
refreshes the page.
The checkout is nine hooks
useCheckoutOrchestration is the composition of one hook per concern: the
cart and its listings, the checkout's notes on the cart, the address, the
delivery and its live quotes, the tender and its fee, the totals, Place
order, where failures go, and the feed follower. CheckoutClient mounts
the composition; a store with its own layout mounts it too, or imports the
concerns it keeps and replaces the ones it does not. useCheckoutBuy is
the one locked piece: prepare, confirm, complete and the bank-challenge
return, imported and used, never rewritten. Every hook explains itself at
the top of its file, and every one has its own test suite.
Pickup points
The checkout pickup picker loads each carrier's complete eligible catalogue through the store API and always offers three points: the nearest to the address found on the map, else the typed town's, else the postcode's, else any three. Its search reaches every point of the network, in Latin or Cyrillic, whatever town was typed; the mounted locale pack selects Speedy's display language. Offices exclude automated lockers. A picker with nothing to pick reports itself to the platform's checkout log. No carrier credentials or copied catalogue are needed in the storefront. Every shipping option carries the connected adapter's identity, mark, destination mode and pickup scope, so the same picker and logo path work for every carrier without storefront branches.
Tracking, in three lines
The merchant configures their pixels in the admin; the storefront mounts what they configured. Nothing per vendor:
<ConsentInit required={consent.enabled} /> // first child of <body>, sets the consent defaults
<StorefrontTags client={client} /> // every configured tag, gated by the above
<TrackInit /> // captures UTMs + ad-click ids on the landing pageconsent.enabled is the store's own switch (GET /api/store/consent): a
store that collects consent starts every visitor denied until they choose
on the banner; a store with the banner off starts them granted and the
pixels fire. The prop is required, so a layout cannot leave it out.
The moments fire on their own: the product view from useProductActions
on the product page, the add to cart from the cart drawer's addLine, the
checkout funnel from the checkout, and <TrackOrderPurchase> on the
confirmation page, once per order and only in the browser that placed it:
the checkout marks the order it places and the page fires only on finding
that mark, so the order email's link, a reload or the merchant opening the
page fires nothing (a checkout of your own calls markOrderPlaced from
@cartbase/storefront/tracking/placed-order when completeCart answers).
Purchase events dedupe against the platform's own
server-side events automatically — the ids are derived from the order
number on both sides, so the browser event and the server event count as
one conversion. Klaviyo rides the same moments once the store saves its
public key (Viewed Product, Added to Cart, Started Checkout, the identify
at the email step); without the key the tag renders nothing and costs
nothing, and the orders go from the platform under the private key.
Customer accounts
The platform signs a shopper in on your store's own address: the session
is an HttpOnly cookie set through your /api/store rewrite, so no script
on the page can read it. Mount the session once and give two pages their
pieces:
<CustomerSessionProvider client={browserClient}>{children}</CustomerSessionProvider> // your providers
<SignInForm client={browserClient} /> // app/account/login/page.tsx
<AccountTemplate client={browserClient} /> // app/account/page.tsxThe sign-in is an emailed code, no password, and a guest's earlier orders
under the same email are on the account. A signed-in customer pays their
price lists, and a customer of the store's B2B group sees the B2B
channel's products at their prices, on the same site. A page that reads
the catalogue on its server for the visitor gives its client
getSessionToken, so the platform answers for them.
Experiments
The merchant creates and starts an A/B test in the admin's Experiments app; the storefront shows each visitor their variant by the test's key:
<ExperimentsProvider client={browserClient}>{children}</ExperimentsProvider> // your providers
const variant = useExperiment("drawer-weight") // "kilos", "control", or null
return variant === "kilos" ? <WeightLine cart={cart} /> : nullnull shows your control: no experiment by that key, a draft, one that
ended without a winner, or a visitor outside it. The variant is a hash of
the visitor cookie and the experiment's seed, the same function the
platform runs, so the same visitor sees the same variant on every visit and
the platform judges exactly what was shown. The hook reports a visitor's
first look at a running experiment, once, from the browser; the platform
counts that visitor's carts, orders and revenue from then on. An experiment
ended with a winner answers the winner to everyone, with no code change.
Hand the provider the experiments and the visitor cookie read on your
server (listExperiments from @cartbase/storefront/api/experiments, the
_cartbase_visitor cookie) and the first paint already shows the variant.
A checkout rule can be the test itself: the merchant names an experiment
on the rule, the control sees the option hidden and the other variant sees
it greyed out with the rule's reason. The package's checkout draws it,
never lets it be chosen, and reports who saw it; your code adds nothing.
Any variant can be previewed with ?cartbase_preview=<key>:<variant> on
any page: that tab shows it, a draft's included, and nothing is counted.
Documentation
The complete reference — every endpoint with request/response shapes and
working examples, plus a step-by-step build runbook — is written to be
followed by a developer or handed to a coding agent as-is. It ships
inside every npm create cartbase scaffold under docs/, and online at
your store's docs site. Start with Build a storefront — the runbook.
License
MIT © Cartbase
