RelayDocs

Feedback board

Embed the board

feedback.js puts our finished board inside any element on your page. It takes your accent color, sits on your page’s background and grows with its content, so there’s never a scrollbar inside it.

Add the snippet#

Put an empty element where the board should appear, then load the script:

feedback.html
<div id="relay-feedback"></div>

<script>
  window.RelayFeedbackSettings = {
    // all optional
    userId: "usr_123",         // votes follow this user across devices
    name: "Jane Cooper",       // pre-fills the name on posts and comments
    target: "#relay-feedback", // where to mount (selector or element)
    minHeight: 640             // px, before the board has measured itself
  };
</script>
<script src="https://support.notaislop.xyz/feedback.js" data-key="wk_XXXXXXXXXXXXXXXXXXXXXXXX" async></script>

The same snippet, with your host filled in, is under Inbox → Settings → Install the feedback board.

Options#

userIdstring | numberoptional
Your user’s id. Votes and posts are tied to this user on every device. Without it, votes are tied to the browser.
namestringoptional
Pre-fills the name field when the user posts or comments. They can still change it.
targetstring | Elementoptional
CSS selector or element to mount into. Defaults to #relay-feedback. You can also set it with a data-target attribute on the script tag.
minHeightnumberoptional
Initial height in pixels, used until the board reports its real height. Defaults to 640.

Framework examples#

FeedbackPage.jsx
import { useEffect } from "react";

export function FeedbackPage({ user }) {
  useEffect(() => {
    const identity = { userId: user?.id, name: user?.name };
    if (window.RelayFeedback) {
      // Loaded on an earlier visit to this page: re-attach to the new element.
      window.RelayFeedback("identify", identity);
      return;
    }
    window.RelayFeedbackSettings = identity;
    const s = document.createElement("script");
    s.src = "https://support.notaislop.xyz/feedback.js";
    s.dataset.key = "wk_XXXXXXXXXXXXXXXXXXXXXXXX";
    s.async = true;
    document.body.appendChild(s);
  }, [user]);

  return <div id="relay-feedback" />;
}

Single-page apps

The script loads once per page. If your router unmounts and re-renders the board’s element, call RelayFeedback("identify", …) (or RelayFeedback("mount") if the user hasn’t changed) and the board re-attaches to the element, as in the React example.

JavaScript API#

CallWhat it does
RelayFeedback("identify", { userId, name })Switches to a new user (or anonymous with {}) and reloads the board. Re-attaches it if it was detached.
RelayFeedback("mount", target?)Re-attaches the board to the target element, or to a new target. Use after your app re-renders the element.

Identify users after sign-in#

When the signed-in user changes, tell the board. The frame reloads with the new identity.

js
window.RelayFeedback("identify", { userId: user.id, name: user.name }); // after login
window.RelayFeedback("identify", {});                                  // after logout

userId and name travel to the board in the URL hash, which browsers never send to the server, so they don’t appear in access logs.

Good for votes, not for authentication

The user id is supplied by the browser, so a determined user could claim another id. That’s fine for counting votes. Don’t rely on it as proof of identity.

How the embed behaves#

  • It fills the width of its container. From 1024px wide it shows two columns (form and list); narrower, they stack.
  • Its height follows the content, including after filtering or opening an idea.
  • The background is transparent, so the board sits on your page’s background.
  • Opening an idea happens inside the frame, and your page scrolls back to the top of the board.
  • Upvotes update instantly and roll back if the request fails.

Branding#

The board uses your accent color from Settings → Brand for the upvote state, focus rings, hovered titles and team replies. Changing it there updates every embed on the next page load. For anything beyond color, build your own UI.

Content Security Policy#

script-src https://support.notaislop.xyz;
frame-src  https://support.notaislop.xyz;

Troubleshooting#

SymptomFix
Nothing appears; console says no element matchesAdd the target element, or point target at an element that exists when the script runs.
The board is cut offSomething in your CSS sets a fixed height on iframes. Let the loader control the height.
Votes reset between devicesPass userId.
The board shows the wrong user after logoutCall RelayFeedback("identify", {}) on logout.

Next#

Manage what comes in from Inbox → Feedback board.