
Push notifications and in-app messages solve opposite halves of the same problem. Push notifications reach a user outside your app, on a lock screen, browser, or system tray, whether or not the app is open, so they are built to pull people back. In-app messages appear inside your app while someone is already using it, so they are built to guide, inform, and convert an active session.
The two are not competitors. The strongest notification strategies use push to bring users in and in-app messages to move them forward once they arrive. This guide breaks down the technical differences, the right use case for each, how to combine them, and how to ship both from a single API with Courier.
| Dimension | Push notifications | In-app messages |
|---|---|---|
| Where they appear | Outside the app: lock screen, home screen, browser, system tray | Inside the app during an active session: toast, banner, inbox |
| App open required | No. Delivered whether the app is open or closed | Yes. Seen only while the user is active |
| Opt-in required | Yes. OS or browser permission (iOS prompt, Android 13+ runtime permission, web push prompt) | No permission needed |
| Primary job | Re-engage, alert, pull users back | Engage, guide, and convert users already present |
| Persistence | Ephemeral. Easily missed or cleared | Ephemeral (toast) or durable (inbox with history) |
| Reach | Everyone who opted in, even when away | Active users only |
| Best for | Abandoned carts, mentions, security and system alerts, reminders | Onboarding, feature launches, billing notices, upgrade prompts |
| Main risk | Notification fatigue: users mute or uninstall | Missed entirely if the user never returns |
Push notifications are messages delivered to a user's device from outside your application. They show up on lock screens, home screens, browser windows, or system trays, and they arrive whether or not the app is currently open. Because they live outside your app, every platform gates them behind an explicit opt-in.
Mobile push appears on a locked screen or as a banner over an unlocked device. On iOS, an app must request notification permission before it can send anything, and the user can decline. On Android 13 and later (API level 33), apps must request the runtime POST_NOTIFICATIONS permission as well. These are platform requirements from Apple and Google, not app choices.

Mobile push reaches the lock screen even when the app is closed, like this Uber ride update.
Web (browser) push needs no install, but it does need an explicit permission prompt in the browser. Apple added Web Push for web apps saved to the iOS Home Screen in iOS 16.4 (2023), so the reach here keeps expanding.

Browser push reaches users who opted in, like this Google Calendar reminder, even on another tab.
Desktop push appears in the OS notification area, such as the Windows tray or the macOS Notification Center, and is common in native and Electron apps.

Desktop push surfaces in the OS from native apps, like this Slack message on macOS.
The defining trait of push is reach without presence: you can notify a user who is not currently in your product. The tradeoff is that push is easy to ignore, easy to mute, and, when overused, a fast route to an uninstall.
In-app messages appear while a user is actively using your app. They need no opt-in because the user is already present, and they range from quick, disappearing prompts to a durable message history.
Toasts are brief, non-blocking messages that surface for a moment and fade, ideal for confirmations and low-priority feedback ("Changes saved").

Toasts show a lightweight message that disappears after a few seconds.
Banners and modals hold more attention for onboarding steps, feature callouts, or account notices.
In-app inboxes are the persistent layer: a notification center inside your product that stores messages so users can scroll a chronological feed, see what is unread, and act on items asynchronously, the way they would in an email client.

