npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@commercengine/js

v0.5.1

Published

Commerce Engine Checkout - Embeddable checkout SDK

Readme

@commercengine/js

Embed Commerce Engine checkout in any website.

Installation

CDN (Recommended)

<script src="https://cdn.commercengine.com/v1.js" async></script>

npm

npm install @commercengine/js

Quick Start

<script src="https://cdn.commercengine.com/v1.js" async></script>
<script>
  window.Commercengine.onLoad = async () => {
    const checkout = await Commercengine.init({
      storeId: "store_xxx",
      apiKey: "ak_xxx",
      environment: "production", // or "staging"
    });

    document.getElementById("cart-btn").onclick = () => checkout.openCart();
  };
</script>

Configuration

CheckoutConfig

interface CheckoutConfig {
  // === Credentials (required) ===
  storeId: string;              // Your Commerce Engine Store ID
  apiKey: string;               // Your Commerce Engine API Key
  environment?: "production" | "staging";  // Default: "production"

  // === Development ===
  url?: string;                 // Direct checkout URL (for local dev)
                                // Overrides environment-based URL

  // === Theme ===
  theme?: "light" | "dark" | "system";  // Per-session override. Default: "system"
                                // Primary config via Checkout Studio (Config API)

  // === Appearance ===
  appearance?: {
    zIndex?: number;            // Overlay z-index. Default: 99999
  };

  // === Authentication ===
  authMode?: "managed" | "provided";  // Default: "managed"
  accessToken?: string;         // Initial access token (if user logged in)
  refreshToken?: string;        // Initial refresh token

  // === Quick Buy (add item on init) ===
  quickBuy?: {
    productId: string;          // Product ID (required)
    variantId: string | null;   // Variant ID (required, null for non-variant)
    quantity?: number;          // Default: 1
  };
  sessionMode?: "continue-existing" | "force-new";  // Default: "continue-existing"
  autoDetectQuickBuy?: boolean; // Auto-detect from parent URL. Default: false

  // Drawer direction, features, and login methods are configured via
  // Checkout Studio (Config API) and are not SDK options.

  // === Callbacks ===
  onReady?: () => void;
  onOpen?: () => void;
  onClose?: () => void;
  onComplete?: (order: OrderData) => void;
  onCartUpdate?: (cart: CartData) => void;
  onTokensUpdated?: (data: AuthTokensUpdatedData) => void;
  onLogin?: (data: AuthLoginData) => void;
  onLogout?: (data: AuthLogoutData) => void;
  onSessionError?: () => void;
  onError?: (error: ErrorData) => void;
}

Example: Full Configuration

const checkout = await Commercengine.init({
  storeId: "store_xxx",
  apiKey: "ak_xxx",
  environment: "production",
  theme: "dark",
  appearance: {
    zIndex: 100000,
  },
  accessToken: userSession?.accessToken,
  refreshToken: userSession?.refreshToken,
  onReady: () => {
    console.log("Checkout loaded");
  },
  onComplete: (order) => {
    window.location.href = `/thank-you?order=${order.orderNumber}`;
  },
  onCartUpdate: (cart) => {
    updateCartBadge(cart.count);
  },
  onTokensUpdated: ({ accessToken, refreshToken }) => {
    // Tokens changed - sync to your auth system (fires on every token change)
    saveUserSession(accessToken, refreshToken);
  },
  onLogin: ({ user, loginMethod }) => {
    // User logged in via checkout - update UI
    console.log("User logged in via", loginMethod, ":", user?.email || user?.phone);
  },
  onLogout: () => {
    // User logged out - update UI for anonymous state
  },
  onSessionError: () => {
    // Session corrupted - SDK cleared all tokens, user needs to re-authenticate
    clearUserSession();
  },
});

Methods

openCart()

Open the cart drawer.

checkout.openCart();

openCheckout()

Open checkout directly, bypassing cart. Use for "Buy Now" flows.

checkout.openCheckout();

close()

Close the checkout overlay.

checkout.close();

updateTokens(accessToken, refreshToken?)

Sync authentication state from parent site. Call when user logs in/out on your site.

// When user logs in on your site
checkout.updateTokens(session.accessToken, session.refreshToken);

