Skip to content
LINEARJEPH
Sign inCreate account
Products
  • GPU Cloud
  • Maintenance
  • Cloud Servers
  • One-click Apps
  • AI Models
  • Developer Tools
Solutions
  • For Developers
  • For Startups
  • For AI Teams
  • For Agencies
  • For Enterprises
Resources
  • Open-Source Library
  • Technology Trends
  • Pricing
  • Help Center
  • FAQ
Company
  • Legal & Privacy
  • Support
Sign inCreate account
Maintenance
OverviewPythonNode.jsGoIngest HTTP API

Node.js SDK

Package @linearjeph/sdk 1.0.0, MIT licensed, Node 18+ (uses the global fetch), no dependencies. Ships CommonJS, ES modules and TypeScript types.

Install

npm install https://linearjeph.cc/sdk/linearjeph-sdk-1.0.0.tgz

Quickstart

const linearjeph = require("@linearjeph/sdk");        // or: import * as linearjeph from "@linearjeph/sdk";

linearjeph.init({ key: process.env.LINEARJEPH_KEY, release: "1.4.2", environment: "production" });

try { risky(); } catch (err) { linearjeph.captureException(err); }

Get the key from Dashboard > Maintenance > your application > Reveal key. init never throws; it returns true when the SDK is enabled. You can also pass the key alone: init("lj_app_...").

By default init installs process handlers (handlers: true): an uncaught exception or unhandled promise rejection is captured, flushed for up to 2 seconds, printed to stderr and the process exits with code 1, as Node would do on its own. If your app already has its own uncaughtException listener, the SDK only observes (through uncaughtExceptionMonitor) and does not change your behaviour. The SDK does not add an unhandledRejection listener, so Node's default crash-on-rejection stays in force (run with --unhandled-rejections=warn and rejections will not be captured automatically). A beforeExit hook flushes the queue.

init(options)

OptionTypeDefaultMeaning
keystringrequiredApplication ingest key.
releasestringnoneVersion or build identifier (max 100 chars). Drives release tracking.
environmentstring"production"Max 40 chars.
endpointstringhttps://linearjeph.ccBase URL; change only for a private deployment.
sampleRatenumber1Fraction of errors and messages sent, 0 to 1.
tracesSampleRatenumber1Fraction of transactions sent.
beforeSend(event) => event | nullnoneChange the event or return null to drop it. If it throws, the event is dropped.
scrubKeysstring[][]Extra tag-key substrings to filter, case-insensitive.
maxQueuenumber100Items waiting to be sent; when full new items are dropped.
batchSizenumber20Events per request, 1 to 100.
retriesnumber4Retries after the first attempt for 429, 5xx and network errors.
backoffMsnumber500Base delay; doubles each attempt with jitter. Retry-After on 429 is used instead (max 60 s).
timeoutMsnumber10000Per-request timeout.
handlersbooleantrueInstall uncaught-exception capture and the beforeExit flush.
exitOnUncaughtbooleantrueWith handlers: after capture, flush and process.exit(1).
flushTimeoutMsnumber5000Longest wait for the flush in beforeExit.
debugbooleanfalseLog SDK problems to stderr.

Functions

FunctionDescription
captureException(err, { tags }?)Report an error (or any thrown value).
captureMessage(msg, level = "info", { tags }?)Report a message as an event of type Message.
captureTransaction(name, durationMs, status = "ok", { tags }?)Report one timed operation.
startTransaction(name)Returns { end(status = "ok") }; only the first end counts.
withTransaction(name, fn)Times a sync or async function; status error if it throws (the error is rethrown, not captured). Returns the result.
heartbeat(name, status = "ok", intervalS?)Check in. intervalS is 30 to 2,592,000. name must match [A-Za-z0-9._-]{1,64}, otherwise ignored.
monitor(name, fn, { intervalS?, capture?, flush? }?)Run fn, send ok on success or error if it throws (then rethrow). capture: true also reports the error; flush: true waits for delivery.
reportPackages(lockPath = ./package-lock.json)Send the packages in package-lock.json (npm lockfile v1, v2 and v3) to the dependency audit. Returns the number queued, 0 if the file cannot be read.
packagesFromLock(lockObject)Parse a lockfile object into { name, version }[].
setTag(key, value)Tag every later event (max 20 tags per event).
setUser(id)Attach a user id; null clears it.
scrub(data)Deep copy with sensitive values replaced by [Filtered].
flush(timeoutMs = 5000)Promise resolving true when the queue is empty.
requestHandler({ ignorePaths? })Express middleware that times requests (also exported as timing).
errorHandler()Express error middleware (also exported as expressErrorHandler).

