A complete breakdown of how the floating chat widget on the Projects page was built - from the bubble button to the AI response, the serverless function, and everything in between. The concepts apply to any hosting platform.
The Project Assistant is a floating chat widget that appears exclusively on the Projects page (Page 3) of the portfolio. Visitors can ask it anything about the projects on display and it responds with intelligent, contextual answers - powered by Claude AI.
How visitors use itLike the Email Parser, this chatbot is built with nothing but web-native tools - no frameworks, no dependencies on the frontend.
FrontendHere is exactly what happens from the moment a visitor clicks the bubble to when they see a reply:
User types a question or taps a chip. JS captures the input.
JS sends the full conversation history to your serverless function endpoint.
The function adds the system prompt and calls the Anthropic API.
The reply is added to the chat panel. History is stored in memory.
The full conversation history is sent every time - this is how Claude remembers what was said earlier in the session. Claude has no memory between sessions, so history only lasts as long as the page is open.
This is the most important file. It's a small Node.js module that sits between your visitors and the Anthropic API. Nothing secret ever touches the browser. The code is the same regardless of platform - only the file location and function URL change.
File location by platformThe system prompt is the secret sauce. It's a block of text that tells Claude who it is and what it knows before any visitor sends a message. It lives only in chat.mjs - never in the browser.
What a good system prompt includesThe more detail you put in the system prompt, the better Claude's answers will be. Think of it as briefing a new team member on your work before they start answering visitor questions.
The chat widget is built from three HTML elements and a block of JavaScript - all inside index.html. No separate files needed.
The three HTML piecesThe chips (e.g. "What's Purrfect Health?") are defined as a JavaScript array at the top of the script. When a chip is clicked, its text is sent directly to sendMessage() just like a typed message - no special handling needed.
To add or change chip questions, just edit this array. The UI rebuilds itself automatically every time the panel opens.
Claude has no built-in memory between API calls - every call starts fresh. To make the conversation feel continuous, the JavaScript maintains a history array and sends the full conversation every time.
How the history array worksThis array is passed to your serverless function on every request. Claude reads the full history each time, which is why it can refer back to earlier parts of the conversation.
Important limitationHistory only lasts as long as the page is open. If the visitor refreshes or comes back later, the conversation starts fresh. For most portfolio use cases this is perfectly fine - visitors aren't looking for long-term relationships with a chat widget!
The core concept works on any platform that supports serverless functions. This guide uses Netlify and Anthropic as the example since that's what this site runs on - but the same steps apply to Vercel, Cloudflare Workers, AWS Lambda, or any similar platform.
Step 1 - Get your Anthropic API keySign up at console.anthropic.com, create a project, and generate an API key. Keep it secret - it never goes in your HTML file.
Step 2 - Choose and set up your hosting platformYou need a platform that supports serverless functions - Netlify, Vercel, and Cloudflare Workers all have generous free tiers. Deploy your portfolio to whichever you prefer. All three detect your function files automatically with no extra configuration.
Step 3 - Add your API key as an environment variableEvery platform has a dashboard where you can store secret keys safely. Add ANTHROPIC_API_KEY with your key as the value. The name of the setting and where to find it varies slightly but is always under something like "Environment Variables" or "Secrets" in your project settings.
Step 4 - The Anthropic SDK ✦ Your platform handles this for youYou won't need to run npm install yourself. Most platforms automatically install any dependencies listed in your project's package.json during deployment - on their servers, not your machine. Make sure @anthropic-ai/sdk is listed as a dependency and your platform takes care of the rest.
Create your function file in the correct folder for your platform. Use the code structure from Section 04 as your starting point - the logic is identical, only the file path changes.
This is the most important step and the one that makes your bot actually useful. Write a detailed description of every project - what it does, the tech used, what makes it interesting. The more detail, the better Claude's answers. This lives inside your function file, never in the browser.
Step 7 - Add the widget HTML to your pageAdd the bubble button, chat panel, and message area HTML to your index.html. Add the JavaScript at the bottom. Update the fetch URL to match your platform's function endpoint and update the chip questions to match your projects.
Step 8 - Deploy and test ✦ Your platform builds everything automaticallyPush your changes or drag-and-drop your folder to your platform's dashboard. It will automatically install dependencies, deploy your function, and make it live. You don't run any build commands yourself. Once deployed, open your portfolio, find the Projects page, click the bubble, and ask it a question. If it answers correctly - you're done!