← Back to Blog
AIChatbotClaude APIBangkok

Building an AI Chatbot for Bangkok Clinics and Restaurants with Next.js and Claude

5 May 2026 · by Yunmin Shin

Why Build a Chatbot with Claude for a Bangkok Business?

A front desk at a Bangkok aesthetic clinic fields the same dozen questions all day: how much is a filler treatment, how long is downtime, do you take walk-ins, is there an English-speaking doctor. A restaurant discovery site gets the same pattern — is this place halal, is there parking, do they take reservations for groups of eight. None of that requires a human until the customer is ready to commit.

Claude's instruction-following and long context make it well suited to this: you can hand it a full treatment menu or restaurant listing as context and get answers that stay accurate to your actual pricing and policies, in whichever language the customer opens with. For a Bangkok business serving Thai locals, English-speaking expats, and — for clinics especially — Korean and Chinese medical tourists, that multilingual handling is the actual product, not a nice-to-have.

The pattern that works in production: the bot answers what it can from your real data, and hands off to a human on LINE the moment the conversation moves toward booking or payment. Claude answering FAQs at 2am and a staff member closing the actual sale on LINE the next morning is a division of labor that holds up.

How Do You Set Up the Claude API?

Install the Anthropic SDK:

npm install @anthropic-ai/sdk

Store the key server-side only:

ANTHROPIC_API_KEY=sk-ant-...
// lib/anthropic.ts
import Anthropic from "@anthropic-ai/sdk";
export const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

Never expose this key in client-side code. All calls must happen in Route Handlers, Server Actions, or server components — a chatbot widget embedded on a clinic's public site is exactly the kind of surface where a leaked key gets scraped and abused within hours.

How Do You Stream the Response?

Users on a mid-range Android phone over 4G notice the difference between a response that starts appearing after 400ms and one that arrives all at once after 4 seconds, even if the total time is similar. Use the Vercel AI SDK with the Anthropic provider:

npm install ai @ai-sdk/anthropic
// app/api/chat/route.ts
import { anthropic } from "@ai-sdk/anthropic";
import { streamText } from "ai";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: anthropic("claude-sonnet-4-5"),
    system: CLINIC_SYSTEM_PROMPT,
    messages,
  });
  return result.toDataStreamResponse();
}

On the client, the useChat hook from ai manages message state and streaming with almost no boilerplate.

How Do You Write a System Prompt That Actually Knows Your Business?

The system prompt is where a generic chatbot becomes your chatbot. For a Bangkok clinic, it needs specifics, not vibes:

const CLINIC_SYSTEM_PROMPT = `You are the assistant for [Clinic Name], an aesthetic
clinic in [district], Bangkok. You answer questions about treatments, pricing tiers,
and downtime using ONLY the information in the treatment menu provided below.

Rules:
- Respond in the language the user writes in (Thai, English, or Korean).
- Never diagnose, recommend a specific treatment for a medical condition, or give
  a firm price for anything not listed — quote the listed price range and note
  final pricing is confirmed by the doctor at consultation.
- If the user wants to book, is asking about a specific date, or wants to discuss
  a photo they're sharing, say you're connecting them to staff and provide the
  LINE OA link: https://line.me/R/ti/p/@clinichandle
- Do not discuss competitors or make delivery/downtime guarantees beyond the
  ranges listed.

Treatment menu:
${treatmentMenuText}`;

That last rule — escalate on booking intent — is the one that matters most. Chatbots that try to complete bookings inline tend to produce awkward, error-prone conversations. LINE is where Thai customers actually expect to finalize a transaction with a real person.

How Do You Ground Answers in Real Treatment or Menu Data?

For a handful of services or a single menu, pasting the full text into the system prompt (as above) is simple and reliable — Claude's context window handles a few thousand words of treatment descriptions without difficulty. For a clinic running multiple locations with dozens of treatments and prices that change, pull the current menu from your database at request time instead of hardcoding it:

const treatments = await db.query("SELECT name, price_range, downtime FROM treatments WHERE active = true");
const menuText = treatments.map(t => `${t.name}: ${t.price_range}, downtime: ${t.downtime}`).join("\n");

This keeps the bot's answers synced with whatever the clinic manager last updated in the admin dashboard, rather than a stale prompt someone forgot to edit after a price change.

How Do You Maintain Conversation History and Control Cost?

Claude's API is stateless — you resend the full conversation on every request. useChat handles this client-side automatically. For persistence across sessions (a customer closes the tab and comes back), store messages in Supabase and reload the last 15–20 on return, which is enough context for a support conversation without inflating token cost.

Cost matters more than it first appears: a clinic's chatbot answering the same treatment questions dozens of times a day adds up. Capping conversation length, using a shorter model for simple FAQ deflection, and rate-limiting the endpoint per session all keep the bill predictable.

Ready to Build Something Fast?

Get a free quote. We reply within 24 hours.

Want this working for your business in Thailand?

We build and run the same systems on 16 live sites of our own. Tell us your business — we reply within 24 hours with what the search data shows.