How to Embed a Feedback Board and Roadmap on Your Website
Your app already has a feedback board. Your website visitors cannot see it. This guide puts it on your site: the board of open requests, the roadmap and the feedback form, each as an iframe you paste into a page. It takes a few minutes in the web dashboard and one snippet per page. At the end there is a section on when the JavaScript SDK is the better tool.
The short version
- Turn on embedding for the project in the web dashboard, under Settings, in the Embeddable Board card. It is available on every plan.
- Copy the iframe code for the board or the roadmap, or the direct link for the form, and paste it into any page.
- The theme is light or dark, set once per project. The iframe is a fixed height, so set the height yourself, and make it taller on phones.
- Pick which requests appear on the roadmap from each request's page in the web dashboard.
- If you want your own markup, use the JavaScript SDK from your server instead.
What you can embed
FeedbackKit can show a project's roadmap and its board of requests on your own website through an iframe, and it has a feedback form page you can embed the same way. The roadmap lists the feature requests you mark for it, grouped by target month, with requests that have no date under "On Our Radar". The board shows open requests in status columns with their vote counts, and visitors can vote on it when you turn voting on. A visitor is counted by an anonymous ID kept in their browser, with no sign-in. The form takes a title, a category, a description and an optional name and email. You turn embedding on per project in the web dashboard, which gives you the iframe code and a direct link for each page. Embeds are on every plan, in light or dark. There is no changelog for your users, and no roadmap site hosted on your own domain.
| Page | Path | Visitors see | Visitors can |
|---|---|---|---|
| Board | /embed/<apiKey>/kanban | Open requests in status columns, with category and vote count, sorted by votes | Vote, if you allow it |
| Roadmap | /embed/<apiKey>/roadmap | The feature requests you picked, by target month, with an optional note | Read |
| Form | /embed/<apiKey>/form | Title, category, description, optional name and email | Submit a request |
The board never shows Completed or Rejected columns, even if you tick them. There are no comments, detail pages or submit button on the board itself: pair it with the form if you want visitors to add requests.
Step 1: Turn on embedding
Open the project in the web dashboard and go to Settings. You need to be the project's Owner or an Admin. Find the Embeddable Board card and set:
- Enable Embed. Off by default. While it is off, the embed pages refuse to load.
- Allow Voting. Off by default. Turn it on to let visitors vote on the board. Voting stops on Completed and Rejected requests, as it does in your app.
- Theme. Light or Dark. More on this below.
- Visible Columns. Which status columns the board shows. Leave them all ticked to show Pending, Approved, In Progress and TestFlight.
Click Save Embed Settings. The card then shows the code for each page.
Step 2: Choose what goes on the roadmap
The board fills itself from your open requests. The roadmap does not: you pick each item. Open a request in the web dashboard and use its Roadmap card:
- Show on public roadmap puts it on the roadmap embed.
- Target Date sets the month it appears under. Leave it empty and it goes under "On Our Radar".
- Public Note is a short line shown with the item, such as "Beta in September".
A few rules decide what appears. The card is offered for requests in Approved, In Progress, TestFlight or Completed, and the roadmap shows requests in the feature request category, so bug reports, improvements and other requests stay off it. Each month shows up to three items, then a "+N more" line. A Completed item drops off once its month has passed, and an item whose month has passed without being completed moves to the current month. Roadmap settings live in the web dashboard. The native admin apps do not have them.
Step 3: Copy the code
Under the settings, the card lists the embeds. For the board and the roadmap, copy the iframe Embed snippet. Each one also has a Direct Link with a preview button, which is handy for checking what visitors will see. For the form, the card gives the direct link, which you place in an iframe yourself. The card shows more than one kind of snippet, so make sure you copy the one labelled iframe Embed.
The board's iframe code looks like this, with your project's key in place of YOUR_API_KEY:
<iframe src="https://api.prod.getfeedbackkit.com/embed/YOUR_API_KEY/kanban"
style="width:100%;height:700px;border:none;"
loading="lazy"></iframe>
The roadmap and form follow the same shape, ending in /roadmap and /form. Copy the URLs from the dashboard rather than typing them, so the host and key are right.
Step 4: Put it on a page
Plain HTML
Paste the snippet where you want the board to appear. Add a title so screen readers can announce what the frame is:
<section>
<h2>What Trailmate hikers are asking for</h2>
<iframe
src="https://api.prod.getfeedbackkit.com/embed/YOUR_API_KEY/kanban"
title="Trailmate feature requests"
style="width:100%;height:700px;border:none;"
loading="lazy"></iframe>
</section>
A React component
In React the attributes are the same, except that style takes an object. Keep the URL in one place so the board, roadmap and form share it:
const EMBED_BASE = 'https://api.prod.getfeedbackkit.com/embed/YOUR_API_KEY';
export function FeedbackEmbed({ page = 'kanban', title, height = 700 }) {
return (
<iframe
src={`${EMBED_BASE}/${page}`}
title={title}
loading="lazy"
style={{ width: '100%', height, border: 'none' }}
/>
);
}
// <FeedbackEmbed page="roadmap" title="Trailmate roadmap" />
The iframe loads on its own, so the component needs no effect, state or client library. It works the same in a server-rendered framework.
A static site
Most static site generators pass raw HTML through Markdown, so you can paste the snippet into a page. Some sanitise it by default. In Hugo, a shortcode is the tidy way: save the iframe as layouts/shortcodes/feedback-board.html, then use it in any content file:
---
title: "Feedback"
---
Vote on what we build next for Trailmate.
{{< feedback-board >}}
In Jekyll, the same file in _includes/ works with an include tag. In site builders that offer a custom HTML or embed block, paste the snippet into that block.
Theme: light or dark
The theme is one setting for the whole project, so every page that embeds the board gets the same one. Choose Light or Dark to match your site. The menu also lists Auto, but the iframe pages render it as light, so pick one of the other two. If your site switches between light and dark, choose the theme your visitors see most, and put the iframe on a surface with a matching background so the edges do not show.
Sizing
The snippet sets a fixed height of 700 pixels, and the frame does not resize itself to its content. Taller content scrolls inside the frame. That is fine on a desktop, but the layouts change on narrow screens: the board stacks its columns into one when the frame is 640 pixels wide or less, with each column scrolling on its own, and the roadmap switches to a vertical timeline at 768 pixels or less. Give the frame more room on phones with a class and a media query:
<style>
.fk-embed { width: 100%; height: 700px; border: 0; }
@media (max-width: 640px) {
.fk-embed { height: 900px; }
}
</style>
<iframe class="fk-embed"
src="https://api.prod.getfeedbackkit.com/embed/YOUR_API_KEY/roadmap"
title="Trailmate roadmap"
loading="lazy"></iframe>
Try the page on a phone with a few months of roadmap items before you publish, and adjust the number. The form is short, so a lower height usually suits it.
Before you publish
- The URL contains your project API key. It is the same key your app ships with, and it identifies the project rather than granting admin access. If you regenerate the key in project settings, the embed URLs change, so update every page that uses them.
- Web votes are anonymous. A visitor is identified by an ID stored in their browser. A new browser or cleared storage counts as a new visitor, and someone who votes in your app and on your website counts twice.
- The web and your app share one list. A vote on the board adds to the same request your app shows, and a request sent through the form appears in your app and your dashboard. It starts with one vote, its submitter's, and your team is notified as for any new request.
- Form emails close the loop. If a visitor leaves an email, they get the status email when their request moves to a status in your project's list, like any submitter. Closing the loop with status emails covers how that list works.
- The Free plan cap applies. On Free, a project shows 10 feedback items. A form submission past that is saved but hidden, and hidden or merged requests do not appear on the board or roadmap. Plans lift the cap.
- Archiving a project or turning embedding off stops the pages from loading, so remove the iframes when you do.
When to use the JavaScript SDK instead
The embeds are ready-made pages in FeedbackKit's design. If you want the board in your own markup and styles, with your own sorting, or with votes tied to signed-in accounts, use the JavaScript SDK. It is a headless client: it gives you the data and calls, and you build the interface.
There is one constraint to plan around. The API allows browser requests from a fixed list of origins: FeedbackKit's own domains and a few localhost ports for development. Your production domain is not on that list, and there is no project setting that adds it, so a fetch from your site's pages is blocked by the browser before you see a response. The iframes are not affected, because they load on FeedbackKit's origin.
So run the SDK on your server. It works in Node.js 18 or newer. Add a thin route, call the SDK there, and let your own front end talk to your own origin. That keeps the key off the page and lets you set the user ID from your signed-in session, so a vote belongs to a real account:
import express from 'express';
import { FeedbackKit, FeedbackCategory } from 'feedbackkit-js';
const app = express();
app.use(express.json());
const feedbackkit = new FeedbackKit({
apiKey: process.env.FEEDBACKKIT_API_KEY
});
app.get('/api/feedback', async (req, res) => {
const items = await feedbackkit.feedback.list();
res.json(items);
});
app.post('/api/feedback', async (req, res) => {
const created = await feedbackkit.feedback.create({
title: req.body.title,
description: req.body.description,
category: FeedbackCategory.FeatureRequest,
userId: req.user.id // from your own sign-in
});
res.status(201).json(created);
});
How to add a feedback widget to a JavaScript web app builds the rest: the list, voting, the submit form and error handling. A good rule: embed when FeedbackKit's design is fine and you want it live today, and use the SDK when the board has to look and behave like the rest of your product.
How FeedbackKit fits in
The embeds show your website visitors the same requests your app users see. Inside the app, users vote and comment through the SDK screens for Swift and SwiftUI, Kotlin, Flutter and React Native. A new request starts with its submitter's vote, and voting stops when a request reaches Completed or Rejected. You manage it all from one dashboard, with the six statuses Pending, Approved, In Progress, TestFlight, Completed and Rejected.
Here is the in-app board the website embed sits alongside, with sample data from a fictional hiking app:
The same requests in your app
Turn on embedding, paste one iframe, set its height, and your website visitors can see and vote on what you are building. Start free and put your board on your site today.