Shopify app spec
Scopes, webhooks and the storefront check flow for the Shopify app.
Protect your Shopify storefront AI assistant from prompt injection, discount/coupon hallucination exploits, and off-topic credit draining while preserving zero-friction shopper UX.
1. Architecture Pattern
Shopify theme extensions and storefront chat widgets run in the shopper's browser. Never put your M6L_GATE_KEY or OpenAI/Anthropic keys in Liquid templates or frontend JS. Instead, route storefront chat messages through your backend endpoint (or Shopify App Proxy /apps/ai-chat) where Gated runs in <1ms before the LLM call:
// Inside your Shopify App backend route (Remix / Node / Cloudflare Worker)
const shopperId =
req.headers.get("x-shopify-customer-id") ||
req.headers.get("cf-connecting-ip") ||
req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
"anon_shopper";
const gateRes = await fetch("https://getgated.ai/v1/check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.M6L_GATE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user: shopperId,
input: shopperMessage,
messages: conversationHistory.length,
context_chars: JSON.stringify(conversationHistory).length,
feature: "shopify_storefront_chat",
anonymous: !req.headers.get("x-shopify-customer-id"),
}),
signal: AbortSignal.timeout(400), // Fail-open after 400ms
}).catch(() => null);
if (gateRes && gateRes.ok) {
const verdict = await gateRes.json();
if (!verdict.allow) {
return Response.json({
reply: verdict.message || "I can only assist with questions about our products, orders, and store policies.",
blocked_by_gate: true,
});
}
}2. Recommended Shopify Merchant Policy Settings
- Allowed Topics:
products, sizing, shipping, returns, order status, gift cards, store policies - Max Input Chars:
1,500(prevents copy-paste document dumps) - Anonymous Shopper Limit:
15 messages / hourper IP - Block Off-Topic:
true(blocks coding, homework, and general essay writing at your store's expense)