AI Chatbot Project ๐Ÿค–

How I went from a Permission Denied error in Dialogflow to a live Claude-powered assistant secured with Cloudflare Workers. The full story, including every struggle.

What this project is

The chatbot in the bottom right corner of every page on this site is something I built completely from scratch.

It's a live, production AI assistant that answers questions about my experience, skills, and career, so anyone visiting the site can explore my background interactively rather than just reading static text.

What started as a simple experiment became a full journey through conversational AI design, API integration, security incidents, and infrastructure decisions.

Every mistake led somewhere useful.

Conversational AI Anthropic API Prompt engineering Cloudflare Workers API security Iterative development

The full journey

Phase 1

IBM Watson and Dialogflow CX

Learning the fundamentals of conversational AI

I started by completing the IBM AI Fundamentals certification to build a proper foundation before writing a single line of code. That led me to IBM Watson, where I got hands-on with intents, entities, and dialogue flows for the first time.

From there I moved to Google Dialogflow CX, which gave me more control over multi-turn conversations and intent routing. I embedded the bot into this portfolio and it worked, until it didn't.

I kept hitting a Permission Denied error, the bot wasn't speaking on page load, and several other issues kept cropping up. I tried implementing a fix multiple times but couldn't get it working, so I made the call to move on and explore other options.

โšก The struggle
โ–ผ

The Dialogflow CX embed required the Messenger integration to be explicitly enabled and domains allowlisted inside the Google Cloud console. Without this, every request returned a permission denied error regardless of whether the code was correct. Debugging across Google Cloud IAM, Dialogflow settings, and the front-end embed was time-consuming and poorly documented.

Phase 2

Switching to the Anthropic API

Replacing intent-based flows with a language model

Rather than mapping every possible question to a predefined intent, I switched to using Claude via the Anthropic API directly. I wrote a detailed system prompt describing my background, experience, and tone, and let the model handle any question naturally.

The difference was immediate. No intent mapping, no training data, no permission configuration. I built a custom chat widget in HTML and JavaScript to match the existing pink theme, with a welcome message that opens automatically two seconds after the page loads.

โšก The struggle
โ–ผ

The first version had the Anthropic API key hardcoded directly in the front-end JavaScript. GitHub's secret scanning flagged it immediately on push and blocked the commit. Valuable lesson: secrets never belong in client-side code, regardless of how quickly you plan to fix it.

Phase 3

Cloudflare Workers proxy

Keeping secrets off the front end properly

To fix the security issue properly, I set up a Cloudflare Worker as a proxy. The Worker sits between this site and the Anthropic API. My front end sends requests to the Worker, the Worker adds the API key server-side, and forwards the request to Anthropic. The key never appears in the code or the browser.

I configured the Worker to only accept requests from madihaintech.me using CORS headers, stored the API key as an encrypted environment secret in Cloudflare, and deployed it on the free tier with no credit card required.

โšก The struggle
โ–ผ

Setting up the Cloudflare Worker involved navigating an unfamiliar console, figuring out how to add encrypted secrets, and understanding CORS preflight requests. The editor also did not support pasting on the initial deploy screen, which meant deploying a Hello World worker first and then replacing the code in the full editor afterwards.

Phase 4

Live and iterating

Production deployment across the full portfolio

The chatbot is now live across all pages, powered by Claude, secured via Cloudflare, and deployed through GitHub Pages. It opens automatically after two seconds, delivers a structured welcome message, and handles follow-up questions with full conversation history maintained client-side for the session.

The system prompt is carefully designed to keep responses warm and professional, grounded only in accurate information about my background, with a fallback directing visitors to my contact page or LinkedIn if something falls outside what the assistant knows.

Tools used

Claude

Anthropic API, the AI powering the chatbot

Cloudflare Workers

Serverless proxy keeping the API key secure

GitHub Pages

Hosting and version control

HTML, CSS and JS

Everything built from scratch, no frameworks

Dialogflow CX

Phase 1 prototype before switching to Claude

IBM Watson

Where the conversational AI journey started

What I learned

๐Ÿ”

Secrets never belong in client-side code

Not even temporarily. GitHub secret scanning will find it before you do. The right solution is a server-side proxy from the start.

๐Ÿ—

AI integration is an infrastructure problem

Where the key lives, how requests are routed, how errors are handled: these decisions matter as much as what the model says.

๐Ÿ”

Iteration beats perfection

The Dialogflow version was imperfect but it shipped. Every error pushed me toward a better solution. Nothing was wasted.

โœ๐Ÿผ

The system prompt is the product

Getting the chatbot to respond warmly, accurately, and within the right boundaries required more thought than the code itself.

Try it yourself ๐Ÿ’ฌ

The chatbot in the bottom right corner is the live version described above. Ask it anything about my experience, what I'm working on, or how I built it.

Powered by Claude ยท Secured by Cloudflare ยท Built by Madiha

๐ŸŒธ

Madiha's Portfolio Assistant

Ask me anything