Adding Voxinly to a custom-built website
How to drop the Voxinly widget into a custom HTML, React, Next.js, Astro, Eleventy or any bespoke site — without breaking your build, your CSP, or your developer's day.
If your website was hand-built — straight HTML, a static-site generator, a React or Next.js app, an Astro or Eleventy build, or anything that doesn't have a one-click plugin marketplace — adding Voxinly is still a sixty-second job. The widget is a single line of JavaScript that mounts itself, so there's nothing for you to wire up beyond pasting it in the right place.
Step 1 — Grab your embed snippet
Open /admin/embed
Sign in to your Voxinly admin and click 'Embed code' in the sidebar. You'll see a one-line <script> tag with your tenant ID baked in. Copy it.
Step 2 — Paste it into your site
Plain HTML
Open your template (or every page if you don't share one) and paste the snippet just before the closing </head> tag. Save, redeploy, done.
Next.js (App Router)
Open src/app/layout.tsx and add the Next.js <Script> component inside the <html> tree with strategy='afterInteractive'. The widget only needs to load after hydration, so afterInteractive is the right strategy — it keeps your Core Web Vitals clean.
Next.js (Pages Router)
Open pages/_document.tsx and paste the script tag inside the <Head /> block. If you'd rather defer it, use the Next.js Script component in pages/_app.tsx with strategy='lazyOnload' instead.
React (Vite / CRA)
Open public/index.html (CRA) or index.html (Vite) and paste the snippet inside <head>. You don't need a React wrapper — the widget mounts its own root.
Astro
Open src/layouts/Layout.astro (or whichever layout wraps every page) and paste the snippet inside the <head>. Astro doesn't need a special directive — it ships the script as-is.
Eleventy / 11ty
Open your base layout (usually _includes/base.njk or similar) and paste the snippet inside <head>. Rebuild, deploy.
Hugo
Open layouts/partials/head.html (or your equivalent) and paste the snippet at the end. Run hugo, deploy your public/ folder.
Step 3 — Content Security Policy (CSP)
If your site sets a strict CSP, you'll need to allow Voxinly's script origin and API endpoint. The two directives you'll usually need:
| Directive | Add |
|---|---|
| script-src | https://cdn.voxinly.com |
| connect-src | https://api.voxinly.com https://*.supabase.co |
| img-src | https://cdn.voxinly.com https://images.unsplash.com |
| frame-src | https://wa.me |
Step 4 — Customising programmatically
Most customers configure Voxinly entirely through the admin UI — colours, copy, knowledge, business hours. If you need to push values from your application (for example, the customer's email after they log in), use the global API:
- window.__voxinly.identify({ email, name }) — link this visit to a known user
- window.__voxinly.open() / .close() — programmatic widget control
- window.__voxinly.on('lead', cb) — subscribe to events for your own analytics
- window.__voxinly.config({ position: 'left' }) — runtime overrides for layout
Step 5 — Test in a private window
Open your deployed site in an incognito window. The chat bubble should appear bottom-right within a second of page load. Click it, ask a test question, watch the answer come back. Check your browser console for any CSP errors — those are the only thing that will silently break the widget on a custom build.
FAQ
Will Voxinly slow down my site?
The bootstrap script is around 9 KB gzipped and loads asynchronously. It does not block first paint, contentful paint, or interactive. Lighthouse scores are unchanged in real-world tests.
Does it work with Server Components?
Yes. The widget is a client-side bundle so it doesn't care whether your shell came from a server component or a static export — it mounts after hydration in either case.
Can I lazy-load it on a button click?
Yes. Remove the script tag from <head> and load it dynamically when your visitor clicks a 'Chat to us' button. The widget will boot, auto-open, and behave normally from there.
What if my site is behind a paywall or auth wall?
Voxinly works behind any auth wall — the script just needs to load on the page. Use identify() to pass the logged-in user's details if you want conversations linked back to a known customer.
Will it break if my CDN strips third-party scripts?
Yes — most aggressive CDNs (Cloudflare Rocket Loader, etc.) can mangle async scripts. Add data-cfasync='false' to the script tag to opt out of Rocket Loader specifically. We include this attribute by default.