Skip to content
LastPing
GUIDE · NODE.JS · FREE

Monitor Node.js scripts: one fetch call, zero dependencies

Node 18+ ships fetch built in, so the whole integration is: ping on success, POST the error to /fail on failure. Absence detection covers what your catch can't: the OOM kill, the crashed process, the cron entry that vanished. Free, no monitor cap.

Your assistant can do this for you

Monitor my Node.js scripts with LastPing

On this page
  1. The snippets
  2. What this catches
  3. Questions people ask

The snippets

Create a monitor in the console (its schedule = how often the job should run, plus a grace window), copy the ping URL, and wrap your entry point.

ESM (top-level await)

// job.mjs — Node 18+ (built-in fetch, no dependencies)
const PING = "https://ping.lastping.dev/<your-monitor-id>";

async function main() {
  // your job
}

try {
  await main();
  await fetch(PING);
} catch (err) {
  // report the failure; the body is stored with the ping (10,000 bytes max)
  await fetch(`${PING}/fail`, {
    method: "POST",
    body: String(err && err.stack ? err.stack : err).slice(0, 10000),
  });
  process.exitCode = 1;
}

CommonJS

// job.js — CommonJS variant
const PING = "https://ping.lastping.dev/<your-monitor-id>";

async function main() {
  // your job
}

main()
  .then(() => fetch(PING))
  .catch((err) =>
    fetch(`${PING}/fail`, {
      method: "POST",
      body: String(err).slice(0, 10000),
    }).finally(() => {
      process.exitCode = 1;
    })
  );

Optional: overrun detection and run duration

A /start ping arms the hung-job alarm (no success inside the grace window → incident), and a shared rid pairs start with finish so each run's duration is recorded:

const PING = "https://ping.lastping.dev/<your-monitor-id>";
const rid = Date.now().toString();

await fetch(`${PING}/start?rid=${rid}`);
try {
  await main();
  await fetch(`${PING}?rid=${rid}`);
} catch (err) {
  await fetch(`${PING}/fail`, {
    method: "POST",
    body: String(err).slice(0, 10000),
  });
  process.exitCode = 1;
}

Why process.exitCode = 1 matters

The non-zero exit keeps the failure visible to whatever runs the script (cron, systemd, a Kubernetes CronJob) so their retry semantics still apply. Using process.exitCode instead of process.exit() lets the fail ping finish sending first.

What this catches

The catch reports what it can; the silence reports the rest.

  • A thrown error: the /fail ping opens an incident immediately, with the stack trace stored on the ping.
  • A crash your code never sees: OOM kill, unhandled hard crash, kill -9. No success ping arrives; the grace window raises the alert.
  • The job never ran: missing cron entry, broken deploy, dead host. Absence → incident. This also covers in-process schedulers like node-cron: if the whole process dies, the scheduler dies with it, and only an external monitor notices.
  • A hung run: with the /start ping armed, a job stuck on a dead connection opens an incident inside the grace window.
  • Recovery: the next successful run closes the incident and sends a recovery notice automatically.

Questions people ask

Front-loaded answers: the most important fact first.

  • How do I monitor a Node.js cron job?

    Wrap the entry point: on success, fetch the monitor URL https://ping.lastping.dev/<your-monitor-id>; on error, POST the error text to the /fail endpoint and set process.exitCode = 1. If the script fails, hangs, or never starts, LastPing alerts you by email, Slack, Discord, Telegram, ntfy, Pushover, Microsoft Teams, Google Chat or webhook.

  • Do I need an npm package to do this?

    No. Node 18 and later ship fetch built in, so the integration is zero-dependency. Any HTTP client works: the ping accepts GET, HEAD, or POST.

  • What if the process crashes before it can ping?

    A crashed or OOM-killed process sends no ping, and that missing ping is itself the alert. LastPing expects a signal on your schedule plus a grace window; silence opens an incident, so the failure path requires no working code.

  • Does this work with node-cron or BullMQ-style schedulers?

    Yes. Wrap the scheduled task body in the same try/catch pattern. The external monitor also covers the failure the in-process scheduler can't see: the whole Node process dying and taking the scheduler with it.

  • Is Node.js job monitoring free?

    Yes. LastPing is free for individuals with no monitor cap. See how it compares to Healthchecks.io and Cronitor.

FREE FOR INDIVIDUALS · FULLY HOSTED

A dead process can't reject a promise.

One fetch call now beats debugging an empty table later. First alert wired up in about a minute, and LastPing monitors itself the same way.