← Blog

Claude API React Frontend Integration Guide

2026-09-30 · 5 min read · SubToAPI Team

Claude API React Frontend Integration

If you're building a React app and want to add Claude-powered chat, search, or content generation, the core challenge isn't calling the API — it's calling it safely from a browser environment while still getting a responsive, streaming UI. This guide covers both: the architecture pattern you need and the actual React code for rendering a Claude response as it streams in.

The short answer: you should never call api.anthropic.com directly from client-side React code, because that exposes your API key to anyone who opens dev tools. Instead, you need a backend proxy (your own server or a hosted API layer) that holds the key, and your React app talks to that proxy over HTTPS. Everything below assumes that setup.

Why You Can't Call Claude Directly from the Browser

Anthropic's API expects an x-api-key header on every request. If you put that key in your React bundle — even in an environment variable prefixed with REACT_APP_ or VITE_ — it ships to every visitor's browser as plain text in the compiled JS. Anyone can extract it and run up your bill.

The standard fix is a thin backend layer:

  1. React sends a request to your own endpoint (e.g. /api/chat).
  2. Your server attaches the real API key and forwards the request to Claude.
  3. The server streams the response back to React.

You can build this yourself with a few lines of Express or a serverless function, or use a hosted proxy like SubToAPI, which gives you an application-scoped key (sub_live_...) you can call from your backend without managing Anthropic credentials, streaming infrastructure, or rate-limit handling yourself.

Backend Proxy Example (Node/Express)

app.post("/api/chat", async (req, res) => {
  const response = 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",
      max_tokens: 1024,
      stream: true,
      messages: req.body.messages
    })
  });

  res.setHeader("Content-Type", "text/event-stream");
  response.body.pipe(res);
});

This keeps your key server-side and passes the stream through unchanged. See /docs/messages and /docs/streaming for the full request/response shape.

React Component: Streaming Chat UI

Once you have a proxy endpoint, the React side is about handling a streamed response and updating state incrementally so the text appears token-by-token instead of all at once.

import { useState } from "react";

function ChatBox() {
  const [input, setInput] = useState("");
  const [reply, setReply] = useState("");
  const [loading, setLoading] = useState(false);

  async function sendMessage() {
    setLoading(true);
    setReply("");

    const res = await fetch("/api/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        messages: [{ role: "user", content: input }]
      })
    });

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

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      const lines = chunk.split("\n").filter(l => l.startsWith("data:"));

      for (const line of lines) {
        const data = line.replace("data: ", "");
        if (data === "[DONE]") continue;
        try {
          const parsed = JSON.parse(data);
          if (parsed.delta?.text) {
            setReply(prev => prev + parsed.delta.text);
          }
        } catch {
          // ignore malformed chunk boundaries
        }
      }
    }

    setLoading(false);
  }

  return (
    <div>
      <textarea value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={sendMessage} disabled={loading}>
        {loading ? "Thinking..." : "Send"}
      </button>
      <p>{reply}</p>
    </div>
  );
}

export default ChatBox;

A few things worth noting about this pattern:

Handling Tool Use and Structured Output in React

If your Claude integration uses tool calling — for example, letting Claude query your database or call an internal API — the React layer doesn't need to know about tool execution at all. That logic stays on the backend: your proxy receives the tool-use request from Claude, executes the function, sends the result back, and only forwards the final text response (or a structured JSON payload) to React. This keeps your frontend simple and avoids exposing internal API contracts to the browser. Details on request format are in /docs/tools.

Error Handling and Rate Limits

Two failure modes matter most in production React apps:

If you're using a managed proxy, usage metadata (tokens consumed, request counts) is typically available per API key, which makes it easier to debug which frontend feature is driving cost without instrumenting this yourself.

Getting Set Up Quickly

If you don't want to build and maintain the proxy layer, SubToAPI turns your existing Claude access into an HTTPS API with per-application keys, built-in streaming, and usage dashboards — so your React app just calls a normal REST endpoint. Plans start at €9/month for solo developers, with team seats at €19 and €49 for larger projects. You can try it with a free trial at /signup, and the /pricing page has the full breakdown.

FAQ

Can I call the Claude API directly from a React component without a backend? Not safely. Doing so exposes your API key in the client bundle. Always proxy requests through a server you control, whether that's your own backend or a hosted API layer.

How do I show streaming text in React without a UI library? Use the Fetch API's ReadableStream reader to read chunks, decode them, and append the parsed text to component state on each chunk — as shown in the example above.

Does tool use change how I structure my React code? No. Tool execution happens on your backend proxy; React only receives the final response, so your components stay focused on rendering, not orchestration.

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 →