Let's start with something most monitoring articles won't say about a platform: Render's health checks are good. Genuinely good. If you run a web service on Render, the platform is doing more for you out of the box than most of its competitors. That's exactly why the gap that this article is about catches so many teams off guard. The health checks are good enough that people assume they cover everything. They don't. They cover web services, and nothing else you deploy.
Credit where it's due: Render health-checks web services well
Per Render's health check documentation, you give a web service a health check path and Render probes it continuously, not just at deploy time. During deploys, a new instance only receives traffic after it passes the check, which gives you zero-downtime rollouts. After deploy, Render keeps probing, and a service that fails its health check gets restarted. That's continuous liveness detection plus automatic remediation, built in, for free.
This matters for how you should read the rest of this article. If a vendor tells you Render leaves your web services unwatched, they're selling you fear. It doesn't. What Render leaves unwatched is a different, quieter class of workload, and if you run anything beyond a web service, you almost certainly have some of it.
The uncovered surface: background workers and cron jobs
Render's health checks apply to web services only. Background workers don't get them: there is no HTTP endpoint to probe, so there is nothing for the health check system to attach to. A worker that has deadlocked, lost its queue connection, or is silently crashing on every job it picks up looks, from the dashboard, exactly like a worker having a slow afternoon.
Cron jobs are the sharper edge. Render will notify you about a cron run that happened and failed: the process started, exited non-zero, and Render saw it. What Render will never notify you about is the run that didn't happen at all. A job you accidentally suspended, a schedule that got mangled in a config change, a run skipped because the previous one hung, a job whose process starts and then stalls forever without exiting. None of those produce a failure event, because from the platform's point of view there was no failure. There was just an absence.
The failure mode that hurts
Heartbeats: the did-not-fire alert Render doesn't have
The fix for absence-blindness is a heartbeat monitor (a dead man's switch). Instead of anything probing your job, the job checks in: it pings a unique URL as the last thing it does, and upti.my alerts you when the ping doesn't arrive on schedule. The alert condition is silence, which is exactly the signal Render can't give you.
For a Render cron job, that's one line at the end of your command or script:
#!/usr/bin/env bash
set -euo pipefail
# ... the actual job ...
python sync_invoices.py
# Last line: reached ONLY if everything above succeeded
curl -fsS "https://heartbeats.upti.my/v1/monitors/<your-token>"Because of set -e, the curl only runs if the job succeeded. Configure the heartbeat's expected period to match the cron schedule (every hour, nightly, whatever it is) and set a grace period a bit longer than the job's worst-case honest runtime. Too tight and a slow-but-fine run pages you; too loose and you add dead time to every real incident. If the nightly job usually takes 10 minutes and has never taken more than 25, a 30-minute grace is reasonable.
Now walk the failure modes. Job crashes mid-run: no ping, alert. Job hangs forever: no ping, alert. Job never starts because the schedule was fat-fingered or the service was suspended: no ping, alert. The heartbeat catches the job that never started, which is precisely the did-not-fire alert missing from Render's notification model. For grace-period sizing in more depth, and for validating that the job actually produced correct output rather than merely exiting zero, see how to monitor cron jobs properly.
Workers: processing heartbeats and queue canaries
Workers need a different shape of the same idea, because a worker isn't supposed to finish. Two patterns cover it.
Processing heartbeats. Have the worker ping a heartbeat after each processed batch (or every N jobs). If the worker deadlocks, loses its broker connection, or gets stuck on a poison message, the pings stop and you get paged. This catches the worker that's alive as a process but dead as a worker, which is the state Render's dashboard cannot distinguish from idle.
The queue canary. Processing heartbeats have one blind spot: a genuinely idle queue also produces no pings. The fix is to enqueue a canary job every 5 minutes (from a Render cron job, or from anywhere) whose only work is pinging a heartbeat with a matching expected period. Now the full path is exercised end to end: enqueue, broker, worker pickup, execution. If the canary's ping stops arriving, something in that chain is broken, even if every process involved reports itself healthy. We cover both patterns, including poison-message handling and per-queue canaries, in detecting silent failures in background workers.
One canary per queue, not per worker
External checks anyway: the view Render can't give you
Even for web services, where Render's checks are strong, add an external layer. Render's health checks run inside Render. If Render's edge network, DNS, or a whole region degrades, the in-platform check can be green while your users see timeouts. An external multi-region HTTP check probes your app the way a customer reaches it, from several continents, and catches the class of failure that in-platform checks structurally can't: the platform itself.
While you're at it, assert on the response body, not just the status code. Render's health check considers your endpoint healthy if it responds; it doesn't know whether the response is correct. Validate a "status": "ok" field from an endpoint that actually checks its dependencies. The full argument is in HTTP 200 is not a health check.
A reality check for free-tier users, since half the searches for "render uptime monitoring" are really asking about this: Render's free web services spin down after a period of inactivity. An external monitor's probe will wake a spun-down service, but the first response is slow (often tens of seconds), and the service spins down again afterward. Don't configure monitoring as a keep-awake hack; it fights the platform and gives you flaky alerts. Instead, monitor honestly: raise the check timeout and require confirmation from multiple probe nodes before an incident opens, so cold starts don't page you for a service behaving exactly as the free tier says it will.
The external layer has a customer-facing half too. When Render itself is degraded, your users don't care whose fault it is; they want to know that you know. A status page hosted off-platform, on infrastructure independent of your Render account, keeps working precisely when your app doesn't. Where a status page fits relative to alerting (and where it doesn't) is worth five minutes: status pages vs alerts, the real tradeoffs.
Recovery: trigger a Render deploy hook from a workflow
Render's auto-restart handles the failing-health-check case for web services. For the cases it can't see (a worker stalled but alive, a service failing body assertions while returning 200s), you can close the loop yourself, because Render exposes deploy hooks: per-service URLs that trigger a redeploy when you POST to them.
In an upti.my workflow, that becomes a Custom Webhook node pointed at the deploy hook URL, gated so it only fires when a failure is real and persistent:
- Trigger: incident opened on the check or heartbeat covering the service.
- Delay: wait a few minutes, long enough for a blip to self-resolve.
- Filter: continue only if the incident is still active. A flap that recovered during the delay stops here.
- Custom Webhook: POST the Render deploy hook URL. Render redeploys the service.
- Escalate: notify a human that an automated redeploy happened, and page harder if the incident survives it.
Put a Deduplicate node in front of the webhook as a guardrail, so a crash-looping service triggers one redeploy per window instead of an infinite redeploy storm. Automated remediation without a rate limit is just automated damage.
Plan gating, stated plainly
Setting it up in upti.my
The whole setup, in order:
- Create an HTTP check for each Render web service, probing from multiple regions, with a response-body assertion on a real health endpoint.
- If you're on Render's free tier, raise timeouts and require multi-node confirmation so spin-down cold starts don't page you.
- Add a heartbeat to every cron job: curl as the last line, period matching the schedule, grace sized to worst-case runtime.
- Give each worker a processing heartbeat, and add a queue canary per queue.
- Publish the off-platform status page.
- Optional, on Growth: wire a Delay, Filter, Deduplicate, Custom Webhook workflow to the service's Render deploy hook for automated recovery.
The free plan includes 10 checks, 5 heartbeats, and 1 status page, which fits a typical Render project comfortably: a couple of web services with external checks, two or three cron jobs on heartbeats, a worker heartbeat, a queue canary, and the status page, with room left over.
One last thing before you point every alert at your phone: route deliberately. Heartbeat misses on a nightly job can wait for morning; a failing production check cannot. The pre-built templates handle dedupe out of the box, and smarter alert routing covers how to split urgent from informational before alert fatigue teaches your team to ignore both.
📌Key Takeaways
- 1Render's health checks are genuinely good: continuous probing plus auto-restart for web services
- 2The coverage stops there. Background workers and cron jobs get no health checks at all
- 3Render notifies on cron runs that failed, never on runs that didn't happen. Heartbeats are the did-not-fire alert it lacks
- 4Workers need processing heartbeats plus a queue canary every 5 minutes to exercise the full enqueue-to-execution path
- 5External multi-region checks with body assertions catch what in-platform checks structurally can't, including Render itself degrading
- 6A Custom Webhook workflow can POST a Render deploy hook for automated recovery (Growth); free-plan users get the pre-built alert templates
Render earned its reputation by making web services easy to run well. Extending that same reliability to your crons and workers takes about fifteen minutes and a handful of curl lines. Start with the free plan: 10 checks, 5 heartbeats, and a status page cover most Render projects end to end.