A weather sensor on a remote hillside stops uploading readings. A payment kiosk in a store back office freezes overnight. A fleet of Raspberry Pi gateways loses its cellular connection during a carrier outage. In every case the device does not raise its hand and say "I'm broken." It just goes quiet, and the silence is invisible until someone notices the dashboard has gone stale or a customer complains that the terminal is dead.

IoT and edge devices are hard to monitor for a specific structural reason: they almost never have a public URL you can poll. A sensor on a factory floor, a Raspberry Pi in a greenhouse, a POS terminal behind a store router, an agricultural probe on cellular — these sit behind NAT and firewalls with no inbound route. Traditional uptime monitoring, where a service curls your URL on a schedule, has nothing to connect to. This guide shows you the pattern that actually works for connected devices: heartbeats, where each device checks in with you instead of the other way around.

Why polling does not work for connected devices

Standard HTTP monitoring is a pull model: a service reaches out to your endpoint, gets a response, and decides whether it is healthy. That works beautifully for web servers, APIs, and status pages — anything with a routable address. It falls apart the moment the thing you care about lives behind a home router, a cellular modem, or a corporate firewall. Most connected devices are exactly that: unroutable from the outside. There is no address to poll, and port-forwarding thousands of field devices to the public internet is a security nightmare nobody wants. The device can make outbound requests — that is how it uploads data — but it cannot receive unsolicited inbound ones.

Heartbeat monitoring inverts the direction. Instead of the monitor checking on the device, the device checks in with the monitor. After each successful work cycle, the device sends a small HTTP ping to a unique CronAlert URL, and CronAlert records the timestamp. If the next ping does not arrive within the expected window, CronAlert concludes the device has gone silent and fires your alerts. This is push-based, passive monitoring — the exact inverse of a URL check, and the same dead-man's-switch pattern used for cron job and background task monitoring.

The heartbeat pattern for devices

When you create a heartbeat monitor in CronAlert, you get a unique ping URL that looks like this:

https://cronalert.com/api/heartbeat/your-unique-token

You embed a request to that URL in the device's firmware loop or in a cron job on the device. Every time the device completes a real work cycle — reads its sensors, uploads a batch, finishes a poll — it hits the URL, and CronAlert marks the monitor UP and remembers when it last heard from the device. If nothing arrives within the configured interval, the monitor transitions to DOWN and your alert channels fire. The endpoint accepts both GET and POST. Keep the payload minimal — for a battery or cellular device an empty GET is ideal, because every byte costs power and data. The ping is not carrying telemetry; it simply proves the device is alive and completing its cycle.

Ping on success, at the end of the cycle

The single most important rule is the same as for cron jobs: ping only after the meaningful work has succeeded, never at the start. If a device pings the moment it wakes up and then hangs during its sensor read or upload, the heartbeat still looks healthy and you learn nothing. Put the ping at the very end of the cycle, gated on success, so a stuck or failing device actually goes silent.

Implementing the heartbeat on a device

The ping is a single HTTP request, so you can add it to nearly anything. On a Linux-based device — a Raspberry Pi, an industrial gateway, an edge box running a small OS — the simplest approach is a cron job that fires after the device's own upload cycle:

# On the device: read sensors + upload, then ping on success
*/10 * * * * /usr/local/bin/sensor-upload.sh && curl -fsS --max-time 15 https://cronalert.com/api/heartbeat/TOKEN > /dev/null

The && is doing the real work: the curl only runs if sensor-upload.sh exits 0. The --max-time 15 keeps a slow or dead network from wedging the device, and -fsS stays quiet on success but surfaces real errors in your device logs. If you are on a low-power target without curl, wget -q -O /dev/null --timeout=15 <url> does the same job.

For a device running its own firmware loop rather than cron, drop the ping in at the bottom of the loop after the upload step succeeds. In pseudocode:

while True:
    reading = read_sensors()
    ok = upload(reading)
    if ok:
        # fire-and-forget; a failed ping must never crash the loop
        try:
            http_get('https://cronalert.com/api/heartbeat/TOKEN', timeout=15)
        except NetworkError:
            pass
    sleep(duty_cycle_seconds)

Wrapping the ping so it cannot throw is essential on a device. A momentary loss of connectivity should not take down the firmware loop — the missed ping will alert you on its own, but the device should keep trying its real work regardless.

Choosing the right interval

