Installing the widget on your platform
The widget is two <script> tags: the first one sets the options, the second one loads the widget. Copy them from Project settings in the app — that copy already has your project ID and the options you chose:
<script>
window.__rm__config = {
projectId: 'YOUR_PROJECT_ID',
locale: 'auto'
};
</script>
<script src="https://widget.revisionme.com/app.js" defer id="rm_app_script"></script>
Any place where a site lets you add your own HTML to every page works. Before </body> is the usual spot, but <head> is fine too: the widget waits for the page to be ready. Keep the two tags together and in this order. Below is where that place is on popular platforms. To show the widget only on some pages or to some people, see Showing the widget only where you need it.
WordPress
The simplest way is a code snippet plugin. With WPCode (formerly Insert Headers and Footers): Code Snippets → Header & Footer, paste the code into the Footer box and press Save Changes. If you use a caching plugin, make sure its cache is cleared so visitors get the new pages.
Without a plugin, add it from the functions.php of a child theme:
add_action('wp_footer', function () {
?>
<script>
window.__rm__config = { projectId: 'YOUR_PROJECT_ID', locale: 'auto' };
</script>
<script src="https://widget.revisionme.com/app.js" defer id="rm_app_script"></script>
<?php
});
On WordPress.com (the hosted service), your own scripts need a plan that allows plugins, with hosting features activated; on the free plan <script> tags are removed. Themes with animated page transitions (they load the next page without a full reload) are supported: the widget stays on the page after each transition.
Google Tag Manager
- Tags → New → Tag Configuration → Custom HTML, paste both tags into the HTML field.
- Triggering: All Pages. For conditions (only some pages, only staging) use a trigger with conditions instead — examples are in Showing the widget only where you need it.
- Save and Submit the container. The preview mode alone does not change the site for visitors.
Leave Support document.write off. GTM may drop attributes of the script tags it inserts, so the inline embedBtn link (it appears where the script tag is) does not work through GTM; the floating button, the text selection button and Ctrl+Enter work as usual.
Site builders
On every builder the code starts working on the published site, not in the editor, and usually needs a paid plan: if the menu below is missing, check what your plan allows.
Tilda
Site Settings → Insert Code → HTML code for the HEAD section, then republish all pages. Tilda has no site-wide field for the end of the page, and the head is fine for the widget. For one page only, use Page Settings → Additional → HTML code for the HEAD section or the T123 block (Embed HTML Code); in the editor the block shows the code as text, it runs on the published page.
Webflow
Site settings → Custom code → Footer code, save and Publish. Custom code needs a paid site plan (or a paid workspace). The Designer shows a placeholder instead of running the code; check on your webflow.io or live domain.
Wix
Settings → Development & integrations → Custom Code → Add Custom Code, paste the code, choose All pages and Load code once, place it in Body – end. Wix requires a Premium plan and a connected domain for custom code, and the snippet is tied to that domain: after switching to another domain, add it again.
Shopify
Online Store → Themes → ⋯ → Edit code, open layout/theme.liquid and paste the code right before </body>. Duplicate the theme first: edits to the code may be lost when the theme is updated. All storefront pages are covered; checkout pages are not, Shopify does not run theme code there.
Squarespace
Pages → Website Tools → Code Injection → Footer, save. Code Injection is available on the Core, Plus and Advanced plans (earlier: Business and Commerce). It may not show while you are logged in, so check in a private window.
Single-page applications
React, Vue, Svelte, Angular and similar applications need nothing special: add the code once to the page that loads the application, and the widget stays across route changes. A report records the address that was open when the visitor opened the form, so reports from different routes are told apart. Highlighting selected text does not interfere with the framework: the widget restores the page text exactly as it was when the form closes.
Set the options as window.__rm__config, as in the code above. A plain var __rm__config works in a page's <script> tag, but inside a JavaScript module it stays local and the widget does not see it.
Vite, Create React App, Vue CLI, Angular
Paste the code into the HTML page of the application, before </body>: index.html in Vite, public/index.html in Create React App and Vue CLI, src/index.html in Angular.
Next.js
In the root layout (app/layout.tsx, App Router), so it is on every route:
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script id="rm-config" strategy="beforeInteractive">
{`window.__rm__config = { projectId: 'YOUR_PROJECT_ID', locale: 'auto' };`}
</Script>
<Script id="rm_app_script" src="https://widget.revisionme.com/app.js" />
</body>
</html>
);
}
beforeInteractive makes sure the options exist before the widget starts; an inline Script needs an id. With the Pages Router, the options Script goes into pages/_document.tsx (beforeInteractive works only there) and the widget Script into pages/_app.tsx.
Nuxt
In nuxt.config.ts:
export default defineNuxtConfig({
app: {
head: {
script: [
{ innerHTML: "window.__rm__config = { projectId: 'YOUR_PROJECT_ID', locale: 'auto' };", tagPosition: 'bodyClose' },
{ src: 'https://widget.revisionme.com/app.js', defer: true, id: 'rm_app_script', tagPosition: 'bodyClose' }
]
}
}
});
Turbo, Livewire and other page swaps
Sites that replace the whole <body> on navigation (Hotwire Turbo, Livewire wire:navigate, Swup, Barba.js) are supported: add the code to the layout once, the widget puts itself back after every swap.
Content Security Policy
If your site sends a Content-Security-Policy header, add these sources to it:
script-src https://widget.revisionme.com https://revisionme.pages.dev;
connect-src https://api.revisionme.com;
style-src 'unsafe-inline';
img-src data:;
script-src: the loader and the widget. The inline options tag also needs to be allowed: with your nonce (<script nonce="…">), its hash, or'unsafe-inline'.connect-src: sending the report.style-src 'unsafe-inline': the widget's own styles, which live in its shadow DOM, and the highlight of the selected text.img-src data:: the icons and the screenshot. The screenshot also reads the images of your page; images from other domains that the policy blocks are left out, and if the policy blocks the screenshot entirely, Revisionme takes it on its server from the page HTML instead.
Staging and other domains
Reports are accepted from the domain of the project, its subdomains and localhost. A staging copy on another domain (for example *.vercel.app or *.netlify.app) shows the form, but its reports are rejected: create a separate project for it. Details are in Showing the widget only where you need it.
Your platform is not here, or something does not work? Write to hello@revisionme.com with the address of the page.