// When user logs out
checkout.updateTokens("", "");

addToCart(productId, variantId, quantity?)

Add an item to cart and open the cart drawer. This is the canonical implementation of "quick buy" functionality.

// Add a product (non-variant)
checkout.addToCart("prod_123", null, 1);

// Add a product variant
checkout.addToCart("prod_123", "var_456", 2);

// Quantity defaults to 1
checkout.addToCart("prod_123", "var_456");

Parameters:

  • productId (string, required) - Product ID
  • variantId (string | null, required) - Variant ID, or null for non-variant products
  • quantity (number, optional) - Quantity to add, defaults to 1

Behavior:

  • Adds item to cart and automatically opens the cart drawer
  • If item already in cart: adds to existing quantity
  • If item not in cart: adds new item
  • If no cart exists: creates cart with the item

getCart()

Get current cart state.

const cart = checkout.getCart();
console.log(cart.count, cart.total, cart.currency);

getTokens()

Get the latest token payload seen by the SDK from auth:tokens-updated. This avoids race conditions when .on("auth:tokens-updated") is attached after init(). Returns null if no token update event has been received yet.

const checkout = await Commercengine.init({ ... });
const tokens = checkout.getTokens();
// tokens.accessToken, tokens.refreshToken

destroy()

Remove checkout iframe and cleanup event listeners.

checkout.destroy();

Properties

| Property | Type | Description | |----------|------|-------------| | ready | boolean | Whether checkout is initialized and ready | | open | boolean | Whether checkout overlay is currently visible |

Events

Subscribe via callbacks (in config) or the event emitter.

Event Types

| Event | Callback | Data | Description | |-------|----------|------|-------------| | ready | onReady | - | Checkout iframe loaded | | open | onOpen | - | Drawer opened | | close | onClose | - | All drawers closed | | complete | onComplete | OrderData | Order placed successfully | | cart:updated | onCartUpdate | CartData | Cart state changed | | auth:tokens-updated | onTokensUpdated | AuthTokensUpdatedData | Tokens changed (any reason) | | auth:login | onLogin | AuthLoginData | User logged in (semantic) | | auth:logout | onLogout | AuthLogoutData | User logged out (semantic) | | auth:session-error | onSessionError | - | Session corrupted, tokens cleared | | error | onError | ErrorData | Configuration error |

Event Data Types

interface OrderData {
  id: string;           // Order ID
  orderNumber: string;  // Human-readable order number
}

interface CartData {
  count: number;        // Number of items
  total: number;        // Subtotal amount
  currency: string;     // Currency code (e.g., "USD", "INR")
}

interface AuthTokensUpdatedData {
  accessToken: string;
  refreshToken?: string;
}

interface AuthLoginData {
  user?: UserInfo;
  loginMethod?: LoginMethod;
}

interface AuthLogoutData {
  user?: UserInfo;        // Anonymous user info
}

interface ErrorData {
  message: string;
}

type LoginMethod = "whatsapp" | "phone" | "email";

interface Channel {
  id: string;
  name: string;
  type: string;
}

interface UserInfo {
  id: string;
  email: string | null;
  phone: string | null;
  username: string;
  firstName: string | null;
  lastName: string | null;
  storeId: string;
  isLoggedIn: boolean;
  isAnonymous: boolean;
  customerId: string | null;
  customerGroupId: string | null;
  anonymousId: string;
  channel: Channel;
  tokenExpiry: Date;
  tokenIssuedAt: Date;
}

Event Emitter API

// Subscribe
checkout.on("cart:updated", (cart) => {
  console.log("Cart:", cart.count, cart.total);
});

// Subscribe once
checkout.once("complete", (order) => {
  console.log("Order:", order.orderNumber);
});

// Unsubscribe
const handler = (cart) => console.log(cart);
checkout.on("cart:updated", handler);
checkout.off("cart:updated", handler);

Authentication Flow

Scenario 1: User Not Logged In

User will be prompted to login within checkout (WhatsApp, Phone, or Email OTP).

