The first successful test of a support widget almost always happens on localhost — or on a vendor sandbox with the script pasted into a demo page. The bot answers, citations look fine, and the team marks embed as done. Then staging ignores the allowlist, production subdomains were never added, or a copy-paste of the embed key onto a random landing page still works because nobody configured locks at all.
Domain locks are not bureaucracy. They are how you keep your crawl budget, your spend cap, and your brand from serving answers on sites you do not control — including someone else’s phishing page if your key leaks.
What localhost actually proves
Local development bypasses the same-origin reality of production. You are often on `http`, without the CDN, without the cookie banner, without the tag manager that loads the widget async on the live site. Passing locally proves the integration code runs. It does not prove:
- The production hostname is on the allowlist.
- Preview deployments (`*.vercel.app`, branch subdomains) are handled intentionally — allowed or blocked.
- The widget survives CSP headers and script ordering on the real site.
- Embedded iframes on third-party domains cannot reuse your key.
The staging trap
Staging domains poison more than answers — they poison confidence. A bot indexed against staging content will cite draft pricing. A bot allowed on staging but locked on production will “work in QA” and fail on go-live. Decide per environment: separate bot, separate crawl, separate allowlist entry, or block staging entirely from the production embed key.
If marketing uses unlisted preview URLs, add them to the allowlist for the test key only. Production keys should not float on every short-lived subdomain your agency spins up. The dedicated post on staging domains goes deeper on indexing; here the point is embed scope must match where that index should speak.
Building an allowlist that matches reality
List every hostname that will load the widget: apex, `www`, regional TLDs, checkout subdomains, partner portals if they embed you. Miss one and support hears “chat is broken” while security hears nothing, because the failure is silent blocked loads in the browser console.
- Inventory production hostnames from DNS and your CDN, not from memory.
- Add staging and preview only to non-production keys.
- Document who approves new domains when marketing launches a campaign site.
- After acquisition or rebrand, audit allowlists before redirect chains hide old embeds.
Wildcard entries (`*.example.com`) are convenient and easy to over-grant. Prefer explicit hosts unless you truly control every subdomain. See domain locks and security for patterns that balance ops burden with leakage risk.
Verify locks the way an attacker would
After configuration, paste the embed snippet into an unrelated HTML file or a personal site. It should not load the bot. Hit production from an unlisted subdomain. It should fail closed. Only then paste into the real property and confirm it succeeds.
Automate nothing here that you will not re-run after every key rotation. Keys leak in tickets, slide decks, and public repos. Rotation without allowlist review is half a fix.
Partner sites that embed your widget in an iframe need their hostname on the list too — not just yours. Agencies forget the client’s marketing subdomain; marketplaces forget the seller portal. Add them when the embed goes live, not when support notices missing chat.
When the widget “disappears” for real users
Over-tight locks show up as intermittent missing chat — often on mobile apps wrapping WebViews, or on international domains added late. Keep a runbook: check allowlist, check CSP, check ad blockers, check console errors. Support should not guess; the runbook should name the hostname the visitor was on.
“Works on localhost is a developer milestone. Works only where we embed is a launch requirement.”
CSP and third-party embeds
Content-Security-Policy headers block widgets as effectively as allowlists — with a worse error message. After domain locks pass, verify production CSP allows your script origin. Security teams tighten CSP over time; chat disappearing after a hardening sprint is a common post-launch surprise unrelated to the bot itself.
Document allowed hostnames in the same runbook as API keys; future you will not remember why `app.example.com` is listed but `example.com` is not. New hires should not need oral history to fix a missing widget.
Make every hostname a decision
Domain locks are boring until they are not — when usage spikes from an unknown site, or when a draft staging answer appears on a customer-facing URL. Configure them on production keys, test the failures on purpose, and treat every new hostname as a deliberate decision. Add a calendar reminder to review allowlists after acquisitions, rebrands, and major marketing launches.



