shopmate-sdk
v1.2.2
Published
Shopmate browser SDK
Maintainers
Readme
ShopMate SDK
Lightweight browser SDK for storefront carts and ShopMate checkout.
Use it to:
- add products to a local browser cart from storefront controls;
- retain cart state in
localStorage; - open ShopMate checkout in a secure cross-origin iframe;
- receive minimal user-facing notifications plus lifecycle events;
- integrate through npm ESM imports in browser apps or through HTML attributes;
- receive verified checkout lifecycle and order-success events.
The SDK is browser-only at runtime. It can be installed from npm and imported into React, Vite, and other client-side browser bundles, but it must not be executed in Node.js or during server-side rendering because it uses native browser APIs (window, document, URL, URLSearchParams, CustomEvent, localStorage, and iframe).
Installation
npm install shopmate-sdkQuick start
JavaScript, TypeScript, or React client application
import ShopMate from 'shopmate-sdk';
const shopmate = new ShopMate({
orgId: 2,
cartPosition: 'right-bottom',
});
shopmate.extract();new ShopMate(...) creates an instance only. Call extract() after the storefront markup has been rendered.
For React, initialize it from a client-only effect so the SDK runs after the browser has mounted the page:
import { useEffect } from 'react';
import ShopMate from 'shopmate-sdk';
export function Storefront() {
useEffect(() => {
const shopmate = new ShopMate({
orgId: 2,
cartPosition: 'right-bottom',
});
shopmate.extract();
}, []);
return <button data-shopmate-product-id="101">Add to cart</button>;
}Explicit initialization helper
Use initShopMate() when you want the SDK to register itself as window.ShopMateInstance and automatically scan the page when the body is ready.
import { initShopMate } from 'shopmate-sdk';
const shopmate = initShopMate({
orgId: 2,
cartPosition: 'right-bottom',
onOrderSuccess: ({ payload }) => {
console.log('Order completed:', payload);
},
});Plain script tag
<script
src="https://cdn.jsdelivr.net/npm/shopmate-sdk@latest/shopmate-sdk.min.js"
data-org-id="2"
data-cart-position="right-bottom"
></script>The browser bundle exposes:
window.ShopMate;
window.initShopMate;
window.ShopMateInstance;When the script is loaded through a normal <script src="..."> tag with data-org-id, it initializes after the page load event and scans the document automatically.
Smallest storefront integration
<button data-shopmate-product-id="101" data-shopmate-quantity="1">
Add to cart
</button>
<button data-shopmate-checkout="true">
Checkout
</button>
<script
src="https://cdn.jsdelivr.net/npm/shopmate-sdk@latest/shopmate-sdk.min.js"
data-org-id="2"
data-cart-position="right-bottom"
></script>The floating cart button uses 🛒; the checkout modal close button uses ✕.
Supported storefront markup
Add a product
<button data-shopmate-product-id="101" data-shopmate-quantity="1">
Add to cart
</button>Supported attributes:
data-shopmate-product-id— positive numeric product ID; required.data-shopmate-quantity— positive integer quantity; optional, defaults to1.data-shopmate-coupon-id— optional coupon applied before adding the product.
Calling the same product trigger again increments its existing cart quantity. The SDK caps a product quantity at 999.
Apply or clear a coupon
<button data-shopmate-coupon-id="WELCOME10">
Apply coupon
</button>Coupon-only triggers must not also have data-shopmate-product-id.
Open checkout
<button data-shopmate-checkout="true">
Checkout
</button>URL-based checkout trigger
<a href="https://shopmate.hoshonto.com/api/v1/pub/checkout?pid=101,102">
Checkout now
</a>For URL triggers, ShopMate supports:
pid=101,102— adds each listed product with quantity1;couponId=WELCOME10— applies a coupon;c=<JSON cart>— imports a cart payload such as{"i":[{"i":101,"q":2}]}.
For c, use URL encoding when constructing the link manually. Prefer URLSearchParams rather than string concatenation.
Configuration
const shopmate = new ShopMate({
orgId: 2,
baseUrl: 'https://shopmate.hoshonto.com',
checkoutPath: '/api/v1/pub/checkout',
cartPosition: 'right-bottom',
enableFloatingCart: true,
showNotifications: true,
checkoutLoadTimeoutMs: 20_000,
});| Option | Type | Default | Description |
|---|---|---:|---|
| orgId | number | Required | Positive integer organization ID. |
| baseUrl | string | https://shopmate.hoshonto.com | HTTP/HTTPS origin hosting ShopMate APIs and checkout. |
| checkoutPath | string | /api/v1/pub/checkout | Checkout iframe route. |
| cartPosition | ShopMateCartPosition | right-bottom | Floating cart location. |
| storageKey | string \| (orgId) => string | shopmate:cart:${orgId} | Cart storage-key override. |
| enableFloatingCart | boolean | true | Renders the floating 🛒 cart control. |
| autoExtract | boolean | true | Used by initShopMate() and browser auto-init to scan the page when ready. |
| selectors | object | See below | Custom product, checkout, and URL checkout selectors. |
| labels | object | See below | Accessible labels and checkout copy. |
| theme | object | See below | UI colors, radius, and stacking level. |
| showNotifications | boolean | true | Shows minimal SDK toast notifications. Events and callbacks still run when false. |
| notificationDurationMs | number | 4500 | Default visible duration for toast notifications. |
| checkoutLoadTimeoutMs | number | 20000 | Iframe load timeout before a retry notification is shown. |
| onNotify | (notification) => void | — | Receives every SDK status notification. |
| onWarn | (warning) => void | — | Receives recoverable SDK warnings. |
| onOrderSuccess | (event) => void | — | Receives verified order-success events from checkout. |
Cart positions
left-top top right-top
left-center center right-center
left-bottom bottom right-bottomselectors
selectors: {
product: '[data-shopmate-product-id]',
checkout: '[data-shopmate-checkout="true"]',
checkoutLink: 'https://shopmate.hoshonto.com/api/v1/pub/checkout?',
}labels
labels: {
floatingCartAriaLabel: 'Open ShopMate checkout',
closeCheckout: 'Close checkout',
openingCheckout: 'Opening checkout...',
}theme
theme: {
primaryColor: '#2563eb',
accentColor: '#0f766e',
dangerColor: '#ef4444',
textColor: '#0f172a',
surfaceColor: '#ffffff',
overlayColor: 'rgba(15,23,42,.62)',
borderRadius: '22px',
zIndex: 2147483647,
}Public API
extract(rootElement?: HTMLElement): void
Scans the supplied element, or document.body, and attaches click handlers to supported storefront triggers. Calling it more than once is safe; the SDK does not attach duplicate handlers to previously processed elements.
shopmate.extract();
shopmate.extract(document.querySelector('#product-list'));addToCart(itemId: number, quantity?: number, element?: HTMLElement): boolean
Adds quantity to an existing product or creates a cart item. Returns false for invalid values, unavailable SDK state, or the maximum distinct-item limit.
shopmate.addToCart(101, 2);The cart allows up to 100 distinct products and up to 999 units per product.
setCartItemQuantity(itemId: number, quantity: number): boolean
Sets an absolute quantity for an item. Use 0 to remove it.
shopmate.setCartItemQuantity(101, 3);
shopmate.setCartItemQuantity(101, 0);setCoupon(couponId?: string | null): void
Applies a coupon. Pass null, undefined, or an empty string to clear it.
shopmate.setCoupon('WELCOME10');
shopmate.setCoupon(null);getCart(): ShopMateCart
Returns an isolated copy of the cart.
const cart = shopmate.getCart();
// { i: [{ i: 101, q: 2 }], couponId: 'WELCOME10' }getCartStorageKey(): string
Returns the active cart localStorage key.
shopmate.getCartStorageKey();
// shopmate:cart:2getCheckoutQuery(nextUrl?: string): ShopMateCheckoutQuery
Returns the current checkout query contract:
{
orgId: '2',
c: '{"i":[{"i":101,"q":2}]}',
next: 'https://storefront.example/cart',
}buildCheckoutUrl(nextUrl?: string): string
Builds the checkout iframe URL. Returns an empty string and reports a notification when URL construction fails or exceeds the 8,000-character safety limit.
openCheckout(buttonElement?: HTMLElement): boolean
Builds and opens the checkout iframe. It shows a processing state on the supplied button and returns false when checkout cannot be opened.
shopmate.openCheckout(document.querySelector('#checkout-button'));The SDK adds only the fullscreen checkout container and close button. Authentication, payment methods, customer account state, and checkout content are handled inside the iframe.
closeCheckout(showNotification = true): void
Closes the iframe, clears the iframe src, restores page scrolling, and optionally shows a close notification.
createCheckoutIframe(): HTMLIFrameElement
Creates the checkout iframe with the required sandbox and payment permissions. This is an advanced API; normal integrations should call openCheckout().
runWhenBodyReady(action: () => void): void
Runs a DOM operation immediately when document.body exists, otherwise after DOMContentLoaded.
initShopMate(config): ShopMate
Creates an instance, assigns it to window.ShopMateInstance, and runs extract() when autoExtract is not false.
Notifications and error handling
ShopMate keeps visible notifications minimal and professional. The SDK still emits every lifecycle notification through callbacks and browser events, but built-in toast UI is reserved for user-impacting states.
Built-in toast UI is shown for:
- invalid configuration;
- cart and storage warnings;
- cart addition and coupon updates;
- checkout failures;
- order success.
Checkout opening, opened, ready, and closed states are still emitted to onNotify and shopmate:notification; they are not shown as redundant toasts.
const shopmate = initShopMate({
orgId: 2,
onNotify(notification) {
console.log(notification.level, notification.code, notification.message);
},
onWarn(warning) {
console.warn(warning.code, warning.message, warning.cause);
},
});To suppress built-in toast UI but retain callbacks and browser events:
const shopmate = initShopMate({
orgId: 2,
showNotifications: false,
});Callback exceptions are isolated. An exception thrown inside onNotify, onWarn, or onOrderSuccess is logged and does not interrupt core SDK behavior.
Browser events
The SDK dispatches native CustomEvent events on window.
shopmate:notification
Dispatched for every SDK notification. event.detail is a ShopMateNotification.
window.addEventListener('shopmate:notification', (event) => {
console.log(event.detail);
});shopmate:order-success
Dispatched after a verified checkout order-success message. event.detail is:
{
orgId: 2,
cart: { i: [{ i: 101, q: 2 }] },
payload: { /* checkout-provided result */ },
}window.addEventListener('shopmate:order-success', (event) => {
console.log('Order success:', event.detail);
});shopmate:close
Dispatch this event from host code to close the checkout.
window.dispatchEvent(
new CustomEvent('shopmate:close', {
detail: { orgId: 2 },
}),
);If no orgId is supplied, each active ShopMate instance can react to the close event. Provide orgId when more than one instance may exist on a page.
Cross-origin checkout contract
Checkout is intentionally cross-origin. The parent storefront sends cart context in the iframe URL and does not inspect iframe DOM, storage, cookies, or authentication state.
The checkout application is responsible for its own authentication, including any cookies or redirect flow it requires.
The SDK accepts postMessage events only when both conditions are true:
event.originmatches the configuredbaseUrlorigin; andevent.sourceis the currently active checkout iframe window.
Supported checkout messages:
| Message type | Effect |
|---|---|
| closeCheckout or shopmate:close | Closes checkout. |
| shopmate:checkout-loading or shopmate:loading | Emits a processing notification. |
| shopmate:checkout-ready or shopmate:ready | Marks checkout ready and clears the load timeout. |
| shopmate:checkout-error or shopmate:error | Shows an error notification and retry action. |
| shopmate:order-success, shopmate:orderSuccess, or orderSuccess | Clears the cart, closes checkout, and emits order success. |
Checkout-frame example
The checkout application must send messages to the exact, allowlisted storefront origin. Do not derive this origin from untrusted request values.
const storefrontOrigin = 'https://storefront.example';
function notifyParent(type: string, payload?: unknown) {
if (window.parent !== window) {
window.parent.postMessage({ type, payload }, storefrontOrigin);
}
}
notifyParent('shopmate:checkout-loading');
try {
await initializeCheckout();
notifyParent('shopmate:checkout-ready');
} catch (error) {
notifyParent('shopmate:checkout-error', {
code: 'CHECKOUT_INITIALIZATION_FAILED',
});
}After order creation:
notifyParent('shopmate:order-success', {
orderId: createdOrder.id,
});Security requirements
The SDK cart payload is convenience state, not a trusted order record. The checkout backend must validate all client-provided values.
The backend must:
- verify that every product exists, is active, and belongs to
orgId; - recalculate prices, discounts, taxes, delivery charges, inventory, and totals server-side;
- validate coupon eligibility and usage server-side;
- validate and constrain quantities server-side;
- validate
nextagainst a strict redirect allowlist before redirecting; - treat
c,pid,couponId, and all URL query values as untrusted input; - use short-lived, server-side checkout sessions when cart URLs can become large or sensitive.
Do not expose credentials, privileged API keys, or trusted pricing data in cart URLs.
Script-tag attributes
The browser bundle supports these attributes:
<script
src="https://cdn.jsdelivr.net/npm/shopmate-sdk@latest/shopmate-sdk.min.js"
data-org-id="2"
data-base-url="https://shopmate.hoshonto.com"
data-auth-token="optional-token"
data-persist-auth-token="true"
data-cart-position="right-bottom"
data-auto-extract="true"
data-floating-cart="true"
data-show-notifications="true"
></script>| Attribute | Description |
|---|---|
| data-org-id | Required positive organization ID. |
| data-base-url | Optional ShopMate base URL. |
| data-auth-token | Optional token used only by the SDK request helper. |
| data-persist-auth-token | Set to false to avoid token persistence. |
| data-cart-position | Floating cart position. |
| data-auto-extract | Set to false to skip automatic DOM extraction. |
| data-floating-cart | Set to false to hide the floating cart. |
| data-show-notifications | Set to false to disable built-in toast UI. |
Build outputs
npm run build generates the package artifacts:
shopmate-sdk.js— readable browser global bundle;shopmate-sdk.min.js— minified browser global bundle;dist/index.mjs— ESM bundle;dist/index.min.mjs— minified ESM bundle;dist/index.d.ts— TypeScript declarations.
NPM scripts
npm run build Build all artifacts
npm run watch Build in watch mode
npm run typecheck Run TypeScript type checking only
npm test Build and verify browser bundle behaviorPackage exports
shopmate-sdk Default ShopMate class export
shopmate-sdk/min Minified module build
shopmate-sdk/browser Browser bundle pathLocal demo
Build the package, then open examples/storefront-demo.html in a browser.
Publishing to npm
Prerequisites
- npm account with publish permission for
shopmate-sdk; - authenticated npm session:
npm loginRelease process
Update version:
npm version patch npm version minor npm version majorValidate and build:
npm run typecheck npm test npm run buildInspect the package contents:
npm pack --dry-runPublish:
npm publishVerify:
npm view shopmate-sdk
The CDN browser bundle is available through jsDelivr after publication:
https://cdn.jsdelivr.net/npm/shopmate-sdk@latest/shopmate-sdk.min.js
https://cdn.jsdelivr.net/npm/shopmate-sdk@<version>/shopmate-sdk.min.jsPublishing checklist
- [ ] Version updated and committed.
- [ ]
npm run typechecksucceeds. - [ ]
npm testsucceeds. - [ ]
npm run buildsucceeds. - [ ] README and changelog are updated.
- [ ]
npm pack --dry-runincludes only intended files. - [ ]
npm whoamiconfirms the correct npm account. - [ ] Package published with
npm publish. - [ ] CDN path checked after publication.
