Install
Add the widget with one script tag and lock it to your domains.
Script tag
Paste this before the closing body tag. The script is async and isolates styles with Shadow DOM. It works on any site you control.
<script
async
src="https://canwechat.dev/api/widget.js"
data-site="pk_live_...">
</script>Next.js
Use next/script with afterInteractive so the widget does not block LCP. React stays in your app; the visitor widget is still vanilla.
import Script from "next/script";
export function CanWeChatWidget() {
return (
<Script
src="https://canwechat.dev/api/widget.js"
strategy="afterInteractive"
data-site="pk_live_..."
/>
);
}React SPA
In a client-rendered React SPA (Vite, CRA, and similar), inject the same script once after mount. Prefer a single root-level effect or index.html tag so hot reloads do not load the widget twice. Call identify() or page() from your router after navigation if you track logged-in users or SPA route changes.
WordPress, Shopify, and Webflow
In WordPress, add the same script in footer.php (or a footer hook) before </body>. In Shopify, paste it in theme.liquid before </body>.
In Webflow, open Project Settings → Custom Code → Footer Code, paste the script tag with your site key, and publish. Custom code does not run in the Designer preview the same way as the published site, so verify on the live domain.
Identify from attributes
Optional data-user-id, data-name, and data-email feed the same identity pipeline as window.canwechat.identify(). Visitors can still chat without these.
<script
async
src="https://canwechat.dev/api/widget.js"
data-site="pk_live_..."
data-user-id="usr_123"
data-name="Ada"
data-email="ada@example.com">
</script>Allowed domains
Lock the public key to hostnames you control. Add production domains such as example.com and docs.example.com on separate lines. Until you add a domain, any origin can load the key, which is useful for setup but not ideal for launch.
After saving allowed domains, test the widget from the exact production hostname. Local preview domains should not be added unless you intentionally want that key to work there.
Detection
The first successful widget config request marks the site as installed. The dashboard shows last widget load time.