Mobile push is available per workspace. Ask us at support@tranthor.com to turn it on for yours. iOS is not available yet.
Before you start
You need:- A Firebase project with your Android app added to it (the app’s package name, for example
com.example.shop). - The Tranthor Android SDK in your app, with its push module (below).
- An Admin or Workspace manager role in Tranthor, to add the key.
1. Create a Firebase service-account key
- Open the Firebase console and select the project your app uses.
- Go to Project settings, then Service accounts.
- Select Generate new private key. Firebase downloads a JSON file. If Firebase says key creation is not allowed, see Troubleshooting.
2. Add the key in Tranthor
- In Tranthor, go to Settings, Mobile, Push.
- On the Android (FCM) card, select Add key.
- Enter your app’s application id (its package name) and choose the JSON file, or paste its contents.
- Select Save.
3. Install the SDK and bind push
Add thetranthor-push module next to tranthor-sdk. Your app adds com.google.firebase:firebase-messaging itself and keeps its own Firebase configuration (google-services.json or manual FirebaseOptions). The app never holds the server key.
The Android SDK artifacts are not on Maven yet. Contact us at support@tranthor.com for the build to add to your project.
Application.onCreate, after the SDK is configured:
push for the life of the app. Forward every FCM token to it: the token from FirebaseMessaging.getInstance().token at launch and every onNewToken callback.
The simplest way is the ready-made messaging service, which forwards tokens, shows each Tranthor push and reports that it arrived:
images lets the notification show the template’s image. The app downloads it only when the image URL starts with https:// and its host is exactly one of the hosts you list there, and by default only a JPG, PNG or GIF up to 5 MB. Otherwise the notification shows without the image.
In the push editor, the Image card takes the image. Upload saves a JPG, PNG or GIF up to 5 MB to your workspace’s assets and uses it; a WebP or a bigger file is refused, here and when you upload in Choose from assets. Choose from assets picks one you already have. Both come from your workspace’s asset storage, so add that host to the list too. To read the host, open ··· › Paste a link on the card: the field shows the image’s full link. Paste a link also takes any other image link, with variables. A link without variables that does not start with https:// is refused and not saved. A link with variables is refused the same way when it starts with a scheme other than https://, such as http:// or ftp://; otherwise, as when it starts with a variable, it is checked by what it fills in as for the preview customer. The AI chat refuses the same links.
Messages that are not from Tranthor go to onOtherMessage, so another push SDK keeps working. To report opens, call TranthorNotifications.interactionFrom(context, intent) in your activity’s onCreate and onNewIntent and pass the result to push.handle(...). To report dismissals, do the same in the dismiss receiver.
On Android 13 and later, posting notifications needs the POST_NOTIFICATIONS permission. The SDK never asks for it on its own; ask at a moment that suits your app, then call push.refreshPermission().
Identity and consent follow the SDK: identify, reset, optOut and optIn on TranthorSDK keep the phone’s registration in step.
Events the SDK sends
The SDK sends these as track events through its queue, under the customer’s user id (or anonymous id when there is none). Tranthor reserves these names.
Each phone of a customer is an Installation. A customer can have several.
What Tranthor sends to the phone
Tranthor sends data-only FCM messages, with nonotification block, so your app always builds the notification itself and can report what happens to it:
tranthoris a JSON string. It holdsversion(always 1), thedeliveryIdthe SDK reports back, theimageUrlwhen the template has one, and"test": truefor a test push.title,body,channelId(the template’s Channel id, under Advanced) andurl(the template’s When tapped, open link) are left out when empty.- The template’s data entries are added as their own keys. A data key named
tranthor,title,body,channelId,url,fromormessage_type, or starting withgoogle.orgcm., is not sent. - Title, body, image URL, the When tapped, open link and data values can use Liquid, like other templates.
- FCM limits a message’s data to 4096 bytes. A longer message is not sent, and the send fails with a reason.
- FCM keeps an undelivered message for up to 28 days.
Which phones receive a push
Tranthor never sends a push only to find out whether a phone is still there. A phone stays reachable until there is real evidence that it is not:- Removed at once: when Google says the token is no longer registered, when the app sends
Installation Removed, or when the phone has not registered for 90 days. The SDK registers on every app start, so a phone in use never reaches 90 days. - Paused after two rejections: when Google rejects a phone’s token twice in a row. A paused phone comes back when the app gets a new token from Firebase.
- Notification permission: a phone the SDK reports as
"denied"is skipped."unknown"still receives push.
Results
Push results show on each journey step, on the journey’s Stats tab and on a broadcast’s results:- Sent: Google accepted the message for at least one of the customer’s phones.
- Delivered: the app on the phone reported
Push Received. This is app-reported: a phone that was off, or an app that did not run its messaging service, reports nothing, so Delivered can be lower than what reached phones. - Opened: the customer tapped the notification (
Push Opened). - Failed: no phone accepted the message. The Stats tab and a broadcast’s results list failures by reason, in words.
- Not sent: a customer with no phone that can get push from the app is skipped, shown as No active Installation under Push not sent. A skip is neither sent nor failed.
deliveryId matches a push Tranthor sent to that same customer. Anything else is ignored. Test pushes never count.
Troubleshooting
Firebase says “Key creation is not allowed on this service account”
Your Google Cloud organization blocks new service-account keys. It does this with the organization policyiam.disableServiceAccountKeyCreation. Google turns this policy on by default for organizations created after mid-2024.
You can turn it off for your Firebase project only. The rest of your organization keeps it.
- Make sure you have the Organization Policy Administrator role. If you do not, ask your Google Cloud admin.
- In the Google Cloud console, go to IAM & Admin, then Organization Policies.
- In the project picker at the top, select your Firebase project. Do not select the organization.
- Open Disable service account key creation. There are two entries with this name, a legacy one and a managed one. Open the one that shows Active.
- Select Manage policy, then Override parent’s policy.
- Add a rule and set Enforcement to Off. Then select Set policy.
- Wait up to 15 minutes for the change to take effect.
- In Firebase, select Generate new private key again.
Current limits
- Android only. iOS (APNs) is not available yet. The editor already lets you prepare iOS: under Settings › Message, Different for each gives the iOS version its own title, subtitle, body and image, and Advanced holds the iOS Sound and Time sensitive options. These are saved with the template and shown in the iOS preview, but nothing is sent to iPhones, and Android phones get the same push as before.
- Turned on per workspace. Ask us to turn it on for yours.
- The Android SDK artifacts are not on Maven yet.
- Push is sent by people in the dashboard. In the push template editor, the AI chat can write and change the template’s draft. It writes the shared (Android) message only, and does not see or edit the iOS version. It cannot publish the template, start a journey or send push.
- The Supervisor and connected assistants such as Claude and ChatGPT can read push templates, journeys and results, but cannot create, start or send push yet.
- Reachable audience and Blast radius counts do not include push yet.

