Start free →

Trooply Chatbot Documentation

Everything you need to ship the Trooply AI shopping assistant on your store — from your first <script> tag to a fully customized, multilingual, multi-channel experience.

Quick start

Three steps. ~5 minutes.

  1. Create your account — pick a plan or start free.
  2. Walk through the onboarding wizard — connect your store, copy your embed snippet.
  3. Paste the snippet into your theme. The widget appears in the corner of every page.

Embed the widget

Paste this just before </body> on every page. Replace the placeholders from your dashboard.

<script async
  src="https://chatbot.trooply.ai/widget.js"
  data-store-id="YOUR_STORE_ID"
  data-api-key="YOUR_API_KEY"></script>

That's the entire integration — two attributes, one script tag. The widget infers its API origin from the script's src, so data-api-url is only needed if you're self-hosting or proxying.

data-*What it does
data-store-idYour Trooply store UUID — visible on every dashboard page.
data-api-keyActive widget API key. Manage at /dashboard/developer.
data-api-urlOptional. The Trooply origin. Auto-inferred from the script src; only set this if you're proxying.
data-user-tokenOptional signed JWT identifying a logged-in shopper for personalized history and recommendations.
data-product-idOptional. When set on a PDP, surfaces product-specific FAQs above the input box.

Per-page customization (overrides)

These optional attributes let you override the dashboard config on a per-page basis — useful for A/B tests, landing-page-specific greetings, or multi-language sites without re-saving from the dashboard.

data-*What it does
data-primary-colorHex color for the bubble + header. Example: "#10b981".
data-bot-nameDisplay name shown in the chat header.
data-welcome-messageFirst message the bot sends when the chat opens.
data-placeholderPlaceholder text inside the message input box.
data-positionbottom-right (default) or bottom-left.
data-launcher-textOptional teaser bubble shown above the launcher button.
data-show-brandingtrue or false — overrides the plan default (Pro/Enterprise can hide branding).
data-auto-open-afterMilliseconds to wait before auto-opening the chat. Set to 0 or omit to disable.
<!-- Example: green widget on the cart page that auto-opens after 5s -->
<script async
  src="https://chatbot.trooply.ai/widget.js"
  data-store-id="YOUR_STORE_ID"
  data-api-key="YOUR_API_KEY"
  data-primary-color="#10b981"
  data-welcome-message="Need help with your order? I'm here."
  data-auto-open-after="5000"></script>
Shadow DOM: The widget runs in an isolated shadow DOM, so your site's CSS can't accidentally restyle it and the widget can't accidentally bleed into your styles.

Match your brand

Brand the widget from /dashboard/widget: primary color, position, greeting text, bot name and avatar, and the placeholder text. Pro and Enterprise plans hide the Trooply branding.

Refinement chips

When a visitor types a broad term like shoe, Trooply doesn't dump 100 results — it asks one short question and shows tappable chips:

Bot: Pick what fits — or tap 🏆 Best for me and I'll choose.

[ Type · Running ]  [ Type · Casual ]  [ Type · Skate ]
[ Color · Black ]  [ Color · White ]  [ Color · Blue ]  [ Color · Red ]
[ Color · Any ]  [ 🏆 Best for me ]

Each chip is its own user message — the visitor never has to type. Chips compose intelligently: tapping Color · Black after Running returns black running shoes specifically, not random black products from other categories.

Best for me

Tapping 🏆 Best for me calls the LLM with the current refinement context (e.g. "running" + "black") plus a candidate pool of matching products, and returns the top 3 picks. If fewer than 4 products match, the system short-circuits and returns them all — no LLM call needed.

Widget events

The widget fires CustomEvents on window so you can hook into your own analytics (Google Analytics, Segment, Mixpanel, dataLayer) without backend integration.

Event nameWhen it firesdetail payload
trooply:chat_openedVisitor opens the chat panel{store_id, at}
trooply:chat_closedVisitor closes the chat panel{store_id, at}
// Pipe widget opens into GA4
window.addEventListener("trooply:chat_opened", (e) => {
  gtag("event", "chat_opened", { store_id: e.detail.store_id });
});

Languages

Trooply auto-detects the visitor's language per message. Supported: English, Hindi (हिन्दी), Spanish (Español), Arabic (العربية). The detection runs on the message itself, not browser locale, so multilingual shoppers get correct replies even mid-session.

Chat API

Public chat endpoints accept an X-API-Key header. Use these to integrate Trooply into a native app, Slack bot, WhatsApp bridge, or any non-widget surface.

