Before you start
- You have a project idea — what should the bot know about?
- Sign up for Anthropic at console.anthropic.com and grab an API key.
- Sign up for Supabase at supabase.com and grab the URL, anon key, and service role key.
- Have an IDE with an AI coding assistant — Claude Code, Cursor, or Windsurf.
Create the project
Create a new Next.js Pages Router project called my-chatbot. Install @anthropic-ai/sdk and @supabase/supabase-js. Add a.env.localwith placeholders for ANTHROPIC_API_KEY, SUPABASE_URL, SUPABASE_ANON_KEY, and SUPABASE_SERVICE_ROLE_KEY. Do not commit.env.local.
npm run dev starts on http://localhost:3000.Add your API keys
- Open
.env.local. - Paste your Anthropic API key.
- Paste your Supabase URL and both keys.
- Restart
npm run dev.
Build the chat widget UI
Add a chat widget to my Next.js site. A fixed bottom-right floating button that opens a panel with a header, a scrollable message list, and a text input. Use CSS modules. Match a dark theme with an amber accent. Do not wire up any backend yet — just the UI, with a dummy "hello" message hard-coded in the list.
Build the backend endpoint
Create a Next.js API route at pages/api/chat.js. Accept POST with{messages: [{role, content}]}in the body. For now, just return{answer: "Echo: " + last user message}. Add basic input validation.
curl -X POST localhost:3000/api/chat -H "Content-Type: application/json" -d '{"messages":[{"role":"user","content":"hi"}]}' returns the echo.Wire the widget to the endpoint
Update the chat widget: when the user sends a message, POST the message history to /api/chat, show a typing indicator while waiting, then render the response as a bot bubble. Maintain the history in React state.
Add Claude
In pages/api/chat.js, replace the echo with a real call to Claude. Use @anthropic-ai/sdk. Model: claude-sonnet-4-5. Max tokens: 1024. Add a system prompt: "You are a friendly assistant for a company called {your company}." Read the API key from process.env.ANTHROPIC_API_KEY.
Set up the database
Create a SQL migration for Supabase with three tables: conversations (id, visitor_id, started_at), messages (id, conversation_id, role, content, ts), and chat_leads (id, name, email, phone, message, captured_at). Enable row-level security. Anon can insert; only the service role can read. Give me the SQL as a copy-paste block.
- Run the SQL in Supabase → SQL Editor.
- Verify tables appear in the Table Editor.
Persist conversations
Update pages/api/chat.js: before calling Claude, insert the incoming user message into the messages table. After Claude replies, insert the assistant message too. Track the conversation_id in the request; if none, create a new conversation row first. Use the service role key server-side.
Add lead capture
Extend the system prompt so Claude appends <<LEAD>>{json}<<END_LEAD>> when the visitor gives their name, email, or phone. In pages/api/chat.js, parse that block out of the response, insert it into chat_leads, and strip the block from the returned text so the user doesn't see it.
Add safety
Add basic safety to pages/api/chat.js: rate-limit by IP (max 20 requests per minute), reject messages longer than 4000 characters, and cap the message history sent to Claude at the last 20 turns.
Deploy
Prepare the app for Vercel deployment. Confirm .env.local is in .gitignore. Give me a checklist of every environment variable I need to add in the Vercel dashboard.
- Push to GitHub.
- Import the repo into Vercel.
- Add environment variables in Vercel (all four from Step 02).
- Deploy.
- Test the widget on the deployed URL.
Monitor and iterate
- Watch Vercel function logs for errors (first 24 hours).
- Watch the Anthropic usage dashboard for cost.
- Read your
chat_leadstable weekly. - Improve the system prompt based on real conversations.
Small verifiable steps, real error messages, visual verification after every step. If a step fails, tell the AI exactly what happened and paste the error. Never let the AI write more than one chunk between tests.