const checkout = await Commercengine.init({
  storeId: "store_xxx",
  apiKey: "ak_xxx",
  onTokensUpdated: ({ accessToken, refreshToken }) => {
    // Sync tokens to your auth system (fires on login, logout, refresh)
    saveSession({ accessToken, refreshToken });
  },
  onLogin: ({ user, loginMethod }) => {
    // Update UI with user info
    console.log("Logged in via", loginMethod, ":", user?.email);
  },
});

Scenario 2: User Already Logged In

Pass tokens to skip login screen.

const checkout = await Commercengine.init({
  storeId: "store_xxx",
  apiKey: "ak_xxx",
  accessToken: currentSession.accessToken,
  refreshToken: currentSession.refreshToken,
});

Scenario 3: Sync Auth Changes

When user logs in/out on your site, sync to checkout.

// User logs in on your site
myAuth.onLogin((session) => {
  checkout.updateTokens(session.accessToken, session.refreshToken);
});

// User logs out on your site
myAuth.onLogout(() => {
  checkout.updateTokens("", "");
});

Features

Features (loyalty, coupons, collect-in-store, free shipping progress, product recommendations) are configured via Checkout Studio (Config API). They are not SDK options.

| Feature | Default | Description | |---------|---------|-------------| | loyalty | true | Loyalty points redemption at checkout | | coupons | true | Coupon and promo code input | | collectInStore | false | Option to collect order in-store | | freeShippingProgress | true | Progress bar showing amount needed for free shipping | | productRecommendations | true | "You may also like" product carousel in cart |

TypeScript

All types are exported:

import {
  Commercengine,
  Checkout,
  type CheckoutConfig,
  type CheckoutEventType,
  type CheckoutFeatures,
  type DrawerDirection,
  type DrawerDirectionConfig,
  type Environment,
  type CartData,
  type OrderData,
  type AuthTokensUpdatedData,
  type AuthLoginData,
  type AuthLogoutData,
  type ErrorData,
  type UserInfo,
  type Channel,
  type LoginMethod,
} from "@commercengine/js";

URL Parameters (Advanced)

For direct iframe integration without the SDK, checkout uses a subdomain-based URL scheme. The store ID and environment are encoded in the hostname — they are not URL parameters.

URL format: https://{storeId}.checkout.commercengine.com?api_key=ak_xxx Staging: https://{storeId}.staging.checkout.commercengine.com?api_key=ak_xxx

| Parameter | Description | Example | |-----------|-------------|---------| | api_key | API Key (required) | ak_xxx | | mode | Deployment mode | iframe | | parent_origin | Parent origin for postMessage | https://brand.com | | theme | Theme preference (per-session override) | light, dark | | token | Access token | JWT string | | refresh_token | Refresh token | JWT string | | auth_mode | Auth management | provided, managed | | product_id | Quick buy product | Product ID | | variant_id | Quick buy variant | Variant ID | | qty | Quick buy quantity | 1 | | session_mode | Session behavior | continue-existing, force-new |

Features (loyalty, coupons, etc.) and drawer direction are configured via Checkout Studio (Config API) and are not accepted as URL parameters.

Auth Modes

  • managed (default): Checkout manages token lifecycle with auto-refresh. Best for lightweight integrations (marketing pages, buy-now buttons)
  • provided (recommended for storefront apps): Parent manages tokens via storefront SDK, checkout uses in-memory only. Tokens are synced via updateTokens() and onTokensUpdated

Session Modes

  • continue-existing (default): Add quick-buy item to existing cart
  • force-new: Delete existing cart and start fresh with only the quick-buy item

Note: When quick buy params are provided (via config or auto-detected), the cart drawer automatically opens once checkout is ready.

Auto-Detect Quick Buy

For ad-driven traffic, enable autoDetectQuickBuy to automatically parse quick buy params from the parent page URL:

// Ad link: https://brand.com?product_id=prod_123&variant_id=var_456&qty=2

const checkout = await Commercengine.init({
  storeId: "store_xxx",
  apiKey: "ak_xxx",
  autoDetectQuickBuy: true,  // Reads product_id, variant_id, qty from parent URL
});

This allows embedded checkout to handle ad clicks natively without custom URL parsing.

URL Cleanup: When quick buy params are detected, they are automatically removed from the browser URL (using replaceState) to prevent duplicate adds on page refresh.