How do I know if my automation didn't run?
You can't find out from the automation itself: a run that never starts can't send an error. Do it the other way round. Each run checks in, an outside monitor knows when to expect it, and silence becomes the alert.
Short answer
Have each run check in when it finishes, tell an outside monitor when to expect that check-in, and get alerted when it doesn't arrive (or arrives with nothing in it). This is called a heartbeat, or a dead man's switch. Did It Run? watches your scheduled agents and automations this way and alerts you when a run is missed, late, failed, or comes back empty.
Why you didn't get an alert
Most platforms alert on *errors*: a run started, a step threw, you get an email. The failures that hurt are the ones where nothing starts, so there's nothing to report:
- The trigger stopped firing. An expired OAuth token, a stale webhook, an IMAP trigger that dropped its connection. Often no execution is created, so the platform's error alert never fires.
- The workflow, Zap or scenario was switched off. A teammate paused it, the platform disabled it after repeated errors, or you ran out of credits or operations. No alert.
- The machine wasn't there. A laptop asleep at 2am, a VPS that rebooted, a container that was OOM-killed. The thing that would alert is down too.
- The schedule is wrong.
5 * * * *(hourly at :05) instead of*/5 * * * *, a server clock in UTC, a daylight-saving jump that skipped 2:30am. It's doing exactly what you told it. - It ran and produced nothing. A search returned 0 rows, an agent replied with a refusal, an empty
catch {}swallowed the error. It reports success.
The fix: watch the outcome, not the error
- Write down the expectation. "Every weekday by 9:15am New York time", "every 5 minutes", or "at least once a day" for event-driven workflows. Add a grace window for normal delays (GitHub Actions schedules are often late; 30–60 minutes is sensible there).
- Check in at the end of every successful run. One HTTP request to a unique ping URL as the last step. Optionally ping
/startat the beginning and/failfrom your error path, so failures alert immediately instead of at the deadline. - Send a little of the output. An item count (
?items=12) or the result text. Then "ran but returned nothing" becomes an alert instead of a green checkmark. - Keep the monitor outside the thing it watches. A "did it run?" check inside the same n8n instance or the same server dies with it.
- Get one alert, then a recovery notice. Not an alert every minute.
Copy-paste check-ins
cron or any script:
15 9 * * 1-5 /opt/jobs/digest.sh && curl -fsS -m 10 --retry 3 https://diditrun.app/p/<your-token> > /dev/nullReport an item count (catches empty runs):
count=$(wc -l < /var/data/today.csv)
curl -fsS -m 10 --retry 3 "https://diditrun.app/p/<your-token>?items=$count"- n8n: add an HTTP Request node at the end of the workflow (POST to the ping URL). n8n's Error Trigger only fires when an execution fails; it can't see a trigger that stopped creating executions. See the n8n recipe.
- Zapier: add Webhooks by Zapier → POST as the last step. Webhooks needs a paid Zapier plan (Zapier's Free plan doesn't include it). See the Zapier recipe.
- Make: finish with HTTP → Make a request and add an error-handler route that calls
/fail. See the Make recipe. - GitHub Actions:
curlthe ping URL in a final step withif: success(), and/failwithif: failure(). Store the URL as a secret and create the watch in UTC. See the GitHub Actions recipe. - ChatGPT and Claude scheduled tasks: where the agent can run a shell command, have it hit the ping URL as its last action. ChatGPT tasks can't make the request themselves, so relay their notification email to the ping URL with an automation tool. See the ChatGPT and Claude Code recipes. Email check-ins are coming soon; they aren't live yet.
Event-driven workflows: "quiet day" vs "dead trigger"
A webhook-triggered workflow can legitimately do nothing on a slow day. Two options:
- Use the longest normal gap as the schedule ("at least once every 24 hours"). You'll hear about a dead trigger within a day.
- For critical flows, send a synthetic test event on a schedule (a test form submission, a test record with a marker) and check that the workflow processed it.
Doing it with Did It Run?
- Create a free account and add a watch: pick the schedule in plain English or as a cron expression, a timezone, and a grace window.
- Paste the ping URL into the last step of your job (recipes for n8n, Zapier, Make, GitHub Actions and cron).
- Optionally set a minimum item count, minimum size, or required keyword so empty runs raise an empty alert.
- Get alerts by email (Free) or Slack, Discord and Telegram (Solo and Pro), plus a daily roll-call of what ran, what's missing and what came back empty (Solo and Pro).
Prefer a developer-first tool or self-hosting? Healthchecks.io, Cronitor, Dead Man's Snitch and UptimeRobot's heartbeat monitors all do the core check-in pattern well; see our heartbeat monitor comparison.
FAQ
Can't I just check the run history every morning?
You can, and it works until you have more than a handful of jobs or you're on holiday. The point of a heartbeat is that silence becomes the alert, so you only look when something's wrong.
What's the difference between late and missed?
Late means the expected time passed and you're still inside the grace window. Missed means the grace window ended with no check-in.
Will this catch a job that runs but does the wrong thing?
It catches the common version, empty or too-small output, if you send an item count or the output and set a minimum. It can't judge whether non-empty output is correct; for that, add a required keyword or your own validation step that calls /fail.
Does Did It Run? run or connect to my automations?
No. It never runs your code or logs into your accounts; it only receives check-ins.
Know the next time it doesn't run
Know when your AI agents and automations didn't run. Free for 3 watches.
Start free