Experiments

We Built a Free AI Chatbot for Our Electronics Store – 8 Failures and What We Learned

Building an AI chatbot for an Adobe Commerce store sounds simple. It was not. CORS blocked direct API calls, our homelab server was unreachable from the internet, ngrok introduced its own problems, Hyvä rejected emoji characters, and OpenAI had no free tier. Eight failures later we have a working chatbot running on Vercel for less than $0.01 per day.

We Built an AI Chatbot for Our Electronics Store — HoneyIndex Experiments
HoneyIndex Experiments - Part 3

We built a free AI chatbot for our electronics store using OpenAI, a Vercel proxy, and a hand-crafted knowledge base. It took longer than expected. Here is every failure along the way.

Date: June 3, 2026
Read: 10 min
By: HoneyIndex Team
AI Chatbot Adobe Commerce OpenAI Vercel CORS
TL;DR
  • We embedded an AI product assistant on okapius.com that knows every spec, price, and product in the catalog
  • Direct browser-to-OpenAI calls do not work due to CORS — you need a proxy server, and deploying it took 6 attempts
  • Final stack: OpenAI gpt-4o-mini + Vercel serverless proxy + vanilla JS widget embedded via Adobe Commerce CMS block

Why we built this

We run okapius.com — an electronics store selling phones, tablets, laptops, and solar products across America, Europe, Africa, and the Middle East. The catalog has 27+ products. Customers constantly ask the same questions: what is the cheapest phone, which one has the best camera, do you have 5G, where can I buy.

A traditional chatbot SaaS would cost $50-300 per month. We wanted to build something ourselves, keep costs near zero, and learn in the process. We also wanted it to run on our own infrastructure as much as possible — consistent with everything else we document in this series.

The goal was simple: a floating chat widget on the store that could answer product questions, recommend devices by budget, handle partnership and support enquiries, and escalate to a human via email when needed.


The plan — and why it immediately broke

Our first instinct was straightforward: build a JavaScript widget, call the OpenAI API directly from the browser, done. We wrote the widget, embedded it, and tested it. The chat opened. We asked a question. Nothing came back.

Failure 1 — Direct browser-to-OpenAI API calls are blocked
The browser threw a CORS error immediately: "Access to fetch at api.openai.com has been blocked by CORS policy: No Access-Control-Allow-Origin header." OpenAI intentionally blocks direct browser calls for security reasons. Every request must come from a server.
Fix — You need a server-side proxy
Any API call to OpenAI must go through a backend server that holds the API key. The browser calls your server, your server calls OpenAI, your server returns the response. This also keeps your API key out of the browser where anyone could steal it.

Attempt 1 — Local proxy on our homelab

We already had an Ubuntu server running at 192.168.20.10 with a full Bitcoin node, LND Lightning, and Ollama AI stack. We built a simple Flask proxy there and pointed the widget at it.

python # proxy.py on our Ubuntu homelab from flask import Flask, request, jsonify from flask_cors import CORS import requests app = Flask(__name__) CORS(app, origins=["https://mcstaging.okapius.com"]) @app.route('/chat', methods=['POST']) def chat(): response = requests.post( 'https://api.openai.com/v1/chat/completions', headers={'Authorization': f'Bearer {OPENAI_API_KEY}'}, json=request.json ) return jsonify(response.json())
Failure 2 — Private IP not reachable from the internet
192.168.20.10 is a private network address. The staging website at mcstaging.okapius.com is on the public internet. It cannot reach our homelab server. The browser threw "Failed to fetch" with a network error — same symptom, different cause.
Fix attempt — ngrok tunnel
We installed ngrok on the Ubuntu server to create a public tunnel to port 5001. This gave us a URL like https://3e34-2600-4040.ngrok-free.app. We updated the widget and retested.
Failure 3 — ngrok adds its own CORS restrictions
ngrok intercepts the preflight OPTIONS request and adds its own headers that conflict with ours. The browser rejected the preflight response. We added an ngrok-skip-browser-warning header to bypass it. This created a new problem.
Failure 4 — Custom headers blocked by Vercel CORS
When we later moved to Vercel, the ngrok-skip-browser-warning header in our fetch call caused Vercel's CORS preflight to fail — "Request header field ngrok-skip-browser-warning is not allowed by Access-Control-Allow-Headers." We had fixed one problem and created another.

Attempt 2 — Adobe Commerce CSP whitelist

We considered whitelisting our ngrok URL in Adobe Commerce's Content Security Policy. The CSP was logging violations for our proxy URL under connect-src. If we could add the URL to the allowed list it would unblock the connection.

Failure 5 — Adobe Commerce Cloud has no CSP UI
Standard Magento 2 has a Security section under Stores > Configuration. Adobe Commerce Cloud on the Hyvä theme either does not expose this, or it was not configured in our instance. We could only see reCAPTCHA and security.txt settings. CSP must be managed via code committed to the repo — which requires a full deployment cycle.

Attempt 3 — Use Ollama locally instead of OpenAI

We already had Ollama running on our homelab with LLaMA 3 70B, Mistral 7B, and LLaMA 3 8B. Why pay for OpenAI when we have local models? We tried pointing the proxy at our local Ollama API.

Failure 6 — Local AI too slow for a customer-facing chat
LLaMA 3 70B on CPU takes 3-5 minutes to respond. Even the smaller Mistral 7B took 30-60 seconds. For an internal homelab monitor this is acceptable. For a customer asking about a phone on a shopping website, it is not. We needed a cloud model.

