Makethisbetter
FreeNot checkedMake This Better JS Widget SDK — embed user feedback collection in any website
About
Make This Better JS Widget SDK — embed user feedback collection in any website
README
makethisbetter
From rage click to agent-ready fix.
Why
You ship with AI agents. Your users hit bugs you never see in dev. They leave. You never find out why.
This widget gives your users a way to report exactly what went wrong — annotated screenshot, console errors, DOM state, browser info — in two clicks. AI triage turns that into a structured task your coding agent (Claude Code, Cursor, Codex) picks up automatically. The agent ships the fix. The user gets notified.
No more "can you describe what happened?" No more lost screenshots in Slack. The full loop, from frustrated user to shipped fix, runs without you context-switching.
Quick Start
CDN (2 lines)
<script src="https://unpkg.com/makethisbetter@1"></script>
<script>
MakeThisBetter.init({ projectKey: 'mtb_proj_YOUR_KEY' })
</script>
npm
npm install makethisbetter
import { MakeThisBetter } from 'makethisbetter'
MakeThisBetter.init({ projectKey: 'mtb_proj_YOUR_KEY' })
That's it. A feedback tab appears on your page.
How It Works
User clicks feedback tab
-> Annotates the problem (click to pin, drag to draw)
-> Adds a comment
-> Submits
+-- Screenshot captured automatically
+-- Console errors collected
+-- Page context assembled (URL, browser, OS, selectors)
+-- Sent to Make This Better API
+-- AI asks a clarifying question if needed
-> Dashboard shows structured feedback
-> AI triage produces an agent-ready task
-> Your coding agent picks it up and ships the fix
-> User gets notified: the fix is live
Framework Guides
React / Next.js
// app/providers.tsx (App Router) or pages/_app.tsx (Pages Router)
'use client'
import { useEffect } from 'react'
export function FeedbackProvider() {
useEffect(() => {
import('makethisbetter').then(({ MakeThisBetter }) => {
MakeThisBetter.init({
projectKey: process.env.NEXT_PUBLIC_MTB_KEY!,
user: { id: userId, email }
})
})
return () => {
import('makethisbetter').then(({ MakeThisBetter }) => MakeThisBetter.destroy())
}
}, [])
return null
}
Vue / Nuxt
// plugins/makethisbetter.client.ts (Nuxt) or main.ts (Vue)
import { MakeThisBetter } from 'makethisbetter'
export default defineNuxtPlugin(() => {
MakeThisBetter.init({
projectKey: useRuntimeConfig().public.mtbKey,
})
return {
provide: { mtbDestroy: () => MakeThisBetter.destroy() }
}
})
Astro
<!-- src/components/Feedback.astro -->
<script>
import { MakeThisBetter } from 'makethisbetter'
MakeThisBetter.init({ projectKey: import.meta.env.PUBLIC_MTB_KEY })
</script>
Rails
<%# app/views/layouts/application.html.erb %>
<% if current_user&.admin? %>
<script src="https://unpkg.com/makethisbetter@1"></script>
<script>
MakeThisBetter.init({
projectKey: '<%= Rails.application.credentials.mtb_project_key %>',
user: { id: '<%= current_user.id %>', email: '<%= current_user.email %>' }
})
</script>
<% end %>
Plain HTML / Static Sites
<script src="https://unpkg.com/makethisbetter@1"></script>
<script>
MakeThisBetter.init({ projectKey: 'mtb_proj_YOUR_KEY' })
</script>
Features
Annotation
Click any element to pin it, or drag to draw a freeform highlight. The SDK captures the element's CSS selector, text content, and position.
Screen Recording
Switch to Record mode in the toolbar to capture a screen recording (up to 60 seconds). Powered by rrweb with lazy loading — zero cost until the user hits Record. No extra install needed: npm users get the recorder bundled as a lazy chunk served from your own assets; script-tag users load it on demand from jsDelivr (SRI-pinned).
Frustration Detection
The SDK watches for signals that a user is struggling and proactively offers to collect feedback:
| Signal | Trigger |
|---|---|
| Rage click | 3+ clicks on the same element within 1 second |
| Dead click | Click on a non-interactive element (with console errors) |
| Dead click (DOM) | Click on interactive-looking element with no DOM response |
| Rapid navigation | 3+ page navigations within 5 seconds |
| Form failure | Form submission with validation errors |
| Error page | Landing on a 404/500 error page |
Disable with frustrationDetection: false.
AI Clarification
After submitting feedback, an AI assistant may ask a short follow-up question to clarify the real need — avoiding XY problems where users describe their attempted solution instead of the actual problem.
Auto-Collected Context
Every submission automatically includes:
- Page URL, browser, OS, screen resolution
- Console errors (via
window.onerrorandwindow.onunhandledrejection) - Target element selector and text
- Annotated screenshot (via
html-to-image) - Annotation coordinates and draw paths
Internationalization
Built-in support for 7 languages:
| Code | Language |
|---|---|
en |
English (default) |
zh-CN |
Chinese (Simplified) |
ja |
Japanese |
ko |
Korean |
es |
Spanish |
fr |
French |
de |
German |
Configuration
MakeThisBetter.init({
// Required
projectKey: 'mtb_proj_xxx',
// Optional
locale: 'en', // UI language
position: 'right', // Tab position: 'left' | 'right'
theme: 'auto', // 'light' | 'dark' | 'auto'
frustrationDetection: true, // Proactive frustration prompts
apiUrl: 'https://...', // Self-hosted API endpoint
// User identification (recommended)
user: {
id: 'usr_123',
email: '[email protected]',
name: 'Alex Chen',
},
})
Identity Verification
Identity verification links feedback to authenticated users and lets them view their own submissions on the feedback board.
Level 0 -- Anonymous (default): No user token. Feedback is anonymous.
MakeThisBetter.init({ projectKey: 'mtb_proj_xxx' })
Level 1 -- Static token: Pass a pre-generated JWT. Simple, but the token may expire during long sessions.
MakeThisBetter.init({
projectKey: 'mtb_proj_xxx',
userToken: 'eyJhbGciOiJIUzI1NiIs...',
})
Level 2 -- Dynamic token (recommended): Pass an async function that returns a fresh JWT. The SDK calls it before each API request, so tokens never go stale.
MakeThisBetter.init({
projectKey: 'mtb_proj_xxx',
userTokenFn: async () => {
const res = await fetch('/api/mtb-token')
const { token } = await res.json()
return token
},
})
When userToken or userTokenFn is set, the widget sends an X-User-Token header with every request. After submitting feedback, a "View my feedback" link appears that opens the project board filtered to the user's submissions.
Generate tokens server-side using your project's HMAC secret (available in your project settings):
# Rails example
payload = { sub: current_user.id, email: current_user.email, exp: 1.hour.from_now.to_i }
JWT.encode(payload, project.widget_secret, 'HS256')
Conditional Loading
// Only show to beta users
if (user.isBetaTester) {
MakeThisBetter.init({ projectKey: 'mtb_proj_xxx', user: { id: user.id } })
}
Self-Hosting
The Widget works with any backend — not just makethisbetter.dev. Implement one API endpoint and point apiUrl at your server:
MakeThisBetter.init({
projectKey: 'your-key',
apiUrl: 'https://feedback.yoursite.com',
})
Your backend needs to handle POST /api/v1/widget/feedbacks (multipart/form-data with description, screenshot, console errors, etc). The Widget takes care of everything else — annotation, recording, frustration detection, context collection.
The cloud platform at makethisbetter.dev adds AI triage, dashboard, GitHub/Linear sync, and email notifications on top.
API
import { MakeThisBetter } from 'makethisbetter'
// Start the widget
MakeThisBetter.init(config: MakeThisBetterConfig): void
// Remove the widget and clean up all listeners
MakeThisBetter.destroy(): void
Architecture
The widget runs inside a Shadow DOM container, isolating its styles from your page. No CSS conflicts, no z-index wars.
Shadow DOM Host (#mtb-widget-host)
+-- Feedback Tab (entry point)
+-- Annotation Toolbar (Mark up / Record toggle)
+-- Annotation Session (pin + draw overlays)
+-- Comment Popup (description + submit)
+-- AI Clarification Card (follow-up conversation)
+-- Success Card (confirmation)
+-- Frustration Prompt (proactive trigger)
Bundle Size
| Format | Size | gzip |
|---|---|---|
| IIFE | ~77 KB | ~23 KB |
| ESM | ~90 KB | ~24 KB |
The rrweb recorder (~78 KB) is loaded on demand when recording starts and not included in these numbers.
Development
git clone https://github.com/makethisbetter/makethisbetter-js.git
cd makethisbetter-js
npm install
npm run dev # Dev server at localhost:5173
npm run build # Build all formats to dist/
npm test # Run tests
npm run type-check # TypeScript validation
Related
| Package | What it does |
|---|---|
| Make This Better | The platform — dashboard, AI triage, feedback board |
| @makethisbetter/mcp | MCP server — your coding agent reads feedback directly |
| makethisbetter CLI | Terminal tool for managing feedback |
| makethisbetter Skills | Claude Code skills — /makethisbetter in your editor |
License
GitHub repo settings
- Description: Drop-in feedback widget — from rage click to agent-ready fix
- Homepage: https://makethisbetter.dev
- Topics: feedback, widget, ai, mcp, claude-code, cursor, vibe-coding
Install Makethisbetter in Claude Desktop, Claude Code & Cursor
unyly install makethisbetterInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add makethisbetter -- npx -y makethisbetterFAQ
Is Makethisbetter MCP free?
Yes, Makethisbetter MCP is free — one-click install via Unyly at no cost.
Does Makethisbetter need an API key?
No, Makethisbetter runs without API keys or environment variables.
Is Makethisbetter hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Makethisbetter in Claude Desktop, Claude Code or Cursor?
Open Makethisbetter on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Makethisbetter with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
