← All projects Case study · React Native

Mobile push

The React Native side of push for the platform's mobile clients: token registration and refresh, the Android 13 permission, foreground banners, and deep-link routing that works whether the app is open, in the background or not running.

  • 3app states routed
  • RN 0.79React 19, TypeScript
  • FCM+ Notifee
  • 1automatic retry on 401
Try it

Send a push to an invented app

Pick an app state and a deep link, press Send, then tap the notification. Turn on a failure drill to see the 401 retry.

push simulator · synthetic dataInteractive demo
The interactive simulator needs JavaScript. It shows a campaign composer, the delivery pipeline and a phone that receives the notification and opens the linked screen.
A simulation of the client behaviour. No message leaves your browser.
Problem

Brands with mobile apps wanted to send campaigns that open the right screen, not just the app.

A tap has to land on the product, category or cart in three different situations, each handled by a different API. Tokens change, sessions expire, and Android 13 added a runtime permission that silently drops notifications if nobody asks for it.

My role

I built the React Native modules and the reference app that the integration is tested with. The backend that queues and sends messages is an existing Java/Spring service with RabbitMQ and an FCM worker; I integrated with it and traced its queue bindings when debugging delivery.

  • FCM token registration through the profile endpoint, and a listener that picks up refreshed tokens
  • JWT login with one automatic re-login and retry on 401
  • Android 13+ permission check and a notification channel
  • Payload normalisation and tap routing for foreground, background and cold start
  • A debug panel and scripts to send by token or topic
Architecture

From campaign to screen

  1. PanelA marketer creates the campaign.
  2. Push backendExisting Spring service queues it on RabbitMQ.
  3. FCM workerExisting worker sends through Firebase Cloud Messaging.
  4. DeviceNormalise payload, show the banner, handle the tap.
  5. RouteOpen Home, Category, Product or Cart.

Violet tint: parts I wrote.

Engineering decisions

What was hard and what I did

One tap handler per app state

Foreground messages arrive in onMessage and are shown with Notifee. Background taps come through onNotificationOpenedApp, cold starts through getInitialNotification. All three feed one router, so a link behaves the same everywhere.

One payload shape

Campaigns arrive with fields in different places. A normaliser maps them to title, body, image, route and data before anything renders, so screens never parse raw messages.

Expired sessions without user impact

On a 401 the client logs in again once and retries the call. If the retry fails it stops, instead of looping.

Debugging a system I didn't write

When delivery looked broken I traced the queue bindings in the existing backend to find where messages stopped, and kept the investigation separate from the client fix.

Have a problem worth solving?Let's make it reliable

Start a conversation

Open to full-stack and applied AI roles, remote or hybrid.

Tell me about the role, the team and the problem.