Create a project in the dashboard and paste its snippet before </body>:
<script src="https://uups.dev/widget.js" data-project-key="pk_…" async></script>
Optional attributes: data-locale (en / hu), data-release, data-environment.
FeedbackWidget.init({ projectKey, locale, appRelease, environment, user, metadata })
FeedbackWidget.open({ type: "bug" | "feature-request" })
FeedbackWidget.close()
FeedbackWidget.identify({ id, email, name, signature }) // or null on logout
FeedbackWidget.setMetadata({ plan: "pro", tenant: "acme" })
FeedbackWidget.track("checkout.failed", { step: 2 }) // into a running recording's log
FeedbackWidget.destroy()Hide the floating button in project settings and call open() from your own help menu.
Sign the user id on your server with the project's identity secret; submissions with a valid signature are marked verified.
const signature = createHmac("sha256", IDENTITY_SECRET).update(user.id).digest("hex");Recording uses the browser's screen-capture API (Chrome, Edge, Firefox desktop). Alongside the WebM video a JSON log is captured only while recording: pointer clicks/moves (sampled), scroll, wheel, focus/visibility, viewport changes, SPA navigation (ids replaced by :id, no query strings), JS errors, failed network requests (method, status, path) and your owntrack() events. Typed text, DOM content and request bodies are never captured. The log is validated server-side against a strict schema.
GET https://uups.dev/api/v1/projects/:projectId/feedback?status=open&type=bug&page=1
GET https://uups.dev/api/v1/projects/:projectId/feedback/:feedbackId
PATCH https://uups.dev/api/v1/projects/:projectId/feedback/:feedbackId
{ "action": "set-status", "status": "resolved" }
{ "action": "set-priority", "priority": "high" }
{ "action": "add-note", "note": "Fixed in 1.4.3" }
Authorization: Bearer sk_…Every report is available as a single document with the schema feedback-agent-context/v1: the report fields, environment, metadata, notes and — if there is a recording — its event timeline with errors pulled out. Use Copy for AI on a report in the inbox, or fetch it from your own agent:
GET https://uups.dev/api/v1/projects/:projectId/feedback/:feedbackId/context GET https://uups.dev/api/v1/projects/:projectId/feedback/:feedbackId/context?format=markdown Authorization: Bearer sk_…
The timeline drops high-frequency noise (mouse moves, scroll) but keeps clicks, navigation, typing markers (never the text), app events and every JS / network error with a millisecond timestamp.
Create a key on the AI & MCP page in the dashboard, then connect your agent:
# Claude Code
claude mcp add --transport http uups https://uups.dev/api/mcp \
--header "Authorization: Bearer sk_…"
# Cursor (.cursor/mcp.json) / VS Code (.vscode/mcp.json)
{ "mcpServers": { "uups": { "url": "https://uups.dev/api/mcp",
"headers": { "Authorization": "Bearer sk_…" } } } }
# Codex (~/.codex/config.toml)
[mcp_servers.uups]
url = "https://uups.dev/api/mcp"
bearer_token_env_var = "UUPS_MCP_KEY"Tools:
list_projects — projects and open report countslist_feedback — search the inbox (open by default)get_feedback — one report with everything: text, environment, metadata, notes, recording timeline with errors, screenshots as images, a 15-minute video linkget_recording_events — the raw, schema-validated interaction logupdate_feedback — set status / priority and leave a noteIn a project's Install & settings page, use Add to Slack or Add to Discord and pick a channel. For Teams, open the channel → ⋯ → Workflows → “Post to a channel when a webhook request is received” and paste the URL. Every new report is posted with its errors and an Open button.
Every new submission is POSTed as JSON with an x-feedback-signature: t=…,v1=… header — HMAC-SHA256 of `${t}.${rawBody}` with the webhook secret.
{
"event": "feedback.created",
"projectId": "…",
"feedback": { "id": "…", "type": "bug", "category": "UI", "excerpt": "…",
"reporter": { "id": "user_123", "email": "…", "name": "…" },
"hasRecording": true, "url": "https://uups.dev/app/p/…/feedback/…" }
}