All posts
EngineeringBest practicesBusiness Use Cases

WebMCP for Shopify: a practical path to agentic checkout

A step‑by‑step guide to implementing WebMCP for Shopify: what works today, how to expose cart and checkout tools safely, runnable code, and ecosystem realities.

Agent LayerOctober 5, 202611 min read

If you’re searching for “WebMCP for Shopify,” you likely want a concrete way to let AI agents add to cart and check out on your store without brittle scraping. By the end, you’ll have working WebMCP tools wired into a Shopify theme, a safe path to agent‑assisted checkout, and a clear view of what works in production today.

TL;DR

  • WebMCP lets your Shopify pages expose JSON‑schema tools (e.g., add_to_cart, apply_discount, proceed_to_checkout) that agents can call in‑page with the user’s session.
  • Implement it by adding a script in theme.liquid (or an app embed) that feature‑detects document.modelContext and navigator.modelContext, then mc.registerTool for each action.
  • Sensitive actions (like checkout, account edits, deletion) must require explicit user confirmation in the page; never pass secrets or payment tokens through tool params.
  • Agent support exists today in some environments (e.g., ChatGPT desktop “site tools”), while browsers are in origin trials. Check the ecosystem tracker and plan for progressive enhancement.
  • To keep tools working as your theme changes, consider drift detection, versioned configs, and analytics; Agent Layer provides these plus a free agent‑readiness audit.

What “WebMCP for Shopify” means (and doesn’t)

“WebMCP” is an in‑page standard: your page registers tools that an agent can discover and call, instead of clicking pixels. Tools run with the user’s current session—no extra backend or API keys. This is not MCP (Anthropic’s server protocol); if you need that distinction, see how WebMCP differs from MCP.

On Shopify, you’re wiring those tools to your existing UI: product page forms, cart buttons, discount inputs, and the checkout link. You’re not changing payments flow or storing secrets in tool params. You’re exposing safe, small, JSON‑returning actions that describe what happened (e.g., “2 units of variant 123 added to cart”).

Today’s ecosystem is early. Some agents read and call these tools in real browsers. Others still scrape. Be honest with stakeholders: build the tools now, gate sensitive ones behind confirmation, and you’ll be ready as support lands. For current status, see the public WebMCP ecosystem tracker.

For a deeper intro to the standard and browser support, read WebMCP in Chrome: what works today and how to build for it and the practical setup in How to Enable WebMCP on Your Website.

Shopify implementation plan

We’ll add a lightweight script to your theme to register three tools:

  • add_to_cart: Add a specific variant and quantity using your existing add‑to‑cart form.
  • apply_discount_code: Fill and submit a discount field on cart (if present) or return an actionable error.
  • proceed_to_checkout: Navigate to checkout, but only after an in‑page explicit user confirmation.

These are examples. You should mirror your actual funnel: search, select variant, add to cart, apply discount, set shipping, checkout. Keep tools small and specific so agents can choose correctly from descriptions.

Where to put the script

  • Theme: Add to theme.liquid before . Or create a small app embed that injects the script only on templates you need (product, cart).
  • Scope: If a tool relies on elements present only on specific templates, register it conditionally when those elements exist.

Feature detection and registration

Use both addresses; some agents still check the older navigator.modelContext.

