# Trapify > Error tracking for developers. Capture unhandled exceptions, promise rejections, and manual events from browser and Node.js applications. View issues, stack traces, breadcrumbs, and user context in the Trapify dashboard at https://trapify.tech. ## SDK Install: `npm install @trapify-tech/browser` Two entry points: - `@trapify-tech/browser` — browser SDK (uses fetch, patches window.onerror) - `@trapify-tech/browser/node` — Node.js SDK (uses https module, no fetch dependency) DSN: a 32-character hex string from your Trapify project settings page. Store it in an environment variable — never hardcode it. ## Browser SDK ```ts import { init, captureException, captureMessage, setUser, setTag, addBreadcrumb, close } from '@trapify-tech/browser'; // Call once at application startup init({ dsn: 'your-32-char-hex-dsn', environment: 'production', // optional release: '1.0.0', // optional autoCapture: true, // hooks window.onerror + unhandledrejection (default: true) captureConsole: true, // console.error/warn/log as breadcrumbs (default: true) captureFetch: true, // fetch requests as breadcrumbs (default: true) debug: false, // log SDK errors to console (default: false) beforeSend: (event) => { // optional — return null to drop if (event.environment === 'development') return null; return event; }, }); // Manual capture captureException(new Error('Something went wrong')); captureMessage('User completed checkout', 'info'); // User context (attached to all subsequent events) setUser({ id: 'u_123', email: 'alice@example.com', username: 'alice' }); setUser(null); // clear on logout // Tags setTag('plan', 'pro'); setTag('region', 'eu-west'); // Manual breadcrumb addBreadcrumb({ timestamp: new Date().toISOString(), type: 'ui', category: 'click', message: 'Checkout button clicked', }); // Teardown (tests / SSR) close(); ``` ### Config options | Option | Type | Default | Description | |--------|------|---------|-------------| | dsn | string | required | 32-char hex key from project settings | | environment | string | null | Attached to every event | | release | string | null | App version string | | maxBreadcrumbs | number | 50 | Max breadcrumbs kept in memory | | autoCapture | boolean | true | Hook window.onerror + unhandledrejection | | captureConsole | boolean | true | Capture console calls as breadcrumbs | | captureFetch | boolean | true | Capture fetch requests as breadcrumbs | | debug | boolean | false | Log SDK errors to console | | beforeSend | function | — | Hook before send; return null to drop | | endpoint | string | Trapify production | Override ingest URL (testing) | ### Framework examples **React / Vite — src/main.tsx** ```ts import { init } from '@trapify-tech/browser'; init({ dsn: import.meta.env.VITE_TRAPIFY_DSN, environment: import.meta.env.PROD ? 'production' : 'development', release: import.meta.env.VITE_APP_VERSION, }); ``` **Next.js App Router — instrumentation.ts** ```ts export async function register() { if (typeof window !== 'undefined') { const { init } = await import('@trapify-tech/browser'); init({ dsn: process.env.NEXT_PUBLIC_TRAPIFY_DSN! }); } } ``` **Direct client (multiple DSNs)** ```ts import { TrapifyClient } from '@trapify-tech/browser'; const client = new TrapifyClient({ dsn: 'your-dsn', autoCapture: false }); client.captureException(new Error('isolated error')); client.close(); ``` ## Node.js SDK ```ts import { init, captureException, captureMessage, setUser, setTag, flush, close, withTrapify, errorHandler } from '@trapify-tech/browser/node'; init({ dsn: process.env.TRAPIFY_DSN!, environment: 'production', autoCapture: true, // hooks process.uncaughtException + unhandledRejection captureConsole: false, // default false — high noise in server logs }); ``` ### withTrapify — Firebase Cloud Functions / any async handler Wraps an async function. Captures unexpected errors and re-throws them. Intentional `HttpsError` throws (unauthenticated, not-found, etc.) are passed through without capture. ```ts import { onCall, HttpsError } from 'firebase-functions/v2/https'; import { defineSecret } from 'firebase-functions/params'; import { init, withTrapify } from '@trapify-tech/browser/node'; const TRAPIFY_DSN = defineSecret('TRAPIFY_DSN'); export const myFunction = onCall( { secrets: [TRAPIFY_DSN] }, withTrapify(async (request) => { // init inside handler — secrets only available at invocation time init({ dsn: TRAPIFY_DSN.value(), environment: 'production', autoCapture: false }); if (!request.auth) throw new HttpsError('unauthenticated', 'Sign in required'); // ... business logic }), ); ``` ### Express error middleware ```ts import express from 'express'; import { init, errorHandler } from '@trapify-tech/browser/node'; init({ dsn: process.env.TRAPIFY_DSN!, environment: 'production' }); const app = express(); app.use('/api', router); app.use(errorHandler()); // must be last ``` ### Flush before process exit (serverless) ```ts import { captureException, flush } from '@trapify-tech/browser/node'; try { await riskyOperation(); } catch (err) { captureException(err as Error); await flush(2000); // wait up to 2s — withTrapify does this automatically throw err; } ``` ## Ingest API (raw HTTP) If you can't use the SDK, post events directly. **Endpoint:** `POST https://us-central1-trapify-tech.cloudfunctions.net/onIngest` **Auth:** `Authorization: DSN ` **Content-Type:** `application/json` **Payload:** ```json { "timestamp": "2024-01-01T00:00:00.000Z", "level": "error", "platform": "browser", "message": "Something went wrong", "environment": "production", "release": "1.0.0", "exception": { "type": "TypeError", "value": "Cannot read properties of undefined", "frames": [ { "filename": "src/app.ts", "function": "handleClick", "lineno": 42, "colno": 12, "inApp": true } ] }, "breadcrumbs": [ { "timestamp": "2024-01-01T00:00:00.000Z", "type": "ui", "category": "click", "message": "Button clicked", "level": "info" } ], "user": { "id": "u_123", "email": "alice@example.com" }, "tags": { "plan": "pro" }, "request": { "url": "https://example.com/checkout", "method": "POST" } } ``` **Required fields:** `timestamp`, `level`, `platform` **level values:** `fatal` | `error` | `warning` | `info` | `debug` **platform values:** `browser` | `node` | `javascript` | `other` **Response (200):** ```json { "id": "", "issueId": "" } ``` **Error responses:** - `400` — invalid payload - `401` — missing or invalid DSN key - `405` — method not allowed (use POST) - `500` — internal error ## Optional: links - Dashboard: https://trapify.tech - npm: https://www.npmjs.com/package/@trapify-tech/browser - GitHub: https://github.com/proverbed/trapify - SDK README: https://github.com/proverbed/trapify/blob/main/sdk/README.md