Over the last 2.5 months, I've been building WidgIq, an AI chatbot widget that can be added to any website with just one script tag.
You can check it out here:
👉 https://widgiq.com
The goal wasn't just to build another chatbot. I wanted to create something that actually understands a website and helps visitors find answers instantly.
Most chatbot solutions are either:
- difficult to integrate
- expensive
- require lots of manual setup
- don't actually understand your website
So I built WidgIq.
It automatically understands website content and provides context-aware answers.
Website owners only need to add one script tag.
Some features include:
- AI-powered customer support
- One-line integration
- Conversation history
- Analytics dashboard
- Weekly AI insights
- Fast setup
- Sreaming Response
- Deep Customization
- Extreme lightweight SDK
- Excellent RAG Circuit
Built with
- Next.js
- TypeScript
- Tailwind CSS
- Drizzle ORM
- PostgreSQL
- Better Auth
- Inngest
- Gemini API
Some challenges I faced:
- Website crawling
- Context retrieval
- Embedding search
- Widget performance
- Secure script loading
I'm still improving WidgIq and adding new features every week.
I'd love to hear your feedback.
Thanks for reading!
If you'd like to see what I've been building, you can explore WidgIq here:
Documentation:
https://widgiq.com/docs
I'd genuinely appreciate any feedback or suggestions.
Top comments (4)
The widget script is public by nature, so whatever identifies a customer's site travels in the clear. What stops someone from lifting site A's key into their own page and burning A's quota or querying A's crawled content? You listed secure script loading as a challenge, so I suspect you've already been through this loop and I'm interested in where you landed.
Hey @vollos first of all thank you so much for giving your interest in WidgIq so let's answer your thought so You are right that the widget script is public, the API key is visible in the page source, and that's intentional. We model it as a publishable key, not a secret.
What actually protects a customer is server-side domain binding. When the widget calls our chat API, we validate the request's Origin/Referer against the domain they registered at project setup. If someone copies site A's key onto site B, those requests fail with 403 — they never hit RAG retrieval or the LLM, so they can't query A's crawled content or burn A's quota from an unauthorised origin.
We layer that with per-key+IP rate limiting (10 req/min) and a credit system that deactivates keys when the account is exhausted. Keys are also revocable/rotatable from the dashboard.
this model assumes browser-enforced origins. A determined attacker with direct HTTP access could spoof headers — same tradeoff every embeddable widget product makes (Maps, analytics, chat widgets).
But still i will try to do my best to secure the server.
Rejecting at the origin check before anything reaches retrieval or the LLM keeps a lifted key a cheap problem instead of a bill. If the dashboard doesn't show it yet, a per-key count of rejected origins would make a decent early warning, a spike means someone is trying a customer's key from somewhere it shouldn't be. Thanks for laying the whole chain out.
Thanks Pon for the suggestion to show the warning in the dashboard with the number of requests that are being rejected for unverified domains. I'm going to implement it.