---
title: "JavaScript and Node.js Monitoring SDK"
description: "The Silly Development monitoring SDK for Node.js and Bun: init() options, counters, gauges, timings, events, capturing errors, heartbeats and flushing."
url: "https://sillydev.co.uk/docs/monitoring/javascript"
updated: "2026-10-14"
---

Monitoring

# JavaScript SDK

Part of the \`sillydev\` package on npm, at \`sillydev/monitoring\`. The main entry does not load it. Works with ES modules and CommonJS, in Node.js and Bun.

[← Monitoring docs](https://sillydev.co.uk/docs/monitoring) · Updated 14 October 2026

**Browse the docs**

## init()

Call it once, as early as you can. Every option is optional. Without a key (as an option or in `SILLYDEV_MONITORING_KEY`) it does nothing and returns `false`.

`runtimeMetrics` sends CPU, memory, heap, event loop lag, garbage collection and handles, and the heartbeat. `captureUnhandled` records uncaught exceptions and unhandled rejections without changing what Node does with them. `sampleRate` is the share of errors and events sent. `beforeSend(type, item)` returns the item, changed or not, or `null` to drop it. `debug` logs every payload.

JavaScript

```
import { monitoring } from 'sillydev/monitoring';

monitoring.init({
    key: process.env.SILLYDEV_MONITORING_KEY, // the default
    service: 'orders-bot',
    environment: 'production',
    release: '1.4.2',
    runtimeMetrics: true,
    captureUnhandled: true,
    sampleRate: 1,
    beforeSend: (type, item) => (type === 'event' && item.name === 'debug' ? null : item),
    debug: false,
});
```

## Metrics

`increment(name, value = 1, tags)` adds to a counter, `gauge(name, value, tags)` records the latest value, and `timing(name, ms, tags)` records a duration in milliseconds. `time(name, fn, tags)` runs a function, times it (waiting for a promise it returns) and gives back its result.

Names are lowercase letters, digits, dots and underscores, starting with a letter. Tags are up to 8 string pairs, and each name and set of tags is one series, so tag by things with few values.

JavaScript

```
monitoring.increment('orders.created', 1, { plan: 'free' });
monitoring.gauge('queue.length', queue.length);
monitoring.timing('payment.duration', 182.5, { provider: 'stripe' });

const report = await monitoring.time('reports.build', () => buildReport());
```

## Errors and events

`captureException(error, { tags, context })` reports an error and `captureMessage(message, { level })` reports something that is not one. Context is shown on the issue page; values whose names look like passwords, tokens or cookies are replaced with `[redacted]`.

`event(name, attributes)` records something that happened. A `deploy` event is marked on the Overview charts.

JavaScript

```
try {
    await charge(order);
} catch (error) {
    monitoring.captureException(error, { tags: { provider: 'stripe' }, context: { order: order.id } });
}

monitoring.event('deploy', { version: '1.4.2' });
```

## Heartbeats, flushing and shutting down

With runtime metrics on, every send is a heartbeat; with them off, call `heartbeat()` yourself. The SDK sends every ten seconds on a timer that does not keep the process alive, and tries once more when the process exits.

`await flush()` sends everything now and `await shutdown()` flushes and stops. Call one before `process.exit()`, or at the end of a short script or serverless function.

Read next

- [Integrations One line each for the common Python and JavaScript frameworks and Discord libraries.](https://sillydev.co.uk/docs/monitoring/integrations)
- [Browser SDK Errors, page views and web vitals from your website.](https://sillydev.co.uk/docs/monitoring/browser)
- [Python SDK Every function in \`sillydev.monitoring\`, for Python 3.9 and newer.](https://sillydev.co.uk/docs/monitoring/python)