Express

const express = require("express");
const linearjeph = require("@linearjeph/sdk");

linearjeph.init({ key: process.env.LINEARJEPH_KEY, release: process.env.RELEASE });

const app = express();
app.use(linearjeph.requestHandler({ ignorePaths: ["/health"] }));   // first
app.get("/items/:id", (req, res) => res.json({ id: req.params.id }));
app.use(linearjeph.errorHandler());                                   // after all routes
app.listen(3000);

Transactions are named from the matched route (GET /items/:id), so ids do not create new names. errorHandler captures the error and passes it on with next(err), so your own error middleware still runs.

For Fastify, Koa and others, call startTransaction / captureException from your own hooks.

ESM and TypeScript

import { init, captureException, monitor, type InitOptions } from "@linearjeph/sdk";

const options: InitOptions = { key: process.env.LINEARJEPH_KEY!, release: "1.4.2" };
init(options);

Types ship in index.d.ts; both import and require resolve through the package exports map.

Cron jobs and heartbeats

const linearjeph = require("@linearjeph/sdk");
linearjeph.init({ key: process.env.LINEARJEPH_KEY });

linearjeph.monitor("nightly-report", buildReport, { intervalS: 86400, capture: true, flush: true })
  .catch(() => process.exitCode = 1);

The first check-in creates the monitor. A failed run, or no check-in within the interval plus 5 minutes, opens an incident and sends alerts. For a scheduler inside a long-running process call linearjeph.heartbeat("worker", "ok", 60) on each tick.

Dependency audit

linearjeph.reportPackages();          // reads ./package-lock.json; call on startup or in CI, not per request

Run it from your build or deploy step with the same init call, then await linearjeph.flush().

Release tracking in CI

env:
  RELEASE: ${{ github.ref_name }}+${{ github.run_number }}
linearjeph.init({ key: process.env.LINEARJEPH_KEY, release: process.env.RELEASE });

Sampling

linearjeph.init({ key, sampleRate: 0.5, tracesSampleRate: 0.1 });

Sampled-out events never leave the process; sampling is applied before beforeSend.

Scrubbing and beforeSend

Tag values under keys containing password, secret, token, authorization, auth, cookie, api_key, session, csrf, bearer, credential or private_key (plus your scrubKeys) are replaced by [Filtered]. Text like password=hunter2 and Bearer eyJ... in error and message text is masked. The SDK never reads request headers, bodies or cookies.

linearjeph.init({
  key,
  scrubKeys: ["ssn"],
  beforeSend(event) {
    if (event.type === "error" && event.exception.type === "AbortError") return null;
    event.tags.tenant = currentTenant();
    return event;
  },
});

Shutdown

Short scripts and containers that exit through process.exit() skip beforeExit; call await linearjeph.flush() first. On SIGTERM handlers: process.on("SIGTERM", async () => { await linearjeph.flush(); process.exit(0); }).

Troubleshooting

  • Use debug: true to see why events are dropped.
  • A 401 prints "ingest key rejected" once and stops sending.
  • init returns false without a key.
  • With --unhandled-rejections=warn or none, unhandled rejections are not captured automatically; call captureException in a process.on("unhandledRejection", ...) handler of your own.
  • See Troubleshooting and the Ingest HTTP API.
LINEARJEPH LTD

Your infrastructure. Your tools. Your freedom to build.

    Products

    • GPU Cloud
    • Maintenance
    • Cloud Servers
    • One-click Apps
    • AI Models
    • Developer Tools

    Solutions

    • For Developers
    • For Startups
    • For AI Teams
    • For Agencies
    • For Enterprises

    Resources

    • Open-Source Library
    • Technology Trends
    • Pricing
    • Help Center
    • FAQ

    Company

    • Legal & Privacy
    • Support
    • OpenSRS
    • remotion
    • Cloudflare
    • Wix
    © 2026 LINEARJEPH LTD. All rights reserved.
    Acceptable Use PolicyAccount Verification & Anti-FraudAge RequirementsBilling & Subscription TermsCookie PolicyCopyright & Abuse NoticesData ProtectionMaintenance Service TermsPrivacy PolicyRefund PolicySecurity & DisclosureTerms of Service
    Prices in USD. Taxes may apply.