// assets/webmcp-shopify.js
(function () {
  const mc = (document && document.modelContext) || (navigator && navigator.modelContext);
  if (!mc) return; // No WebMCP consumer; fail quietly.

  const has = (sel) => !!document.querySelector(sel);

  // Utility: confirm sensitive action in-page.
  function confirmAction(message) {
    // Minimal, accessible confirmation. Replace with your modal if you have one.
    const ok = window.confirm(message);
    return ok;
  }

  // add_to_cart: Works on product pages with a variant input.
  if (has('form[action*="/cart/add"] input[name="id"]')) {
    mc.registerTool({
      name: 'add_to_cart',
      description:
        'Add a specific variant to the cart. Use on product pages only when the variant id and quantity are known. Side effect: modifies cart.',
      inputSchema: {
        type: 'object',
        properties: {
          variant_id: { type: 'string', description: 'Shopify variant id from the page' },
          quantity: { type: 'integer', minimum: 1, default: 1 },
        },
        required: ['variant_id'],
        additionalProperties: false,
      },
      execute: async ({ variant_id, quantity = 1 }) => {
        const form = document.querySelector('form[action*="/cart/add"]');
        const idInput = form && form.querySelector('input[name="id"]');
        if (!form || !idInput) {
          return { ok: false, error: 'No add-to-cart form on this page' };
        }
        // Set selected variant and quantity; submit natively so theme logic runs.
        idInput.value = String(variant_id);
        const qty = form.querySelector('input[name="quantity"]');
        if (qty) qty.value = String(quantity);
        form.requestSubmit ? form.requestSubmit() : form.submit();
        return { ok: true, action: 'added_to_cart', variant_id, quantity };
      },
    });
  }

  // apply_discount_code: On cart pages where a discount field exists.
  if (has('form[action*="/cart"] input[name*="discount" i]')) {
    mc.registerTool({
      name: 'apply_discount_code',
      description:
        'Apply a discount code on the cart page when a discount input is visible. Preconditions: on cart page with discount field. Side effect: updates totals.',
      inputSchema: {
        type: 'object',
        properties: { code: { type: 'string', minLength: 1 } },
        required: ['code'],
        additionalProperties: false,
      },
      execute: async ({ code }) => {
        const form = document.querySelector('form[action*="/cart"]');
        const input = form && form.querySelector('input[name*="discount" i]');
        if (!form || !input) {
          return { ok: false, error: 'Discount input not found on this page' };
        }
        input.value = code.trim();
        form.requestSubmit ? form.requestSubmit() : form.submit();
        return { ok: true, action: 'discount_applied_attempt', code };
      },
    });
  }

  // proceed_to_checkout: Always requires explicit user confirmation.
  if (has('a[href*="/checkout"], button[name="checkout"], form[action*="/checkout"]')) {
    mc.registerTool({
      name: 'proceed_to_checkout',
      description:
        'Go to checkout from cart. Sensitive action requiring explicit user confirmation. Preconditions: items in cart. Side effect: navigates to checkout.',
      inputSchema: { type: 'object', properties: {}, additionalProperties: false },
      execute: async () => {
        const confirmed = confirmAction('Agent requests to open checkout. Continue?');
        if (!confirmed) return { ok: false, error: 'user_denied' };
        const btn = document.querySelector('button[name="checkout"]');
        const link = document.querySelector('a[href*="/checkout"]');
        const form = document.querySelector('form[action*="/checkout"]');
        if (btn) btn.click();
        else if (link) window.location.assign(link.getAttribute('href'));
        else if (form) form.requestSubmit ? form.requestSubmit() : form.submit();
        else return { ok: false, error: 'checkout_control_not_found' };
        return { ok: true, action: 'checkout_started' };
      },
    });
  }
})();

Notes:

  • We intentionally interact with your existing DOM forms and buttons so your theme apps, validation, analytics and cart logic still run.
  • We don’t fetch secrets or push raw card data. Checkout remains a Shopify‑hosted flow.
  • Tool results are small JSON objects that describe the action, which helps agents chain steps.

Good tool descriptions drive correct usage

Agents choose tools by reading their descriptions. State when to use the tool, preconditions, and side effects. Avoid vague “do everything” tools. Keep names snake_case and inputs minimal.

If you want more examples of “right‑sized” commerce tools, see Essential WebMCP Tools for AI‑Ready Websites.

Flow: agentic cart to checkout

This diagram shows an agent discovering and calling tools in the shopper’s page session, with a guardrail before checkout.

Agent calls in-page tools to add to cart and start checkout with confirmation

Testing your Shopify WebMCP tools

  • Manual: Use a browser or desktop agent that supports page tools. The ecosystem tracker lists what’s verified. Today, ChatGPT desktop “site tools” can call page tools; Chrome and Edge are in origin trials, with Brave behind a flag.
  • Developer flow: open DevTools, run document.modelContext or navigator.modelContext to confirm presence. If an agent is attached and supports tools, your registered tools should appear and be callable.
  • Scenario tests: If you use Agent Layer, define test intents like “add two size M blue tees, apply SUMMER10, then checkout,” and assert which tool is called when. See WebMCP for testing: how to verify your site works with agents.

Progressive enhancement and fallbacks

It’s fine if document.modelContext isn’t present; the page should behave normally. Agents that don’t support WebMCP will still scrape and click—your tools simply won’t be used. Over time, as support expands, more traffic will hit your tools instead of your DOM.

To keep yourself honest, build the tools and run an audit. The free agent‑readiness audit flags missing tools, invalid JSON‑LD, unlabeled form fields and other issues that trip up agents.

Hardening for production

