@opencommerceprotocol/runtime
v1.0.0
Published
Open Commerce Protocol — Browser JavaScript runtime (~8KB gzipped)
Maintainers
Readme
@opencommerceprotocol/runtime
Browser runtime for the Open Commerce Protocol. Registers OCP tools with WebMCP (navigator.modelContext) in Chrome 146+ with graceful fallback to window.__ocp for all other browsers. Optionally mounts an embedded chat widget.
~8KB gzipped. Zero dependencies at runtime.
Quick Start (CDN)
<script src="https://cdn.opencommerceprotocol.org/runtime/v1/ocp-runtime.min.js"></script>
<script>
OCP.init({
handlers: {
search_products: async ({ query }) =>
fetch(`/api/products?q=${encodeURIComponent(query)}`).then(r => r.json()),
get_product: async ({ id }) =>
fetch(`/api/products/${id}`).then(r => r.json()),
add_to_cart: async ({ product_id, quantity }) =>
fetch('/api/cart', { method: 'POST', body: JSON.stringify({ product_id, quantity }) }).then(r => r.json()),
begin_checkout: async ({ prefill }) =>
fetch('/api/checkout', { method: 'POST', body: JSON.stringify(prefill) }).then(r => r.json()),
},
widget: true,
});
</script>ESM Import
npm install @opencommerceprotocol/runtimeimport { OCP } from '@opencommerceprotocol/runtime';
const ocp = OCP.init({ handlers: { ... } });OCP.init(config)
Returns an OCP instance. Must be called once per page.
OCPConfig
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| handlers | Partial<OCPHandlers> | — | Tool handler implementations |
| adapter | 'shopify' \| 'woocommerce' \| 'custom' | — | Use a preset adapter |
| manifest | string | '/.well-known/ocp.json' | URL to fetch the OCP manifest |
| permissions | OCPPermissions | — | Override agent permissions |
| widget | boolean \| OCPWidgetConfig | false | Mount the chat widget |
| analytics | boolean \| AnalyticsConfig | false | Enable opt-in analytics |
| jsonld | { enabled?, mode?, productSelector? } | — | JSON-LD injection/augmentation |
| silent | boolean | false | Suppress console logs |
OCP instance
const ocp = OCP.init({ ... });
ocp.tools // string[] — names of registered tools
ocp.webmcpSupported // boolean — is WebMCP available in this browser?
ocp.widget // OCPWidget | null
ocp.analytics // OCPAnalytics | nullChat Widget
Mount a conversational shopping assistant for human visitors:
OCP.init({
handlers: { ... },
widget: {
position: 'bottom-right', // 'bottom-right' | 'bottom-left'
theme: 'purple', // CSS color or 'purple' | 'blue' | 'green'
title: 'Shop Assistant',
placeholder: 'Ask me anything about our products…',
welcomeMessage: 'Hi! How can I help you shop today?',
confidenceThreshold: 0.7, // minimum confidence before escalating to cloud LLM
maxResults: 5,
showBranding: true,
},
});Three-Tier Processing Pipeline
The widget uses a tiered approach to answer shopper questions:
| Tier | Mechanism | When Used | |------|-----------|-----------| | 1 | Regex intent matcher | High-confidence matches (≥ 0.85) | | 2 | Browser LLM (WebGPU) | Mid-confidence (≥ 0.40, < 0.85) | | 3 | Cloud LLM fallback | Low-confidence (< 0.40) |
Platform Adapters
Shopify
import { OCP, createShopifyHandlers } from '@opencommerceprotocol/runtime';
OCP.init({
handlers: createShopifyHandlers({
storeDomain: 'mystore.myshopify.com',
storefrontToken: 'your-storefront-api-token',
}),
widget: true,
});WooCommerce
import { OCP, createWooCommerceHandlers } from '@opencommerceprotocol/runtime';
OCP.init({
handlers: createWooCommerceHandlers({
siteUrl: 'https://mystore.com',
consumerKey: 'ck_xxx',
consumerSecret: 'cs_xxx',
}),
widget: true,
});Custom
import { OCP, createCustomHandlers } from '@opencommerceprotocol/runtime';
OCP.init({
handlers: createCustomHandlers({
searchUrl: '/api/products',
productUrl: '/api/products/:id',
cartUrl: '/api/cart',
checkoutUrl: '/api/checkout',
}),
});Browser LLM
Load a local language model (requires Chrome with WebGPU):
import { BrowserLLM } from '@opencommerceprotocol/runtime';
const llm = new BrowserLLM({
model: 'gemma-2b', // model identifier
loadStrategy: 'lazy', // 'eager' | 'lazy' | 'idle'
onProgress: (p) => console.log(`Loading: ${p.progress}%`),
onStatusChange: (s) => console.log(`Status: ${s}`),
});
await llm.load();
const result = await llm.generate('Summarize this product: ...');BrowserLLMStatus
'idle' | 'loading' | 'ready' | 'generating' | 'error'
Analytics (Opt-In)
OCP.init({
handlers: { ... },
analytics: {
enabled: true,
endpoint: '/api/ocp-analytics', // your analytics server
storageKey: 'ocp_events', // localStorage key for buffering
flushInterval: 5000, // ms between flushes
},
});
// Access the analytics instance
const ocp = OCP.init({ ... });
ocp.analytics?.trackToolCall('search_products', { query: 'headphones' });JSON-LD Integration
import { injectProductJsonLd, augmentExistingJsonLd, extractProductFromPage } from '@opencommerceprotocol/runtime';
// Inject Schema.org Product JSON-LD
injectProductJsonLd({
id: 'prod-001',
name: 'Headphones',
price: 149.99,
currency: 'USD',
url: window.location.href,
});
// Augment existing JSON-LD with OCP fields
augmentExistingJsonLd({ agent_notes: 'Best noise-cancelling headphones under $200.' });
// Extract product data from existing Schema.org JSON-LD on the page
const product = extractProductFromPage();Auto-Init via HTML Attribute
Initialize OCP without JavaScript by adding an attribute to the script tag:
<script
src="https://cdn.opencommerceprotocol.org/runtime/v1/ocp-runtime.min.js"
data-ocp-auto-init
data-ocp-config='{"widget":true}'
></script>WebMCP Detection
import { isWebMCPAvailable } from '@opencommerceprotocol/runtime';
if (isWebMCPAvailable()) {
console.log('Chrome 146+ with WebMCP enabled');
}Exports Reference
| Export | Description |
|--------|-------------|
| OCP | Main runtime class |
| OCPWidget | Chat widget component |
| OCPAnalytics | Analytics tracker |
| BrowserLLM | WebGPU-based browser LLM |
| createShopifyHandlers | Shopify adapter factory |
| createWooCommerceHandlers | WooCommerce adapter factory |
| createCustomHandlers | Generic REST adapter factory |
| isWebMCPAvailable | WebMCP feature detection |
| injectProductJsonLd | Inject Schema.org JSON-LD |
| augmentExistingJsonLd | Augment existing JSON-LD |
| extractProductFromPage | Extract product data from page |
