Guide · OpenAI · Chatbot

How to Build a Chatbot for Your Website Using the OpenAI API

Step-by-step guide to adding an AI chatbot to your website using the OpenAI API and Next.js — streaming responses, conversation history, custom prompting, and deployment.

JS

Jatinder Sandhu

Published 7 July 2026 · 9 min read

Website visitors expect instant answers. A contact form that gets a reply in two days loses leads to a competitor who answers questions the moment they're asked. That's the practical reason so many businesses I work with ask for an AI chatbot before they ask for almost anything else — it's the fastest way to turn passive traffic into qualified conversations.

The OpenAI API makes this achievable without a huge engineering budget. You don't need a dedicated data science team or a custom-trained model — you need a well-structured Next.js API route, a clear system prompt, and a chat widget that feels native to your site.

This guide walks through the exact process I use when shipping a chatbot for a client's website: project setup, the API route, streaming responses, conversation history, custom prompting so the bot actually knows the business, and what it takes to run this safely in production.

Why Add a Chatbot to Your Website

Before writing any code, it's worth being clear on what a chatbot is actually solving. On most business websites I build, it replaces three things at once: a slow contact form, an FAQ page nobody reads, and a support inbox that piles up overnight.

Instant lead qualification

The bot can ask qualifying questions — budget, timeline, service needed — before a lead ever reaches a human.

24/7 coverage

Visitors in different time zones get answered immediately instead of waiting for business hours.

Lower support load

Repetitive questions — pricing, hours, how something works — get handled without a human touching the ticket.

Higher engagement

Interactive chat keeps visitors on the page longer than a static block of text ever will.

Step 1: Project Setup and API Key

Start by installing the official OpenAI SDK in your Next.js project:

npm install openai

Add your API key to .env.local. This key must never be exposed to the browser — it only ever runs on the server:

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx

Next.js API routes and Server Actions run server-side by default, which is exactly what keeps this key safe. If you ever see an OpenAI key inside client-side JavaScript, that's a security bug — fix it before shipping.

Step 2: Build the Chat API Route

In the App Router, create a route handler at src/app/api/chat/route.ts:

import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

export async function POST(req: Request) {
  const { messages } = await req.json();

  const completion = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: 'You are a helpful support assistant for Acme Co.' },
      ...messages,
    ],
  });

  return Response.json(completion.choices[0].message);
}

This gives you a working, non-streaming chatbot. It's fine for a first test, but real users will notice the delay on longer replies — which is why streaming matters for anything you actually ship.

Step 3: Stream Responses to the Browser

The OpenAI SDK supports streaming out of the box. Instead of waiting for the full reply, you forward each token to the client as it arrives:

export async function POST(req: Request) {
  const { messages } = await req.json();

  const stream = await openai.chat.completions.create({
    model: 'gpt-4o',
    stream: true,
    messages: [
      { role: 'system', content: 'You are a helpful support assistant for Acme Co.' },
      ...messages,
    ],
  });

  const encoder = new TextEncoder();
  const readable = new ReadableStream({
    async start(controller) {
      for await (const chunk of stream) {
        const text = chunk.choices[0]?.delta?.content || '';
        if (text) controller.enqueue(encoder.encode(text));
      }
      controller.close();
    },
  });

  return new Response(readable, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  });
}

On the client, read the stream with fetchand a reader loop, appending each chunk to component state as it comes in. This one change — showing text as it's generated — is what makes a chatbot feel responsive instead of stuck.

Managing Conversation History

Every message you send the API costs tokens, and full conversation history gets expensive fast on longer sessions. In client projects, I handle this with a few consistent rules:

  • Keep history client-side — store the message array in component state or local storage, and send it with every request.
  • Cap the window — trim to the last 10–15 messages so token usage stays predictable as a conversation grows.
  • Summarize old context — for long support sessions, periodically compress older messages into a short summary instead of dropping them entirely.
  • Persist server-side for support handoff — if a human might need to take over, log the conversation to a database, not just the browser.

Custom Prompting So the Bot Knows Your Business

A generic system prompt gives you a generic chatbot. The real work is in the system prompt — feeding it the business context it needs to answer real questions instead of hedging.

Prompt elementWhy it matters
Business factsServices, pricing ranges, hours, location — without this the bot invents or refuses to answer.
Tone instructionsTell it explicitly to be concise, friendly, or formal — this is where brand voice lives.
BoundariesTell it what not to promise — discounts, legal advice, exact delivery dates — to avoid liability.
Escalation pathGive it a clear instruction to collect an email and hand off when it doesn't know an answer.

For larger knowledge bases — product catalogs, long documentation — a static system prompt isn't enough. That's where a lightweight retrieval step (searching your own content and injecting the relevant chunk into the prompt) keeps answers accurate without ballooning the prompt size.

Building the Chat Widget UI

The widget itself should be a small, self-contained component — a floating launcher button, an expandable panel, a message list, and an input box. Keep the state simple: an array of messages, a loading flag, and the input value.

A few UI details make a real difference in how “finished” the widget feels: auto-scroll to the latest message, a typing indicator while the stream is active, disabling the input while a response is in progress, and a persistent session so a page refresh doesn't wipe the conversation.

Controlling Cost and Abuse

An open chatbot endpoint on a public website is an easy target for abuse — bots hammering your API can run up a bill fast. Every chatbot I ship to production has these guardrails in place before launch:

  • Rate limiting per IP or session, so a single visitor can't spam the endpoint.
  • Max tokens set explicitly on every request, capping the cost of any single reply.
  • A cheaper model for simple queries — not every message needs your most expensive model.
  • Usage monitoring — alerts on unusual spend so a problem gets caught in hours, not at the end of the month.

Conclusion

A production-ready chatbot comes down to a handful of decisions done properly: keep the API key server-side, stream responses so the UI feels alive, manage conversation history deliberately, write a system prompt that actually reflects the business, and put rate limits in place before launch, not after a surprise bill.

I build this exact chatbot pattern into Next.js sites for clients — from a simple FAQ assistant to a fully custom support and lead-qualification bot trained on a company's own content.

Want an AI chatbot built into your website? Get in touch — jatindersandhuinfo@gmail.com

ShareXLinkedIn

About the Author

Hi, I'm Jatinder Sandhu, a Full-Stack Developer with 6+ years of experience building websites, web applications, business management systems, and AI-powered solutions using technologies like Next.js, React, Node.js, and MongoDB.

I share practical technology guides, development tutorials, and business growth insights based on real-world experience working on client projects.

If you're looking to build a website, custom software, business automation system, or AI-powered solution, explore my portfolio at jatinder.malwaland.com.