cluebase-next
v0.6.2
Published
AI-powered error handling for Next.js applications
Downloads
5,150
Maintainers
Readme
cluebase-next
An agentic rescue widget for Next.js applications. When an error hits one of your users, Cluebase catches it, opens a live conversation with that user — calm, human, and honest about what broke — finds out what they were doing, and gets their email so your team can follow up. The whole conversation is logged to your Cluebase dashboard, with Slack/Telegram alerts to your team.
This isn't a developer-facing error explainer. The agent talks to your end user, not to you.
Installation
npm install cluebase-nextQuick Start
Just wrap your app with CluebaseProvider and add your API key:
// pages/_app.tsx
import { CluebaseProvider } from 'cluebase-next';
export default function App({ Component, pageProps }) {
return (
<CluebaseProvider
apiKey={process.env.NEXT_PUBLIC_CLUEBASE_API_KEY ?? ''}
>
<Component {...pageProps} />
</CluebaseProvider>
);
}That's it! Cluebase will automatically:
- Catch errors and open a side-panel conversation with the affected user
- Talk them through what happened, in plain language, with no technical jargon
- Ask what they were doing and capture their email so your team can follow up
- Log the full transcript and outcome (saved / at risk / lost) to your dashboard
- Alert your team on Slack/Telegram when the conversation closes (immediately for P0s)
Get Your API Key
- Sign up at cluebase.dev
- Create a project
- Copy your API key from the project settings
Features
- Talks to the user, not the developer — the agent's job is to calm down and gather context from whoever actually hit the error
- Real streaming replies — tokens appear as the model generates them, not a simulated typewriter effect
- Low-confidence honesty — if the agent can't tell what broke, it says so plainly instead of inventing a plausible-sounding explanation
- Light/dark/auto theming — matches the host page via
prefers-color-scheme, or set it explicitly - Style-isolated — renders inside a Shadow DOM, so your page's CSS can never leak into (or break) the widget
- Under 10KB gzipped — the widget ships inside your app during an incident; it can't be part of the problem
Props
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| apiKey | string | Yes | - | Your Cluebase API key |
| apiEndpoint | string | No | Cluebase's hosted backend | Override for self-hosted/proxied setups |
| environment | 'development' | 'production' | No | 'production' | Current environment |
| colorMode | 'light' | 'dark' | 'auto' | No | 'auto' | Widget color mode. 'auto' follows the host page's prefers-color-scheme once at mount |
| userId | string | No | - | Optional user identifier attached to reports |
| sessionId | string | No | generated + persisted in sessionStorage | Optional session identifier |
| onError | (report) => void | No | - | Called with the full report whenever an error is captured |
| logo | ReactNode | No | - | Custom logo shown in the fallback boundary UI |
| sanitize | (text: string) => string | No | - | Extra redaction rules applied on top of the built-in PII scrubber |
Manual Error Reporting
Report caught errors that don't crash the app:
import { useCluebaseReport } from 'cluebase-next';
function MyComponent() {
const { reportError } = useCluebaseReport();
const handleClick = async () => {
try {
await fetch('/api/action');
} catch (error) {
reportError(error, { action: 'button_click' });
}
};
return <button onClick={handleClick}>Action</button>;
}You can also tag the error with an errorType so the AI explanation and dashboard
reflect what actually happened, instead of a generic message:
reportError(error, { action: 'checkout' }, 'payment_integration');Available types: 'api_error' | 'network_timeout' | 'payment_integration' | 'render_crash' | 'component_crash' | 'unhandled_rejection' | 'global_error' | 'generic'.
Identify a Known User
If you already know who the user is (e.g. right after login), attach their identity so any incident created afterward already has an email and name — the agent won't need to ask for contact info it already has:
import { useCluebaseIdentify } from 'cluebase-next';
function Dashboard({ user }) {
const { identify } = useCluebaseIdentify();
useEffect(() => {
identify({ email: user.email, name: user.name });
}, [user]);
// ...
}Automatic Fetch Classification
useCluebaseFetch is a drop-in fetch wrapper that automatically detects and reports
API failures with the real HTTP status code and request host — so a failed Stripe
call gets a payment-specific explanation, and a 500 gets framed as "on our end,"
without you writing any classification logic yourself:
import { useCluebaseFetch } from 'cluebase-next';
function Checkout() {
const { cluebaseFetch } = useCluebaseFetch();
const handlePay = async () => {
const res = await cluebaseFetch('https://api.stripe.com/v1/charges', { method: 'POST' });
// non-ok responses and thrown errors are reported automatically;
// the response/error is still returned/thrown as normal.
};
return <button onClick={handlePay}>Pay</button>;
}Isolated Component Recovery
By default, a crash anywhere in your app is caught by the root CluebaseProvider
boundary and the whole page shows the fallback overlay. Wrap a specific risky
section in <CluebaseBoundary> to isolate a crash to just that section instead —
the rest of the page keeps working, and "Try Again" remounts just that piece with
fresh state:
import { CluebaseBoundary } from 'cluebase-next';
<CluebaseBoundary label="checkout-form">
<CheckoutForm />
</CluebaseBoundary>If you don't wrap anything, nothing changes — the app-wide boundary still catches everything as before.
PII Redaction
Before anything leaves the browser, Cluebase automatically redacts common PII —
emails, SSNs, phone numbers, and credit-card-shaped digit runs — from error
messages, stack traces, URLs, the feedback box, and any additionalContext you
pass to reportError(). No configuration required.
To add your own rules on top, pass sanitize to CluebaseProvider:
<CluebaseProvider
apiKey={process.env.NEXT_PUBLIC_CLUEBASE_API_KEY ?? ''}
sanitize={(text) => text.replace(/acct_[a-zA-Z0-9]+/g, '[redacted-account]')}
>
<Component {...pageProps} />
</CluebaseProvider>The built-in redaction is a safety net, not a substitute for care — avoid putting PII directly in error messages in the first place.
Documentation
Visit cluebase.dev/docs for full documentation.
License
MIT
