Own your feedback API with FeedbackAdapter
Most teams that care about data residency want the widget without shipping post content to a vendor. That is BYO mode.
Bootstrapware hosts board configuration (toggles, branding, publish revisions). Your backend stores posts and votes. You pass a FeedbackAdapter: or wrap the same four callbacks with createByoAdapter.
The four methods
listPosts: return{ posts, nextCursor }; optionalstatusfilter, cursor, andq(similar-request search beyond the loaded page).createPost: accept title/body/author; return aFeedbackPost.vote/unvote: keyed bypostId+author.
Full TypeScript shape: Adapter reference. Limits: title 200 characters, body 5000, plain text. Statuses: open | planned | in_progress | shipped | declined.
Minimal adapter wiring
<Feedback
boardId="brd_..."
user={currentUser}
adapter={{
listPosts: async ({ boardId, status, cursor, q }) => {
const params = new URLSearchParams({ boardId });
if (status) params.set("status", status);
if (cursor) params.set("cursor", cursor);
if (q) params.set("q", q);
return fetch(`/api/feedback?${params}`).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",
body: JSON.stringify({ author }),
});
},
unvote: async ({ postId, author }) => {
await fetch(`/api/feedback/${postId}/unvote`, {
method: "POST",
body: JSON.stringify({ author }),
});
},
}}
/>Your routes are illustrative. Feedback does not prescribe your URL layout, only the adapter contract the widget calls. Forward optional q so similar requests can search beyond the page currently on screen.
What you must enforce
- Authz on the server. Do not trust the browser alone. Derive the author from your signed-in session when writing.
- One vote per author per post. Hosted enforces this; BYO must match if you want honest counts.
- Stable opaque ids.
user.id/author.idshould not be emails you plan to rotate.
Pricing and resolve order
Live publishable board config still needs BYO ($9.99) or Hosted ($19.99). Passing an adapter means posts stay with you , you do not need Hosted ($19.99) storage. Explicit adapter always wins over Hosted props.
Compare modes: BYO vs Hosted. Postgres walkthrough: Store posts in Postgres.
What Bootstrapware does not do in BYO
- No Hosted inbox for your rows.
- No
feedback.post_created/feedback.status_changedwebhooks for your store, emit your own from your API if needed. - MCP still configures boards only; never send title/body through MCP.
Related: Adapter · Modes · BYO vs Hosted · Postgres store · Identity · Pricing