Add a feedback widget to a Docusaurus site

Add the widget to the scripts array in docusaurus.config.js with defer and the public key as a data-key attribute. Docusaurus loads it on every page. To ask whether a docs page helped, swizzle the DocItem Footer with the wrap option and add buttons that carry data-escuta-open, which preselects the feedback type.

By 路 Published 路 Last updated

Where does the widget go in docusaurus.config?

Docusaurus has a scripts option in its site configuration. Each entry is added to every page the site builds, in the document head, so you do not need to touch a theme file. Open docusaurus.config.js (or .ts) at the root of the project and add the widget to the array:

const config = {
  title: "Example docs",
  url: "https://docs.example.com",
  baseUrl: "/",
  scripts: [
    {
      src: "https://escutaproduto.com/widget.js",
      defer: true,
      "data-key": process.env.ESCUTA_KEY,
    },
  ],
  // The rest of your configuration stays as it is.
};

export default config;

Each object in scripts is written to the page as a script tag, and extra keys become attributes. The defer flag keeps the script from blocking the page, and data-key carries the public product key. Docusaurus builds the site at build time, so process.env.ESCUTA_KEY is read from the environment of the build, not from the browser.

If the variable is empty, the attribute is empty too, and the widget cannot send. Keep the key in an environment variable so you can use one product for local work and another for the published site.

How do I pass the product key from the environment?

Set ESCUTA_KEY in your shell before you run npm run start or npm run build, or set it in the build settings of your hosting provider. Docusaurus does not load a .env file on its own, so export the variable or install a package that loads one if you prefer that workflow.

Create one Escuta Produto product for local work and another for the published docs. Each product has its own allowed origins. Add http://localhost:3000, the default address of the Docusaurus dev server, to the development product, and your published domain to the production product. A request from any origin not on the list gets a 403, so a copied key cannot send feedback from a different site.

The product key is public and ships in the HTML by design. Its only power is to create feedback, which is why an allowed origins list and rate limiting are enough to protect it. The widget reference lists every attribute you can add next to data-key.

How do I add a "Was this page helpful?" prompt to docs?

The floating Feedback button works on every page, but a docs reader is more likely to answer a direct question at the end of an article. Docusaurus renders the footer of each doc page through a component called DocItem/Footer, and you can wrap it to add your own content while keeping the original.

Generate the wrapper from the command line. The --wrap flag keeps the original footer in place:

npm run swizzle @docusaurus/theme-classic DocItem/Footer -- --wrap

Docusaurus creates a file at src/theme/DocItem/Footer/index.js. Replace its contents with this wrapper, which renders the original footer followed by the prompt:

import React from "react";
import Footer from "@theme-original/DocItem/Footer";

export default function FooterWrapper(props) {
  return (
    <>
      <Footer {...props} />
      <aside className="feedback-helpful">
        <p>Was this page helpful?</p>
        <button type="button" data-escuta-open="praise">Yes, it helped</button>
        <button type="button" data-escuta-open="idea">Not quite</button>
      </aside>
    </>
  );
}

Each button carries data-escuta-open with a type. The value preselects the form, so a reader who answers "Yes, it helped" lands on the praise type, and "Not quite" opens the idea type with the message box ready. Valid types are bug, idea, praise and other. A click opens the widget form, and the page address is recorded automatically, so each answer points to the article.

Does the floating button conflict with the docs prompt?

It does not conflict, but it can feel redundant on docs pages. You have two sensible options. Keep both, which works well for sites where readers may want to report a bug anywhere. Or hide the floating button on the docs and keep only the footer prompt, by setting data-trigger to none in the scripts entry.

To hide it only on docs, you would need a different script entry per section, which Docusaurus does not offer as a simple switch. A practical approach is to keep the floating button on all pages and let the footer prompt do the job on docs. Remove the floating button only if your analytics show that readers never use it.

How do I allow Docusaurus pages through a strict CSP?

Docusaurus is a static site, so the policy belongs to your host. Add the widget host to script-src and connect-src in the response headers, as you would for any static site:

/*
  Content-Security-Policy: default-src 'self'; script-src 'self' https://escutaproduto.com; connect-src 'self' https://escutaproduto.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:

Docusaurus writes small inline scripts into its pages during the static build, and the React runtime may need them too. A strict policy without any inline allowance can block those, so after the first build check the browser console for blocked scripts. Allow them with a hash or nonce only if your host supports it, and avoid adding 'unsafe-inline' to the whole site if you can avoid it. The CSP guide for widgets explains how to read a blocked request.

What should I check after a build?

Run ESCUTA_KEY=pk_your_dev_product_key npm run start, then open a docs page. Check the page source for the widget.js script tag and confirm it carries your development key. Scroll to the footer, click one of the helpful buttons and send a test message. Then run npm run build with the production key and serve the output with npm run serve, which shows the production behavior.

If the script is missing, ESCUTA_KEY was empty during the build. If the prompt is absent on docs pages, check that the swizzled file is at src/theme/DocItem/Footer/index.js and that the import path uses @theme-original. If sending fails with a 403, add the exact origin, including the port, to the allowed origins.

Connecting the docs prompt to Escuta Produto

After the prompt works, read the results in the inbox. Each item carries the page it came from, so you can see which article generates the most "Not quite" answers, and you can filter the inbox by the idea or praise type. Escuta Produto stores each item in the product you created for the docs site, so the same inbox can hold feedback from your app, your API and your docs at once.

For the same layout approach on a static site built with a different tool, read the Hugo guide or the Eleventy guide. If your docs site is a React single-page app, the React guide explains how identify works there.

Frequently asked questions

Where do I add the feedback widget to a Docusaurus site?

Add an entry to the scripts array in docusaurus.config.js with src set to the widget URL, defer set to true, and data-key set to your public product key. Docusaurus then adds the script to every page it builds.

How do I add a Was this page helpful prompt to Docusaurus docs?

Swizzle the DocItem Footer component with the wrap option, then render buttons below the original footer. Give each button a data-escuta-open attribute, so a click opens the feedback form with the matching type preselected.

Should I keep the floating feedback button on Docusaurus docs pages?

You can keep both. The floating button works on every page, and the footer prompt asks a direct question at the end of an article. Hide the floating button only if your readers never use it.

Why does my Docusaurus feedback widget not load after a production build?

The most likely cause is an empty product key, because the build reads the variable from the environment. Check that ESCUTA_KEY is set for the build command, and check the browser console for a blocked script caused by your Content Security Policy.