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)