Attempt 4 — OpenAI API quota exceeded

We created a fresh OpenAI API key, updated the proxy, and tested. Got a new error: insufficient_quota. The account had no credits. OpenAI requires a paid billing setup even for test usage.

Failure 7 — OpenAI requires billing setup upfront
Unlike some APIs that offer a free tier with rate limits, OpenAI requires you to add credits before any API calls work. We added $5 of credits. gpt-4o-mini costs approximately $0.002 per conversation, so $5 covers roughly 2,500 customer interactions — more than enough for testing and early production.

The solution that actually worked — Vercel serverless

We stopped trying to expose our homelab to the internet and instead deployed a two-function serverless proxy on Vercel's free tier. No server to manage, no ngrok tunnels, permanent public URL, automatic HTTPS, free for our usage level.

Browser (okapius.com) | | POST /api/chat | Content-Type: application/json v Vercel Serverless Function okapi-proxy-vercel.vercel.app/api/chat | API key stored as env variable | Never exposed to browser | | POST /v1/chat/completions v OpenAI API (gpt-4o-mini) | | Response v Vercel returns response to browser
api/chat.js — vercel function export default async function handler(req, res) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') return res.status(200).end(); const response = await fetch( 'https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify(req.body) } ); const data = await response.json(); return res.status(200).json(data); }
What made this work
Three things: (1) the OPTIONS preflight handler returns correct CORS headers before the browser sends the real request, (2) the API key is stored as a Vercel environment variable — never in the HTML, (3) the function URL is public and permanent, no tunnels needed.

The knowledge base — what we actually put in the system prompt

The chatbot's intelligence is not the model — it is the system prompt. We baked in the complete product catalog: 27 products across phones, tablets, laptops, solar, and accessories, with full specs, pricing, availability by region, recommendation logic, and contact information.

The system prompt is approximately 3,000 tokens. At gpt-4o-mini pricing this adds about $0.0005 per conversation — negligible. The benefit is the model never hallucinates product specs because every spec is explicitly provided.

CategoryProductsPrice range
Phones18 models$30 - $1,000
Tablets6 models$112 - $350
Computers2 models$299 - $459
Solar1 product$45
Accessories2 products$19 - $29

The system prompt also includes a recommendation guide — "best phone under $100", "best for battery", "best 5G" — so the model gives confident answers instead of listing everything and saying "it depends".


Embedding in Adobe Commerce — one more surprise

We planned to paste the HTML widget into an Adobe Commerce CMS block and inject it globally via layout XML. The CMS block editor refused to save the content.

Failure 8 — Hyvä CMS block rejects emoji characters
The Hyvä theme's CMS block editor throws a validation error on any non-ASCII characters: "Please remove invalid characters: emoji, special symbols." Our original widget used emoji for icons in buttons and the avatar. We had to strip all emoji and replace with plain text labels.
Fix — Plain ASCII only in Hyvä CMS blocks
Replace all emoji with text. Replace special characters like em-dashes, bullet dots, and box-drawing characters with plain ASCII equivalents. The widget lost some visual flair but gained compatibility.

What we learned

01
Never call AI APIs from the browser directly
Always use a server-side proxy. This is both a security requirement and a technical one — CORS will block you every time.
02
Your homelab is not the right proxy host
Private IPs are private for a reason. For anything customer-facing, use a cloud function. Vercel free tier is genuinely free at low volume.
03
Local AI is not ready for synchronous customer UX
LLaMA 3 70B on CPU takes minutes. For internal tools this is fine. For customers expecting a chat reply it is not. Use cloud models for customer-facing apps.
04
The system prompt is the product
A complete, accurate knowledge base in the system prompt beats a bigger model with a vague prompt every time. Spend time on the prompt, not on model selection.
05
CORS errors always have a cause
Every CORS failure has a specific reason visible in the browser console. Read the error carefully — it tells you exactly what header is missing or what is being blocked.
06
Cache is invisible until it is not
We updated the CMS block twice and tested without flushing cache, both times seeing old behavior. Always flush Magento cache and hard-reload after any CMS change.

Final architecture

JS
Vanilla JS + CSS widget
No framework. Embedded via Adobe Commerce CMS block. Injected globally via layout XML. ~400 lines total including all styles.
V
Vercel serverless proxy
Single Edge Function. Free tier. API key stored as environment variable. Handles CORS preflight correctly. Permanent URL, no maintenance.
AI
OpenAI gpt-4o-mini
$0.002 per conversation. 3,000-token system prompt with full product catalog. Fast enough for customer UX (under 3 seconds typically).
KB
Hand-crafted knowledge base
27+ products, full specs, pricing, regional availability, recommendation logic, contact info — all in the system prompt. No RAG, no vector database needed at this scale.

What is next

The current setup works well for testing. Before going to production we will move the proxy to a dedicated subdomain like api.okapius.com, tighten the CORS origins to only allow okapius.com, and swap the OpenAI model to gpt-4o for more nuanced product comparisons.

Longer term we want to connect the chatbot to the actual Magento product API so specs and prices update automatically rather than requiring manual edits to the system prompt. That is a future post.

The full source code — widget HTML, Vercel proxy function, and system prompt template — is on our GitHub.

Share 𝕏 in Y

About Lemuntu

Crypto & AI editor

Get the weekly digest

New AI projects, launches, and homelab notes — every Friday in your inbox.

Subscribe free →

No comments yet. Be the first to share your experience.

Join the discussion —