How to send push notifications from Node.js
Send a push notification from Node.js to your iPhone with one fetch call. No SDK, no APNs certificates, ~6 lines of JavaScript.
Your Node script just finished importing 40,000 rows at 2am. Did it work? You won't know until you wake up and check the logs. Unless your phone buzzes the second it's done.
Here's the thing about Node.js and push notifications: most guides send you straight to Firebase Cloud Messaging, which means a service account JSON, an SDK, registration tokens, and a topic schema — for what should be a single HTTP request. If all you want is to ping your own iPhone when something happens on your server, that's wild overkill.
So let's skip it. One fetch call, no SDK, no APNs certificates. About six lines.
The one-call version
Node 18 and up ships with fetch built in, so there's nothing to install. Here's the whole thing:
const res = await fetch('https://thenotification.app/api/sendNotification', {
method: 'POST',
headers: {
'app_key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Import finished',
body: '40,000 rows in 4m12s. Zero errors.'
})
})That's it. The notification lands on your iPhone. title and body are the only required fields — link (a URL that opens on tap) and image are optional extras when you want them.
Grab your app_key from the dashboard after you sign in. Treat it like a password: keep it in an environment variable, never hard-code it into anything that ships to a browser.
A reusable function you'll actually keep
You're not going to paste that block every time. Wrap it once, handle the failure case, and import it wherever you need it:
// notify.js
export async function notify(title, body, extra = {}) {
const res = await fetch('https://thenotification.app/api/sendNotification', {
method: 'POST',
headers: {
'app_key': process.env.NOTIFICATION_APP_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title, body, ...extra })
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
throw new Error(err.error || `Notification failed: ${res.status}`)
}
return res.json()
}Now sending a notification is one line anywhere in your codebase:
import { notify } from './notify.js'
await notify('Backup done', 'Nightly DB dump uploaded to S3.')The extra argument lets you pass link or image when a notification deserves a tap target:
await notify('New signup', 'someone@example.com just registered', {
link: 'https://your-admin.example.com/users'
})A successful call returns something like { "success": true, "message": "Notification sent to 1 device(s)", "devices_sent": 1, "failed_count": 0 }, so you can check devices_sent if you want to be sure it actually reached a phone.
A real use case: alert on an Express error
Where this earns its keep is the stuff you'd otherwise only hear about from an angry user. Drop it into an Express error handler and your phone becomes your uptime monitor:
import { notify } from './notify.js'
app.use((err, req, res, next) => {
// fire and forget — don't let the alert block the response
notify('Server error', `${req.method} ${req.path}: ${err.message}`)
.catch(console.error)
res.status(500).json({ error: 'Internal server error' })
})Same pattern works for a queue worker that hits a dead job, a webhook that receives a payment, or a long migration that finally crosses the finish line. If your server can call fetch, it can text your pocket.
Real talk: this isn't a notification firehose
This is built for you and your servers, not for blasting marketing pushes to ten thousand users. The free tier caps at 100 notifications total, and Pro ($2.99/month) gives you 1,000 a month — plenty for error alerts and job-done pings, not enough to spam a user base. If you're notifying customers at scale, you want FCM after all. If you're notifying yourself, this is the right tool. Worth knowing the rate limits before you wire it into a hot loop and burn your month in an afternoon.
That's the whole thing
No SDK, no certificates, no token registry — just a POST you already know how to write. Full options are in the JavaScript docs, and if your stack is polyglot, the same one-call approach works from Python too.
Worth a look if you're tired of SSHing in just to check whether a job survived the night: thenotification.app.
Stop babysitting your scripts.
Free to download. Free tier available. Swiss-hosted, private by design.