How to Integrate Claude/GPT into a Reusable Chatbot Web Component
Hands‑on guide to build a reusable chatbot web component that switches between Claude and ChatGPT, with React/Vue/vanilla examples and modular prompt templates.
Cut development time: build a reusable chatbot web component that calls Claude and ChatGPT
Decision fatigue, slow UI wiring, and uncertainty about vendor APIs slow teams down. If you need a reusable chatbot for micro‑apps (think dining recommender, meeting planner, or code helper), this hands‑on guide shows how to build a single, framework‑agnostic web component with plug‑in adapters for Claude and ChatGPT. You’ll get React, Vue 3, and vanilla Web Component implementations, modular prompt templates, server proxy patterns for secure keys, streaming, accessibility tips, and production hardening notes for 2026.
The why (2026 trends)
Micro apps — small, single‑purpose applications that the creator uses themselves or shares with a few people — keep growing in 2025–2026. People like Rebecca Yu built dining apps (Where2Eat) quickly using Claude and ChatGPT to generate multi‑step UX flows without heavy backend investment. Anthropic’s Cowork (late 2025 / early 2026 previews) lowered the barrier for desktop AI agents; teams are pairing this with low-latency hardware like edge‑first laptops and local inference for better responsiveness. This moment means your teams should standardize a fast, secure integration pattern so micro apps ship quickly but safely.
What you’ll get
- Reusable Web Component chatbot that works in React, Vue, and plain HTML
- Server proxy patterns to protect API keys and support both Claude and ChatGPT
- Modular prompt templates for micro apps (dining recommender example)
- Streaming and non‑streaming examples, accessibility, caching, and latency tips
Architecture overview
- Client Web Component: exposes a small API and events; responsible for UI, ARIA, and local state.
- Server Proxy: signs requests to OpenAI/Anthropic, rate limits, strips sensitive data, and returns streaming tokens or completed responses.
- Prompt Templates: JSON+/JS modules with slots and validators to compose messages for either provider.
- Adapters: provider-specific plumbing that maps your prompt template to the provider's API shape.
Security & policy first
Never embed API keys in the browser. Use a server proxy with strict CORS, per‑user rate limits, and monitoring. Also add content filters and conservative default prompt constraints for user‑generated content — Claude and ChatGPT may return sensitive or hallucinated information if prompts encourage it.
Server proxy (Node + Express) — single endpoint, multi‑provider
Use a single /api/chat endpoint that accepts a provider param: provider: "openai" or "anthropic". The proxy authenticates the user session, rate limits, and forwards the composed messages. Below is a concise example you can adapt. For production, pair this with strong observability and tracing so you can spot abuse and performance regressions quickly.
// server/proxy.js (Node/Express, simplified)
const express = require('express');
const fetch = require('node-fetch');
const rateLimit = require('express-rate-limit');
const app = express();
app.use(express.json());
const limiter = rateLimit({ windowMs: 60_000, max: 60 });
app.use('/api/chat', limiter);
app.post('/api/chat', async (req, res) => {
const { provider, payload } = req.body;
// Basic auth/session check (implement your actual auth)
if (!req.headers.authorization) return res.status(401).end();
try {
if (provider === 'openai') {
const r = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const json = await r.json();
return res.json(json);
}
if (provider === 'anthropic') {
const r = await fetch('https://api.anthropic.com/v1/complete', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const json = await r.json();
return res.json(json);
}
res.status(400).json({ error: 'unknown provider' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'proxy_error' });
}
});
app.listen(3000);
Prompt engineering: modular templates
Make prompt templates composable. Build a small template system that has: metadata, system message, user template with slots, and optional postprocessors that parse or validate the model output. Treat templates like code — version, test and document them as in a templates-as-code approach.
// prompts/dining.js
module.exports = {
id: 'dining-recommender-v1',
system: `You are a helpful dining recommender. Ask clarifying questions if the user's preferences are missing.`,
userTemplate: `Given this group: {{group}}, cuisine preferences: {{cuisines}}, price: {{price}}, location radius: {{radius}}km. Return 3 recommendations in JSON array: [{"name":"","address":"","reason":"","score":0.0}]`,
slots: ['group', 'cuisines', 'price', 'radius'],
postprocess: (output) => {
try { return JSON.parse(output); } catch(e) { return null; }
}
}
At runtime substitute slots and produce a messages array for ChatGPT or a prompt string for Claude. Keep the template small so micro apps can swap templates easily.
Template rendering helper (simple)
// utils/renderTemplate.js
function render(template, data) {
return template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => data[key] ?? '');
}
module.exports = { render };
Adapter: map template to provider payloads
Create a tiny adapter function that maps the rendered template into the correct API shape. This isolates changes if Anthropic or OpenAI change endpoints — think of adapters like a lightweight open middleware layer between your UI and providers.
// adapters/index.js
function openaiPayload(system, user, options = {}) {
return {
model: options.model || 'gpt-4o',
messages: [ { role: 'system', content: system }, { role: 'user', content: user } ],
max_tokens: options.max_tokens || 800
};
}
function anthropicPayload(system, user, options = {}) {
// Claude expects a single prompt string with system/user concatenated
const prompt = `\n\nHuman: ${user}\n\nAssistant:`;
return {
model: options.model || 'claude-2.1',
prompt: `${system}\n${prompt}`,
max_tokens_to_sample: options.max_tokens || 800
};
}
module.exports = { openaiPayload, anthropicPayload };
Client: reusable Web Component (vanilla)
Build a custom element that emits events and exposes simple properties. This component focuses on UI and delegates API calls to your server proxy.
// components/chat-bubble.js
class ChatBubble extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
`;
this.messagesEl = this.shadowRoot.querySelector('.messages');
this.form = this.shadowRoot.querySelector('form');
this.form.addEventListener('submit', this.onSubmit.bind(this));
}
set provider(v) { this._provider = v; }
get provider() { return this._provider || 'openai'; }
async onSubmit(e) {
e.preventDefault();
const q = this.form.q.value.trim();
if (!q) return;
this.appendMessage('user', q);
// fire event for host to handle networking
const evt = new CustomEvent('send', { detail: { provider: this.provider, text: q }, bubbles: true, cancelable: true });
this.dispatchEvent(evt);
}
appendMessage(role, text) {
const el = document.createElement('div');
el.textContent = `${role}: ${text}`;
this.messagesEl.appendChild(el);
this.messagesEl.scrollTop = this.messagesEl.scrollHeight;
}
}
customElements.define('chat-bubble', ChatBubble);
Embedding in plain HTML
<script src="/components/chat-bubble.js"></script>
<chat-bubble id="reco" provider="openai"></chat-bubble>
<script>
const comp = document.getElementById('reco');
comp.addEventListener('send', async e => {
const { provider, text } = e.detail;
const payload = { provider, payload: /* compose adapter payload here */ {} };
const res = await fetch('/api/chat', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(payload)});
const json = await res.json();
// map provider response to text and append
comp.appendMessage('assistant', json.choices?.[0]?.message?.content || json.completion || JSON.stringify(json));
});
</script>
React integration
Use the same web component inside React. Expose a small adapter to map component events to your client fetch logic. When integrating with React and other frameworks, keep an eye on the latest ECMAScript 2026 proposals that affect module loading and Web Component ergonomics.
// App.jsx
import React, { useRef, useEffect } from 'react';
import './components/chat-bubble.js';
export default function App(){
const ref = useRef(null);
useEffect(() => {
const node = ref.current;
async function onSend(e){
const provider = e.detail.provider;
const text = e.detail.text;
const payload = { provider, payload: { /* adapter payload */ } };
const r = await fetch('/api/chat', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(payload)});
const json = await r.json();
node.appendMessage('assistant', json.choices?.[0]?.message?.content || json.completion || JSON.stringify(json));
}
node.addEventListener('send', onSend);
return () => node.removeEventListener('send', onSend);
}, []);
return <chat-bubble ref={ref} provider="openai" />;
}
Vue 3 integration (Composition API)
// ChatWrapper.vue
<template>
<chat-bubble ref="chat" provider="anthropic"/>
</template>
<script setup>
import { onMounted, ref } from 'vue';
const chat = ref(null);
onMounted(() => {
const node = chat.value;
node.addEventListener('send', async e => {
const { provider, text } = e.detail;
const payload = { provider, payload: { /* adapter payload */ } };
const r = await fetch('/api/chat', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(payload)});
const json = await r.json();
node.appendMessage('assistant', json.completion || json.choices?.[0]?.message?.content);
});
});
</script>
Handling streaming responses
Streaming drastically improves perceived latency. Both OpenAI and Anthropic offer streaming endpoints (SSE/HTTP2). Implement streaming in the proxy by piping bits to the client (Server‑Sent Events or WebSockets), then append tokens client‑side. Make sure your network design accounts for failover and edge routing so partial streams don't hang — techniques covered in channel failover and edge routing playbooks (channel failover & edge routing).
// client-side append loop (pseudo)
const sse = new EventSource(`/api/stream?session=${id}`);
sse.onmessage = e => {
const token = JSON.parse(e.data).token;
component.appendMessage('assistant', token); // append incrementally
};
Accessibility & testing
- Label inputs and ensure keyboard focus management (role="log" for transcript).
- Support text alternatives for generated suggestions, and provide a "copy" or "save" action for outputs.
- Write unit tests for the prompt renderer and adapter mappings; E2E tests (Playwright) should record and replay API calls (use fixtures). Document test and compliance workflows similar to a docs-as-code approach for legal and audit teams.
Performance, cost, and observability
Measure token usage and latency. Store telemetry: tokens_in, tokens_out, latency_ms. Cache deterministic prompts (e.g., repeated recommendation seeds) and use a short LRU cache to reduce calls. For micro apps, constrain max_tokens to control cost; pair instrumentation with a cloud cost optimisation strategy so you can alert on spikes. In 2026, models like GPT‑4o and Claude 2.x offer better context windows — but costs vary, so instrument and alert unusual usage.
Edge cases & hardening
- Fallback to non‑streaming if the client doesn’t support EventSource or WebSocket.
- Rate limit per user and per API key to protect from abuse.
- Postprocess outputs (JSON schema validation) — never trust raw model JSON unless validated.
Dining recommender: end‑to‑end flow (example)
- User opens micro app, selects group size and basic preferences.
- Client renders template: injects group/cuisine/price/radius into the dining template.
- Adapter maps template => provider payload; request goes to /api/chat with provider flag.
- Proxy calls provider API, streaming tokens back; client appends tokens for instant feedback.
- On completion, postprocessor validates JSON; UI displays top 3 recommendations with links and share actions.
Example: simple postprocess validator
// validators/jsonSchema.js
const Ajv = require('ajv');
const ajv = new Ajv();
const schema = {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
address: { type: 'string' },
reason: { type: 'string' },
score: { type: 'number' }
},
required: ['name', 'address']
}
};
const validate = ajv.compile(schema);
module.exports = validate;
Provider selection guidance
- Claude: often preferred for long‑form reasoning and settings where you want conservative outputs. Assess Claude’s context and file access features (e.g., Cowork) if your micro app requires workspace integration.
- ChatGPT: broader ecosystem tools, function calling, and large model family (e.g., GPT‑4o) can be more flexible for multimodal tasks. Consider function calling to extract structured data from replies.
- When to offer both: provide a toggle in advanced settings for power users to switch provider and compare outputs side‑by‑side.
Maintenance & licensing
For components you ship commercially: explicitly document supported provider versions, maintain adapter tests, and add a deprecation policy. Track provider TOS and model licensing — some enterprise customers will require contractual agreements for data handling and retention. Treat documentation as code and maintain versioned policy artifacts (see templates-as-code patterns).
2026 predictions
Expect the following through 2026:
- More granular edge compute options: you’ll see low‑latency regional model endpoints ideal for micro apps embedded in enterprise networks and paired with edge-assisted collaboration.
- Unified tooling that composes LLMs, retrieval, and UI components will continue to mature — but reusable, audited components (like this one) will still save time.
- Model introspection APIs and function registries will make validation and safety checks easier to automate; open middleware and standards help interoperability (OMX).
"Micro apps plus reliable AI backends let non‑engineers ship utilities quickly, but teams must standardize secure integration patterns to scale." — engineering perspective, 2026
Actionable checklist (ship-ready)
- Implement a server proxy; never expose API keys. Pair this with strong observability and tracing.
- Build modular prompt templates and adapters; version them — treat templates as code (templates-as-code).
- Use streaming for perceived latency; fall back cleanly and design for channel failover.
- Validate model outputs (JSON schema / function calls) and keep validators in CI.
- Monitor token usage, latency, and errors; link monitoring to cloud cost optimisation and alerting.
- Document provider and model versions; add deprecation timelines and middleware compatibility notes (OMX).
- Test accessibility and keyboard UX for the component; consider voice & on-device privacy tradeoffs (on-device voice).
Final notes
This approach gives you a single, reusable chatbot component that can pivot between Claude and ChatGPT with minimal changes. It supports the micro‑app trend (personal, small apps) while keeping engineering, security, and maintenance concerns under control. The key is modularity: templates, adapters, and a simple server proxy let you adapt quickly as providers evolve in late 2025 and 2026.
Get started — template repo
Clone a starter repo: include server/proxy.js, adapters, prompts, validators, and the chat‑bubble component. Start with a dining template and iterate: swap providers, instrument metrics, and expose provider selection to users.
Call to action
Ready to cut weeks of UI work? Download the starter repository, plug in your API keys to a protected server, and run the dining recommender micro app in 1–2 hours. If you want a production review, we audit prompts, security, and cost‑controls for teams building micro apps — get in touch for a tailored checklist and sample integrations.
Related Reading
- The Evolution of Cloud Cost Optimization in 2026: Intelligent Pricing and Consumption Models
- Advanced Strategy: Observability for Workflow Microservices — From Sequence Diagrams to Runtime Validation (2026 Playbook)
- ECMAScript 2026: What the Latest Proposal Means for E-commerce Apps
- Open Middleware Exchange: What the 2026 Open-API Standards Mean for Cable Operators
- Gerry & Sewell: From Gateshead Social Club to the Aldwych — The Regional Story Behind the West End Transfer
- Makeup Artist with Vitiligo: Behind-the-Scenes Techniques for Camera-Ready Coverage
- Autonomous Agents, Elevated Privileges, and Quantum Cryptography: Risk Assessment for IT Admins
- Gaming Monitor Showdown: Alienware AW3423DWF vs Top 34" OLEDs — Is $450 the No-Brainer Buy?
- Designing a Collectible 'Mini-Poster' Flag Series — From Renaissance Postcards to Modern Keepsakes
Related Topics
javascripts
Contributor
Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.
Up Next
More stories handpicked for you
From Our Network
Trending stories across our publication group