Feature-request voting for SaaS
Most SaaS teams do not need a public voting portal. They need customers inside the product to upvote ideas so the roadmap reflects real demand.
Bootstrapware Feedback embeds that loop: list posts, submit, vote, unvote, and filter by status. Voting is keyed by the host-asserted author.id your app already knows from session, Feedback does not log end users in.
How voting works
- One vote per post per opaque
author.id. - Unvote removes that author's vote.
- Published board config toggles
votingEnabledandshowVoteCounts. - Sort in the widget is by votes or recent. Status filter is separate (
open|planned|in_progress|shipped|declined).
Hosted enforces uniqueness server-side. BYO must enforce the same rule in your API if you want honest counts.
Hosted vs BYO
| Mode | Who stores votes |
|---|---|
| Hosted ($19.99) | Omit adapter; pass boardId + publishable key. Widget talks to Feedback API. |
| BYO ($9.99) | Implement vote / unvote on your FeedbackAdapter. Posts stay on your backend. |
| Local / demo | createLocalAdapter: free forever, browser storage, not for production multi-user truth. |
Adapter resolution order: explicit adapter → Hosted when boardId + publishableKey → otherwise local.
BYO adapter sketch
<Feedback
boardId="brd_..."
user={currentUser}
adapter={{
listPosts: async ({ boardId, status, cursor }) =>
fetch(`/api/feedback?boardId=${boardId}`).then((r) => r.json()),
createPost: async (input) =>
fetch("/api/feedback", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(input),
}).then((r) => r.json()),
vote: async ({ postId, author }) => {
await fetch(`/api/feedback/${postId}/vote`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ author }),
});
},
unvote: async ({ postId, author }) => {
await fetch(`/api/feedback/${postId}/unvote`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ author }),
});
},
}}
/>Your Route Handlers must trust the session cookie (or equivalent), not the client-supplied author.id alone, when writing votes.
Hosted rate limits
Per board and action, Hosted publishable routes use roughly 30 creates per minute and 120 list or vote actions per minute. Treat these as operational safeguards, not a billable meter. Details: limits.
Pitfalls
- Unstable
user.idacross devices, votes look like different people. - Leaving
votingEnabledon while you meant read-only roadmap. - BYO without a unique (post_id, author_id) constraint, duplicate votes inflate counts.
- Assuming Feedback authenticates users, it does not; see host-asserted identity.
Related: Statuses · Identity · Limits · Status lifecycle · Demo