Skip to Content
v0.8.0 · shippedNative mobile SDKs, optional Sentry enrichment, and bring-your-own keys/storage. Read the changelog →
SDK reference@mushi-mushi/web

@mushi-mushi/web

Catch what users felt — screenshots, console logs, and a shake-to-report widget — without bolting on another dashboard. The browser SDK runs in a Shadow DOM so your CSS never leaks in or out.

Migrating from another bug-capture tool? We have step-by-step guides for Instabug / Luciq, Shake, LogRocket Feedback, BugHerd, and Pendo Feedback. Each maps the competitor’s API to the Mushi equivalent and includes an interactive checklist.

See Quickstart → Vanilla JS for setup. Notable extras:

  • onProactiveTrigger(({ context }) => …) — fires when the SDK detects user friction (rage clicks, repeated navigation, console errors during the same interaction). Use it to surface the report widget contextually.
  • onBeforeSubmit((report) => report | null) — last-mile transform. Return null to drop the report client-side.
  • pii — built-in scrubber masks emails, phones, SSNs, credit-card-shaped strings, and JWTs by default. Add custom regex via pii.customPatterns.

When screenshot capture is enabled (capture.screenshot: 'on-report' or 'auto'), the details step shows a visible preview of the image that will be attached — not just a “Screenshot attached ✓” label. Reporters can Remove the screenshot before submit and optionally read a privacy caption beneath the preview.

Mushi.init({ projectId: '00000000-0000-0000-0000-000000000000', // UUID from Projects page apiKey: 'mushi_xxxxxxxxxxxxxxxxxxxxxxxxxxxx', // report:write key widget: { // true → localized default caption (en/es/ja/th) // string → your compliance copy verbatim // false → hide caption (preview + Remove still show) screenshotSensitiveHint: true, }, capture: { screenshot: 'on-report' }, })

Tune the caption from the admin console (Projects → SDK install → Screenshot privacy caption) without rebuilding — it travels in GET /v1/sdk/config under widget.screenshotSensitiveHint.

The preview stays in sync if the reporter uses Mark up (blur/highlight). Keep img-src data: in your CSP when using screenshots on locked-down pages. See the Next.js App Router + CSP recipe.

Maintainer deep-dive: SDK_SCREENSHOT_PREVIEW.md 


Identifying users & the Rewards program

Call identify() as soon as your auth state resolves. The SDK links all subsequent reports and activity events to that user identity server-side.

// On login / auth state change const { user } = await supabase.auth.getUser() if (user) { mushi.identify(user.id, { email: user.email, name: user.user_metadata?.full_name, provider: 'supabase', }) }

identify() is idempotent — calling it again with the same userId updates the stored traits. Calling it with a new userId flushes any buffered events for the previous session first.

Enabling the Rewards program

Add a rewards block to your init() config:

import { Mushi } from '@mushi-mushi/web' const mushi = Mushi.init({ projectId: 'YOUR_PROJECT_ID', apiKey: 'YOUR_API_KEY', rewards: { enabled: true, trackActivity: true, // auto-capture page_view, navigate, session_start consentMode: 'explicit', // 'explicit' | 'auto' showInWidget: true, // show tier + points in the bug-report widget showNotifications: true, // "+X pts" toast on each award flushIntervalMs: 300_000, // how often to POST activity (min 30s) }, })

trackActivity: true automatically captures:

ActionTrigger
session_startFirst SDK init after 30 min idle, capped 3×/day
page_viewEvery history.pushState / popstate event
navigate<a> clicks and programmatic router pushes
button_pressClicks on [data-mushi-track] or [data-testid] elements

For custom actions:

mushi.submitActivity([ { action: 'lesson_complete', metadata: { lessonId: 'l_123', score: 0.9 } }, ])

Querying points & tier

// Current user's points const points = await mushi.getReputation() // → { totalPoints, points30d, reputation, confirmedBugs, totalReports } // Current tier const tier = await mushi.getTier() // → { id, slug, displayName, pointsThreshold, perks } | null

See Concepts → Rewards & contributor identity for the full data model, anti-gaming integration, and webhook reference.

Reporter API

Let reporters see and follow up on their own submissions without a login. Every method is keyed to the persistent anonymous reporterToken the SDK stores in localStorage, so no auth wiring is required.

// The reporter's own report history (newest first) const reports = await mushi.listMyReports() // → MushiReporterReport[] (each carries `unread_count` for a badge) // The comment thread on one of their reports const comments = await mushi.listMyComments(reportId) // → MushiReporterComment[] (their comments + team replies) // Post a follow-up comment on their own report const comment = await mushi.replyToReport(reportId, 'Still happening on iOS 18') // → MushiReporterComment | null // The project's public contributor leaderboard const leaders = await mushi.getHallOfFame(10) // → MushiHallOfFameEntry[] (display_name, tier_name, points_30d, total_points)

All four methods fail soft: they return [] / null (never throw) when the network is down or no reporter token exists yet, so they’re safe to call on first render.

React

The same methods are exposed on the useMushi() hook, memoised so they’re stable across renders:

import { useMushi } from '@mushi-mushi/react' function MyReports() { const { listMyReports, replyToReport } = useMushi() // ... call inside an effect or event handler }

useMushi() returns no-op fallbacks (() => Promise.resolve([])) before the SDK finishes initialising, so you never need to null-check the instance.

Last updated on