← Blog

Claude API Chat Widget for Website: Build & Embed Guide

2026-10-13 · 5 min read · SubToAPI Team

A Claude API chat widget is a small embeddable interface — usually a floating button that expands into a chat window — that lets visitors talk to Claude directly on your website. It's the same pattern as Intercom or Drift, except the "agent" is powered by Anthropic's models instead of a human or scripted bot.

To build one you need three pieces: a frontend widget (HTML/CSS/JS, or a React component) that captures user messages and renders replies, a backend endpoint that forwards those messages to the Claude API with your credentials, and a way to stream responses back so the widget feels responsive instead of freezing for several seconds per reply. This article walks through all three.

Why you can't call Claude directly from the browser

Anthropic's API keys are meant to stay server-side. If you put a key in frontend JavaScript, anyone who opens dev tools can copy it and start making requests on your bill. Every working Claude API chat widget therefore has a backend step in between — even if it's a single serverless function.

That backend step also gives you a place to:

Minimal backend endpoint

A basic Node.js/Express proxy looks like this:

app.post("/api/chat", async (req, res) => {
  const { messages } = req.body;

  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": process.env.ANTHROPIC_API_KEY,
      "anthropic-version": "2023-06-01",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      system: "You are a helpful support assistant for Acme Co.",
      messages,
    }),
  });

  const data = await response.json();
  res.json(data);
});

This works, but every reply waits for the full response before the widget shows anything. For a chat widget that feels alive, you want streaming.

Streaming replies into the widget

Streaming sends the reply token by token using server-sent events. On the frontend, you read the stream and append text as it arrives instead of waiting for a full JSON blob. If you're routing requests through SubToAPI instead of managing raw Anthropic credentials, streaming works the same way but over a single stable HTTPS endpoint with your own sub_live_... key:

const res = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    stream: true,
    messages: [{ role: "user", content: userMessage }],
  }),
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value);
  // parse SSE lines, append text deltas to the chat bubble
}

Full details on event formats and parsing are in the streaming docs. The same endpoint also handles non-streaming calls — see the messages reference if you'd rather fetch the full reply at once for a simpler first version.

Frontend widget structure

Keep the widget itself framework-agnostic so it's easy to drop into any site — WordPress, a static site, a React app, whatever. A minimal version needs:

<div id="chat-widget">
  <button id="chat-toggle">Chat with us</button>
  <div id="chat-window" class="hidden">
    <div id="chat-messages"></div>
    <input id="chat-input" placeholder="Ask a question..." />
  </div>
</div>

Each time the user sends a message, push it to the local messages array, send the whole array to your backend endpoint (not just the latest message — Claude needs the full history for context), and append the assistant's streamed reply as a new bubble.

Adding tool use for real functionality

A widget that only answers generic questions is limited. If you want it to look up order status, check documentation, or trigger a support ticket, you'll want tool calling — Claude decides when to call a function you've defined, your backend executes it, and the result goes back into the conversation. This is covered in the tools documentation, and it's the difference between a chat widget that sounds helpful and one that actually does something.

Rate limiting and abuse prevention

Public-facing widgets get hit by scrapers and occasionally bad actors trying to jailbreak your system prompt. Practical mitigations:

Where SubToAPI fits

If you already have Claude access through a subscription and want to turn it into an API your widget's backend can call — with per-key usage tracking, streaming support, and team seats if more than one person manages the integration — SubToAPI gives you a sub_live_... key and a single HTTPS endpoint instead of juggling raw Anthropic credentials and billing separately. Setup takes about the time it takes to read the quickstart guide, and there's a free trial at signup if you want to wire up a prototype widget before committing to a plan.

questions

Do I need a backend to build a Claude API chat widget, or can it run purely in JavaScript? You need a backend or serverless function. Calling the Claude API directly from browser JavaScript exposes your API key to anyone who inspects network requests, which is a security risk and usually a violation of API terms.

How do I make the widget feel fast instead of waiting for a full response? Use streaming responses (server-sent events) so text appears token by token as Claude generates it, rather than waiting for the complete reply. See the streaming docs for implementation details.

Can the widget do more than answer questions, like checking order status? Yes, with tool calling. You define functions (lookup order, create ticket, search docs) and Claude decides when to invoke them during the conversation, with your backend executing the actual logic and returning results.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →