This page is the curated reference. The complete, generated type reference lives at /kit/api/react and is regenerated from the published typings. For a walkthrough, start with React setup.
"use client" directive. React is an optional peer dependency, ^18.2 || ^19. The slug, id and promise forms of <ProductProvider>, and <SEO /> tag hoisting, need React 19.
The components render no markup of their own: no wrapper, no class names. The exceptions are <ProductImage /> (one <img>), <Checkout> (one <div> holding the frame), the SEO components (head tags), and the consent banner’s default dialog and <ConsentSettingsButton> (which render only when you give them no content of your own).
Providers and context
ShopkitProvider
CartStore available to the tree. Both are created once and kept for the provider’s lifetime. By default it also mounts cookie consent, the default banner and the shop’s own analytics, gated on the shopper’s decision (see the consent prop).
ShopkitConfig
A plain config object, which can cross a server-to-client boundary. Read once, not a render dependency. See Client.
ShopkitClient
A client you built yourself. Takes precedence over
config.Cart | null
A cart read on the server. The store starts
ready, so SSR and the first client paint agree.string | null
Sell the whole tree into one campaign storefront. Changing it rebuilds the client and the cart store. With a prebuilt
client, it must match that client’s binding or it throws.string | null
Shorthand for
config.currency: the currency to browse in until the shopper picks one, so a default, not an override. A later change switches the same client with setCurrency() without rebuilding it: catalog hooks refetch and the same cart is re-read. A change to null returns to the value the provider mounted with, not necessarily the shop’s own currency; mount with no currency if null should mean the shop’s own. With a prebuilt client the mount-time value is ignored (give the client its currency) and only later changes are forwarded. See Currencies.ShopkitConsentOptions | false
Shapes the cookie consent and analytics the provider mounts, which are on by default. It does not switch them off: the one switch is
consent: false in the client config, which a server client’s checkout handoff reads too. consent={false} on the prop still turns consent off for this tree, but is deprecated and warns, because a server-started checkout cannot see it.A provider nested inside another (a campaign provider inside the site’s) reuses the outer consent store, banner and analytics hub. See Consent and analytics.ReactNode
required
useShopkit / useShopkitContext
ShopkitConfigError when there is no provider above. ShopkitContext is exported for advanced composition.
Cart
useCart
Cart | null
number
Sum of quantities, for a badge.
'idle' | 'loading' | 'ready' | 'error'
number
Mutations in flight.
Error | null
Captured, not thrown.
number
Bumped once per successful mutation made through the store.
Promise<Cart | null>
{ productId, variantId?, quantity? }. null on failure.Promise<Cart | null>
Line id.
0 removes the line.Promise<Cart | null>
Promise<void>
Deletes the remembered cart and forgets it.
clearCart is an alias.Promise<Cart | null>
Catalog hooks
All returnAsyncState<T>: { data: T | null; loading: boolean; error: Error | null; refetch(): void }. Each fetch is aborted on unmount and on every re-run, and a superseded response is discarded, so a search-as-you-type box cannot land an out-of-order result. They are not a cache; an app with TanStack Query or SWR should call the client directly.
useProducts
currency parameter prices one read in another currency (null for the shop’s own).
useProductSearch
products.search parameter. All are primitives, so an inline object literal does not re-fetch.
useProduct
data is null for a hidden or missing product.
useCategories
useShop
Currency
useCurrency
checkout:read). See Currencies.
string | null
What prices are shown in: the choice when the shop offers it, else the shop’s own.
string | null
What was asked for (the remembered choice, else the configured default), whether or not the shop offers it.
string | null
The shop’s own currency.
ShopCurrency[]
{ code, mode, rate }[], base first. Only the base entry when the converter is off; empty while loading.'base' | 'display' | 'charge'
display: shown converted, charged in the shop’s currency. charge: priced and charged in it.number
Units of
currency per 1 unit of the shop’s currency.string | null
What the checkout will charge.
Promise<void>
Switch and remember. Every product hook refetches,
useCart() re-reads the same cart, and the next checkout opens in it. null returns to the default.boolean
True while the shop, and with it the list of currencies, is loading.
Error | null
useClientCurrency
client.currency, re-rendering when it changes. No shop read.
useAsync
Product and variant selection
ProductProvider
slug or id lookup re-reads the product when the client’s currency changes. With analytics on, it tracks view_item once per product.
Product | Promise<Product | null> | null
A resolved product, or a promise unwrapped with React 19
use() (wrap in <Suspense>). Takes precedence over slug and id.string
Looks the product up. Walks the catalog; needs React 19 and a
<ShopkitProvider>.string | number
Looks the product up by id. Needs React 19 and a
<ShopkitProvider>.ReactNode
Rendered when the product is missing or hidden.
number
Preselect a variant, for
?variant= deep links.boolean
default:"false"
Start on the first non-hidden variant instead of a price range.
string
A formatting fallback, used only when the product does not state its own
product.currency (a platform older than the field). Passed through to useProductPrice and <SEO />.(variant: ProductVariant | null) => void
ReactNode
required
useProductState
Product
VariantOptionGroupState[]
Each group with its values,
selected and available.Record<number, number>
ProductVariant | null
boolean
The selection pins one variant.
boolean
VariantPriceState
amount, compareAtAmount, min, max, isRange.string | undefined
The product’s own
product.currency, else the provider’s currency prop. Format with this.void
Repairs contradictions instead of refusing.
void
void
void
Selection hooks
useProductAddToCart
Promise<Cart | null>
Adds the selected variant. A no-op while the selection is incomplete.
boolean
False until one variant is pinned, while a mutation is in flight, and during a buy-now.
number
Error | null
VariantOptionGroupState[]
The groups still missing a choice, for a “Select a size” prompt.
Promise<void>
Adds the selected variant and navigates to the hosted checkout.
input is a StartCheckoutInput.boolean
True while a buy-now runs, and after it navigated until the page is restored.
Error | null
Headless components
Each renders only what itschildren function returns.
fallback renders when the product has no such group, so a component written for “Color” degrades quietly.
Images
ProductImage
<img> with the CDN URL and srcSet resolved. Product precedence: image, product, the surrounding <ProductProvider>, then a lookup by productId or slug.
number
CSS pixels. Drives the resize, the
srcSet and the box.number
number
default:"0"
Which image, in display order.
number
A specific image, for example
variant.imageId.number[]
default:"[1, 2]"
[] disables the srcSet.number[]
w descriptors instead; pair with sizes.ImageTransform
quality, format, fit, crop and so on.string
Defaults to the image’s alt text, then the product name, then
"".ReactNode
Rendered when there is no image. Never a broken
<img>.boolean
loading="eager" and fetchPriority="high", for the LCP image. Everything else lazy-loads.boolean
default:"false"
boolean
default:"true"
various
Which product and image; see above.
<img> attribute passes through.
useProductImage
next/image, a CSS background or an og:image.
Checkout
useCheckout
Promise<StartCheckoutResult | null>
Creates the session without navigating.
Promise<void>
Creates the session and navigates with
location.assign.Promise<void>
Adds one item to the remembered cart and navigates.
boolean
True while starting, and after a navigation until the page is restored from the back/forward cache. A navigation that never unloads releases it after 10 seconds.
Error | null
string | null
The last handoff URL.
input is a StartCheckoutInput; pass cartId: cart?.id from useCart() where cookies may be blocked (an app builder’s preview).
useOrderConfirmation
sessionId it uses the one the kit remembered when the checkout started. With analytics on, a completed order is reported as the purchase event once, deduplicated across reloads.
boolean
default:"true"
false never polls.SessionConfirmation | null
The snapshot the server already took with
shopkit.checkout.confirmation(). A completed or failed one is final: nothing is polled, the bought cart and session are forgotten (as a completed poll does), and a completed one is reported as the purchase. A pending one is polled from.boolean
default:"true"
Report the
purchase event once the order exists.'completed' | 'processing_payment' | 'no_attempt' | 'failed' | null
number | null
ConfirmationOutcome | null
timeout is not a failure.SessionConfirmation | null
boolean
Error | null
For example “no checkout session to confirm” on a direct visit.
Checkout
<div> with the frame inside. The session is created once, on mount; changing props afterwards does not rebuild it. It follows the cart: nothing mounts for an empty cart, and emptying the cart takes the frame down. See Embedded checkout.
string
Relative URLs resolve against the page. Only the origin is used for the landing.
string
string
'light' | 'dark'
Omitted, the checkout follows the merchant’s setting.
'redirect' | 'inline'
default:"redirect"
number
default:"600"
string
CSSProperties
(detail: { sessionId, shopId, step }) => void
(detail: { step }) => void
(detail: { name, params }) => void
(detail: { sessionId, orderNumber, successUrl }) => void
(detail: { code, message, fatal }) => void
A checkout that could not start is reported here, never thrown.
(detail: { reason, url }) => void
() => void
Called once when the cart settles empty.
Consent and analytics
<ShopkitProvider> mounts all of this by default; the pieces are public for a page that composes them itself. See Consent and analytics.
ConsentProvider
ConsentStoreOptions field (revision, cookieName, maxAgeDays, domain, sameSite, secure, persist, initialState), plus store (a ConsentStore you built, for example one bridged to a third-party consent platform with persist: false) and lang. A <ConsentProvider> inside one that already exists shares the existing store: one decision per page.
useConsent / useOptionalConsent
'undecided' | 'decided'
Undecided is treated as denied.
boolean
boolean
The preferences panel is open.
boolean
"necessary" is always allowed.void
void
{ analytics, marketing }.void
Withdraw: forget the decision and show the banner again.
void
ConsentStore
useConsent() throws without a consent provider above.
ConsentBanner
(state: ConsentBannerState) => ReactNode
state is the consent snapshot plus visible, labels, draft, setDraft(partial), acceptAll, rejectAll, save (saves the draft), reset, openSettings, closeSettings.string | null
Partial<ConsentLabels> | null
string | null
string
boolean
Leave out the stylesheet.
boolean
Keep it visible after a decision.
visible is true while undecided, while the preferences panel is open, or with showWhenDecided. The banner renders nothing before hydration unless the provider got initialState.
ConsentSettingsButton
<button type="button"> that reopens the banner’s preferences, for a footer. Labelled “Cookie settings” in the provider’s lang when given no children. Takes every <button> attribute plus lang.
ConsentGate
children only once category is allowed, fallback until then.
AnalyticsProvider
<ShopkitProvider> mounts one by default; an explicit one inside it joins that hub (its destinations are added) instead of loading the pixels twice.
AnalyticsDestination[]
Destinations of your own, on top of (or with
auto: false, instead of) the shop’s.boolean
default:"true"
Load the merchant’s GA4, GTM and Meta pixel from
shop.tracking.boolean
default:"true"
false runs analytics ungated, and makes the hosted checkout track ungated too. Only for a storefront that owes its shoppers no consent.boolean
default:"false"
Load GTM or gtag.js before the shopper decides, under a Consent Mode default of everything denied. A GTM container loaded this way runs all of its tags.
string
The currency for events that carry none. Falls back to the cart’s.
string | number | null
The shop’s numeric store id, for the purchase dedup key and Meta’s
eventID. Learned from the cart when omitted.number
default:"50"
Events remembered for destinations not ready yet. Minimum 1.
boolean
Log every dispatch.
useAnalytics / useOptionalAnalytics
Analytics hub. See Utilities for its methods and the event builders.
useTrackPurchase
purchase for an order number you already have, from the checkout session’s lines and total. Deduplicated per order across page loads, so it never double-counts beside useOrderConfirmation. Pass sessionId explicitly when useOrderConfirmation runs on the same page, because its completed poll forgets the remembered session. tracked is true once reported, here or on an earlier visit.
SEO
See SEO.SeoProvider
SeoDefaults field: baseUrl, siteName, titleTemplate, locale, defaultImage, twitterSite, twitterCreator, currency, productPath, categoryPath, shop, organization. useSeoDefaults() reads them back.
SEO
SeoInput and SeoDefaults field, plus skipTitle and skipJsonLd. React 19 hoists the tags into <head>; on React 18 use useSeo() with your framework’s head.
useSeo
JsonLd
<script type="application/ld+json"> for one node or many. For Next.js generateMetadata pages, whose metadata has no JSON-LD slot.
CartStore
CartStore and its CartSnapshot type are exported from this entry. See Cart. So are ConsentStore, Analytics and the consent and analytics types (ConsentState, ConsentSnapshot, ConsentCategory, ConsentChoice, ConsentLabels, AnalyticsDestination, CommerceEvent, CommerceItem, PurchaseEvent), so a React app needs no second import.