Generated from the typings of
@quickbutik/kit@1.8.0 as published on npm. Do not edit this page by hand: run npm run generate in tools/kit-api-reference. For guided, example-led documentation see the API reference.Classes
Analytics
The hub: onetrack() the storefront calls, fanned out to every
destination the shopper’s consent allows.
Events are remembered (bounded) rather than dropped when a destination is
not ready for them: before the shopper decides, a view_item waits, and is
delivered the moment marketing is granted — or forgotten the moment it is
denied. The same memory covers destinations that arrive late, which is the
normal case: destinationsFromShop() needs one request to learn the
merchant’s ids, and the product page’s view_item has usually fired by
then. Gating happens at dispatch time, so withdrawing consent stops a
destination immediately even though its script stays on the page.
Purchases are deduplicated across page loads through the platform’s own
localStorage key, and carried to destinations with the platform’s own Meta
eventID, so a thank-you page can be reloaded without counting the order
twice — and the platform’s server-side event, when there is one, merges
with the browser’s.
Constructors
Constructor
Parameters
Returns
Analytics
Properties
requireConsent
requireConsent: false).
Accessors
consentState
Get Signature
Returns
ConsentState | null
destinations
Get Signature
Returns
readonlyAnalyticsDestination[]
Methods
addDestination()
destinationsFromShop()
feeds in once the shop’s ids are known. It receives the events the hub
still remembers, consent permitting.
Parameters
Returns
void
allows()
Parameters
Returns
boolean
attachCart()
add_to_cart / remove_from_cart
events — the quantities that changed, not the whole basket — and learn
the shop’s currency and numeric store id from it. Both are kept once
seen: a cart that goes away (bought, expired) does not unlearn the shop.
Returns the detach function.
Parameters
Returns
Returns
void
destroy()
stop(), plus forget the cart and the remembered events.
Returns
void
observeCart()
add_to_cart / remove_from_cart through this
hub, without making it THE cart: the currency and store id are still
learned from the one attachCart was given, and attaching does not
replace it. For a nested shop (a campaign storefront inside the site’s
provider) that shares the outer hub rather than loading the pixels
twice. Returns the detach function.
Parameters
Returns
Returns
void
removeDestination()
Parameters
Returns
void
start()
stop() undoes it, so a React effect can call the pair
on every mount/unmount.
Returns
void
stop()
Returns
void
track()
Parameters
Returns
void
trackPageView()
Parameters
Returns
void
trackPurchase()
storeId falls back to the hub’s (its option, else the attached
cart’s); without any the key is still unique per order, just not shared
with the platform’s own surfaces.
Parameters
Returns
boolean
AsyncResource
One in-flight fetch and its result, observable, with no framework attached. The non-React twin ofreact/use-async.ts, and the same non-promise: this is
NOT a cache. shopkit ships no data-layer opinion — it exists so the elements
layer can load a product list without the package growing a query library.
A superseded run is aborted and its late response discarded, which is what a
search-as-you-type box needs: run() called five times must land the fifth
answer, not whichever server replied last.
Type Parameters
Constructors
Constructor
Parameters
Returns
AsyncResource<T>
Properties
getSnapshot()
Returns
AsyncSnapshot<T>
subscribe()
Parameters
Returns
Returns
void
Methods
abort()
Returns
void
hydrate()
Parameters
Returns
void
run()
Parameters
Returns
Promise<T | null>
CartResource
The shopper’s cart. Two layers live here. The plain methods (create, get, addItem, …) are a
thin, stateless mapping of the Cart API. The current/ensure pair adds the
one piece of state a storefront always ends up writing itself: remembering
WHICH cart this visitor has, in a way that works the same in the browser, in
a server component and in a server action.
Constructors
Constructor
Parameters
Returns
CartResource
Methods
add()
Parameters
Returns
Promise<Cart>
addItem()
Parameters
Returns
Promise<Cart>
clear()
add() starts a fresh one.
- No remembered cart — nothing to clear, so no request is made. A visitor who never added anything, or a second click, causes no write.
- The cart is already gone (404/410 from the delete — expired, or bought in another tab) — the goal was an empty basket and the shopper has one, so the stale id is forgotten all the same. Surfacing that as an error would leave a button that can never succeed, because the id it keeps retrying is the one that no longer resolves.
- Any other failure (a network error, a 5xx) throws, and the id is KEPT: the cart may well still exist server-side, and forgetting it would strand those items in a cart this visitor can no longer reach.
fallbackCartId is the cart to delete when NONE is remembered — a cart
rendered from a server read that this browser’s storage does not hold.
A remembered id always wins over it.
Parameters
Returns
Promise<void>
create()
storefrontId is
passed here) the cart is created BOUND to that campaign: the platform
prices it with the campaign’s overrides on every read, and a checkout
session created from it inherits the binding. Otherwise the request
carries no body, as it always has. This is the stateless call, so any
campaign may be named — pass the returned cart.id as cartId to
checkout.start() to check it out.
Parameters
Returns
Promise<Cart>
current()
Parameters
Returns
Promise<Cart | null>
currentId()
Returns
Promise<string | null>
delete()
Parameters
Returns
Promise<void>
ensure()
storefrontId
may only restate the client’s binding: this call reuses the remembered
cart, and a different campaign could neither apply to it nor be
remembered safely (see StorefrontAttribution).
Parameters
Returns
Promise<Cart>
get()
Parameters
Returns
Promise<Cart | null>
removeItem()
Parameters
Returns
Promise<Cart>
updateItem()
item.id, not the product id).
Parameters
Returns
Promise<Cart>
CategoriesResource
The shop’s category tree. Read-only for a storefront credential.Constructors
Constructor
Parameters
Returns
CategoriesResource
Methods
get()
cat_12) or numeric id, or null.
A bare number is prefixed on the way out — the gateway validates the path
param against ^cat_\d+$ and 400s a plain 12, the same trap
products.search({ categoryId }) already normalises away.
Parameters
Returns
Promise<Category | null>
list()
root: true for the top level, or a
parentId (prefixed cat_…) to walk one level down.
Parameters
Returns
Promise<Page<Category>>
CheckoutResource
Checkout, as a headless storefront uses it: build a session from a cart, hand the shopper to the hosted Quickbutik checkout, then confirm the order when they come back. Payment itself is deliberately NOT part of this surface. The hosted checkout owns the PSP integration, PCI scope, 3-D Secure, wallets and the payment retry logic — the storefront owns the catalog, the cart and the thank-you page.Constructors
Constructor
Parameters
Returns
CheckoutResource
Methods
buyNow()
useCheckout().buyNow and <qb-buy-now> are the navigating wrappers.
The result also carries cart — the cart as the add left it — so a
caller that keeps its own cart state (the shared CartStore does) can
fold it in without a second read: a page that stays put (no-redirect,
a new tab) or is restored from the back/forward cache must not show a
badge that missed the item it just added.
Parameters
Returns
Promise<BuyNowResult>
confirmation()
processing_payment and there is no order number yet.
Takes either handle — a checkout-v2 session id or a legacy order uuid (both
arrive as StartCheckoutResult.handoffId); the platform resolves which it
is. Read the statuses with care on a legacy handoff: that checkout leaves a
failed payment looking untouched, so no_attempt means “not paid yet”, NOT
“the shopper never tried”. See LegacyHandoff.
Parameters
Returns
Promise<SessionConfirmation>
createSession()
successUrl may be any https URL — http only for localhost/loopback
— see CreateSessionInput.successUrl. The same rule applies to
cancelUrl and backUrl (where the checkout’s “continue shopping” links
point). Only the ORIGIN of successUrl is used for the return redirect.
A campaign storefront (storefrontId on the input, else the client’s
storefront) is sent along with its surface; the platform then prices
the session with the campaign, refuses with a typed error when the
campaign is not live, a quantity limit is exceeded or the cart belongs to
another campaign (see storefrontRefusal()), and puts the campaign on
the order. With neither set, nothing is sent and a cart that was created
bound to a campaign passes its own binding on server-side. Because the
caller names the cart here, any campaign may be named.
Parameters
Returns
Promise<CheckoutSession>
currentSessionId()
Returns
Promise<string | null>
embedUrl()
/embed/{storeId}/{sessionId}.
The sibling of hostedUrl, and everything that doc says about
storeId applies here verbatim: it is the shop’s NUMERIC id
(Cart.storeId), not the prefix in the publishable key, and both ids ride
the path because storage is partitioned — or absent — inside a
third-party frame, so the URL has to carry everything needed to rehydrate.
A distinct top-level /embed/ prefix rather than a path under
/checkout/: the two documents are not interchangeable. The embed one is
chrome-less, never navigates itself, and is served with a
frame-ancestors header naming the session’s recorded embed origin — so a
session created WITHOUT an embed block renders a refusal here, whatever
URL you build. mount is the supported way to reach this; build it
by hand only when you are framing the checkout yourself.
Parameters
Returns
string
finalize()
completed, so the next visit starts a clean basket instead of
resurrecting a cart that has already been bought.
The shop’s numeric store id remembered off the cart is kept, here as
everywhere a cart is forgotten (a header badge finding the cart gone,
cart.clear()): it is a constant of the shop, not of the order, and it
is what a thank-you page keys the purchase event on
(rememberedStoreId()). A reload of that page — with the session id on
its URL — has to build the same key as the first visit, or the order is
counted twice. The copy kept next to the checkout session goes with the
session, as documented on SessionStore.
Returns
Promise<void>
getSession()
data.cart_products, data.order_total) without a second cart lookup.
Null when the session is unknown or has been cleaned up.
Parameters
Returns
Promise<CheckoutSessionSnapshot | null>
hostedUrl()
/checkout/{storeId}/{sessionId} — the canonical, shareable, resumable
form. Both ids are in the path because the checkout must be able to
bootstrap itself from the URL alone (a link opened on another device has no
storage to fall back on).
checkout-v2 only, and it asks the platform nothing. A shop on the
legacy checkout needs a URL naming an order the platform has to create
first, which no synchronous local builder can produce — so for such a shop
this returns a link that cannot be opened. Prefer start, which asks
which checkout the shop runs and returns the right URL either way; reach
for this only when you hold a checkout-v2 session id and want the URL
without a round trip.
storeId is the shop’s NUMERIC id, Cart.storeId. It is not the prefix
in the publishable key (shopkit.shopPrefix, 101928Y), which the
checkout answers with “We couldn’t find 101928Y”. The id is taken from the
input when given, else from the one remembered off the last cart this
client received; when neither exists this throws rather than guess — pass
storeId: cart.storeId, or use start, which has the cart in hand.
Parameters
Returns
string
mount()
/checkout/handoff
with an embed block added, so a mounted checkout costs a storefront
exactly what a redirected one does.
It always resolves. When there is nothing to frame — the shop runs the
legacy checkout, the platform returned no embed URL, or this page cannot
navigate its own top window — the handle comes back in its fallback
state, emits fallback, and (unless fallbackRedirect: false) sends the
shopper to the hosted checkout instead. None of those is a bug in the
calling page and none of them is retryable, so none of them throws. A
genuine failure — no cart, a rejected key, a 500 — still rejects, exactly
as start() would.
The same hosted URL is kept for one more case, decided later: a frame that
is built but never answers (this page is not the origin the session was
created for, typically). Fifteen seconds in, the handle takes the frame
down, moves to fallback with reason handshake-timeout, and sends the
shopper the same way — so a misconfigured embedOrigin costs a redirect,
not a sale.
One checkout per container. Mounting into an element that already
shows one destroys the earlier handle — its frame, its listeners, its
handshake timer — before the new frame goes in, so a page that calls
mount() again from a re-render or a “try again” button ends up with one
checkout, not two stacked. Last mount wins. The platform hands the same
cart the same session back, so the new frame shows the same checkout at
the same step; nothing is charged twice. <qb-checkout> lives by the same
rule when it is detached and put back. Keep the handle if you want to
destroy() it yourself; you do not have to for a second mount().
Browser only: it builds a DOM node and listens for message.
Parameters
Returns
Promise<EmbeddedCheckout>
parseReturnUrl()
<successUrl origin>/success/<orderNumber>?hash=…&t=…
— note that only the ORIGIN of successUrl is used, so this path is where a
headless storefront must mount its thank-you route. Both checkouts return
this way, the legacy one included (see LegacyHandoff); the handle to
confirm the order by is the one start() remembered either way.
hash is a legacy integrity token and is returned for completeness only;
treat the order as real once confirmation says completed.
Parameters
Returns
HostedCheckoutReturn | null
pollConfirmation()
timeout outcome is NOT a failure — the order may still land. Show “we
are still processing your order” and let the customer refresh. On a legacy
handoff timeout is the NORMAL outcome for a shopper who has not paid yet,
because that checkout never reports failed; do not present it as an error
there.
Parameters
Returns
Promise<ConfirmationOutcome>
rememberedStoreId()
hostedUrl() without a cart). Synchronous and request-free, like
hostedUrl(); see SessionStore.peekStoreId for what “remembered”
covers. The session’s copy is consulted first because that is the one
still alive on a thank-you page.
Returns
string | null
resume()
?qb_checkout_session=<id> on it. This is what that page calls with the
id: no handoff, no new session, straight back into the frame the shopper
was already in, which resumes at its confirmation step.
<qb-checkout> and <Checkout> do this for you. Reach for it directly
only when you route that parameter yourself.
The URL is built locally, because there is no handoff call to ask. Pass
storeId — the return URL carries it as qb_checkout_shop, next to the
session id (readReturnedCheckout() reads both) — and no storage is
involved at all. Without it the id remembered with the session, then the
one off the last cart, is used; only when none of the three exists does
this reject.
Degrades the way mount does when the frame never answers: the
hosted checkout URL for the same session is built from the same inputs,
and a handshake-timeout sends the shopper there (unless
fallbackRedirect: false). A return leg that lands on the wrong origin —
a www redirect between leaving and coming back — thus still reaches the
confirmation, on the hosted checkout, instead of an empty box.
Parameters
Returns
Promise<EmbeddedCheckout>
start()
redirect(url)), a route handler (302) and the browser
(location.assign). The URL’s store id comes from the cart itself —
the only place the storefront API states the shop’s numeric id.
On a server client (one built with a cookies accessor) the shopper’s
consent decision is forwarded on the URL too, read from the request’s
qb_consent cookie: consentCategories, and the GA client and session
ids when analytics is granted and the accessor has getAll(). That is
what lets the hosted checkout set Consent Mode before its own tags load.
consent: false in the config turns it off. In a browser the React hooks
and the elements decorate the URL from the live consent store instead.
Parameters
Returns
Promise<StartCheckoutResult>
syncCart()
cartId server-side: a second
POST /checkout/sessions for the same cart returns the FIRST session,
complete with the cart as it looked back then. That is right for a retry
and wrong for a shopper who went to checkout, came back, added something,
and set off again — their new lines would never reach the checkout, with no
error anywhere to say so.
Patching cart: {} is the platform’s own “rehydrate from the Cart API”
instruction, and is what the hosted checkout does when the shopper edits
quantities inside it.
Only patches when the snapshot actually differs, so a session the shopper
is midway through is not needlessly disturbed. Pass cart when you already
have it (start() does) and the check costs no request at all.
Parameters
Returns
Promise<CheckoutSessionSnapshot | null>
ConsentResource
The shopper’s consent decision as this client sees it, and the settings every part of the kit has to agree on to read it. Not a request to the platform: the decision lives in theqb_consent
cookie on the storefront’s own origin, so on a server it is read through
the same cookies accessor the cart id is, and in a browser from
document.cookie.
Constructors
Constructor
Parameters
Returns
ConsentResource
Accessors
cookieName
Get Signature
Returns
string
enabled
Get Signature
consent: false.
Returns
boolean
revision
Get Signature
Returns
number
Methods
decorateHandoff()
consentCategories, plus gaClientId / gaSessionId
when analytics is granted and the accessor has getAll()).
What checkout.start() applies on a server client. The URL comes back
untouched when consent is off or the client has no cookie accessor:
a browser client’s handoff is decorated by the React hooks and the
elements instead, from the live consent store.
Parameters
Returns
Promise<string>
read()
cookies accessor when
one was configured, else document.cookie, else undecided. A decision
made under another revision, or a cookie that is not one, reads as
undecided.
Returns
Promise<ConsentState>
ConsentStore
The shopper’s consent decision, observable. One per page, shared by the banner, the “Cookie settings” link in the footer, every<ConsentGate> and the analytics hub — the same shape as
CartStore (subscribe / getSnapshot, an immutable snapshot replaced on
every change) so useSyncExternalStore and the elements’ bindings can read
it the same way they read the cart.
The decision is the cookie’s; this object is a view over it that can also
write. Reading happens once, at construction (or never, with
initialState), and every write goes through save() — there is no second
source of truth to drift from.
Constructors
Constructor
Parameters
Returns
ConsentStore
Properties
getSnapshot()
Returns
ConsentSnapshot
revision
subscribe()
Parameters
Returns
Returns
void
Accessors
pristine
Get Signature
Returns
boolean
Methods
acceptAll()
Returns
void
allows()
necessary always may; the
others only after an explicit yes — undecided is a no.
Parameters
Returns
boolean
closeSettings()
Returns
void
getState()
Returns
ConsentState
hydrate()
Parameters
Returns
void
openSettings()
Returns
void
rejectAll()
Returns
void
reload()
document.cookie, for a page that knows another tab decided.
Returns
void
reset()
Returns
void
save()
persist: false), closes the
preferences panel and announces it on document as qb:consent, so a
page’s own scripts can react the way the hosted storefront’s do.
Parameters
Returns
void
EmbeddedCheckout
A checkout rendered inside the merchant’s own page, and the conversation with it. The iframe document is always served from the checkout’s own origin, so the PSP integration, the same-origin API proxy and the wallet domain registrations keep working exactly as they do on the redirect path. What changes is who owns the window: the frame may not navigate anything, so every exit — the back link, a PSP redirect, the completed order — arrives here as a message and is performed by this host. A handle is also returned when there is nothing to embed (see EmbeddedCheckoutFallbackReason). That is not an error and does not throw: it is an expected shop configuration, reported as afallback event
on a handle whose state is "fallback". An embed handle whose frame never
answers ends up in the same place: the frame is removed, state flips to
"fallback", and the same event carries the hosted checkout URL — so one
listener covers every way the shopper can end up on the hosted checkout.
Constructors
Constructor
Parameters
Returns
EmbeddedCheckout
Properties
sessionId
Accessors
iframe
Get Signature
Returns
HTMLIFrameElement | null
state
Get Signature
"embed" while framed, "fallback" when there was nothing to frame — or
when the frame there was never answered and has been taken down.
Returns
"fallback" | "embed"
Methods
cartUpdated()
<qb-checkout> and React’s <Checkout> call this for you, off the kit’s
own cart store. Call it yourself only when you drove mount() by hand, or
when you change the cart through something other than
Quickbutik.cart — and then only after the change has actually been
saved, because the frame reads the server’s cart, not yours.
Held — not dropped — before the frame has said ready, and ignored by a
fallback handle: there is no frame to tell, and there never will be. It is
cheap and safe to over-call — the frame coalesces a burst into at most one
extra read.
Holding it is the whole point. The frame does NOT re-read the cart as it
boots: the session’s cart is a snapshot taken when the session was
created, and this message is the only thing that refreshes it (see
use-cart-rehydrate.ts in checkout-frontend, and EMBED_CONTRACT §3). The
window between the frame being built and its first ready is the iframe
load plus the frame’s own session fetch — seconds on mobile — and a
mutation dropped in it would be a shopper charged for the cart as it
stood before they changed it. One flag, not a queue: the message carries
nothing, so two of them say exactly what one says.
Returns
void
destroy()
Returns
void
focus()
Returns
void
off()
Type Parameters
Parameters
Returns
void
on()
off.
Type Parameters
Parameters
Returns
Returns
void
ProductController
The variant-selection state machine for one product, with no framework attached. It owns nothing but aVariantSelection — every field on the snapshot is
derived from (product, selection) by the pure functions in
variant-matrix.ts. That is deliberate: the matrix is the only place variant
logic lives, and both bindings over it (React’s useProductState, the
<qb-product> element) are glue.
Built for useSyncExternalStore, hence the cached snapshot: that hook
compares snapshots by identity and would loop forever on a freshly-allocated
object. The same caching is what lets the elements layer skip re-binding the
DOM when nothing changed.
Constructors
Constructor
Parameters
Returns
ProductController
Properties
getSnapshot()
Returns
ProductSnapshot
subscribe()
Parameters
Returns
Returns
void
Accessors
product
Get Signature
Returns
Product
Methods
clear()
Parameters
Returns
void
reset()
Returns
void
select()
Parameters
Returns
void
selectVariant()
?variant= deep link.
Parameters
Returns
void
setProduct()
Parameters
Returns
void
ProductsResource
The shop’s public catalog. Reads hit api-core’s storefront controller, which serves only visible products and omits everything a shopper has no business seeing (cost prices, suppliers, internal notes). There is no write surface here on purpose: a publishable key cannot create or edit products.Constructors
Constructor
Parameters
Returns
ProductsResource
Methods
get()
prod_123) or numeric id.
Returns null when it does not exist or is not visible.
A bare number is prefixed on the way out — the gateway validates the path
param against ^prod_\d+$ and 400s a plain 27. See
normalizePrefixedId.
Parameters
Returns
Promise<Product | null>
getBySlug()
limit/offset — there is no ?slug= filter to push the lookup
server-side — so the cost grows with the catalog. That is fine for a small
shop and for build-time generation, and wrong for a hot request path on a
large one. Two ways to avoid it:
- cache the result per slug (in Next.js, wrap the call in
cache()and set a revalidate window), or - build a slug → id map once at deploy time from listAll and look the id up with get, which is a single request.
storefrontId — so the product it returns carries that campaign’s prices.
Parameters
Returns
Promise<Product | null>
list()
Parameters
Returns
Promise<Page<Product>>
listAll()
Parameters
Returns
Promise<Product[]>
search()
list()
offers nothing but limit/cursor, which forces a storefront to read the
whole catalog and filter in its own process — fine for a handful of
products, wrong the moment there are thousands.
- No facet counts. The gateway rebuilds every paginated response into
{ data, has_more, next_cursor }, so an aggregate could not survive the trip even if the server sent one. Derive facet values fromcategories.list(), or keep your own index. - No option-value filter. Option values are per-product rows, so “Svart” is a different id on every product and a cross-catalog filter would have to match on an unindexed name column.
list() — visibility
is applied in the query rather than after paging, so pages come back full.
Parameters
Returns
Promise<Page<Product>>
SessionStore
What shopkit remembers between requests, and nothing else: the cart id, the checkout session id, and the numeric id of the shop — twice. Deliberately minimal: all of them are opaque server-side handles, so a leaked or stale value costs at most a fresh cart. No prices, no PII and no credential is ever persisted — that is what keeps a cookie-based store safe to use without consent banners in most jurisdictions (it is strictly necessary functionality) and what makes “just clear it” a valid recovery. The store id is the odd one out. shopkit never needs it to talk to the API (the publishable key already scopes every request to one shop), but it is the one value the hosted checkout URL is built from, and the API only ever states it on a cart. Remembering it off every cart that passes through is what letscheckout.hostedUrl() stay a synchronous, request-free call.
It is kept twice because the two copies are written at different times and
expire on different clocks. The copy next to the cart id is refreshed off
every cart and expires with the cart’s TTL; the copy next to the checkout
session id is written on handoff and goes with the session
(clearCheckoutSessionId), so the return leg of an embedded checkout can
build /embed/{storeId}/{sessionId} from a value no cart read disturbs.
Neither copy is removed when the cart is FORGOTTEN: the platform drops the
cart the moment an order is created, which on a redirect payment (Klarna,
Swish) is normally before the shopper is back on the page, and the
thank-you page then keys its purchase event on the id
(checkout.rememberedStoreId()). A reload of that page, after a header
badge has found the cart gone and the completed confirmation has forgotten
the session, must still find the same value or the order is counted twice.
Only clear() forgets it.
Constructors
Constructor
Parameters
Returns
SessionStore
Properties
storage
Methods
clear()
Returns
Promise<void>
clearCartId()
Returns
Promise<void>
clearCheckoutSessionId()
Returns
Promise<void>
clearStoreId()
clear() calls this: forgetting a cart keeps the id (see the class doc).
Returns
Promise<void>
getCartId()
Returns
Promise<string | null>
getCheckoutSessionId()
Returns
Promise<string | null>
getStoreId()
Returns
Promise<string | null>
peekCheckoutStoreId()
hostedUrl() and embedUrl(), after the cart’s copy. Same
rules as peekStoreId.
Returns
string | null
peekStoreId()
hostedUrl() reads.
Answers from memory first (every cart the client received set it), then
from storage when the adapter answers synchronously — memory,
localStorage, document.cookie and a request cookie jar all do, which
is what carries the value across page loads and server requests. An
adapter that only answers with a promise (Next’s cookies()) cannot be
consulted here; until a cart has been read in that request the answer is
null and the caller has to be told the id explicitly.
Returns
string | null
setCartId()
Parameters
Returns
Promise<void>
setCheckoutSessionId()
StartCheckoutResult.handoffId). Both are v4 UUIDs and
both are what checkout.confirmation() takes, so nothing downstream has to
tell them apart — but do not assume a stored value addresses a session.
storeId is the shop’s numeric id the session’s URLs are built from,
remembered alongside for as long as the session is (see the class doc).
Best-effort, like setStoreId: the session id is the value nothing
else can recover, so that write is the one allowed to fail loudly.
Parameters
Returns
Promise<void>
setStoreId()
hostedUrl() works for the rest
of the request either way. Storage is only written when the value is new,
so a server request that merely reads the cart does not emit a cookie.
Parameters
Returns
Promise<void>
ShopkitApiError
A non-2xx response from the Quickbutik API.Extends
Constructors
Constructor
Parameters
Returns
ShopkitApiError
Overrides
ShopkitError.constructor
Properties
body
details
details / context from the platform’s error envelope, when present.
status
Accessors
retryable
Get Signature
Returns
boolean
Methods
fromResponse()
Parameters
Returns
Promise<ShopkitApiError>
ShopkitClient
A configured Quickbutik storefront client. One instance is cheap and stateless apart from the remembered ids (cart, checkout session, the cart’s store id), so create one per request on the server (the cookie accessor belongs to that request) and one per app in the browser.Constructors
Constructor
Parameters
Returns
ShopkitClient
Properties
cart
categories
checkout
consent
revision, cookieName) from the config. On a
server: await shopkit.consent.read(), handed to <ShopkitProvider> as
consent={{ initialState }} so the banner is right on the first paint.
products
runtime
scopes
shop
shopPrefix
101928Y), decoded from the publishable key.
It is the folder the shop’s files live under on the CDN —
https://cdn.quickbutik.com/images/<shopPrefix>/products/<file> — and
the value to build an imageBaseUrl from. It is NOT the shop’s numeric
id: the hosted checkout URL wants that one, and it is Cart.storeId
(checkout.start() reads it from the cart for you).
storefront
ShopkitConfig.storefront.
Accessors
apiUrl
Get Signature
Returns
string
checkoutUrl
Get Signature
Returns
string
currency
Get Signature
ShopkitConfig.currency, else null (the shop’s own currency).
It is what is REQUESTED, not necessarily what comes back: a currency the
shop does not offer falls back to the shop’s, so format prices with
product.currency / cart.currency, and use describeCurrency() with
shop.get() to know the mode.
Synchronous: answered from memory, or from storage when the adapter can
answer synchronously (memory, localStorage, cookies, a request cookie
jar). With an async-only adapter (Next’s cookies()) this reads the
configured default; requests still consult the adapter.
Returns
string | null
defaultCurrency
Get Signature
currency this client was configured with, ignoring any choice.
Returns
string | null
imageBaseUrl
Get Signature
url the API sends (the normal case). See ShopkitConfig.imageBaseUrl.
Returns
string | null
shopId
Get Signature
Deprecated
Renamed to shopPrefix in 1.0.0-beta.4, because that is what the value is: the shop’s storage prefix from the key. It is NOT the numeric id the hosted checkout needs — for that usecart.storeId, or let
checkout.start() read it from the cart. Removed before 1.0.0.
Returns
string
storage
Get Signature
Returns
StorageAdapter
Methods
onCurrencyChange()
setCurrency(). Returns an
unsubscribe function. The React hooks and the custom elements use this to
refetch prices and refresh the cart.
Parameters
Returns
Returns
void
setCurrency()
ShopkitConfigError for a value
that is not a three-letter code; a code the shop does not offer is
accepted and simply resolves to the shop’s currency server-side.
Parameters
Returns
Promise<void>
withStorage()
Parameters
Returns
ShopkitClient
ShopkitConfigError
A badcreateShopkitClient config — a malformed key, a missing apiUrl.
Extends
Constructors
Constructor
Parameters
Returns
ShopkitConfigError
Overrides
ShopkitError.constructor
ShopkitError
Base class for everything shopkit throws, socatch can narrow on one type.
Extends
Error
Extended by
Constructors
Constructor
Parameters
Returns
ShopkitError
Overrides
ShopkitNetworkError
The request never produced a response (offline, DNS, abort, timeout).Extends
Constructors
Constructor
Parameters
Returns
ShopkitNetworkError
Overrides
ShopkitError.constructor
Properties
cause
Overrides
ShopkitScopeError
A call was made that the client’s declared scopes do not cover. Thrown locally, BEFORE the request goes out, so the developer sees the missing scope by name instead of an opaque 403 from the gateway.Extends
Constructors
Constructor
Parameters
Returns
ShopkitScopeError
Overrides
ShopkitError.constructor
Properties
declared
required
ShopResource
Shop-level presentation data: name, logo, brand colour, default language, terms link. Everything a storefront shell needs before it renders.Constructors
Constructor
Parameters
Returns
ShopResource
Methods
get()
checkout:read scope for what looks
like plain branding.
Parameters
Returns
Promise<Shop>
Transport
The one place a request to Quickbutik is made. A thin adapter over@quickbutik/sdk-gateway, the platform’s own API client,
which is bundled into this package rather than depended on — it is
published to a private registry, so a third-party storefront could not
install it. Everything underneath comes from there: bearer auth derived from
the publishable key, the QB-Version header, per-attempt timeouts,
exponential-backoff retries that honour Retry-After, adaptive rate-limit
pacing driven by the gateway’s X-RateLimit-* headers, and an automatic
Idempotency-Key on every mutation (so a retried POST /cart can never
create two carts). shopkit behaves like every other Quickbutik client
instead of re-implementing all of that.
What stays here is shopkit’s own contract: mapping the platform’s error
taxonomy onto shopkit’s, treating a vanished resource as null, unwrapping
api-core’s response envelope, and adopting a rotated publishable key.
Constructors
Constructor
Parameters
Returns
Transport
Methods
request()
Type Parameters
Parameters
Returns
Promise<T>
requestOrNull()
Type Parameters
Parameters
Returns
Promise<T | null>
requestVoid()
Parameters
Returns
Promise<void>
Interfaces
AddCartItemInput
Properties
AnalyticsContext
What the hub knows when it calls a destination.Properties
AnalyticsDestination
Where events go. The kit ships Google (gtag.js / GTM) and the Meta Pixel; anything else — TikTok, Klaviyo, a server-side collector — is one object that implements this.Properties
Methods
load()?
<qb-shop>s) calls it again.
Parameters
Returns
void
onConsent()?
load(), on every change, allowed or not.
Parameters
Returns
void
track()
Parameters
Returns
void
trackPurchase()?
purchase_{storeId}_{orderNumber}). Optional: a destination without it
receives the purchase through track() as a purchase event instead.
Parameters
Returns
void
AnalyticsOptions
Properties
ApiEnvelope
api-core wraps most responses in this envelope. The gateway strips it on some routes and forwards it on others, so the transport unwraps defensively rather than per-route (seeunwrapEnvelope).
Type Parameters
Properties
AsyncSnapshot
Type Parameters
Properties
Cart
A server-owned cart. Prices are recomputed on every read, so a cart held in a cookie for a week still reflects today’s prices — never cache these numbers client-side beyond the current render.Properties
CartItem
Properties
CartLineDiff
Properties
CartMutationEvent
A successful change made THROUGH this store, with the cart before and after — what an analytics layer diffs intoadd_to_cart /
remove_from_cart. Never emitted for load, refresh or hydrate
(nothing changed, something was read) nor for a failed mutation.
Properties
CartPresentment
See Cart.presentment.Properties
Category
Properties
CategoryAncestor
One entry of Category.ancestors: a lightweight parent reference.Properties
CategoryListParams
Properties
CheckoutCartProduct
A cart line as the checkout session snapshotted it.Properties
CheckoutDataNodes
The data nodes shopkit types; the map carries others too.Properties
CheckoutOrderTotal
The server-authoritative total: products + shipping + payment fee + discounts. This is the figure the shopper is charged — never recompute it.Properties
CheckoutPricing
Product-only subtotals.order_total is the one that includes everything.
Properties
CheckoutSession
WhatPOST /v2/checkout/sessions answers with.
Extended by
Properties
CheckoutSessionSnapshot
WhatGET /v2/checkout/sessions/:id answers with.
Properties
CommerceEvent
Properties
CommerceEventParams
Indexable
Properties
CommerceItem
A GA4 item.item_id is the bare numeric PRODUCT id, never the variant’s:
it is what the hosted storefront’s tags emit and what the Google Shopping
feed carries, so it is the only id that matches a catalogue on the other
end. The variant rides along as item_variant. Prices are in MAJOR units.
Indexable
Properties
ConsentChoice
What a shopper chooses: the optional categories, on or off.Extended by
Properties
ConsentCookieOptions
Extended by
Properties
ConsentCookieWriteOptions
Extends
Extended by
Properties
ConsentLabels
The copy of the default banner, in the languages Quickbutik shops sell in. The kit renders no markup of its own except where an empty element would be a bug, and an empty consent banner is one — so<ConsentBanner> and
<qb-consent-banner> fill themselves with a minimal dialog when given no
content, and this is its text. Every string is overridable; a storefront
with its own voice passes labels.
Properties
ConsentModeSignals
The four Google Consent Mode v2 signals the platform sets. The mapping is the hosted storefront’s, byte for byte:analytics drives
analytics_storage; marketing drives the three advertising signals.
functionality_storage and personalization_storage are deliberately not
set — the platform never has, and a storefront that wants them can push
its own gtag('consent', …) call.
Properties
ConsentSnapshot
What the store exposes: the decision plus the one piece of UI state a banner and a far-away “Cookie settings” link have to share — whether the preferences panel is open. Not persisted.Extends
Extended by
Properties
ConsentState
The persisted decision. Both flags arefalse while undecided, so a
consumer that only reads the flags gets the safe answer without checking
the status first.
Extends
Extended by
Properties
ConsentStoreOptions
Extends
Extended by
Properties
CookieAccessor
The three cookie operations shopkit needs from a server framework. Model it on whatever the host gives you — Next’scookies(), a Hono context, an
Express req/res pair.
set/remove are optional: a read-only accessor (an RSC, which cannot
mutate cookies) is a legitimate, common case. Writes are then dropped rather
than throwing, so rendering a server component never crashes just because it
touched the cart.
Methods
get()
Parameters
Returns
MaybePromise<string | null | undefined>
getAll()?
cookies().getAll() returns them.
Optional, and read by one feature only: the checkout handoff looks for
Google Analytics’ _ga / _ga_<property> cookies (whose names it cannot
know in advance) to stitch the storefront’s GA session to the hosted
checkout’s. Without it the consent decision is still forwarded and the
GA ids are not.
Returns
MaybePromise<readonly object[]>
remove()?
Parameters
Returns
MaybePromise<void>
set()?
Parameters
Returns
MaybePromise<void>
CookieAttributes
Cookie primitives with no dependencies, usable on both sides of the wire. Kept deliberately small: shopkit only ever stores two opaque ids (the cart id and the checkout session id), so there is no need for signing, chunking or the fullcookie package.
Properties
CreateSessionInput
Input tocheckout.createSession().
successUrl is REQUIRED unless successMode is "inline"; a redirect
session without one throws a ShopkitConfigError before any request.
successMode is sent only when set.
Properties
CurrencyInfo
What a currency choice means for one shop. See describeCurrency.Extended by
Properties
DataState
A server-computed value derived from the fields (prices, shipping options).Type Parameters
Properties
DestinationsFromShopOptions
Properties
DisplayCurrency
The currency a checkout may show an APPROXIMATE amount in, next to the real prices — set when the session was created with a"display" currency.
Properties
EmbeddedCheckoutEventMap
Properties
EmbeddedCheckoutInitEmbed
Presentation and default-behaviour options, shared bymount and resume.
Extends
Properties
EmbeddedCheckoutInitFallback
Properties
EmbedRenderOptions
Presentation and default-behaviour options, shared bymount and resume.
Extended by
Properties
EmbedViewport
The host’s visible region, as the frame needs to see it. This is what lets a modal or a 3-D Secure overlay position itself inside the visible slice of a 2000px-tall auto-sized frame instead of at the frame’s own centre, which can be far off screen.Properties
FieldState
A shopper-supplied value plus the server’s verdict on it.Type Parameters
Properties
FormatMoneyOptions
Properties
GaLink
The Google Analytics ids a page’s_ga / _ga_<property> cookies carry,
for stitching the storefront session to the checkout’s. The regexes are
the hosted storefront’s (cart.php), so both surfaces extract the same
values from the same cookies.
Properties
GoogleTagOptions
Properties
HandoffParamsOptions
Properties
HostedCheckoutReturn
What the hosted checkout appends when it sends the shopper back after a completed order:/success/<orderNumber>?hash=…&t=….
Properties
HostedCheckoutUrlInput
Properties
ImageSrcSetOptions
Resize/encode parameters for Quickbutik’s image CDN (imgix-compatible). Every field is optional and omitted params fall back to the CDN’s own defaults. In a local/rig environment images are served straight from S3, which ignores these — the URLs stay valid, they just come back full-size.Extends
Properties
ImageTransform
Resize/encode parameters for Quickbutik’s image CDN (imgix-compatible). Every field is optional and omitted params fall back to the CDN’s own defaults. In a local/rig environment images are served straight from S3, which ignores these — the URLs stay valid, they just come back full-size.Extended by
Properties
LegacyHandoff
Alegacy handoff, and what does and does not carry over from v2.
The shopper comes back, the same way as from v2. After a completed
order the legacy checkout redirects to
<successUrl origin>/success/<orderNumber>?t=…&hash=… — only the ORIGIN of
your successUrl is used, exactly as on v2, so one thank-you route serves
both checkouts — and its back links go to your backUrl.
CheckoutResource.parseReturnUrl reads that return, and the uuid
start() remembered is what pollConfirmation() (and
useOrderConfirmation() / <qb-order-confirmation> with no id given)
confirms the order by. hash is computed the same way on both checkouts. The
post-purchase-offer token (&ppo=) is only appended when successUrl is on
a host the shop owns, so a headless storefront on its own domain should not
expect one.
Up to kit 1.3 this said the opposite — the legacy checkout used to redirect
to the shop’s own platform storefront and could not be pointed anywhere
else. The platform now honours the handoff’s successUrl and backUrl on
both checkouts.
Three things that still differ from v2:
successMode: "inline"does not apply. The legacy checkout always redirects, so the platform refuses an inline handoff for a legacy shop with a 400 (details.reason: "legacy_checkout_unsupported") before any order is created. Pass a realsuccessUrl.- There is no session.
getSession()and patching do not apply. Poll CheckoutResource.confirmation with legacyOrderUuid instead — the confirmation endpoint takes either handle. - A failed payment reads as
no_attempt, notfailed. The legacy checkout leaves a failed order looking untouched, so atimeoutorno_attemptoutcome is not evidence the shopper gave up. Rely on the merchant’s own order confirmation email as the source of truth.
Properties
ListParams
Properties
MetaPixelOptions
Properties
MountCheckoutInput
Input tocheckout.start(): a CreateSessionInput whose cart is optional.
The successUrl rule is the same — required unless successMode: "inline".
Extends
Properties
NextLikeMetadata
Next.jsMetadata, structurally.
Declared here rather than imported from next: shopkit must not depend on a
framework, and this is the subset buildSeo can fill. Assignable to Next’s own
Metadata type at the call site.
Properties
OrderLine
A line the server added on top of the products (shipping, fee, discount).Properties
Page
Cursor-paginated collection, as the gateway returns it.Type Parameters
Properties
ParsedPublishableKey
Properties
PatchResult
What aPATCH /v2/checkout/sessions/:id answers with — the fields and data
after the change, plus what the change invalidated.
Properties
PickProductImageOptions
Properties
PollConfirmationOptions
Properties
Product
A product as the storefront sees it — visible products only, no cost prices, no supplier data. Served by api-core’s storefront controller, which is the only products surface a publishable key can reach.Properties
ProductControllerOptions
Properties
ProductImage
Properties
ProductImageUrlOptions
Resize/encode parameters for Quickbutik’s image CDN (imgix-compatible). Every field is optional and omitted params fall back to the CDN’s own defaults. In a local/rig environment images are served straight from S3, which ignores these — the URLs stay valid, they just come back full-size.Extends
Extended by
Properties
ProductJsonLdOptions
Properties
ProductListParams
Which campaign storefront prices a product read. A client bound to a campaign (ShopkitConfig.storefront /
storefrontId) sends its id on every product read, so the catalog it shows
carries the same campaign prices its cart will charge — a product page that
says 199 kr above a cart that says 149 kr is the bug this closes. Pass one
here to price a single read for a different campaign; reads are stateless,
so any campaign may be named. null opts a bound client out for this call
and reads the shop’s ordinary prices.
Extends
Properties
ProductOptionType
A selectable option (“Size”), owned by the product.Properties
ProductOptionValue
One concrete choice of an option (“XL”), referenced by a variant.Properties
ProductReadOptions
Which campaign storefront prices a product read. A client bound to a campaign (ShopkitConfig.storefront /
storefrontId) sends its id on every product read, so the catalog it shows
carries the same campaign prices its cart will charge — a product page that
says 199 kr above a cart that says 149 kr is the bug this closes. Pass one
here to price a single read for a different campaign; reads are stateless,
so any campaign may be named. null opts a bound client out for this call
and reads the shop’s ordinary prices.
Extended by
Properties
ProductSearchParams
Which campaign storefront prices a product read. A client bound to a campaign (ShopkitConfig.storefront /
storefrontId) sends its id on every product read, so the catalog it shows
carries the same campaign prices its cart will charge — a product page that
says 199 kr above a cart that says 149 kr is the bug this closes. Pass one
here to price a single read for a different campaign; reads are stateless,
so any campaign may be named. null opts a bound client out for this call
and reads the shop’s ordinary prices.
Extends
Properties
ProductSection
A merchant-authored content section of a product page (“Size guide”, “Care”, “Delivery”), in the order the merchant arranged them. Rendered server-side exactly as the Quickbutik theme renders it: a section linked to a shared template already carries the template’s text, and the[STOCKLEFT], [PRICE] and [BEFOREPRICE] merge tags are replaced.
Properties
ProductSnapshot
Everything derived from one product plus the shopper’s current choices. The read half of ProductController, and the exact shape React’sProductState is built from — the two must not drift, so the hook spreads
this rather than restating it.
Properties
ProductVariant
Properties
ProductVariantPrice
Properties
ProductVariantStock
Properties
PurchaseEvent
The order a thank-you page reports, in major units.Properties
RelatedProducts
Properties
RelatedProductSummary
A related product, reduced to what a product card needs.Properties
RequestOptions
Extended by
Properties
ResolvedShopkitConfig
Config with every default applied and the key already parsed.Properties
ResumeCheckoutInput
Presentation and default-behaviour options, shared bymount and resume.
Extends
Properties
ReturnedCheckout
What the checkout’s return route put on this page’s URL.Properties
ScopeGuard
Properties
Methods
assert()
scope is not covered.
Parameters
Returns
void
has()
Parameters
Returns
boolean
SeoBreadcrumb
Properties
SeoDefaults
Site-wide values every page shares. Supply once (viaSeoProvider or as an
argument) so a page only has to name what is specific to it.
Extended by
Properties
SeoImage
One image, as OpenGraph and schema.org want it.Properties
SeoInput
What the page is about. Exactly one of these shapes is used.Extended by
Properties
SeoOpenGraph
Properties
SeoRobots
Properties
SeoTags
Everything a page needs in<head>, as data.
Deliberately a plain object rather than markup: Next’s App Router wants a
Metadata export, Astro wants tags in its own layout, and a React 19 app can
render them anywhere. One builder, three consumers.
Properties
SeoTwitter
Properties
SessionConfirmation
Properties
SessionEmbed
Where a checkout session may be embedded. The session is the trust anchor for framing: the party that creates it — the same party that already choosessuccessUrl — declares which single origin
may put the checkout in an iframe, and the checkout emits exactly that origin
as its Content-Security-Policy: frame-ancestors. A session created without
this cannot be framed at all, by anyone.
checkout.mount() fills both fields in for you from the current page. Pass
them yourself only when the page that CREATES the session is not the page
that will frame it — a server-side create for a storefront route, say.
Properties
SessionPrefill
Everything seeded at creation. A value the field rejects lands asstatus: "invalid" on that field — it never fails the create call, so a
stale saved address can’t block a shopper from checking out.
Properties
SessionPrefillAddress
Properties
SessionPrefillCustomer
Known shopper identity, seeded into the session so the checkout prefills.Properties
Shop
Shop-level presentation data a storefront needs before it can render anything: the name, the logo, the default language, the terms link. Served by the checkout’s shop endpoint, which is the only shop surface a publishable key can reach — shop settings are a merchant credential’s business, not a storefront’s.Properties
ShopBrand
Properties
ShopBrandColor
Properties
ShopCurrency
One currency a shop offers.Properties
ShopkitConfig
Properties
ShopkitConsentConfig
The consent settings every part of the kit has to agree on, kept on the client config so the server client, the browser provider and the checkout handoff all read them from the same object.Properties
ShopkitRuntimeInfo
What the client resolved about its environment — handy when debugging.Properties
ShopkitStorefrontConfig
ShopkitConfig.storefront — bind a whole client to one campaign.
Properties
StartCheckoutInput
Input tocheckout.start(): a CreateSessionInput whose cart is optional.
The successUrl rule is the same — required unless successMode: "inline".
Extends
Omit<CreateSessionInput,"cartId">
Extended by
Properties
StorageAdapter
Where shopkit keeps the ids it must remember between requests: the cart id, the checkout session id and the cart’s numeric store id. Every method may return a promise. That is not decoration — Next.js 15’scookies() is async, so a synchronous-only contract would lock the most
common server integration out.
Properties
Methods
get()
Parameters
Returns
MaybePromise<string | null>
remove()
Parameters
Returns
MaybePromise<void>
set()
Parameters
Returns
MaybePromise<void>
StorageSetOptions
Properties
StorefrontAttribution
Per-call attribution. Accepted freely by the STATELESS calls —cart.create(), and
checkout.createSession() / checkout.start() given an explicit cartId —
where the caller owns which cart is involved. On the REMEMBERING calls
(cart.ensure(), cart.add(), start() / buyNow() without a cartId) a
storefrontId must match the client’s binding, because those calls reuse
the cart the client remembers, and that cart was created for one campaign:
a different id would be refused by the platform (storefront_mismatch), and
on an unbound client it would leave a campaign-priced cart remembered as the
shop’s ordinary one for thirty days. See assertRememberingCallBinding.
Properties
StorefrontBinding
The binding with the default applied — whatShopkitClient.storefront is.
Properties
TransportRequest
Properties
V2Handoff
Av2 handoff: an ordinary checkout session, plus which checkout answered.
Extends
Properties
VariantOptionGroupState
Properties
VariantOptionValueState
Properties
VariantPriceState
Properties
Type Aliases
AsyncStatus
BuyNowResult
checkout.buyNow() resolves to: the StartCheckoutResult of the
handoff, plus the cart the add produced. cart is the state BEFORE the
shopper pays — the same basket the checkout was started from.
Type Declaration
CartCreateOptions
create() any campaign may
be named; on ensure() / add(), which reuse the remembered cart, a
storefrontId must match the client’s binding — see StorefrontAttribution.
CheckoutFlavour
"v2"— the current Quickbutik checkout. The handoff is a checkout session, and the whole SDK surface applies:getSession, patching,parseReturnUrl, the lot."legacy"— the older checkout. The handoff is an unpaid ORDER, not a session, and the platform creates it for you. See LegacyHandoff for what that costs you.
CheckoutHandoff
POST /v2/checkout/handoff answers with, before the URL is resolved.
Type Declaration
CommerceEventName
<Checkout onEvent>), and because
a GTM container reads it off the dataLayer with no extra configuration.
The string escape hatch is for a storefront’s own events.
ConfirmationOutcome
timeout is not a failure: order creation is
asynchronous and may still land — render “we’re still working on it” rather
than “your payment failed”.
ConfirmationStatus
completed— the order exists.processing_payment— payment authorized, order being created (6–17s).no_attempt— no payment attempt known for this session yet.failed— the payment attempt failed terminally.
ConsentCategory
consentCategories=analytics,marketing) and Google Consent
Mode’s signals all map onto exactly these. A fourth category would be a
non-breaking addition to the union, but nothing downstream would read it
today, so there is none.
necessary is never a choice: the cart id and checkout session id the kit
stores are strictly necessary and need no consent (see SessionStore).
ConsentModeValue
ConsentStatus
undecided— no decision stored for the current revision. Everything optional is treated as denied until the shopper chooses.decided— the shopper chose;analyticsandmarketingsay what.
CookieList
cookies().getAll() returns.
CountryCode
CurrencyCode
CustomerType
EmbeddedCheckoutErrorCode
error event can carry.
All of them come from the frame today. The host raises none of its own: the
one failure it can notice by itself — a frame that never answers — is not an
error to the shopper but a reason to open the hosted checkout instead, so it
travels as a fallback (see EmbeddedCheckoutFallbackReason).
EmbeddedCheckoutEventType
EmbeddedCheckoutFallbackReason
legacy— the shop runs the legacy PHP checkout, which is not embeddable and will not be made so.no-embed-url— the platform returned no embed URL for a v2 session.no-top-navigation— this page cannot navigate its own top window (it is itself inside a sandboxed builder preview), so a redirect payment method could never break out of the frame.handshake-timeout— the frame never saidreadywithin 15 seconds, and has been removed. Almost always aframe-ancestorsrefusal: the page showing the frame is not the origin the session was created for (a wrongembedOrigin,wwwagainst the bare domain, a session resumed on another origin). A kit and a checkout that disagree on the message version look the same from outside. The browser reports either only inside the frame, so this is the host’s one way of noticing.
EmbeddedCheckoutHandler()
Type Parameters
Parameters
Returns
void
EmbeddedCheckoutInit
EmbedErrorCode
HostErrorCode.
EmbedFrameMessage
EmbedHostMessage
EmbedNavigateReason
EmbedRedirectMethod
EmbedStep
FieldStatus
MaybePromise
Type Parameters
MinorUnits
OptionalConsentCategory
ProductCurrency
product.currency
(the client’s chosen currency when the shop offers it, else the shop’s own).
ProductLookup
Type Declaration
ProductSortField
createdAt is catalog order.
RelatedProductsMode
category— products from the same category (the default);specific— a hand-picked list, in the merchant’s order;none— switched off for this product, or not used by the shop.
SchemaAvailability
SeoOptions
SessionDataMap
SessionFieldMap
ShopCurrencyMode
"base"— the shop’s own currency."display"— prices are SHOWN converted; the checkout charges the shop’s currency."charge"— priced AND charged in this currency.
ShopkitRuntime
browser means there is a real window AND a document — the two things
the client-side storage adapters actually need. A worker has neither, so it
is deliberately NOT a browser here even though it runs client-side code.
ShopkitScope
StartCheckoutResult
url is present on both arms, so a “Checkout” button that only navigates
needs no branching at all — and both arms return the shopper to
<successUrl origin>/success/<orderNumber> after paying, so neither does the
thank-you page. Branch on checkout when the difference matters — chiefly
that a legacy handoff has no session to read or patch, and confirms by
legacyOrderUuid. See CheckoutFlavour and LegacyHandoff.
Type Declaration
StoragePreference
"auto"(default) — in a browser: cookies when writable, elselocalStorage, else memory. On a server: thecookiesaccessor when one was supplied, else memory. Cookies win overlocalStoragein the browser on purpose: they are the only client-side store the SERVER can also read, which is what makes an RSC/SSR page see the same cart the browser has."cookie"/"localStorage"/"memory"— force one.- a
StorageAdapter— bring your own (Redis, KV, signed cookie, …).
StorefrontRefusal
details.reason beside the error message.
storefront_not_live(409) — the campaign is not open right now.effectiveStatesays why:paused,expired,coming_soon(or, exceptionally,draft/archived). Show the campaign-closed treatment; there is nothing for the shopper to fix.storefront_quantity_limit(409) — the cart asks for more of a campaign line than the merchant allows.limitTypedecides the recovery:per_ordermeans “reduce the quantity to at mostmaxQuantity”,poolmeans the campaign’s dedicated stock is down tomaxQuantity(possibly 0 — sold out).productIdis the prefixed id (prod_123) of the line.storefront_mismatch(400) — the checkout named one campaign (storefrontId) but the cart was created for another (cartStorefrontId). A programming error, not a shopper condition: bind the client to the campaign, or check out a cart created for it.
StorefrontSurface
SuccessMode
"redirect"— the default. After payment the hosted checkout sends the shopper to<successUrl origin>/success/<orderNumber>; your thank-you page confirms the order withconfirmation()/pollConfirmation()."inline"— the hosted checkout renders the order confirmation itself and never redirects.successUrlis optional;parseReturnUrl()never fires; the storefront learns of completion only by polling the confirmation.backUrlis what brings the shopper home — set it.
successMode on the session, the
session snapshot and the confirmation. A platform without inline support
rejects a session that has no successUrl with a 400, so keep passing
successUrl until inline mode is verified on your shop.
VariantSelection
Variables
ANALYTICS_SCRIPT_ATTR
CHECKOUT_SESSION_PARAM
CHECKOUT_SHOP_PARAM
/embed/{storeId}/{sessionId} with no storage
at all.
CONSENT_EVENT
document after every decision.
CONSENT_LABEL_LANGUAGES
CONSENT_STYLE_ID
<ConsentBanner> and
<qb-consent-banner> so one set of rules (and one set of custom
properties) styles both.
Three rules about how it gets along with a site’s own CSS:
- Everything sits in
@layer qb-consent. Unlayered styles beat layered ones whatever their specificity, so any rule a site writes for a.qb-consent*class wins without!importantor a longer selector. - The knobs are custom properties, read with a fallback, so setting one on
:root(or on the banner) is enough:--qb-consent-bg,-fg,-muted,-border,-accent,-accent-fg,-radius,-button-radius,-font,-font-size,-padding,-gap,-offset,-max-width,-shadow,-focus,-z-index. The built-in colours followprefers-color-scheme; a colour you set applies in both schemes. - It only matches the default markup, and not when that markup carries
qb-consent--unstyled(theunstyledprop / attribute), so a page that wants none of it gets none of it.
CONSENT_STYLES
CONSENT_UPDATE_EVENT
DEFAULT_API_URL
apiUrl is omitted.
This is the storefront half of the platform API: it answers CORS preflights
for any origin and accepts publishable keys only, so a browser can call it
straight from the shop’s own domain with no proxy in between. The merchant
API — personal access tokens, admin scopes, no wildcard CORS — is a separate
host, https://api.quickbutik.com, and is not what this SDK talks to.
DEFAULT_CHECKOUT_URL
checkoutUrl is
omitted.
Up to 1.1.0 this named checkout.quickbutik.com, which is the LEGACY
checkout — a different application that reads the last path segment as an
order id, not a checkout session id, so every URL built from it answered
“we couldn’t find it”. Shops on the legacy checkout are no longer served by
guessing a host at all: checkout.start() asks the platform, which knows
which checkout the shop runs and returns the matching URL. This constant is
only the last-resort fallback for the checkout-v2 flavour.
DEFAULT_CONSENT_COOKIE
cc_cookie): the
two cookies never share a hostname, and this one carries the revision and
the timestamp a compliance review asks for.
DEFAULT_CONSENT_MAX_AGE_DAYS
DEFAULT_CONSENT_REVISION
DEFAULT_SHOPKIT_SCOPES
create-token.ts --type publishable), minus storefront:read.
DEFAULT_STOREFRONT_SURFACE
EMBED_MESSAGE_SOURCE
qb-checkout-preview on purpose: the
preview is a render target with no session and no network, the embed is the
real checkout taking real money, and a message meant for one must never be
readable as a message for the other.
EMBED_MESSAGE_VERSION
handshake-timeout fallback after 15 seconds, which takes
the frame down and opens the hosted checkout — rather than to a misread
payload.
PUBLISHABLE_KEY_PREFIX
SHOPKIT_SCOPES
services/gateway/src/config/scopes.ts. Only this subset is
reachable with an actorType: 'storefront' credential — the write scopes for
products, orders and customers are merchant-only by design and a publishable
key presenting them is rejected at the gateway.
Type Declaration
STOREFRONT_ID_PATTERN
sf_ + 26 characters of Crockford base32 (no I, L, O, U). Case-insensitive:
the platform accepts either case and stores one canonical spelling.
STOREFRONT_SURFACES
hosted— the campaign’s own page on the shop’s domain.link— a short or shared link that lands on the campaign.embed— rendered inside a third-party page (iframe / script embed).shopkit— inside a storefront built on this SDK. The default here.agentic— reached by an AI agent acting for the shopper.
SUCCESS_MODES
Functions
absoluteUrl()
<link rel="canonical"> is worse than none, because it resolves
against whatever URL the crawler happens to be on.
Parameters
Returns
string | undefined
appendCheckoutHandoffParams()
consentCategories=analytics,marketing, gaClientId,
gaSessionId. The checkout reads them on arrival and sets Consent Mode
before any tag loads.
An undecided shopper is reported as consentCategories= (present, empty):
a signal that nothing was granted, so the checkout runs denied. Only
requireConsent: false omits the parameter, which makes the checkout track
ungated. The legacy hosted checkout ignores these parameters.
Idempotent: applying it twice leaves the URL the second call describes, so
a URL a server client already decorated can be decorated again in the
browser without stacking or contradicting itself.
Returns the URL untouched when it cannot be parsed.
Parameters
Returns
string
applyImageTransform()
Parameters
Returns
string
applyTitleTemplate()
%s is the page title; the default appends the
site name, and a page whose title already IS the site name is left alone so
the homepage does not read “Min butik · Min butik”.
Parameters
Returns
string
bareProductId()
"prod_27" → "27"; a number passes through as its string.
Parameters
Returns
string
breadcrumbJsonLd()
BreadcrumbList.
Positions are 1-based and must be contiguous, so entries without a name are
dropped before numbering rather than leaving a hole.
Parameters
Returns
Record<string, unknown> | undefined
buildImageSrcSet()
srcSet for one image, or null when there is nothing to build one from.
Density descriptors (the default) are right for an image rendered at a fixed
CSS size — a thumbnail, a card at a known column width. Width descriptors
plus sizes are right for one that reflows with the viewport.
Parameters
Returns
string | null
buildPriceState()
Parameters
Returns
VariantPriceState
buildSeo()
<head>, from Quickbutik’s own data.
Prefers what the merchant wrote — seoTitle / seoDescription are fields
they filled in for exactly this purpose and are otherwise invisible to a
headless storefront — and falls back to the product name and description.
Parameters
Returns
SeoTags
buildVariantMatrix()
Parameters
Returns
VariantOptionGroupState[]
canNavigateTopWindow()
- this page IS the top window (the normal case) — yes;
- it is framed by a document it can reach (same origin) — yes, and reading
top.location.hrefproves it; - it is framed cross-origin, or sandboxed without
allow-top-navigation— the read throwsSecurityError, and a sandboxed frame could not navigate even if it could read.
hasLocalStorage above: the property
exists in every case, and only touching it tells you the truth.
Returns
boolean
cartLineDiff()
after: null) yields every line as removed.
Parameters
Returns
CartLineDiff
clearConsentCookie()
Parameters
Returns
void
clearOptionValue()
Parameters
Returns
VariantSelection
clearProductCache()
WeakMap and
cannot be enumerated, so a “clear everything” call would have to be a silent
no-op.
Parameters
Returns
void
clearShopCache()
Parameters
Returns
void
consentCategoriesParam()
consentCategories value the hosted checkout reads off its URL.
Three answers, and they mean different things to the checkout:
null— no consent signal at all. The checkout tracks ungated, exactly as it does for a hosted shop without the consent app. Only for a storefront that has opted out of consent (requireConsent: false).""— a signal, with nothing granted. Undecided is reported this way: the checkout must not track a shopper who has not said yes."analytics,marketing"— the granted subset.
Parameters
Returns
string | null
consentLabels()
lang is a BCP 47 tag or a bare code; only the primary subtag matters
(sv-SE → sv), Norwegian’s no/nn fold into nb, and anything
unknown falls back to English. Left out, it is read from <html lang> in a
browser, so a storefront that already sets its document language gets the
right copy for free.
Parameters
Returns
ConsentLabels
consentModeSignals()
Parameters
Returns
ConsentModeSignals
consumeReturnedSessionId()
ready before
deciding the return leg is over. The kit’s own surfaces no longer use it:
<qb-checkout> and <Checkout> read with readReturnedCheckout on
load and call stripReturnedSessionId from their ready handler, so a
resume that fails before the frame answers leaves the parameters — and the
reload that follows something to resume. Prefer that order.
Not idempotent on purpose: the second call returns null. Hold the value
rather than calling it again. Returns the session id alone, as it always
has; read the shop id with readReturnedCheckout BEFORE calling this.
Returns
string | null
createCookieStorage()
Parameters
Returns
StorageAdapter
createDocumentCookieStorage()
document.cookie. Browser-only; readable by the server on the next request.
Parameters
Returns
StorageAdapter
createLocalStorage()
window.localStorage, with every access guarded (see hasLocalStorage).
Returns
StorageAdapter
createMemoryStorage()
Returns
StorageAdapter
createRequestCookieStorage()
Request (or any Headers), optionally
collecting writes as Set-Cookie strings for the caller to attach to its
response. Framework-free — the fit for Astro endpoints, TanStack Start
server functions, plain fetch handlers and Workers.
Parameters
Returns
StorageAdapter
createScopeGuard()
scopes: null turns enforcement off — useful when the key’s scopes
are decided by an admin and the app genuinely does not know them. The gateway
still enforces; all that is lost is the friendly local error.
Parameters
Returns
ScopeGuard
createShopkitClient()
Parameters
Returns
ShopkitClient
currencyDecimals()
Parameters
Returns
number
deleteDocumentCookie()
document.cookie. No-op outside a browser.
Parameters
Returns
void
describeCurrency()
Parameters
Returns
CurrencyInfo
destinationsFromShop()
metaCapiEnabled is informational here: the Conversions API is
sent by the platform for the hosted checkout’s own events, not from a
storefront.
Parameters
Returns
AnalyticsDestination[]
detectRuntime()
Returns
ShopkitRuntime
firstAvailableVariant()
Parameters
Returns
ProductVariant | null
formatMoney()
{ amount, currency } and the app formats it however its design system
says. HTML bindings have no such escape — data-qb-text="price.formatted"
needs a string — so the elements layer must be able to produce one, and this
is it.
Parameters
Returns
string
formatMoneyRange()
VariantPriceState reports min, max and
isRange, and every storefront then writes the same three-branch formatter.
Parameters
Returns
string | null
formatSchemaPrice()
"99.00").
A string, not a number: price in schema.org is text, and a float would
reintroduce exactly the rounding error minor units exist to avoid.
Parameters
Returns
string
getOptionGroups()
product.options is optional on the wire, so the groups are reconstructed
from the variants’ own option values when it is absent — otherwise a product
that omits the top-level list would render no picker at all.
Parameters
Returns
ProductOptionType[]
getProductPromise()
Parameters
Returns
Promise<Product | null>
getShopPromise()
Parameters
Returns
Promise<Shop>
googleTagDestination()
gtag and one
dataLayer. Consent Mode v2 is set up BEFORE any script is injected: a
denied default with wait_for_update, then — when the shopper has
already decided — an update straight after. The pair matters: a
merchant’s own GTM container ships region-scoped consent defaults applied
at container init, and a default never outranks another default, so a
lone granted default would be silently discarded and every Google tag
would run cookieless. Only an update outranks a default.
Events: with a GA4 measurement id (or an Ads id) they go through
gtag('event', …), which a GTM container on the same page also sees. With
a container ONLY, they are pushed as { event, ecommerce } with the GA4
ecommerce: null reset in between. Never both — a container that hosts a
GA4 tag would otherwise count every event twice.
Parameters
Returns
AnalyticsDestination
hasDocumentCookies()
document.cookie is readable/writable — the browser half of the
cookie story. The server half needs an injected accessor (see
createCookieStorage), because there is no ambient request to read from.
Returns
boolean
hasLocalStorage()
localStorage is present AND usable. Presence alone is not
enough: Safari private mode and “block all cookies” both expose the object
and throw on write, and an iframe on a partitioned origin throws on mere
access. The probe is the only reliable answer.
Returns
boolean
injectConsentStyles()
<head>, once per document. A
no-op outside a browser and when it is already there. The React banner
does not need this (it renders the same rules as a hoisted <style>, so
they are in the server HTML too); it is for <qb-consent-banner> and for
a page of your own that reuses the default class names.
Parameters
Returns
void
injectScript()
<head>, once per src for the lifetime of the
page. A second call for the same URL — from a second hub, a re-configure,
a React StrictMode double effect — is a no-op; so is a call outside a
browser. The tag is async and carries data-qb-analytics="<id>".
The CSP consequence is the storefront’s to carry: a page with a
script-src must allow the vendor hosts it opts into (see the consent and
analytics guide). The kit never evaluates strings.
Parameters
Returns
HTMLScriptElement | null
isBrowser()
typeof on purpose: bundlers targeting server runtimes replace
window with nothing at all rather than undefined, so a bare reference
throws instead of returning false.
Returns
boolean
isSafeNavigationUrl()
url in the contract — navigate.url, redirect.url — is checked on
both sides before any navigation, and this is the host’s copy of that
check. Not defence in depth for its own sake: the frame validates what it
sends, but the host is the party that actually performs the navigation, and
it is the one holding the merchant’s origin. A javascript: URL handed to
location.assign executes in THIS document — the merchant’s page, with the
merchant’s cookies — so the check has to live where the navigation does.
https: only, with http: allowed for loopback so a rig and a vite dev
page work. Relative URLs are rejected rather than resolved: the contract says
absolute, and resolving an attacker-chosen path against the host page is a
more surprising outcome than dropping the message.
This must agree with the frame’s copy EXACTLY, down to which hostnames count
as loopback. A host that is stricter than the frame does not fail loudly — it
drops a message the frame was happy to send, and a dropped message makes no
sound at all. That lands on a developer running their storefront on
http://app.localhost:5173, in local development, where the redirect
break-out is the least likely thing to be exercised by hand. So the function
below is a port of isLoopbackHostname in the frame’s embed-messages.ts,
not an equivalent of it.
Parameters
Returns
value is string
isStorefrontId()
Parameters
Returns
value is string
isStorefrontSurface()
Parameters
Returns
value is “embed” | “link” | “hosted” | “shopkit” | “agentic”itemFromCartLine()
Parameters
Returns
CommerceItem
itemFromProduct()
Parameters
Returns
CommerceItem
itemsFromCart()
Parameters
Returns
CommerceItem[]
itemsFromCheckoutProducts()
data.cart_products) as GA4 items.
Parameters
Returns
CommerceItem[]
itemsParams()
{ currency, value, items } for a set of items — the shape of every cart event.
Parameters
Returns
CommerceEventParams
metaPixelDestination()
marketing: nothing — not the script, not
PageView — happens before the shopper grants it, and nothing more is
sent after they withdraw it. The event names are Meta’s standard events,
mapped from the GA4 vocabulary the way the hosted storefront maps them:
Meta’s own consent API follows the decision:
fbq("consent", "grant")
before init, and revoke / grant on every later change, so a
withdrawal also stops the pixel’s cookies, not just the kit’s events.
remove_from_cart and the shipping step have no Meta equivalent and are
dropped. The purchase eventID is purchase_{storeId}_{orderNumber}, the
id the platform’s own server-side events use, so Meta merges them; with no
store id known the Purchase carries no eventID at all.
Parameters
Returns
AnalyticsDestination
normalizeApiUrl()
/v2. Every request path in this SDK
carries its own /v2 prefix, so an apiUrl that already ends in /v2 would
otherwise produce /v2/v2/... and 404 — a mistake operators make often
enough that the platform’s own checkout normalizes for it too.
Parameters
Returns
string
normalizeCurrency()
"eur" / " EUR " → "EUR"; null, undefined and "" → null.
Throws a ShopkitConfigError for anything that is not three letters: the
platform rejects a malformed code with a 400, and a typo in a config is
better reported here, by name, than as a failed product grid.
Parameters
Returns
string | null
organizationJsonLd()
Organization — the shop itself, for the knowledge panel.
Parameters
Returns
Record<string, unknown>
parseConsentCookieValue()
Parameters
Returns
ConsentState
parseCookieHeader()
Cookie: header (or document.cookie) into a plain record.
Parameters
Returns
Record<string, string>
parseEmbedFrameMessage()
MessageEvent.data as a frame message, or return null.
Null for anything that is not ours, anything whose envelope version we do not
implement, and anything whose payload does not hold up — a navigate with no
safe URL, a height that is not a number. The caller has already checked the
sender’s origin and window; this checks the content, and the two together are
the whole trust boundary.
Parameters
Returns
EmbedFrameMessage | null
parsePublishableKey()
qb_pk_<shopPrefix>_<random> into its parts.
The platform mints publishable keys with the shop’s storage prefix in the
third segment — the same value it uses in CDN paths — never the numeric shop
id. A prefix may not contain _ (token minting enforces this, because _
is the field delimiter), so it is exactly the third segment.
Parameters
Returns
ParsedPublishableKey
pickProductImage()
position is the merchant’s ordering and is nullable, so this sorts by it
with nulls last and falls back to the array’s own order — the same ordering
the merchant sees in the admin.
Parameters
Returns
ProductImage | null
plainText()
<meta> would put stray angle brackets in the snippet.
Parameters
Returns
string | undefined
productAvailability()
Parameters
Returns
SchemaAvailability
productImages()
Parameters
Returns
ProductImage[]
productJsonLd()
Product, the part that actually earns a rich result.
Price and availability go in an Offer for a single-priced product and an
AggregateOffer when the variants differ — Google reads both, and an
AggregateOffer is the honest shape for “from 99 kr”. Offers are omitted
entirely when no currency is known, because priceCurrency is required and
guessing it would publish a wrong price.
Parameters
Returns
Record<string, unknown>
purchaseDedupKey()
qb_purchase_tracked_{storeId}_{orderNumber} — the localStorage key the
hosted storefront’s success page and the hosted checkout’s inline
confirmation also write, so no surface reports an order another already
reported in this browser.
Parameters
Returns
string
purchaseEventId()
purchase_{storeId}_{orderNumber} — the platform’s Meta eventID for an order.
Parameters
Returns
string
purchaseFromSession()
trackPurchase itself.
Parameters
Returns
PurchaseEvent | null
purchaseToEvent()
track can take.
Parameters
Returns
CommerceEvent
readConsentCookie()
Cookie: header (or document.cookie). The
server-side entry point: readConsentCookie(request.headers.get("cookie"))
in a route handler, readConsentCookie(cookies().toString()) in Next.
Parameters
Returns
ConsentState
readDocumentCookie()
document.cookie. Returns null outside a browser.
Parameters
Returns
string | null
readGaCookies()
Parameters
Returns
GaLink
readReturnedCheckout()
window: the page that renders the return can
decide server-side whether to render a checkout, and with which ids.
Read-only: nothing is consumed, so it is safe to call during a render or
from a framework’s router. The shop id is checked, not trusted: store ids are
integers, and a query string is writable by anyone, so anything else reads as
“not carried” rather than as a store id.
Parameters
Returns
ReturnedCheckout | null
readReturnedSessionId()
checkout.resume().
Returns
string | null
redactKey()
Parameters
Returns
string
resolveCategoryImageUrl()
<img src> for a category’s cover image, or null when it has none.
Same shape as resolveProductImageUrl: imageUrl is absolute and
preferred, image is the bare filename kept for backwards compatibility.
Parameters
Returns
string | null
resolveConfig()
Parameters
Returns
ResolvedShopkitConfig
resolveLanguage()
Parameters
Returns
string
resolveProductImageUrl()
<img src> for one product image, or null when there is nothing to show.
Parameters
Returns
string | null
resolveStorage()
Parameters
Returns
StorageAdapter
resolveVariant()
Parameters
Returns
ProductVariant | null
searchEvent()
Parameters
Returns
CommerceEvent
selectionForVariant()
Parameters
Returns
VariantSelection
selectOptionValue()
Parameters
Returns
VariantSelection
serializeConsentState()
clearConsentCookie is how “undecided” is written.
Parameters
Returns
string
serializeCookie()
Set-Cookie value.
Parameters
Returns
string
serializeJsonLd()
<script type="application/ld+json">.
Every < becomes \u003c, which is what stops a merchant-authored product
name containing </script> from closing the tag and turning shop content into
executable markup. A JSON parser reads the escape identically, so nothing is
lost by being paranoid here.
Parameters
Returns
string
storefrontRefusal()
null when it
is something else — a network error, a 404, an ordinary 409 (an out-of-stock
line, say).
details.reason, not on the HTTP status, so the decoder does not
have to know which status each reason travels on.
Parameters
Returns
StorefrontRefusal | null
stripReturnedSessionId()
ready — not on the pass that starts the resume — because a resume can
fail before the frame ever answers: a document the browser refused, a store
id nobody could supply, a handshake that timed out into the hosted checkout.
With the parameters gone, a reload of that page would find no return leg and
take the mount() branch; with them still there, the reload resumes again.
The platform hands the same cart the same session back either way, so
neither path can produce a second order — this is about a reload landing the
shopper back in the checkout they paid in, not on a fresh one.
replaceState, not pushState — the parameters were never a place in
anyone’s history. A no-op when neither is present, so it is safe on every
ready a frame sends, reloads included.
Returns
void
toMajorUnits()
9900 SEK → 99, 990 JPY → 990).
What GA4, Meta and every other analytics vendor want value and price
in. Rounded to the currency’s own decimals so the float that comes out is
the shortest exact representation (12.34, never 12.340000000000002).
Without a currency two decimals are assumed, which is right for every
currency the platform sells in by default.
Parameters
Returns
number
toNextMetadata()
generateMetadata export.
Metadata has no slot for a
<script type="application/ld+json">, so the jsonLd array has to be
rendered in the page — <JsonLd data={tags.jsonLd} /> does it. Since that is
where the rich-result value lives, it is the half not to forget; using
<SEO /> instead emits both.
Parameters
Returns
NextLikeMetadata
undecidedConsent()
Parameters
Returns
ConsentState
unwrapEnvelope()
{ data, message, statusCode } wrapper when present.
Detection is structural rather than per-route on purpose: the gateway unwraps
on some routes and forwards the envelope on others, and which is which has
changed over time. A payload is treated as an envelope only when it has a
data key alongside statusCode/message and nothing else of substance —
so a genuine resource that happens to own a data field is never unwrapped,
and neither is a paginated { data, has_more, next_cursor } collection.
Type Parameters
Parameters
Returns
T
variantAvailability()
stock: null means the shop does not track inventory for it — the same signal
the variant picker treats as purchasable. Reporting OutOfStock there would
hide every product of every non-tracking shop from rich results, so null is
InStock. preorder wins when set, because a shopper can order it but it has
not shipped.
Parameters
Returns
SchemaAvailability
variantMatchesSelection()
variant carries every (optionId → valueId) pair in selection.
Parameters
Returns
boolean
viewItemEvent()
Parameters
Returns
CommerceEvent
viewItemListEvent()
Parameters
Returns
CommerceEvent
writeConsentCookie()
document.cookie. No-op outside a browser.
Parameters
Returns
void
writeDocumentCookie()
document.cookie. No-op outside a browser.
Parameters
Returns
void