The heartbeat interval is where device monitoring differs most from server monitoring, because field devices live on unreliable networks and often on batteries. Two principles keep you out of trouble:

  • Match the interval to the duty cycle. If a device uploads every 15 minutes, its heartbeat naturally comes every 15 minutes. Do not ping faster than the device already does real work — an extra dedicated ping on a cellular or battery device burns power and data for no benefit.
  • Add a tolerant grace window. Cellular and Wi-Fi links drop packets. If you set the monitor interval to exactly the duty cycle, a single dropped ping pages you at 2 AM for a device that is completely fine. For a 15-minute cycle, a 25 to 30 minute monitor interval absorbs one lost ping and only alerts when the device is genuinely gone. This is the core defense against false-positive alerts, and it is closely related to how you set timeout and threshold values for any monitor.

The tradeoff is detection speed versus noise. A tighter window catches outages faster but pages on transient blips; a looser window is quieter but takes longer to notice a real failure. Size it around the actual reliability of your network, not around a best-case assumption.

What "down" actually means for a device

A silent heartbeat could mean the device crashed, hung in a stuck loop, lost power, or lost connectivity entirely. All of these produce the same signal — no ping — which is exactly what you want, because all of them mean the device is not doing its job. But hold onto one distinction: a silent device heartbeat is not the same as your backend being down. If your ingestion API is unreachable, hundreds of healthy devices might all go quiet at once simply because they cannot reach anything. When you see a wall of devices go dark simultaneously, suspect the backend or a network path first; when one device goes dark while its neighbors keep reporting, suspect that unit. That is why you monitor both ends of the pipeline — the next section.

Monitor the backend, not just the devices

Device heartbeats tell you when a device stops sending, but nothing about whether your backend stopped receiving. A complete setup watches both directions so you can tell "the device died" apart from "the pipeline died." Three backend pieces are worth monitoring with standard HTTP checks:

  • The ingestion endpoint. The HTTP(S) API your devices upload to is a normal, publicly routable URL — poll it with a standard HTTP check. This is the same discipline as any API endpoint monitoring: verify it responds, returns a healthy status, and does so within a sane response time.
  • A dedicated health endpoint. Rather than hammering your real ingestion route, expose a lightweight health check endpoint that also confirms downstream dependencies (database, queue) are reachable. CronAlert's keyword and content-hash checks can assert the response actually says ok rather than just returning a 200 from a broken app.
  • The processing pipeline. Device data usually lands in a queue and gets processed by a worker. If that worker stalls, devices keep uploading happily while data silently backs up. Put a heartbeat on the worker itself — the same pattern covered in background worker monitoring and message queue monitoring — so a stuck consumer surfaces immediately.

With both halves in place, device heartbeats catch "the device stopped sending" and backend checks catch "the backend stopped receiving or processing." Missing either half leaves a blind spot. If your devices feed a mobile or app backend, the same principle extends to mobile app backend monitoring.

Managing a fleet at scale

One or two devices is easy. A fleet of hundreds needs a little structure so alerts stay useful instead of turning into noise:

  • One monitor per device, or per logical group. If ten interchangeable sensors share a single heartbeat, one dead sensor is invisible because the others keep the monitor green. Give each device (or each meaningful group) its own monitor so you can tell exactly which unit went dark.
  • Name for the 3 AM reader. "Heartbeat 47" tells you nothing. "greenhouse-3 soil-probe (cellular)" tells you what failed, where it is, and how it connects — which is half the diagnosis before you even log in.
  • Mind your plan's monitor limit. The Free plan covers 25 monitors at a 3-minute interval, Pro covers 100 at 1-minute, Team covers 500, and Business is unlimited. For a large fleet, pick the plan that fits the device count, remembering you also need a few monitors for the backend.
  • Route alerts to the right owner. The person responsible for the retail POS fleet is not the person responsible for the agricultural sensors. CronAlert delivers to email, Slack, Discord, Microsoft Teams, Telegram, PagerDuty, Opsgenie, Splunk On-Call, webhooks, and PWA push, so you can send each device group's alerts to the team that owns it.

Do not create hundreds of monitors by hand. The CronAlert REST API is available on every plan, including Free, so you can loop over your device inventory, bulk-create one heartbeat monitor per device during provisioning, and store each returned ping URL in the device's config. If you work in an AI editor, the CronAlert MCP server lets you create and manage fleet monitors conversationally from Claude Code, Cursor, or Windsurf.

