Cronwize
Guide · Vercel

Monitor a Vercel Cron Job

Copy the schedule from vercel.json, set the zone to UTC, then ping from the route handler.

1. Create the monitor from vercel.json

Paste the schedule value and set the zone to UTC, because Vercel always reads cron schedules in UTC.

{
  "crons": [{ "path": "/api/nightly-backup", "schedule": "0 2 * * *" }]
}

2. Set the grace period for your plan

On Pro and Enterprise, Vercel invokes the job within the scheduled minute, so a few minutes of grace plus the job's own runtime is enough.

On Hobby, a job runs once a day at most and can be invoked at any point within the scheduled hour. Set the grace period to more than an hour, or the monitor will alert on normal runs.

3. Ping from the route handler

Add the ping URL as an environment variable named CRONWIZE_PING_URL. Await each ping: a function can stop once it has responded.

import type { NextRequest } from "next/server";

const PING = process.env.CRONWIZE_PING_URL!;

// A failed ping is swallowed, so that it never fails the job.
async function ping(signal: string, body?: string) {
  await fetch(PING + signal, {
    method: "POST",
    body,
    signal: AbortSignal.timeout(10_000),
  }).catch(() => undefined);
}

export async function GET(request: NextRequest) {
  if (request.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response("Unauthorized", { status: 401 });
  }

  await ping("/start");
  try {
    await runBackup();
    await ping("");
    return Response.json({ ok: true });
  } catch (error) {
    await ping("/fail", String(error));
    return Response.json({ ok: false }, { status: 500 });
  }
}

Why this job needs a monitor

Vercel documents cron delivery as best effort. A scheduled run can occasionally fail to reach the function, and no log is created when that happens. Vercel does not retry a failed invocation. A run that does not ping is how you find out.

Vercel can also invoke the same scheduled run more than once, so keep the job itself safe to repeat.

4. Check the first ping

Run the job from the project's Cron Jobs settings, or call the route with the CRON_SECRET header. The monitor turns from new to up.