Cart adapters
Choose between the shipped Brink and mock cart adapters, or implement a custom CartAdapter, while keeping cart ownership at the app boundary.
Use this guide when the React SDK shell needs live cart behavior instead of visual-only commerce components.
The adapter entry points and the Brink factory fields shown in this guide are verified from SDK package reference for the current docs track. Exact normalized cart types, deeper runtime behavior, and backend-specific implementation details still belong to package reference. This guide covers the public integration boundary: what the SDK owns, what the adapter owns, and how to choose between the shipped adapter paths.
What a cart adapter owns
The SDK uses a pluggable cart boundary. EnadProvider accepts a cartAdapter, and cart-aware SDK components or hooks consume that normalized interface.
That split is intentional:
- the SDK owns cart UI, composition guidance, and normalized cart-facing types.
- the adapter owns backend calls, cart-session mechanics, and response mapping.
- the app owns which adapter is chosen, when it is created, and how it fits the broader storefront runtime.
Keep cart setup at the app shell. Do not create backend clients inside CartDrawer, CartTrigger, CartSummary, or product-card presentation code.
The three adapter choices
| Choice | Best fit | App still owns |
|---|---|---|
| Brink cart adapter | Live Brink Commerce shopper carts. | Runtime config selection, shopper country/language/store-group identity, and where checkout handoff lives. |
| Mock cart adapter | Development, demos, isolated UI testing, and early composition work. | Seed data, delay tuning, and when to replace the mock with a live backend. |
Custom CartAdapter | Any non-Brink or app-specific commerce backend. | The backend contract, mapping layer, session policy, and any extra checkout/business flows. |
Use the Brink cart adapter for live Brink sessions
The package ships a Brink-specific cart adapter entry point for live storefront cart behavior.
For this docs track, the example below uses the current verified public Brink adapter factory fields.
import { EnadProvider } from "@enadhq/enad-react-sdk";
import { createBrinkCartAdapter } from "@enadhq/enad-react-sdk/client/cart/brink-adapter";
const cartAdapter = createBrinkCartAdapter({
env: shopper.brinkEnv,
storeGroupId: shopper.storeGroupId,
countryCode: shopper.countryCode,
languageCode: shopper.languageCode,
});
export function AppShell({ children }: { children: React.ReactNode }) {
return <EnadProvider cartAdapter={cartAdapter}>{children}</EnadProvider>;
}Use the Brink adapter when the app already owns real Brink shopper context and wants SDK cart surfaces to operate against that live cart session.
Keep these responsibilities in the application layer even when using the shipped Brink adapter:
- resolving the active Brink environment.
- choosing the correct store group, country, and language per shopper context.
- deciding where checkout or cart-page routes live.
- handling any broader analytics or business-policy side effects around cart events.
The adapter itself should stay the cart backend boundary, not the home of general storefront orchestration.
Use the mock cart adapter for development and visual work
The mock adapter is the safest starting point when the shell or cart UI still needs local iteration.
import { createMockCartAdapter } from "@enadhq/enad-react-sdk/client/cart/mock-adapter";
const cartAdapter = createMockCartAdapter({ delay: 200 });Use it when you want to:
- validate cart-aware layouts without waiting for backend integration.
- demo drawer, summary, or quantity flows locally.
- seed development states before a live commerce backend is ready.
- keep early UI work moving while the real backend contract is still owned elsewhere.
Treat the mock adapter as a temporary integration surface. It is great for composition and testing, but it should not become a disguised production dependency.
Write a custom adapter when the backend is not Brink
If the app uses another commerce backend, implement the SDK's CartAdapter seam and keep backend-specific details behind it.
import type { CartAdapter } from "@enadhq/enad-react-sdk/client/cart";
const cartAdapter: CartAdapter = {
getCart: async () => {
// fetch or create the current cart session
},
addItem: async (productVariantId, quantity) => {
// add a line item and return the normalized cart
},
updateItem: async (itemId, quantity) => {
// update a line item and return the normalized cart
},
removeItem: async (itemId) => {
// remove a line item and return the normalized cart
},
};When writing a custom adapter:
- return normalized SDK cart objects rather than raw backend payloads.
- keep backend-specific fields in adapter-owned mapping or metadata instead of teaching SDK components a second schema.
- own cart session mechanics inside the adapter rather than in UI components.
- keep checkout, payment, and fulfillment workflows in app- or backend-owned layers unless the cart interface explicitly owns them.
A good custom adapter makes the rest of the app simpler: cart UI sees one stable contract even if the underlying backend is different.
Distinguish shipped adapters from app-owned behavior
The shipped adapters give you a cart boundary, not a full commerce application. The SDK does not decide:
- how your app chooses the active market or locale.
- how navigation to full cart or checkout routes should work.
- how analytics, promotions, or experimentation wrap cart events.
- how account identity, auth cookies, or other runtime seams are wired.
Those stay app-owned. For the provider-level routing, cookie, and locale seams around cart work, use Runtime adapters.
A good placement rule
Create the adapter once at the app or route shell that owns live storefront runtime, then pass it to EnadProvider.
That keeps cart concerns cleanly separated:
- adapter creation lives with shopper runtime setup.
- cart-aware components focus on rendering and interaction.
- backend-specific cart mechanics stay behind one boundary.
If you find yourself importing cart backend clients directly into presentational components, the adapter seam is in the wrong place.