Know the Moment Someone Signs Up
A push notification on every signup is the best motivation a new product has, right up until it is not. Here is how to wire it and when to turn it off.

There is a specific feeling when a product you built tells you that a stranger just signed up for it. It is a genuinely good feeling, and it is completely reasonable to want it on your phone rather than in a weekly analytics email.
It is also a notification with a shelf life, which nobody mentions. This covers both: how to wire it in five minutes, and how to know when to take it out.
Find the one right place
Every codebase has exactly one line where a signup is definitely real: after the row is committed, after the payment cleared if there is one, after the verification email went out. Not in the form handler, which fires for abandoned attempts, and not on the client, which fires for bots.
Put the call there and nowhere else. One place means one thing to change when you inevitably adjust it.
The call
Create an application in TheNotificationApp, call it after your product, and copy the app_key. Then, wherever your signup completes:
async function notifySignup(user) {
try {
await fetch("https://thenotification.app/api/sendNotification", {
method: "POST",
headers: {
app_key: process.env.TNA_APP_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "New signup",
body: `${user.email} from ${user.country ?? "unknown"}`,
link: `https://yourapp.example.com/admin/users/${user.id}`,
}),
});
} catch (error) {
console.warn("[notify] signup notification failed", error);
}
}Or in Python:
import os, requests
def notify_signup(user) -> None:
try:
requests.post(
"https://thenotification.app/api/sendNotification",
headers={"app_key": os.environ["TNA_APP_KEY"], "Content-Type": "application/json"},
json={
"title": "New signup",
"body": f"{user.email} from {user.country or 'unknown'}",
"link": f"https://yourapp.example.com/admin/users/{user.id}",
},
timeout=5,
)
except requests.RequestException as exc:
print(f"[notify] {exc}")Note the try in both. A failed notification must never fail a signup. That is the whole hierarchy of what matters here, and it is worth being explicit about because the naive version puts an uncaught network call directly in the path of your most important conversion.
Do not make them wait
Awaiting this adds its latency to the response the new user is looking at. Usually milliseconds, occasionally not.
If you have a job queue, use it. If not, the cheapest correct fix is to send the response first and let the notification finish afterwards, which works cleanly on a long-lived server:
res.json({ ok: true });
notifySignup(user); // deliberately not awaitedOne caveat: on serverless platforms the function can be frozen the instant you return, and an un-awaited promise gets dropped. There you either await it or use the platform's background primitive, like waitUntil on Vercel.
Put something judgeable in the body
"New signup" tells you a number went up. The useful version tells you enough to decide whether to do something:
- The email domain. A personal address and a company address are different events, and the company one might be worth a personal reply.
- Where they came from. The referrer or campaign, if you have it. This is how you find out a post landed somewhere.
- What they picked. Plan, use case, whatever your signup form asks.
body: `${user.email} (${user.plan}) via ${user.referrer ?? "direct"}`,"alex@acme.com (pro) via news.ycombinator.com" is a notification you act on. "New signup" is one you eventually stop reading.
The part people skip: turning it off
At one signup a week this is delightful. At twenty a day it is noise, and the transition happens gradually enough that you do not notice you have started ignoring it.
Three graceful exits, in the order you will want them:
Notify only on the ones that matter. The simplest change and usually the right first move:
if (user.plan !== "free") {
notifySignup(user);
}Switch to a daily digest. One notification a day, from a scheduled job, with the count and anything notable:
const count = await countSignupsSince(yesterday);
const notable = await topReferrers(yesterday);
await notify({
title: `${count} signups yesterday`,
body: notable.length ? `Top source: ${notable[0]}` : "No standout sources.",
});Invert it entirely. The version mature products actually want: do not tell me when someone signs up, tell me when nobody does.
if (count === 0) {
await notify({
title: "No signups yesterday",
body: "First zero-signup day in a while. Worth checking the funnel.",
});
}That last one is the most valuable notification in this post and the one almost nobody sets up. A day with no signups is a much stronger signal than a day with four, and it is also the one that catches a broken signup form, which is otherwise invisible precisely because nothing happens.
The honest part
The free tier is 100 notifications for the lifetime of the account, not per month. For a product in its first weeks, that is a genuinely well-matched budget: a hundred signups is a real milestone, and hitting the cap means the notification has done its job and it is time to move to a digest.
Pro is $2.99 a month for 1,000 if you want to keep the per-signup version longer. And this reaches iPhone only, because it rides Apple's push service.
Where this fits
If your signups land in a database you control, the trigger-level version is in Supabase database change notifications. If they arrive through a form tool or a payment provider, a webhook URL does it with no code: webhook push notifications. Field list in the API reference.
Grab a free key at thenotification.app and enjoy the first hundred properly.

