Notifications stop arriving on a phone that otherwise browses fine through the corporate VPN. Web pages load, the app opens, and messages appear only at home or after the tunnel is switched off. For an app built on Firebase Cloud Messaging, the push channel is a separate long-lived outbound connection, not the HTTPS path the browser just proved. Work through these checks in order and stop at the first one that fails.

Confirm the app actually uses FCM

Not every notification is a push. Some are scheduled locally by the app, some are polled over HTTPS, and some arrive through a vendor channel that has nothing to do with Firebase. If the app's manifest and dependencies include Firebase Messaging, its notifications normally travel over the FCM connection, and the client library logs registration under a predictable tag.

adb logcat -s FirebaseMessaging:V
adb shell dumpsys package <package> | grep -i firebase

A registration token in the log confirms the transport. Without one, you are debugging an app-level notification pipeline, and firewall changes will not help. This distinction matters because a delivered message that never displays and a message that never arrives look identical to the user.

Check the outbound ports, not the website

FCM device connections are device-originated TCP to port 5228, with 5229 and 5230 as fallbacks and 443 as a last resort. A firewall that permits 443 for browsing can still break push, and a rule that allows an app's API domain does not cover the messaging endpoints, which are separate services.

These are outbound connections from the phone. You do not publish an inbound port on the device or the VPN gateway, so if someone suggests a port forward, the design has already gone wrong. The same is true of a rule that opens one port to every address on the internet: scope it to the documented destinations.

PortRoleWhat to verify
5228Primary FCM connectionOutbound allowed and session state kept
5229, 5230Fallback portsOften missing from hand-written allowlists
443Last-resort fallbackWorks only if the client actually falls back
HTTP proxyNot a supported FCM transportProxy exclusion or bypass, not a port rule

Firebase's network guidance also states that the FCM delivery protocol cannot be carried over an ordinary HTTP proxy. A browser succeeding through the corporate web proxy therefore proves nothing about the push socket: the two are different clients with different paths.

Check the idle timeouts that kill the socket

The FCM connection stays open between messages, which makes it sensitive to NAT and stateful-inspection timeouts. Firebase's guidance asks for at least 30 minutes of idle tolerance where such policies apply. A five-minute session timeout silently removes the mapping, and the phone only reconnects when something wakes it, so messages arrive in bursts or not at all.

Read the session table on the firewall or VPN gateway and find the phone's connection to 5228-5230. Compare its remaining lifetime with the documented value. If it is shorter, raise the timeout for those ports rather than changing every policy on the device, because a global timeout change is hard to justify and harder to undo.

Push delivery also depends on the endpoint mapping surviving a roam between Wi-Fi and cellular. A mapping keyed to one interface can be dropped on the handover even when both networks allow the ports.

Decide whether VPN bypass is acceptable

Android VPN clients can permit traffic to bypass the tunnel, and FCM may use the underlying network when that bypass is allowed. The push channel stays encrypted in that case, but it no longer carries the tunnel's address, so the VPN's IP masking does not apply to it. That is a policy trade-off, not a malfunction.

If your policy prohibits bypass, the tunnel path has to carry the connection: ports open, timeouts long enough, proxy not in the way. Do not quietly exclude a managed service or loosen lockdown just because notifications work on an unmanaged network. The VPN icon does not tell you which path a given service selected.

Separate delivery from display, then test once

Permission, channel settings, Do Not Disturb and per-app toggles decide whether a delivered message is shown. On Android 13 and later the notification permission is a runtime grant, and a denied grant produces silence that looks exactly like a blocked port. A message that arrived but did not display is a presentation problem; treat it separately.

Run one controlled test instead of sending messages ad hoc. Keep the device, account and app fixed, send a single message with a known timestamp, and compare the VPN condition with an approved non-VPN network. Record the logcat receipt time and the display time for each run. If delivery differs but display does not, the network path is the variable; if both are identical, keep looking at the app.

Give the network owner the ports, the proxy limitation, the measured timeout and the bypass decision in one note. "Turn off the VPN" is not a finding, and allowing all Google traffic is not a scoped fix.

Inyandiko zihuye