Add an AI support agent to Next.js, WordPress, Shopify, or any site
One hub for every install path we ship: the universal script tag, the WordPress plugin, the Shopify app embed, and the iframe. Working snippets for each, plus a candid guide to picking one.

You can add an AI support agent to any website by pasting one <script> tag before </body>. WordPress gets a plugin, Shopify gets an app embed, and an iframe covers builders that allow none of the above. This guide shows all four installs with working snippets.
Full disclosure up front: this is our product tutorial. We build MovinSupport, an open-source (MIT), self-hostable support agent that answers from your docs and escalates to a human when it should. Every snippet below is the real, current install path — including the two channels where we'll tell you plainly what's live and what's still on its way.
The script tag: works on every stack
This is the install we designed first, and it's the one everything else wraps. Paste this just before the closing </body> tag of your site:
<script
src="https://api.movinsupport.movinware.com/widget.js"
data-project="pk_your_project_key"
async
></script>
That's the whole install. widget.js is a single self-contained file — React, the chat UI, markdown rendering, streaming, all inlined — served with a five-minute cache. The script mounts the widget into a shadow DOM appended to document.body, so your site's CSS can't break the widget and the widget's styles can't leak into your page. It loads async, so it never blocks your page render.
Your project key is safe to expose in HTML. It only identifies which project answers the chat — movinsupport.movinware.com itself runs the widget with its real key committed in the repo. The dashboard generates this snippet pre-filled for you under Projects → your project → Widget → Install.
Configuration lives in exactly five data-* attributes:
data-project(required) — your project's public key. Without it the script throws instead of silently doing nothing.data-api(optional) — the API origin. Defaults to whatever origin servedwidget.js.data-brand(optional) — accent color; defaults to#111827. Most people set this in the dashboard instead.data-mode(optional) —bubble(default, the floating launcher) orinline.data-escalation-threshold(optional) — how many visitor messages before the widget offers a human. The agent default is 3.
There is no sixth attribute. Position, welcome message, starter questions — those are project settings in the dashboard, fetched at runtime, so you can change them without touching your site's HTML.
The data-api default is the detail we're most pleased with. The widget derives its API origin from the URL that served the script. So if you self-host — the whole product is MIT-licensed, bring your own model keys — you serve widget.js from your own domain and the exact same snippet points at your own API. Zero config divergence between hosted and self-hosted.
If you're on Rails, Django, Laravel, plain HTML, Astro, Vue, Hugo — anything that renders a </body> — this is your install, and you're done. Full reference: docs.movinsupport.movinware.com/integrations/widget.
Next.js: the script tag is still the install
Next.js 15 and the App Router need nothing extra. Paste the same script tag from the first section into your root layout, just before </body>:
import Script from "next/script";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://api.movinsupport.movinware.com/widget.js"
data-project="pk_your_project_key"
async
strategy="afterInteractive"
/>
</body>
</html>
);
}
Same widget, same dashboard, same settings — there's no separate integration to learn. The widget loads after your page is interactive, so it never delays first paint or hydration.
WordPress: plugin via zip upload (today)
Honest status first: the plugin has been approved for the WordPress.org plugin directory, but as we publish this (July 2026) the listing isn't live yet. Until it is, you install it the classic way — a zip upload. No FTP, no code edits, but also not yet a one-click search-and-install from wp-admin.
The install today:
- Get the plugin zip from the GitHub repo (the README has the current build steps).
- In wp-admin: Plugins → Add New → Upload Plugin, pick the zip, activate.
- Under Settings → MovinSupport, paste your project's public key and save.
The plugin (v1.0.1, GPLv2 or later, requires WordPress 5.8+ and PHP 7.4+) enqueues widget.js asynchronously with the same data-* attributes the dashboard snippet uses, on every public page and nowhere in wp-admin. Settings cover the floating-bubble toggle, the project key, the API URL (default https://api.movinsupport.movinware.com, changeable if you self-host), brand color, and escalation threshold. The settings page runs a live connection check against the API and shows you a status pill, so a typo'd key fails loudly at save time instead of silently on your live site.
If you want the chat in a page instead of (or as well as) the floating bubble, the plugin's settings include a shortcode you can drop into any post or page. The plugin stores exactly one option and one transient in your WordPress database — conversations live in MovinSupport, not in WP — and uninstalling removes both.
The launch post has the longer story: our WordPress AI support plugin. Reference: docs.movinsupport.movinware.com/integrations/wordpress.
Shopify: app embed now, App Store listing on the way
Same candor here: the MovinSupport Shopify app exists, is deployed, and works — it's a theme app extension we've tested on a live storefront. The public Shopify App Store listing is on its way but not live yet as we publish (July 2026). Until it lands, any Shopify store can run the agent today with the script tag.
The manual path today: Online Store → Themes → Edit code → layout/theme.liquid, paste the script tag from the first section just before </body>, save. Done — same widget, same dashboard.
Once you have the app installed, the flow is nicer: paste your project key on the app's settings page in Shopify admin, then in the theme editor open App embeds, toggle MovinSupport on, and hit Save. One thing Shopify makes per-theme: app embeds don't follow you when you publish a different theme, so re-enable the toggle after a theme switch.
Two design decisions worth knowing before you install anything on a store:
- Zero permission scopes. The app requests no access to your orders, customers, or products. It stores only its own settings. If a support app asks for read access to your entire order history just to render a chat bubble, ask why.
- A double-bubble guard. If the manual script tag is already in your theme when you enable the app embed, the embed detects it and stands down. One widget, never two — we verified this in testing because we knew people would migrate from the manual install.
The widget loads after page load, so it doesn't drag on storefront performance scores. Uninstalling the app removes the embed and clears its stored data. Reference: docs.movinsupport.movinware.com/integrations/shopify.
Everything else: the iframe embed
Some platforms won't let you add a script tag at all — locked-down site builders, sandboxed help-center pages, internal tools. For those, the API serves a CSP-hardened full-page chat at /embed/<key> that you can iframe from anywhere:
<iframe
src="https://api.movinsupport.movinware.com/embed/pk_your_project_key"
width="400"
height="600"
title="Support chat"
style="border: 0; border-radius: 12px;"
loading="lazy"
></iframe>
The embed page mounts the widget in inline mode with your project's brand color and escalation threshold baked in server-side — it reads them from your project settings, so there are no attributes to pass and nothing to update when you rebrand. Its Content-Security-Policy locks down everything except the one thing an embed must allow:
default-src 'none'; script-src 'self'; style-src 'unsafe-inline'; connect-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'none'; frame-ancestors *
frame-ancestors * because being iframed by any site is the point; everything else is shut. It also ships noindex, a no-referrer policy, and denies camera/microphone/geolocation/payment outright.
One more use for it: open the embed URL directly in a browser tab and you're talking to your agent — the fastest way to test your knowledge base before installing anything anywhere.
Which install should you pick?
Our honest decision guide, shortest answer first:
- Any server-rendered or static site (Rails, Django, Laravel, Astro, plain HTML, Hugo, ...): the script tag. It's the product's native install; everything else is a wrapper around it.
- Next.js 15: the same script tag in your root layout. Framework-specific wrappers add nothing here — the script is the native install everywhere.
- WordPress: the plugin, because the settings page, connection check, and shortcode earn their keep — but know it's a zip upload today, not a directory search result.
- Shopify: script tag in
theme.liquidtoday; switch to the app embed when the listing is live (the double-bubble guard makes the migration safe). - Site builders with no script access: the iframe embed. It's the fallback that works when nothing else is allowed.
And when not to use us at all: if your support runs primarily over WhatsApp, SMS, or phone, we don't do those channels — we're web widget plus email threading. And there's no hosted metered tier; the product is self-hosted under a renewable license with your own model keys.
After install: two things before you close the tab
Whichever channel you installed through, the same product is behind it, and an agent with nothing to read is just an apology generator. Two setup steps make the difference:
Add knowledge sources. In the dashboard, a project's knowledge base takes three source kinds: URLs (we crawl the page into a snapshot — there's a re-crawl button when your docs change), free-text snippets, and hand-written Q&A pairs for the questions you already answer weekly. There's no vector database in the pipeline — sources are byte-budgeted directly into the system prompt — and the models can search the live web when a question goes beyond your docs. Later, when an operator writes a particularly good reply in the inbox, you can promote it into the knowledge base straight from the thread, so the agent learns your best answers.
Set your escalation email. When a visitor asks for a human (or the agent decides it's out of its depth), the conversation escalates: an email goes to your project's notify address and, optionally, a message to a Slack webhook. The email's Reply-To is wired so that just replying from your inbox threads your answer straight back into the visitor's chat — no dashboard login required, though the dashboard inbox (tags, search, AI triage summaries, unread counts) is there when you want it. We wrote up how the email threading works in setting up email threading.
Visitors can rate individual answers thumbs up/down and leave a 1–5 CSAT when the conversation closes, so you'll know quickly whether the sources you added are pulling their weight.
FAQ
How do I add an AI support agent to my website without a developer?
If you can paste one line of HTML before </body>, you can install it yourself — the dashboard generates the exact snippet with your key pre-filled. On WordPress it's a plugin upload with a settings page and no code at all. The only genuinely no-code-access path is the iframe embed, which needs just an embed block.
Does a support widget slow down my site?
Ours is designed not to: the script loads async so it never blocks rendering, it's a single self-contained file cached for five minutes, and it mounts into a shadow DOM after the page is up. On Shopify specifically, the embed loads after page load so storefront performance scores aren't affected.
Can I use the same widget if I self-host?
Yes — that's a deliberate design decision. The widget resolves its API origin from wherever widget.js was served, so a self-hosted install uses the identical snippet pointed at your own domain. The whole product is MIT-licensed on GitHub; it's self-hosted under a renewable license with your own model keys.
How much does a hosted AI support agent cost?
MovinSupport is self-hosted under a renewable license — the code is MIT open source and you bring your own model keys, so there are no per-seat fees, no per-resolution fees, and no metered response quotas. Details on /pricing.
How does the agent know what to answer?
It answers from your project's knowledge base — crawled URL snapshots, text snippets, and hand-written Q&A pairs — combined with your system prompt, on web-search-capable models via LLM Gateway. When it can't answer, it escalates to your email and Slack instead of improvising.