AI Chatbot Builder Guide

Step 1 of 8

What is an AI chatbot?

Understand the core concept before writing a single line of code.

Plain English

An AI chatbot is a program that takes text input, sends it to an AI model over the internet, and shows the model's text response back to the user. That's it.

The AI model lives on a server (Google's, in our case). Your code just asks it questions and displays answers. You don't need to train anything — the hard work is already done.

┌─────────────┐ ┌──────────────────┐ ┌─────────────┐ │ Browser │──POST──▶│ Gemini API │──────▶ │ AI Model │ │ (Your App) │ │ gemini-2.0-flash│ │ (Google) │ └─────────────┘◀────────└──────────────────┘◀────────└─────────────┘ ▲ JSON response │ │ { candidates: [{ text: "..." }] } │ User types Generates text

3 Real-World Examples

Customer Support Bot

Answers FAQs 24/7, escalates to humans only when needed. Reduces support ticket volume by ~60%.

Coding Assistant

Explains code, suggests fixes, generates boilerplate. Like having a senior dev always available.

Language Tutor

Practices conversation, corrects grammar, adapts to your level. Available in 40+ languages.

Why Gemini API?

FeatureGemini APIOpenAIClaude
Free tier✓ Generous✗ Paid only✗ Paid only
Speed (Flash)✓ Very fast~ Medium~ Medium
Context window✓ 1M tokens✓ 128k✓ 200k
Multimodal✓ Native✓ Yes✓ Yes
REST API✓ Simple✓ Simple✓ Simple
Step 2 of 8

Get your API key

Your API key is the password that lets your code talk to Gemini.

How to get your key

  1. Go to aistudio.google.com/app/apikey — sign in with your Google account.
  2. Click "Create API key""Create API key in new project".
  3. Copy the key that appears (starts with AIza). Store it somewhere safe — it won't show again.
  4. Come back here and paste it in the field below (or the one in the top bar).

⚠ Keep your key private

Never put your API key directly in code you share publicly or push to GitHub. For this guide we store it in localStorage (your browser only — never sent anywhere else). For production apps, use a backend server or environment variables.

Live API Key Tester

Step 3 of 8

Your first API call

Send a message to Gemini from your browser with plain JavaScript.

How fetch() + REST APIs work

fetch() is a built-in browser function that sends HTTP requests. The Gemini API is a REST API — it accepts HTTP POST requests with JSON bodies and returns JSON responses.

You send: { contents: [{ parts: [{ text: "your message" }] }] }

You get back: { candidates: [{ content: { parts: [{ text: "the reply" }] } }] }

Live Code Playground — edit and run
Click "Run this code" to see the result...

Common errors explained

400 Bad Request — your JSON body is malformed. Check the structure matches exactly.

401 / 403 — API key is invalid or missing. Paste your key in the top bar first.

429 Too Many Requests — you've hit the rate limit. Wait a minute and try again.

undefined response — the path to the text is wrong. Log data to check the shape.

Step 4 of 8

Add conversation history

Make the chatbot remember what was said earlier in the conversation.

The messages array pattern

Gemini (like all LLMs) is stateless — each request is independent. To give it memory, you send the entire conversation history with every request.

Each message has a role ("user" or "model") and parts containing the text. You append each new message to the array before sending.

javascript
// Maintain history across turns
const history = [];

async function chat(userMessage) {
  // Add user's message
  history.push({
    role: 'user',
    parts: [{ text: userMessage }]
  });

  const response = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ contents: history })  // Send ALL history
  });

  const data = await response.json();
  const reply = data.candidates[0].content.parts[0].text;

  // Add bot's reply to history
  history.push({
    role: 'model',
    parts: [{ text: reply }]
  });

  return reply;
}

Try it — Live chat demo

Mini Chat (with memory)
Hi! I'm your Gemini demo. I remember what we talk about — try asking a follow-up question!
Step 5 of 8

System prompts & personas

Give your chatbot a personality, rules, and a purpose.

What is a system prompt?

A system prompt is a hidden instruction you give the model before the conversation starts. It sets the persona, tone, task, and constraints. Users don't see it, but it shapes every response.

With Gemini, you add a system_instruction field alongside contents:

javascript
const response = await fetch(API_URL, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    system_instruction: {
      parts: [{ text: "You are a friendly pirate. Speak in pirate slang and say 'Arrr!' often." }]
    },
    contents: history
  })
});

Try example system prompts:

Helpful Assistant
🏴‍☠️ Pirate
📚 Tutor
🎭 Shakespeare
😏 Sarcastic
Persona Chat
Choose a persona above and start chatting!
Step 6 of 8

Build the UI

A complete, copy-ready HTML chat interface with CSS included.

Structure overview

A chat UI needs 3 parts: a message display area, an input row, and a send button. The JS fetches from Gemini and appends message bubbles to the display area.