POST /api/v1/chat/message
Content-Type: application/json
X-API-Key: sk_live_…

{
  "message": "show me running shoes",
  "session_id": "any-unique-session-string",
  "visitor_id": "optional-cross-session-id"
}

Response:

{
  "text": "Pick what fits…",
  "message_type": "quick_actions" | "product_card" | "text" | …,
  "products": [{"id":"…","name":"…","price":89.99, "image_url":"…", …}],
  "quick_actions": ["Type · Running", "Color · Black", "🏆 Best for me"],
  "metadata": {"intent":"refinement", "source":"refinement", …}
}

Code samples

The exact same call, in the language you're already writing in:

curl

curl -X POST https://chatbot.trooply.ai/api/v1/chat/message \
  -H "X-API-Key: sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"message":"show me running shoes","session_id":"sess-1234"}'

Python (requests)

import requests

r = requests.post(
    "https://chatbot.trooply.ai/api/v1/chat/message",
    headers={"X-API-Key": "sk_live_…"},
    json={
        "message": "show me running shoes",
        "session_id": "sess-1234",
        "visitor_id": "v-42",
    },
    timeout=30,
)
data = r.json()
print(data["text"])
for product in data.get("products") or []:
    print(f"  - {product['name']} (${product['price']})")

Node.js (fetch / Node 18+)

const res = await fetch("https://chatbot.trooply.ai/api/v1/chat/message", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    message: "show me running shoes",
    session_id: "sess-1234",
    visitor_id: "v-42",
  }),
});
const data = await res.json();
console.log(data.text);
(data.products || []).forEach(p => {
  console.log(`  - ${p.name} ($${p.price})`);
});

React hook

import { useState, useCallback } from "react";

export function useTrooplyChat(apiKey, sessionId) {
  const [messages, setMessages] = useState([]);
  const [loading, setLoading] = useState(false);

  const send = useCallback(async (text) => {
    setMessages(prev => [...prev, { role: "user", text }]);
    setLoading(true);
    try {
      const r = await fetch("https://chatbot.trooply.ai/api/v1/chat/message", {
        method: "POST",
        headers: {
          "X-API-Key": apiKey,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ message: text, session_id: sessionId }),
      });
      const data = await r.json();
      setMessages(prev => [...prev, {
        role: "bot",
        text: data.text,
        products: data.products || [],
        chips: data.quick_actions || [],
      }]);
    } finally {
      setLoading(false);
    }
  }, [apiKey, sessionId]);

  return { messages, send, loading };
}

Streaming (Server-Sent Events)

// JS / Browser
const res = await fetch("https://chatbot.trooply.ai/api/v1/chat/stream", {
  method: "POST",
  headers: { "X-API-Key": "sk_live_…", "Content-Type": "application/json" },
  body: JSON.stringify({ message: "show me shoes", session_id: "s-1" }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  // each chunk is one or more "data: {...}\n\n" SSE events
  for (const line of decoder.decode(value).split("\n\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));
    if (event.type === "token") process.stdout.write(event.text);
    if (event.type === "done") {
      console.log("\nproducts:", event.products);
      console.log("chips:", event.quick_actions);
    }
  }
}

Billing API

EndpointMethodPurpose
/api/v1/billing/pricingGETPublic pricing table (3 tiers).
/api/v1/billing/checkoutPOSTCreate a Stripe Checkout session. Returns {url, session_id}.
/api/v1/billing/portalPOSTOpen the Stripe customer portal.
/api/v1/billing/subscriptionGETCurrent plan + billing status for the authed store.
/api/v1/billing/webhookPOSTWhere Stripe POSTs events (signed by Stripe-Signature).

Onboarding API

EndpointMethodPurpose
/api/v1/onboarding/statusGETChecklist of remaining setup steps.
/api/v1/onboarding/embed-snippetPOSTMints an API key + returns the ready-to-paste snippet.
/api/v1/onboarding/brandPUTSave brand color + greeting.
/api/v1/onboarding/import-catalogPOSTKicks off a crawl of the store URL.
/api/v1/onboarding/completePOSTMark onboarding done.

Stripe webhooks

Point Stripe at https://chatbot.trooply.in/api/v1/billing/webhook and subscribe to:

Trooply verifies the Stripe-Signature header against STRIPE_WEBHOOK_SECRET. Events update the store's billing_status, subscription_plan_id, and plan_expires_at in real time.

Need help? Email [email protected] — we typically respond within a few hours during business days.