An in-app inbox built with Courier keeps a durable, scrollable history of notifications from every channel.
An inbox is what makes a notification durable. Push and toast messages vanish, but an inbox keeps billing updates, product announcements, and mentions available until the user deals with them. That permanence matters most for asynchronous workflows, team products, and regulated industries where a record of what was communicated is not optional.
Reach for push when the value depends on reaching a user who is not currently in your app, and when timeliness or urgency is real.
Avoid overuse. Push should earn its place on the lock screen. Irrelevant or too-frequent notifications are the fastest way to get muted or uninstalled, which is a permanent loss of the channel.
Reach for in-app messages when the user is already present and you want to guide, inform, or convert without interrupting them.
Because the user is already engaged, in-app messages can be richer and more detailed than the tight character budget push allows.
The best experiences use both, in sequence. Push does the pulling; in-app does the guiding. Once a push brings someone back, an in-app message gives them the context and the next step.
The principle: use the right channel at the right time. Push re-engages, in-app completes. The hard part is not sending either one; it is coordinating them so the same person does not get the same message twice across three channels.
Coordinating push, in-app, email, SMS, and chat is not really a sending problem. It is an orchestration problem: deciding what to send, when, on which channel, and how to keep it all consistent across a user's devices. Courier is the layer that handles that so you do not stitch it together across separate SDKs and providers.
With Courier you:
Courier's current React package is @trycourier/courier-react. Authenticate the user with a JWT your backend issues, then drop in the component:
// npm install @trycourier/courier-reactimport { useEffect } from "react";import { useCourier, CourierInbox } from "@trycourier/courier-react";export default function App() {const courier = useCourier();useEffect(() => {// JWT is minted by your server for the signed-in usercourier.shared.signIn({ userId, jwt });}, []);return <CourierInbox />;}
Inbox and Preferences components ship across web and mobile, with Toast on the web. On the web there are SDKs for React, Vue, Angular, and framework-agnostic web components (drop into plain JavaScript or any framework), plus a headless @trycourier/courier-js client if you want to build your own UI. On mobile, native SDKs cover React Native, iOS, Android, and Flutter.
One request can target several channels in priority order. Here Courier tries push first, falls back to the Inbox if push is unavailable, then to email, so the message lands on the best channel for each user:
// npm install @trycourier/courierimport Courier from "@trycourier/courier";// Reads COURIER_API_KEY from the environmentconst client = new Courier();await client.send.message({message: {to: { user_id: "user_123" },content: {title: "Your report is ready",body: "Open the app to view your Q3 summary.",},routing: {method: "single",channels: ["push", "inbox", "email"], // first available wins, in order},},});
Because delivery flows through one system, you can keep channels coordinated instead of contradictory: sync Inbox read state in real time, set preferences so a user who already saw a message in one place is not pinged everywhere, and fail over from one provider to another automatically.
Push notifications and in-app messages are not an either/or choice. Push reaches users wherever they are and pulls them back; in-app messages meet users inside the product and move them forward. Used together, they create a multi-touch experience that neither channel delivers alone.
Courier makes running both practical. From one API and one set of SDKs you can send push and in-app notifications (plus email, SMS, Slack, and Microsoft Teams), embed a themeable Inbox, respect user preferences, and orchestrate the whole flow without rewriting logic for every channel.
Ready to build modern, multichannel notifications? Start free or request a demo to see how Courier fits your stack.
Push notifications are delivered to a device from outside your app and appear on lock screens, browsers, or system trays whether or not the app is open, so they require an opt-in. In-app messages appear inside your app while the user is active, as toasts, banners, modals, or a notification inbox, and need no permission.
Yes, and you usually should. Push brings a user back to your app, and in-app messages give them the context and next step once they arrive. The main challenge is coordination, which is why teams route both through one system to avoid duplicate messages across channels.
Use push when the user is not currently in your app and the message is time-sensitive: re-engagement, abandoned checkouts, mentions, security alerts, and reminders. Use in-app messages when the user is already present and you want to onboard, announce a feature, or convert.
No. In-app messages appear during an active session and do not need OS or browser permission. Push notifications do require an opt-in: an iOS permission prompt, the Android 13+ runtime notification permission, or a web push prompt.
Yes. Courier's @trycourier/courier-react SDK provides a drop-in <CourierInbox /> component for React, with equivalent SDKs for Vue, Angular, and framework-agnostic web components (usable from plain JavaScript), plus React Native, iOS, Android, and Flutter. You authenticate the user with a JWT and render the component.

Dark mode email design: a primer for every major email client
Dark mode is three different behaviors, not one. Apple Mail needs an explicit opt-in before it reads your dark CSS, Gmail ignores it entirely and rewrites your colors on its own, and classic Outlook gives you no control at all. This guide covers what each client actually does, the CSS that reaches the ones you can influence, and the design rules that survive the ones you cannot.

Product notifications API: what it handles and how to build
A product notifications API sits between your product's events and every channel you send on. You post an event, and the API decides what message goes out, to whom, on which channel, at what time, with that user's preferences applied. This post covers the ten things one has to handle, what building it yourself costs, and how to wire your event feed into Courier.

The federal texting rule your transportation and logistics software is breaking
A single text to a driving trucker can trigger a federal fine of up to $11,000 for the motor carrier, and your transportation and logistics software is often what sent it. How to design driver notifications that stay on the right side of FMCSA rules.
© 2026 Courier. All rights reserved.