Honest scope: what CronAlert does and does not do

Set this up correctly by knowing the boundaries. CronAlert is agentless and runs on Cloudflare's edge. It does two things: outbound HTTP and HTTPS checks (with SSL monitoring, keyword and regex matching, and SHA-256 content-hash verification) and inbound HTTP heartbeats.

It does not speak MQTT, CoAP, raw TCP, or ICMP, and it never opens a connection to your devices. Your devices must be able to make an outbound HTTPS request to send a heartbeat — which nearly all connected devices can, since that is how they upload data. For device-initiated HTTP pings and for HTTP ingestion or health endpoints, CronAlert is an excellent fit. For raw protocol monitoring — say, checking that an MQTT broker's port is open — expose a small HTTP health endpoint in front of the broker and monitor that endpoint instead. If your architecture depends heavily on native MQTT or TCP-level checks with no HTTP surface anywhere, CronAlert is not the tool for that layer.

Practical setup checklist

To wire up device monitoring end to end:

  • Create one heartbeat monitor per device (via the dashboard for a few, via the API for a fleet) and copy each unique ping URL.
  • Add an outbound HTTP request to that URL at the end of each device's work cycle, gated on success and wrapped so it cannot crash the loop.
  • Set the monitor interval to the device's duty cycle plus a grace window that tolerates at least one dropped ping.
  • Add a standard HTTP check on your ingestion API and a health endpoint, using keyword or content-hash checks to confirm real health, not just a 200.
  • Add a heartbeat on the worker that processes device data so a stalled pipeline surfaces even when devices keep uploading.
  • Give every monitor a descriptive name and route each device group's alerts to the team that owns it.
  • Confirm your plan's monitor limit covers your device count plus the backend monitors.

Frequently asked questions

Can CronAlert connect to my IoT devices over MQTT or ping them directly?

No. CronAlert does not speak MQTT, CoAP, raw TCP, or ICMP, and it never initiates a connection to your devices. It performs outbound HTTP and HTTPS checks and receives inbound HTTP heartbeats. Your devices must be able to make an outbound HTTPS request to send a heartbeat. If you run an MQTT broker or another non-HTTP service, expose an HTTP health endpoint in front of it and monitor that with a standard HTTP check.

My devices are behind NAT with no public IP. How do I monitor them?

This is precisely what heartbeats solve. Because the device initiates the connection outbound, it needs no public IP, no port forward, and no static address. Each device pings a unique CronAlert heartbeat URL after every successful cycle, and if a ping does not arrive within the expected interval, CronAlert marks the device offline and alerts you.

How do I choose a heartbeat interval for a battery or cellular device?

Match the interval to the device's duty cycle, then add a grace buffer for flaky networks. If a sensor uploads every 15 minutes, a 25 to 30 minute monitor interval tolerates a single dropped ping without paging you. Never ping faster than the device already does real work, since every extra request costs battery and cellular data. See our guide to setting timeout thresholds for the general approach.

Do I need one heartbeat monitor per device, or can I share one?

Use one heartbeat monitor per device, or per logical group when devices are genuinely interchangeable. If ten sensors share a single heartbeat, one silent sensor stays invisible because the other nine keep the monitor healthy. Separate monitors let you identify exactly which unit went dark and route its alert to the right owner.

How do I create heartbeat monitors for a whole fleet at once?

Use the CronAlert REST API, available on every plan including Free. Loop over your device inventory, create one heartbeat monitor per device, and store each returned ping URL in your provisioning system. You can also use the CronAlert MCP server from Claude Code, Cursor, or Windsurf to bulk-create and manage fleet monitors conversationally.

Start monitoring your devices

Connected devices fail silently by nature — they sit behind NAT, run on unreliable networks, and never announce their own death. Heartbeats turn that silence into a signal: each device checks in on its cycle, and the absence of a check-in becomes an immediate alert. Pair device heartbeats with HTTP checks on your ingestion API and a heartbeat on your processing worker, and you can tell "the device died" apart from "the backend died" at a glance. Create a free CronAlert account — the Free plan includes 25 monitors, heartbeat monitoring, and the full REST API for bulk-provisioning a fleet, so you can wire up your first devices in minutes.

Related reading: cron job and heartbeat monitoring, background worker monitoring, API endpoint monitoring, and HTTP health check endpoints.