How to send a push notification to your phone from a bash script
The fastest way to send a push notification from a bash script is a single curl command: POST your message to a notification API and let it deliver the push. With Pingwire that is one HTTP call with a Bearer key — the message lands in a real-time chat and arrives on your phone as a web push notification, usually within a couple of seconds. No SMTP setup, no mobile app to build, no third-party chat workspace required.
The one-liner
Create a free account at pingwire.dev, generate an API key under Account → API keys with the send scope, and run:
curl -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer pw_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"channel":"alerts","text":"Backup finished","priority":"high"}'The channel is created automatically on first send, the message appears in your Pingwire chat, and — once you have installed Pingwire on your phone as a web app and enabled notifications — it pushes to your lock screen. The API documentation covers every field; the three that matter most in scripts are text, title, and priority.
Why not just send an email?
Email from a server is the traditional answer, and it is usually the wrong one in 2026. Outbound SMTP from a VPS lands in spam unless you maintain SPF, DKIM, and sender reputation; delivery takes anywhere from seconds to minutes; and an email in an inbox does not interrupt you the way an alert should. A push notification is delivered or it is not — there is no spam folder in the middle — and a priority flag can make it stay on screen until you acknowledge it.
Making it useful inside real scripts
Notify on failure only
The most common pattern: run the job, and ping yourself only when it breaks.
#!/usr/bin/env bash
set -euo pipefail
notify() {
curl -sS -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer $PINGWIRE_KEY" \
-H "Content-Type: application/json" \
-d "{\"channel\":\"ops\",\"title\":\"$1\",\"text\":\"$2\",\"priority\":\"$3\"}"
}
if ! /usr/local/bin/nightly-backup.sh; then
notify "Backup FAILED" "nightly-backup.sh exited non-zero on $(hostname)" "urgent"
fiPipe output straight into a message
If you install the Pingwire CLI, a script can send its own log tail without any JSON quoting:
tail -20 /var/log/deploy.log | pingwire send --channel deploys --title "Deploy log"Send the whole thing as raw text
The notify endpoint accepts a raw text body, which is handy when the message is the output of another command:
df -h / | curl -sS -X POST "https://pingwire.dev/api/v1/notify.php?channel=ops" \
-H "Authorization: Bearer $PINGWIRE_KEY" \
-H "Content-Type: text/plain" --data-binary @-The failure mode a notification cannot catch
There is one important gap in every notify-on-failure design: a script that never runs sends nothing. A disabled cron entry, a server that did not come back after a reboot, or an expired credential that makes the job exit early all produce the same result — silence — and silence looks exactly like success.
The fix is to invert the signal with a heartbeat: the script pings a unique URL every time it succeeds, and the monitoring side alerts you when the pings stop arriving. That is a dead man's switch, and it catches the failures your error handler never sees. Pingwire's heartbeat monitoring does this with one extra line at the end of your script:
curl -fsS --retry 3 https://pingwire.dev/hb/YOUR-TOKEN > /dev/nullUse both patterns together: failure notifications tell you what broke, the heartbeat tells you that something broke even when the script could not say so itself.
Good habits for script notifications
- Use priorities honestly. If every message is urgent, none are. Reserve
urgentfor pages that should survive a silent phone profile. - One channel per concern. A
deployschannel you skim and anopschannel that pages you are easier to live with than one noisy stream. - Do not fear retries. Pingwire collapses identical text from the same machine sender within 60 seconds into one message, so a retrying script cannot spam the channel.
- Keep the key out of the script. Put it in an environment variable or a root-readable config file, not in the script body that ends up in version control.
- Meaningful exit codes. The Pingwire CLI exits
0on success,2when credentials are missing, and3on network errors — so your wrapper can distinguish "my message was rejected" from "the network was down".
What about two-way alerts?
A bash one-liner covers the send side. When you need the receiving side too — acknowledging an incident, escalating to a teammate's channel when nobody reacts, or publishing a status page your users can check — that is where a notification platform earns its keep over a bare push relay. Those pieces (incidents, escalation chains, and public status pages) ride on the same API described here, so the one-liner you start with today does not need to be replaced later.
Frequently asked questions
How do I send a push notification from a bash script without building an app?
POST to a notification API with curl. With Pingwire: create a free API key, then send one HTTP request to https://pingwire.dev/api/v1/messages.php with your channel and text. The message pushes to your phone once you have installed the Pingwire web app and enabled notifications.
Do I need to install anything on my server?
No. Plain curl is enough, and it is preinstalled on virtually every Linux server. An optional single-file CLI adds conveniences like piping a log file straight into a message.
Can cron jobs send push notifications?
Yes — the same curl command works in a crontab line or inside any script cron runs. For cron jobs specifically, pair it with a heartbeat monitor so you also find out when the job silently stops running, which a failure notification cannot detect.
What happens if my script retries and sends the same message twice?
Pingwire collapses identical text from the same machine sender within 60 seconds into a single message, so retry loops do not flood the channel. Messages typed by humans and scheduled reminders are never deduplicated.
Is this free?
Pingwire is currently in free mode: every account gets the Pro limits at no cost while billing is paused.
Try Pingwire
Send your first alert in under 30 seconds — one HTTP call, straight to a chat and your phone.