html — full starter template
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My AI Chatbot</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: sans-serif; background: #0f0f0f; color: #e0e0e0; height: 100vh; display: flex; flex-direction: column; }
    #header { background: #1a1a1a; padding: 16px 20px; font-weight: 700; border-bottom: 1px solid #2a2a2a; }
    #messages { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 12px; }
    .msg { max-width: 75%; padding: 10px 16px; border-radius: 12px; line-height: 1.5; }
    .user { background: rgba(184,200,232,0.15); align-self: flex-end; }
    .bot  { background: #1a1a1a; border: 1px solid #2a2a2a; align-self: flex-start; }
    #input-row { display: flex; gap: 10px; padding: 16px; background: #1a1a1a; border-top: 1px solid #2a2a2a; }
    #user-input { flex: 1; background: #0f0f0f; border: 1px solid #2a2a2a; border-radius: 8px; color: #e0e0e0; padding: 10px 14px; font-size: 1rem; outline: none; }
    #send-btn { background: #b8c8e8; color: #0f0f0f; border: none; border-radius: 8px; padding: 10px 20px; font-weight: 700; cursor: pointer; }
  </style>
</head>
<body>
  <div id="header">My AI Chatbot</div>
  <div id="messages"></div>
  <div id="input-row">
    <input id="user-input" type="text" placeholder="Type a message..." />
    <button id="send-btn" onclick="send()">Send</button>
  </div>

  <script>
    const API_KEY = 'YOUR_API_KEY';  // ← replace this
    const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${API_KEY}`;
    const history = [];

    document.getElementById('user-input').addEventListener('keydown', e => { if (e.key === 'Enter') send(); });

    function addMsg(text, role) {
      const div = document.createElement('div');
      div.className = `msg ${role}`;
      div.textContent = text;
      document.getElementById('messages').appendChild(div);
      div.scrollIntoView({ behavior: 'smooth' });
    }

    async function send() {
      const input = document.getElementById('user-input');
      const text = input.value.trim();
      if (!text) return;
      input.value = '';
      addMsg(text, 'user');
      history.push({ role: 'user', parts: [{ text }] });

      const res = await fetch(API_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ contents: history })
      });
      const data = await res.json();
      const reply = data.candidates?.[0]?.content?.parts?.[0]?.text ?? 'Error getting response';
      history.push({ role: 'model', parts: [{ text: reply }] });
      addMsg(reply, 'bot');
    }
  </script>
</body>
</html>
Step 7 of 8

Add features

Upgrade your basic chat UI with these practical enhancements.

Typing Indicator

Show an animated "..." while waiting for the API response — prevents users from thinking the app froze.

Show code snippet
// Show before fetch
function showTyping() {
  const div = document.createElement('div');
  div.className = 'msg bot typing';
  div.id = 'typing-indicator';
  div.textContent = '...';
  messages.appendChild(div);
}
// Remove after fetch
document.getElementById('typing-indicator')?.remove();

Copy Button

Add a small copy icon to each bot message so users can copy the response with one click.

Show code snippet
function addBotMsg(text) {
  const wrap = document.createElement('div');
  wrap.className = 'msg-wrap';
  const msg = document.createElement('div');
  msg.className = 'msg bot';
  msg.textContent = text;
  const btn = document.createElement('button');
  btn.textContent = '📋';
  btn.onclick = () => navigator.clipboard.writeText(text);
  wrap.appendChild(msg);
  wrap.appendChild(btn);
  messages.appendChild(wrap);
}

Clear Chat

Let users start a fresh conversation without reloading the page.

Show code snippet
function clearChat() {
  history.length = 0;  // Reset history array
  document.getElementById('messages').innerHTML = '';
  // Optional: add a welcome message back
  addMsg('Chat cleared! Start a new conversation.', 'bot');
}

Token Counter

Estimate how much of the context window you've used (helpful for long conversations).

Show code snippet
// Rough estimate: ~4 chars per token
function estimateTokens() {
  const allText = history
    .map(m => m.parts[0].text)
    .join(' ');
  return Math.round(allText.length / 4);
}
// Update after each message
document.getElementById('token-count').textContent =
  `~${estimateTokens()} tokens used`;

Export Chat

Let users download the conversation as a .txt file.

Show code snippet
function exportChat() {
  const text = history.map(m =>
    `${m.role === 'user' ? 'You' : 'Bot'}: ${m.parts[0].text}`
  ).join('\n\n');

  const blob = new Blob([text], { type: 'text/plain' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'chat-export.txt';
  a.click();
  URL.revokeObjectURL(url);
}
Step 8 of 8

Deploy to GitHub Pages

Put your chatbot on the internet — free, fast, and permanent.

Step-by-step deploy

  1. Go to github.com/new and create a new public repository (e.g. my-ai-chatbot).
  2. On your computer, open a terminal in your project folder and run: git init && git add . && git commit -m "initial commit"
  3. Push to GitHub: git remote add origin https://github.com/YOUR_USERNAME/my-ai-chatbot.git then git push -u origin main
  4. In your GitHub repo, go to Settings → Pages. Set Source to "Deploy from a branch", Branch to main, folder to /. Click Save.
  5. Wait ~2 minutes. Your site will be live at https://YOUR_USERNAME.github.io/my-ai-chatbot/

Pre-launch checklist

  • Remove hardcoded API key — use a prompt for users to enter their own key
  • Test on mobile (resize browser to 375px width)
  • Test with a slow connection (Chrome DevTools → Network → Slow 3G)
  • Add a README.md explaining what the chatbot does and how to use it
  • Add an error message when the API call fails

Keep building — 100 AI Agents Project

This guide is Agent #28 of the 100 AI Agents challenge — a series of 100 useful AI tools built with HTML and Gemini.

Explore the full collection for inspiration on what to build next: hhanng.github.io