You can go far with the code above. If you’re maintaining a larger Shopify theme or several locales, a few extra steps help:

  • Version and template scoping: Keep a small registry per template (product, cart, search). If you centralize this, ship versioned configs so you can roll back quickly when a theme change lands on Friday.
  • Drift detection: UIs change. A renamed selector can silently break add_to_cart. Agent Layer runs health checks that flag breakage and suggest new selectors, so you’re not guessing why conversion dipped.
  • Observability: Log which agents call your tools, success or error, and duration. Analytics make tool ROI visible and surface odd usage patterns.
  • Guardrails: The example uses window.confirm; in production, use your modal with clear copy. For any sensitive action—payments, account changes, deletion—require explicit confirmation in‑page.
  • Intent tests: Write a few core journeys and assert the expected tool sequence. This catches regressions quickly. See Preparing Your E‑Commerce Store for AI‑Driven Checkout.

Extending beyond the basics

Common next steps on Shopify:

  • select_variant: Accepts option names/values (e.g., size=M, color=Blue). The execute implementation sets the relevant selects or buttons, then updates the hidden variant id input. Keep it idempotent.
  • remove_from_cart and update_quantity: On the cart page, click the theme’s minus/plus or set the quantity input and submit. Reflect the result as JSON.
  • open_product and search_products: Navigate to product handles or use your site search page with a query param. Return which URL opened.

Keep each tool focused, state preconditions, and avoid duplicating server logic. Let your theme and Shopify handle business rules.

Security, privacy, and sensitive actions

  • Do not pass secrets, payment tokens, or card data through tool parameters. Tools run in the shopper’s browser and should operate only on visible UI/DOM.
  • Always require an explicit user confirmation for payment and account‑level actions. Keep a human in the loop.
  • Bound actions to the page you’re on. If a tool precondition isn’t met (e.g., not on cart), return a clear error. Don’t try to do multi‑page state juggling inside a single tool.

What works today vs. what’s early

From the ecosystem status page:

  • Agents: ChatGPT desktop “site tools” and ChatGPT Work call page tools today. Brave Leo is behind a flag. Claude for Chrome and Gemini do not call tools as of the latest verification. Others are unconfirmed.
  • Browsers: Chrome and Edge have origin trials underway; Brave is behind a flag; Firefox has no support; Safari is opposed currently; some niche browsers partially support the older address.
  • Frameworks: Vercel agent‑browser, Stagehand, and Browser Use work today in environments they launch; Puppeteer has a flag‑gated path. Playwright currently declines support.

Implication: it’s worth implementing now, especially for shoppers using agents that already respect page tools. Treat it as progressive enhancement and get your guardrails in place.

For a reality‑check on broader usage and when to invest more, skim WebMCP example: concrete uses that work today.

Debugging checklist

  • Confirm the context exists: run document.modelContext ?? navigator.modelContext in DevTools.
  • Verify tools registered: log registrations in development and check they’re gated to the right templates.
  • Exercise each tool manually: fire execute() from the console with sample params and watch the DOM change.
  • Ensure copy makes sense: tool descriptions should mention preconditions and side effects.
  • Validate JSON Schemas: keep inputs minimal; agents rely on these to structure calls.

Common pitfalls

  • Missing preconditions: Registering add_to_cart on pages without an add‑to‑cart form leads to agent confusion and errors. Scope tools to templates where elements exist.
  • Overloaded tools: A single “manage_cart” tool with many optional parameters is harder for agents to choose and for you to test. Prefer small, single‑purpose tools.
  • Silent breakage after theme updates: A renamed selector breaks execute. Without health checks, you won’t know. Introduce monitoring or a platform that alerts on drift.
  • Skipping user confirmation: Proceeding to checkout (or changing account data) without in‑page confirmation is risky and erodes shopper trust.
  • Returning DOM blobs: Tool results should be small JSON. Don’t return huge HTML strings; describe what happened in compact fields.
  • Assuming universal support: Not all agents call tools yet. Build for progressive enhancement and keep normal UX paths first‑class.

A note on Shopify specifics

We intentionally interacted with DOM forms/buttons rather than private or theme‑specific JavaScript APIs. This keeps your existing validation, upsells, and analytics intact. If your theme uses non‑standard controls (custom variant pickers, AJAX carts), target those elements in execute, but keep the contract small and the description precise. Test across your locales and templates.

If you later centralize this across many templates and need drift detection, versioned configs, analytics, and intent tests, Agent Layer lets you define tools per template, publish as versioned configs, and roll back. Health checks catch selector changes and suggest fixes. It also logs which agents actually called what, so you can prioritize work on real traffic.

Try it

Add the script to your Shopify theme and test it with an agent that supports page tools. Then run the free agent‑readiness audit to see where you stand and get page‑by‑page tool suggestions. Keep an eye on browser and agent support on the ecosystem tracker.

Get started

Don't Be Invisible to Tomorrow's Buyers.

Make your platform executable for every AI assistant your customers already use. No engineering, no lock-in, no breakage.