
Embeddable widgets have a bad reputation, and it is deserved. They fight your CSS, they block your page, and they break when you deploy. Here is what ours does instead, in the order it happens.
It does not block anything
The tag is deferred, so it loads after your page is interactive:
<script src="https://cdn.welcomeai.dev/widget/v1.js" data-wai-key="wg_your_key_here" defer></script>The bundle is about 20 KB compressed. It is Preact rather than React, because the widget does not need reconciliation of anybody else's tree.1
It renders in a shadow root
Everything the widget draws lives inside a shadow root with its own styles. Your CSS cannot reach in, and ours cannot leak out.
This is the single decision that removes most embed bugs: no reset conflicts, no specificity war, no !important.
The cost is real, though. You cannot restyle the widget from your own stylesheet, because your stylesheet never reaches it.
The widget editor covers colours, radius, placement and copy. The custom CSS field is injected inside the shadow root, which is the only way in.
It knows what page it is on
The widget sends the current path with each question, and retrieval gives a small boost to passages from that page. On a pricing page, a question about "the limit" finds the pricing content first.
For a single-page app it follows client-side navigation too, so the context is right after a route change rather than one page behind.
It refuses to run where it should not
A widget key sits in public HTML, which is fine as long as the key is bound to something. Every request carries an origin-bound token, and the widget only answers on the domains you listed.
If someone copies your key onto their own site, the request is refused, and the refusal names the origin we saw:
[welcomeai] refused: origin "https://not-your-site.example" is not on the allow list for key wg_your_key_hereThat message shows up in your browser console, which turns a misconfigured staging domain into a thirty second fix rather than an afternoon.
Deploy previews usually get a fresh hostname per build. If you want the widget answering there, list the pattern, not the one URL you happen to be looking at.
Questions people ask
Will it slow down my Lighthouse score?
It should not. The tag is deferred, so the bundle is not fetched or parsed until after your page is interactive, and nothing the widget does is on your critical path.
Can I style it with my own CSS?
Not from your stylesheet, because the shadow root blocks it in both directions. Use the widget editor for the common properties and the custom CSS field for everything else.
Does it work in a single-page app?
Yes. It follows client-side route changes and updates the page context it sends with each question.
What happens if I rotate the key?
The old key stops answering immediately, everywhere it is pasted. Swap the tag before you rotate, not after.
Paste the tag on one page, open your console, and check that the first question comes back with its sources attached.


