Installation steps
- 1
Prepare
Copy your public site key from the MivoChat Install page.
- 2
Configure
Find your framework below and add the script once, in the shared document or head configuration.
<script src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" async></script> - 3
Publish
Deploy, then add the exact production origin to Allowed websites in MivoChat.
- 4
Verify
Navigate between routes on the deployed site and confirm a single launcher stays on screen.
The generic tag
Every framework below ends up emitting the same tag. If yours is not listed, find the file that renders the outer HTML document, usually the one that contains <head> and <body>, and add the tag before </body>. A second tag for the same site key does nothing, but keep one for clarity.
Single-page apps do not reload the document on navigation, so the launcher persists across routes. Do not add the tag again on a route change, and do not remove it when a component unmounts.
<script src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" async></script>Next.js Pages Router
Render next/script once in pages/_app.tsx so every page shares it. Plain HTML in pages/_document.tsx also works, because the document renders only on the server and never remounts. App Router projects, Nextra and Fumadocs use the layout approach from the Next.js guide.
// pages/_app.tsx
import type { AppProps } from "next/app"
import Script from "next/script"
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<Script src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" strategy="afterInteractive" />
</>
)
}Nuxt and Vue
In Nuxt 3, add the script under app.head.script in nuxt.config.ts; Nuxt writes it into every rendered page. For a plain Vue app built with Vite, put the tag in index.html before </body>.
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
script: [
{ src: "https://mivochat.app/widget.js", async: true, "data-site": "YOUR_SITE_KEY" },
],
},
},
})SvelteKit and Astro
SvelteKit renders src/app.html for every page, so add the tag there after the body placeholder. In Astro, add it to the shared layout and mark it is:inline; without that, Astro bundles the script and drops the attributes as you wrote them.
<!-- src/app.html -->
<body>
<div style="display: contents">%sveltekit.body%</div>
<script src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" async></script>
</body>---
// src/layouts/Layout.astro
---
<html lang="en">
<body>
<slot />
<script is:inline src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" async></script>
</body>
</html>Remix and React Router
Render the script inside <body> of the root layout in app/root.tsx, after the framework's own scripts. Keep it out of route modules, which remount as visitors move around.
// app/root.tsx
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
<script src="https://mivochat.app/widget.js" data-site="YOUR_SITE_KEY" async />
</body>
</html>
)
}Docs generators
VitePress accepts head entries in .vitepress/config.ts, and Starlight takes a head array in its integration options. Docusaurus and Mintlify have their own guides because their configuration differs.
// .vitepress/config.ts
import { defineConfig } from "vitepress"
export default defineConfig({
head: [
["script", { src: "https://mivochat.app/widget.js", async: "", "data-site": "YOUR_SITE_KEY" }],
],
})// astro.config.mjs
import starlight from "@astrojs/starlight"
export default {
integrations: [
starlight({
title: "Docs",
head: [
{ tag: "script", attrs: { src: "https://mivochat.app/widget.js", async: true, "data-site": "YOUR_SITE_KEY" } },
],
}),
],
}Before you change the setup
- Who this is for
- a developer on a framework without its own MivoChat guide who wants the exact file to edit
- What you need
- your public site key, the framework's root layout or config file, and the production hostname
- Where it goes
- the shared HTML document, root layout or head configuration that every page of the site renders
- Watch out for
- a framework that pre-renders pages will not execute the loader at build time, so confirm it on the deployed site
Test the support boundary
- Does exactly one launcher show after moving between two routes?
- Does the production build, not only the dev server, contain the script tag?
- Does a question the docs answer cite the right page?
Frequently asked questions
Does the loader run during server rendering?
No. It is an ordinary browser script, so keep it out of server-only code and never read window while rendering.
Do I need to install a package?
No. MivoChat has no npm package; the hosted widget.js is the only thing you load.
Can I load it on only some routes?
Yes. Put the tag in a nested layout or a page-level head instead of the root, then test that exactly those routes show the launcher.
The launcher appears twice in development
A hot reload or a strict-mode effect can add a second tag. Load it from the HTML shell, or guard an effect with a selector check, and test on the built site.
Keep exploring
The r3-final-a evaluation measured 95% answerability-tier accuracy on 224 questions; this is an evaluation result, not a guarantee. AI replies use Anthropic. See the method and results and subprocessors and data locations.