Option 1
Set up with plain HTML
Embed a streaming agent chat in any HTML page — no build step, no framework. Loads the Amplitude Browser SDK from CDN, calls /api/chat with fetch, and renders streamed deltas into the DOM.
1
Add the Amplitude SDK to your <head>
Use the official browser SDK so backend events stitch to the same Session Replay. Initialize before any chat scripts run.
html
<script src="https://cdn.amplitude.com/libs/analytics-browser-2.11.1-min.js.gz"></script>
<script src="https://cdn.amplitude.com/libs/plugin-session-replay-browser-1.18.0-min.js.gz"></script>
<script>
window.amplitude.add(window.sessionReplay.plugin({ sampleRate: 1 }));
window.amplitude.init("YOUR_AMPLITUDE_API_KEY", {
autocapture: true,
defaultTracking: true,
});
</script>2
Drop in the chat container
One <div>for the transcript, one for the input. Keep it in the host page's DOM — no iframes, or Session Replay won't capture it.
html
<div id="chat" style="max-width:760px;margin:0 auto;">
<div id="messages" style="min-height:300px;padding:16px;"></div>
<form id="chat-form" style="display:flex;gap:8px;">
<input id="chat-input" placeholder="Ask anything…" autocomplete="off"
style="flex:1;padding:10px;border:1px solid #e5e7eb;border-radius:8px;" />
<button type="submit" style="padding:10px 16px;border-radius:8px;">Send</button>
</form>
</div>3
Wire up the streaming call
Read device_id and session_id from the live SDK and include them in the request body. The server forwards both to its backend track() calls so events land on the same replay timeline.
html
<script type="module">
const messagesEl = document.getElementById("messages");
const formEl = document.getElementById("chat-form");
const inputEl = document.getElementById("chat-input");
const history = [];
formEl.addEventListener("submit", async (e) => {
e.preventDefault();
const text = inputEl.value.trim();
if (!text) return;
inputEl.value = "";
appendBubble("user", text);
const assistant = appendBubble("assistant", "");
history.push({ role: "user", content: text });
const res = await fetch("https://demo-agent-analytics-server.vercel.app/api/chat", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
messages: history,
agentId: "shopping-agent",
amplitude: {
apiKey: "YOUR_AMPLITUDE_API_KEY",
deviceId: window.amplitude.getDeviceId(),
sessionId: window.amplitude.getSessionId(),
userId: window.amplitude.getUserId(),
},
}),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let full = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
full += decoder.decode(value, { stream: true });
assistant.textContent = full;
}
history.push({ role: "assistant", content: full });
});
function appendBubble(role, content) {
const el = document.createElement("div");
el.textContent = content;
el.style.cssText = role === "user"
? "text-align:right;margin:8px 0;padding:8px 12px;background:#2563eb;color:#fff;border-radius:12px;display:inline-block;"
: "margin:8px 0;padding:8px 12px;background:#f3f4f6;border-radius:12px;";
messagesEl.appendChild(el);
messagesEl.scrollTop = messagesEl.scrollHeight;
return el;
}
</script>4
Verify events flow into Amplitude
Send a message and open User Lookup in your Amplitude project. You should see, on the same replay timeline:
[Agent] Message Sent— emitted at request start[Agent] Message Received— emitted at stream end (with token usage + latency)