Docs
Everything public about a project lives under one slug. Replace your-project with yours.
Every widget on this page is live — this page loads the same embed.js you would, pointed at our demo project. Click things.
Your public hub
Every project gets a hub page with a tab per enabled module. Turn a module off in Settings and its tab disappears.
- https://feedfa.st/p/your-project
- Changelog — the hub's default tab
- https://feedfa.st/p/your-project/feedback
- Feedback board
- https://feedfa.st/p/your-project/status
- Status page
- https://feedfa.st/p/your-project/changelog/entry-slug
- A single changelog entry
Install the script
One script tag, then place widgets wherever you want them. Every widget renders inside a shadow root, so your CSS and ours can never collide.
<script src="https://feedfa.st/embed.js" data-project="your-project" defer></script>- data-project
- Required. Your project slug.
- data-theme
- auto (default) · light · dark
- data-accent
- Override the accent colour, e.g. #4F46E5
- data-badge
- false to turn the floating badge off
- data-position
- bottom-right (default) · bottom-left
- data-user-id / -email / -name
- Identify the signed-in user — see below
Feedback button
Put data-feedfast="feedback" on any element — a button, a link, a menu item. It opens a modal that posts straight to your board.
If the element already has content, we leave your markup and styling completely alone and only attach the click handler.
<button class="my-button" data-feedfast="feedback">
Send feedback
</button>The modal asks for a category, title, optional details and an optional email — the same fields as the public board, with the same rate limiting and spam trap. The submitted idea starts with the author's own upvote.
Identify your users
When the button lives inside your dashboard, you already know who's clicking it. Pass them along and the modal drops its name and email fields entirely.
No setup. Whatever your page sends is accepted and stored, marked unverified.
<button
data-feedfast="feedback"
data-user-id="${user.id}"
data-user-email="${user.email}"
data-user-name="${user.name}"
>Send feedback</button>This is only asserted, not verified
- data-user-id
- Your own user id. Opaque to us, never shown publicly.
- data-user-email
- Prefills the author, and makes their votes portable.
- data-user-name
- Shown as “Posting as …” in the modal.
- data-user-hash
- HMAC-SHA256 of the user id. Required once a secret is set.
Set the same attributes on the loader script to cover every trigger on the page, or call Feedfast.identify(...) once your SPA has the session. Identity on a trigger beats identity on the loader, so one page can have both an authenticated and an anonymous entry point.
Feedfast.identify({ id: user.id, email: user.email, name: user.name });
Feedfast.identify(null); // back to anonymous on sign-outUptime bar
The same 90-day strip as your status page, at any size.
<div data-feedfast="uptime"></div>- data-monitor
- Show a single monitor, by name
- data-days
- 1–90. How much history to draw
- data-compact
- true | false — shorter bars
- data-overall
- true | false — the status line above the monitors
Which day is a bar?
Changelog
Two shapes. Cards for a landing page or a dedicated “what's new” section; inline for a compact list in a sidebar or footer.
<div data-feedfast="changelog" data-variant="card" data-limit="3"></div>- data-variant
- card (default) | inline
- data-limit
- 1–10. How many entries
- data-excerpt
- true | false — card variant only
- data-tags
- true | false — show tag pills
Floating badge
On by default: a “What's new” badge pinned to a corner, with an unread dot that clears once the visitor opens it.
<!-- on by default -->
<script src="https://feedfa.st/embed.js" data-project="your-project" defer></script>
<!-- off, if you'd rather place widgets yourself -->
<script src="https://feedfa.st/embed.js" data-project="your-project" data-badge="false" defer></script>These docs load the script with data-badge="false", so the badge isn't pinned over the page — this button opens the same panel it would.
The unread state lives in the visitor's own browser. If maintenance is scheduled, a notice appears above the entries.
JavaScript API
The loader exposes window.Feedfast once it runs.
- Feedfast.openFeedback(opts?)
- Open the modal. { categoryId, title, subtitle, user }
- Feedfast.openChangelog()
- Open the “What's new” panel
- Feedfast.identify(user)
- Set the signed-in user; null clears it
- Feedfast.close()
- Close whatever is open
- Feedfast.refresh()
- Re-fetch and re-render every widget
- Feedfast.mount(root?)
- Scan for new widgets (usually automatic)
- Feedfast.data()
- The current payload, or null before first load
RSS feeds
Both feeds are RSS 2.0 with content:encoded, cached for five minutes.
- https://feedfa.st/p/your-project/rss.xml
- Published changelog entries
- https://feedfa.st/p/your-project/status.rss
- Incidents and maintenance windows
JSON payload
The widgets read one small public document. It's CORS-open and cached for 60 seconds, so you can build your own UI on top of it.
- GET https://feedfa.st/api/widget/your-project
- No auth required
{
"project": { "name": "Acme Analytics", "slug": "acme", "accentColor": "#4F46E5" },
"hubUrl": "https://feedfa.st/p/acme",
"modules": { "changelog": true, "feedback": true, "status": true },
"entries": [{ "id": "…", "title": "…", "url": "…", "excerpt": "…",
"tags": ["New"], "publishedAt": "2026-08-14T05:12:59.305Z" }],
"categories": [{ "id": "…", "name": "Bug", "color": "#EF4444", "isDefault": false }],
"uptime": {
"overall": { "state": "operational", "label": "All systems operational" },
"monitors": [{ "name": "API", "state": "up", "uptimePct": 99.82,
"bars": "uuuuuuuuduuu…" }],
"days": 90, "startDay": "2026-05-19", "timezone": "Europe/Bucharest"
},
"maintenance": { "title": "Database upgrade", "status": "SCHEDULED",
"startsAt": "2026-08-19T08:41:12.638Z",
"endsAt": "2026-08-19T09:41:12.638Z" }
}Each character in bars is one day, oldest first: u up, d down, g degraded, m maintenance, n no data. Every timestamp is ISO 8601 in UTC.
Board filters
Feedback board filters live in the URL, so any view you can see is a link you can share.
- ?category=bug
- One category, by slug
- ?category=bug,feature-request
- Several categories
- ?status=open,planned
- Filter by status
- ?sort=top | new | trending
- Top votes (default), newest, or votes in the last 7 days
- ?q=slack
- Free-text search across title and body
Status subscribers
Anyone can subscribe from your status page, with no account.
Subscriptions are double opt-in — the address only receives mail after the confirmation link is clicked — and every email carries a one-click unsubscribe link.
Subscribers are emailed when an incident opens or resolves, and at whichever maintenance milestones you enabled (scheduled, started, completed).
API keys
The REST API and the MCP server both authenticate with a bearer key from Settings → Account.
Keys look like ff_…. Only a SHA-256 hash is stored, so the plaintext is shown exactly once, at creation.
curl https://feedfa.st/api/v1/projects \
-H "Authorization: Bearer ff_your_key_here"- Scope
- READ_ONLY or READ_WRITE — writes 403 on a read-only key
- Rate limit
- 120 requests per minute per key
- Reach
- Every project on the account that owns the key
REST API
Everything the dashboard can do to a project, over HTTP.
- GET /api/v1/projects
- Every project this key can reach
- GET /api/v1/projects/:slug/changelog
- ?status=&limit=
- POST /api/v1/projects/:slug/changelog
- Create, and publish by default
- PATCH /api/v1/projects/:slug/changelog
- Edit, publish or unpublish
- GET /api/v1/projects/:slug/feedback
- ?category=&status=&sort=&q=&limit=
- GET /api/v1/projects/:slug/feedback/:postId
- One post with its comment thread
- PATCH /api/v1/projects/:slug/feedback
- Status, category, pin, owner reply
- POST /api/v1/projects/:slug/feedback/:postId/resolve
- Close it, reply, and publish the changelog entry in one transaction
- GET /api/v1/projects/:slug/uptime
- ?days= — state, uptime windows, incidents
- GET /api/v1/projects/:slug/maintenance
- ?upcoming=true
- POST /api/v1/projects/:slug/maintenance
- Schedule a window
- PATCH /api/v1/projects/:slug/maintenance
- start | complete | cancel
Two ways to say when
timezone ("2026-09-01T02:00") or a full ISO instant ("2026-08-31T23:00:00Z"). The first is what a person would say; the second is what a machine already has.curl -X POST https://feedfa.st/api/v1/projects/acme/maintenance \
-H "Authorization: Bearer ff_…" \
-H "Content-Type: application/json" \
-d '{
"title": "Database upgrade",
"startsAt": "2026-09-01T02:00",
"endsAt": "2026-09-01T03:30",
"timezone": "Europe/Bucharest",
"monitors": ["API"]
}'MCP server
Connect Claude or any MCP client and let it publish release notes, schedule maintenance, and read your board and uptime.
{
"mcpServers": {
"feedfast": {
"command": "npx",
"args": ["-y", "feedfast-mcp"],
"env": {
"FEEDFAST_API_KEY": "ff_your_key_here",
"FEEDFAST_URL": "https://feedfa.st"
}
}
}
}- list_projects
- Slugs, enabled modules and content counts
- get_uptime
- Monitor state, uptime windows, open and recent incidents
- list_feedback
- Filter by status, category, search; sort by top/new/trending
- get_feedback
- One post with its full comment thread
- update_feedback
- Status, category, pin, and public owner replies
- resolve_feedback
- Close the loop: mark it done, reply publicly, publish the changelog entry, link them
- list_changelog
- Published and draft entries
- publish_changelog
- Write a release note — public immediately
- update_changelog
- Edit, publish a draft, or unpublish
- list_maintenance
- Scheduled, in progress and completed windows
- schedule_maintenance
- Announce planned downtime
- transition_maintenance
- Start now, complete early, or cancel
It can only do what the key can
Want to see it all working? Browse the live demo hub.