JavaScript / TypeScript
The tinymon package works in browsers, Node, Deno, Bun, and Cloudflare Workers. It has zero runtime dependencies and ships as both ESM and CJS with TypeScript types.
Install
$ npm install tinymonjs # or: $ pnpm add tinymonjs $ yarn add tinymonjs $ bun add tinymonjs
init()
Call init() once, as early as possible in your app's startup. It installs global handlers for window.onerror / unhandledrejection in browsers, and process.on('uncaughtException') / 'unhandledRejection' in Node.
import { init } from 'tinymonjs'; init({ dsn: process.env.TINYMON_DSN, environment: 'production', release: '1.0.0', sampleRate: 1.0, });
Options
| Field | Type | Description |
|---|---|---|
| dsn | string | Required. Your project DSN, e.g. tm_pub_…. |
| endpoint | string | Override the ingest URL. Defaults to https://console.tinymon.dev/api/ingest. |
| environment | string | Free-form tag — typically production, staging, development. |
| release | string | A version string for your app — git SHA, semver, anything. Used to scope source maps. |
| sampleRate | number | 0 to 1. Fraction of events to send. Default 1 (send all). |
| beforeSend | (e) => e | null | Mutate or drop events before they go out. Return null to drop. |
Capturing errors
Most errors are caught automatically. For errors you handle but still want to report, use captureException:
import { captureException, captureMessage } from 'tinymonjs'; try { riskyThing(); } catch (err) { captureException(err); } // Or a plain message, no exception object: captureMessage('cron job took 28 seconds', 'warning');
captureMessage takes a level: 'error', 'warning', or 'info'.
User & tag context
Attach a user identifier and arbitrary tags to subsequent events. Useful for filtering in the dashboard.
import { setUser, setTag } from 'tinymonjs'; setUser({ id: user.id }); setTag('plan', user.plan); setTag('feature_flag.new_checkout', 'on');
setUser takes { id } by design — no email, no name, no IP.
Breadcrumbs
Breadcrumbs are short notes about what happened before an error. The SDK keeps the last 30; when an error fires, they're attached to the event.
import { addBreadcrumb } from 'tinymonjs'; addBreadcrumb({ timestamp: Date.now() / 1000, category: 'http', message: 'POST /api/orders → 500', level: 'error', });
Filtering with beforeSend
Drop noisy errors, redact fields, or sample by error type:
init({ dsn: process.env.TINYMON_DSN, beforeSend: (event) => { // Drop ResizeObserver loop spam from old browsers. if (event.exception.value.includes('ResizeObserver')) return null; // Redact email-looking strings from the breadcrumbs. return event; }, });
Frameworks
React
Call init() in index.tsx before ReactDOM.createRoot. Wrap routes in an error boundary that calls captureException:
class ErrorBoundary extends React.Component { componentDidCatch(err) { captureException(err); } render() { return this.props.children; } }
Next.js
Call init() in instrumentation.ts for server-side, and in a top-level client component for the browser. Use the NEXT_PUBLIC_TINYMON_DSN env var for the client side.
Express
import { captureException } from 'tinymonjs'; app.use((err, req, res, next) => { captureException(err); res.status(500).send('Internal Server Error'); });
Cloudflare Workers
Workers don't have a global process. Pass the DSN as a binding and call captureException manually in your handler's catch block. Add ctx.waitUntil(...) so the event flushes before the request ends.
Source maps
For minified browser bundles, upload source maps so stack traces are readable. Set a unique release on each build, then upload your .js.map files via the dashboard or the upcoming CLI. The server will resolve frames automatically at view time.
X-Content-Source-Map from a non-public URL, or strip the //# sourceMappingURL= comment from the production bundle.