# How to Send Node-RED Push Notifications to a PingRoom Room

> Turn one useful Node-RED event into a concise shared phone alert, keep the webhook secret out of the flow, and make retries safe.

- Published: 2026-10-19
- Author: PingRoom
- Category: Developers
- Topics: Node-RED push notifications, Node-RED webhook phone alert, send Node-RED result to phone
- Canonical: https://pingroom.io/blog/node-red-push-notifications
- Cover image: https://pingroom.io/blog/node-red-push-notifications-cover.webp
- Cover description: Two PingRoom avatars watch a miniature Node-RED-style flow carry one result token to a shared dish while Pingo observes the final gate.

To send a Node-RED push notification to a group, put a **Function** node and an **HTTP Request** node after the event you care about. The Function node shapes one short Ping. The HTTP Request node posts it to a PingRoom incoming webhook, whose complete URL stays in an environment variable.

This is a webhook recipe, not a native Node-RED integration. Node-RED remains responsible for sensing, filtering, and deciding when the event matters. PingRoom gives the result a shared destination: a Room whose members can receive and answer the Ping.

## Choose the destination before adding nodes

Node-RED's flow library includes dedicated community nodes for services such as [Pushover](https://flows.nodered.org/node/node-red-node-pushover) and [PushStaq](https://flows.nodered.org/node/node-red-contrib-pushstaq). Those may be the shortest route when you already use that service.

Use this PingRoom recipe when the event belongs to a small group rather than one device:

| Need                                                                | Better starting point                           |
| ------------------------------------------------------------------- | ----------------------------------------------- |
| Alert one person's existing notification app                        | Its maintained Node-RED node or documented API  |
| Send one recognizable alert to housemates, teammates, or volunteers | A private PingRoom Room and this webhook recipe |
| Preserve charts, sensor history, or machine state                   | The system that already owns that data          |
| Page an on-call rotation for a critical incident                    | Your monitored incident and escalation system   |

Do not forward every reading. Add a **Switch**, **RBE**, **Delay**, or another suitable control before the notification step so the flow emits only a state change someone can act on.

## Create the Room webhook without putting its secret in the flow

In PingRoom, open the destination Room, add an incoming webhook, and copy its complete URL. Incoming webhooks require PingRoom Pro, and a Room can have up to four. The final path segment is the secret, so treat the whole URL as a credential.

Set that URL as `PINGROOM_WEBHOOK_URL` in the environment that starts Node-RED. Then configure the HTTP Request node like this:

- **Method:** `POST`
- **URL:** `${PINGROOM_WEBHOOK_URL}`
- **Return:** a parsed JSON object

Node-RED supports `${ENV_VAR}` substitution in node properties. This keeps the real URL out of the exported flow. It does not make the URL harmless: restrict access to the host, editor, runtime configuration, and logs. Do not attach a Debug node configured to print the complete message after Node-RED has resolved a credential-bearing URL.

## Build the payload and retry key

Place a Function node immediately before the HTTP Request node. This example expects the useful event in `msg.payload`:

```javascript
const event = msg.payload;

if (!event?.source_event_id || !event?.title || !event?.message) {
  node.error("Missing source_event_id, title, or message", msg);
  return null;
}

msg.headers = {
  Accept: "application/json",
  "Content-Type": "application/json",
  "Idempotency-Key": String(event.source_event_id),
};

msg.payload = {
  title: String(event.title).slice(0, 40),
  message: String(event.message).slice(0, 120),
  correlation_id: String(event.source_event_id).slice(0, 180),
};

return msg;
```

The stable `source_event_id` is the important part. Use the identity assigned by the system that owns the event—a job ID, booking ID plus state, or sensor cycle ID—not the current time. When Node-RED retries an unchanged request with the same idempotency key, PingRoom can return the original result instead of creating another Ping. Reusing that key with a changed body returns a conflict, which exposes an identity mistake rather than quietly duplicating or replacing the event.

For an illustrative laundry flow, the node before the Function might emit:

```json
{
  "source_event_id": "washer-cycle-4821-finished",
  "title": "Washer finished",
  "message": "The shared washer is free"
}
```

That copy tells the Room what changed and what is now possible. It avoids raw telemetry, private household details, and a vague “automation fired” message.

![Two PingRoom avatars inspect a sealed credential box and a duplicate gate while Pingo watches one replay token stop.](/blog/node-red-push-notifications-1.webp)

[Pingo the Pigeon](/Pingo), PingRoom's fictional CMO, appears here as the observer beside the duplicate gate. He does not read Node-RED, enter private Rooms, hold credentials, or send Pings. The real filter, event identity, destination, and retry policy remain human choices in the flow.

## Check the response before the flow continues

After the HTTP Request node, use a Switch or Function node to inspect both `msg.statusCode` and the parsed response:

| Result                                   | Meaning                                                 | Flow action                                                         |
| ---------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------- |
| `200` and `msg.payload.success === true` | PingRoom accepted and queued the Ping                   | Record success without logging the webhook URL                      |
| `409` with `idempotency_conflict`        | The same key was reused with a different request body   | Stop blind retries and fix the source identity                      |
| `429`                                    | The Room webhook is cooling down or has reached a limit | Honor the response's retry guidance; aggregate or debounce upstream |
| Other timeout or network error           | Acceptance is unknown                                   | Retry the identical body with the same stable key                   |

PingRoom's default webhook cooldown is five seconds. A noisy sensor can exceed that quickly, so suppress chatter before the HTTP node. Never handle a `429` by spraying more requests.

An HTTP `200` proves acceptance, not display on every phone. Connectivity, operating-system notification permissions, Focus modes, battery settings, and Room preferences still affect delivery. Keep the source system as the durable record, and keep critical escalation in the system designed to own it.

## Test four cases with a harmless Room

Before connecting the real event source:

1. Send one well-formed event and confirm one Ping appears in the test Room.
2. Repeat the exact body and idempotency key and confirm a second Ping does not appear.
3. Change the message while keeping the key and confirm the flow receives `409`.
4. Trigger events faster than the Room's cooldown and confirm your upstream filter or retry path behaves as intended.

For this article, we also ran the recorded flow on Node-RED `5.0.8` against a local mock of the PingRoom endpoint. The check covered the environment-variable URL, request headers, exact replay, and changed-body conflict. It did not call a live PingRoom Room or represent a phone-delivery test, so your harmless end-to-end check remains necessary.

Review the complete [incoming webhook contract](/documents/webhooks) for field limits, acknowledgement options, cooldowns, and error shapes. The broader [webhook-to-phone walkthrough](/blog/webhook-to-push-notification) covers the same PingRoom endpoint without Node-RED.

When those four checks pass, [open PingRoom](/app/rooms), create the destination Room, and connect only the Node-RED events that give someone a useful next action.

_The two editorial illustrations were created with AI using approved PingRoom character references and reviewed by the PingRoom team._
