@shipshape/core
v0.1.4
Published
Feedback widget for React apps — screenshot, annotate, submit.
Readme
Shipshape
Feedback widget for React apps — screenshot, annotate, submit.
Drop a single component into your app and let users report bugs and suggest improvements with annotated screenshots, console logs, and network request captures.
Features
- Screenshot capture — fast viewport capture via the browser's Screen Capture API, with an html-to-image fallback for older browsers or when the user declines the prompt (handles WebGL canvases)
- Annotation tools — arrow, rectangle, ellipse, freehand drawing, and text overlays on a Konva canvas
- Undo/redo — full history support for annotations
- Console log capture — intercepts
console.log/warn/error/infowith timestamps - Network request capture — intercepts
fetchandXMLHttpRequestwith method, URL, status, and duration - Configurable form — customizable feedback types, labels, placeholders, and reporter display
- Configurable trigger button — color, label, and corner position
- CSS isolation — scoped styles via PostCSS, no conflicts with your app's CSS
- Provider-based submission — built-in Notion support, extensible with custom providers
Quick Start
1. Install
npm install @shipshape/core2. Add the widget (client)
import { FeedbackWidget } from '@shipshape/core'
function App() {
return (
<FeedbackWidget
onSubmit={async (data) => {
await fetch('/api/feedback', {
method: 'POST',
body: JSON.stringify(data),
})
}}
reporter={{ name: 'Jane Doe', email: '[email protected]' }}
clientOrganization="Acme Inc." // optional — tags the feedback with the customer/tenant
/>
)
}Linking to your feedback dashboard
Pass feedbacksUrl to render a "View feedbacks" icon next to the trigger button. Clicking it opens your dashboard (e.g. the Notion database where submissions land) in a new tab. The icon only renders when the prop is set.
<FeedbackWidget
onSubmit={handleSubmit}
reporter={reporter}
feedbacksUrl="https://www.notion.so/your-workspace/Feedback-..."
/>3. Handle submissions (server)
import { createHandler } from '@shipshape/core/server'
const handler = createHandler({
notion: {
apiKey: process.env.NOTION_API_KEY,
databaseId: process.env.NOTION_DB_ID,
},
})
// Express / Hono / any framework
app.post('/api/feedback', async (req, res) => {
const result = await handler(req.body)
res.json(result)
})Configuration
Pass a config prop to customize the widget:
<FeedbackWidget
onSubmit={handleSubmit}
reporter={reporter}
config={{
button: {
color: '#007f67',
label: 'Feedback',
position: 'bottom-right', // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
},
form: {
types: [
{ value: 'bug', label: 'Bug', icon: 'bug' },
{ value: 'improvement', label: 'Improvement', icon: 'lightbulb' },
],
summaryLabel: 'Summary',
descriptionLabel: 'Description',
submitLabel: 'Submit Feedback',
showReporter: true,
},
devtools: {
consoleLogs: true,
networkRequests: false,
},
}}
/>Providers
Notion
Creates a page in your Notion database with the feedback title, type, description, reporter info, submission date, client organization, screenshot, console logs, and network requests.
const handler = createHandler({
notion: {
apiKey: process.env.NOTION_API_KEY,
databaseId: process.env.NOTION_DB_ID,
},
})The Notion API does not auto-create database columns, so add these properties to your database before the first submission (names must match exactly):
| Property | Type | Set by |
| --------------------- | ----------- | ----------------------------------------- |
| Type | Select | Feedback type (Bug, Improvement, …) |
| Reporter | Text | reporter prop (name (email)) |
| Feedback Date | Date | Auto-set by the widget at submission time |
| Client Organization | Text | clientOrganization prop (optional) |
Custom provider
Implement the FeedbackProvider interface for any destination:
import { createHandler, type FeedbackProvider } from '@shipshape/core/server'
const slackProvider: FeedbackProvider = {
async submit(feedback) {
// Send to Slack, email, database, etc.
return { id: 'msg_123' }
},
}
const handler = createHandler({
providers: [slackProvider],
})Roadmap
Studio — visual configuration app
A local dev tool (like Storybook) for configuring the widget visually. Launch with npx @shipshape/studio, see a live preview, tweak settings, and export a shipshape.config.ts file.
- Live widget preview with current config applied
- Visual editors for button style, form fields, feedback types, and devtools toggles
- Provider setup wizard (connect to Notion, select database, map fields)
- Config file read/write — loads existing config on launch, saves changes back
More providers
Built-in support for additional destinations:
- GitHub Issues — create issues with labels, screenshots as attachments
- Linear — create issues in your Linear workspace
- Jira — create tickets in your Jira project
- Trello — create cards with attachments
Hosted mode
Optional hosted API for zero-config setup:
- Widget sends feedback to
api.shipshape.dev— no server code needed - OAuth for provider connections (no manual API keys)
- Web dashboard for viewing and managing feedback
- Usage:
<FeedbackWidget projectId="proj_abc123" />
Framework adapters
First-class integrations:
- Next.js — API route handler + server action helpers
- Remix — action handler
- Vanilla JS — non-React wrapper for any web app
License
MIT
