Node.js SDK
The Pionne SDK for Node.js. Auto-captures uncaughtException and unhandledRejection, enriches every event with runtime context (Node version, OS, hostname, PID, memory).
Current version: 0.3.6
Install
Section titled “Install”npm install @pionne/nodeQuickstart
Section titled “Quickstart”import { Pionne } from '@pionne/node';
Pionne.init({ token: 'pio_live_…', release: '1.0.0', environment: 'production',});const { Pionne } = require('@pionne/node');
Pionne.init({ token: 'pio_live_…', release: '1.0.0', environment: 'production',});Auto-capture
Section titled “Auto-capture”process.on('uncaughtException')— uncaught sync exceptionsprocess.on('unhandledRejection')— promises rejected without.catch()
Auto-context
Section titled “Auto-context”process.version— Node versionos.platform(),os.release()— OS and releaseos.hostname()— machine nameprocess.pid— PIDprocess.memoryUsage()— RSS, heap used, heap total
Auto-breadcrumbs
Section titled “Auto-breadcrumbs”console.log/console.warn/console.error- Outbound HTTP requests via
http/https(instrumentation ofrequest)
Pionne.init(options);Pionne.captureException(error, { tags, contexts });Pionne.captureMessage('Cache miss', { level: 'info' });Pionne.setUser({ id: 'user_42' });Pionne.setTags({ region: 'eu-west-1' });Pionne.setEnabled(false);Pionne.addBreadcrumb({ category: 'db', message: 'SELECT * FROM users' });Frameworks
Section titled “Frameworks”import express from 'express';import { Pionne } from '@pionne/node';
Pionne.init({ token: 'pio_live_…' });
const app = express();
// ... your routes ...
// The error middleware MUST be registered lastapp.use(Pionne.expressErrorHandler());
app.listen(3000);import Fastify from 'fastify';import { Pionne } from '@pionne/node';
Pionne.init({ token: 'pio_live_…' });
const fastify = Fastify();
fastify.setErrorHandler((error, request, reply) => { Pionne.captureException(error, { contexts: { request: { url: request.url, method: request.method } }, }); reply.status(500).send({ error: 'Internal Server Error' });});
fastify.listen({ port: 3000 });import { NestFactory } from '@nestjs/core';import { Pionne } from '@pionne/node';import { AppModule } from './app.module';import { PionneExceptionFilter } from './pionne.filter';
Pionne.init({ token: 'pio_live_…' });
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new PionneExceptionFilter()); await app.listen(3000);}bootstrap();import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';import { Pionne } from '@pionne/node';
@Catch()export class PionneExceptionFilter implements ExceptionFilter { catch(exception: unknown, host: ArgumentsHost) { Pionne.captureException(exception as Error); throw exception; // re-throw so Nest handles the response }}import { Pionne } from '@pionne/node';
Pionne.init({ token: 'pio_live_…' });
async function main() { try { await doSomething(); } catch (err) { Pionne.captureException(err as Error); }}
main();Background jobs
Section titled “Background jobs”For BullMQ, Bee-Queue, Agenda, Worker Threads or any job runner, wrap each handler in try/catch:
worker.on('failed', (job, err) => { Pionne.captureException(err, { tags: { job: job.name }, contexts: { job: { id: job.id, data: job.data } }, });});Geography (opt-in)
Section titled “Geography (opt-in)”On a Node backend, the IP used for the lookup is the server’s, not the end client’s. Useful to spot a crash localised to one cloud region (e.g. eu-west-3 vs us-east-1) without touching infra logs.
Pionne.init({ token: 'pio_live_…', sendGeography: true, // ← opt-in});At boot, a single HTTP call to https://ipapi.co/json/ (4 s timeout) attaches contexts.geo = { city, region, country, country_code } to every subsequent event. If the lookup fails (egress firewall, rate-limit), the SDK silently keeps shipping events without geo.
Running an auto-scaled cluster? Set the pod region directly in tags (tags: { region: process.env.AWS_REGION }) — more reliable than an IP lookup from inside the SDK.
Performance monitoring
Section titled “Performance monitoring”Anti-token-theft
Section titled “Anti-token-theft”Bundle ID pinning is mobile only (iOS/Android/RN/Flutter) — it protects against APK/IPA decompilation. On Node, your token lives server-side (.env, secrets manager, EAS env vars…) and is never shipped to a client: the threat doesn’t exist.
The “Bundle ID” field is hidden in the mobile dashboard for Node projects — filling it manually would 403 every event (the SDK does not send app_id). To differentiate deployments, use tags:
Pionne.init({ token: process.env.PIONNE_TOKEN, tags: { deployment: process.env.APP_DEPLOYMENT ?? 'prod', region: process.env.AWS_REGION },});More details: Bundle ID Pinning → Backends without bundle_id.
See also
Section titled “See also”- Web SDK — browser frontend
- Ingest API — raw HTTP protocol
- Source maps — symbolication