A rich push carries two extras beyond title and body: an image and a custom sound. Configure both in the campaign composer or a journey Send push node, or send them in content via the API.
Note
Sending via the API
Every field is optional. Include only what you need:
{
"content": {
"title": "Weekend sale",
"body": "20% off, today only",
"imageUrl": "https://cdn.yourapp.com/media/sale.png",
"soundIos": "chime.caf",
"soundAndroid": "chime"
}
}Image
Paste an HTTPS URL or upload a file to the media library from the composer's Image field. Uploaded files are hosted on your configured storage/CDN and reused across sends.
- iOS — delivered as a notification attachment. The image shows as a thumbnail on the banner and full-size when the notification is expanded. Requires the Notification Service Extension from iOS setup.
- Android — delivered as a
BigPictureStyle: a thumbnail when collapsed and a full-width picture when expanded. No extra setup beyond the SDK.
Custom sound
iOS and Android name sounds differently, so there are two independent fields. Fill in whichever platforms you target — a blank field falls back to the system default.
| Field | Platform | Format | Example |
|---|---|---|---|
soundIos | iOS (APNs) | filename with extension | chime.caf |
soundAndroid | Android (FCM) | res/raw name, no extension | chime |
iOS implementation
- Add a short audio file (
.caf,.aiff,.wav, ≤30s) to the app target's Copy Bundle Resources. - Enter the filename with extension in the iOS sound field. iOS plays it automatically from
aps.sound— no code changes needed.
Android implementation
On Android 8+ a sound is a property of the notification channel and is locked once the channel is created, so a custom sound means routing to a channel that has it. Add the file to android/app/src/main/res/raw/ (lowercase, no spaces), enter its extensionless name in the Android sound field, then read ek_sound from the data payload and create a per-sound channel:
// In PayghaamFirebaseMessagingService.showNotification(...)
val soundName = message.data["ek_sound"] // e.g. "chime"
val channelId = if (soundName.isNullOrBlank()) "payghaam_default"
else "payghaam_sound_$soundName"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
nm.getNotificationChannel(channelId) == null) {
val channel = NotificationChannel(
channelId, "Notifications", NotificationManager.IMPORTANCE_HIGH,
)
if (!soundName.isNullOrBlank()) {
// soundAndroid arrives already extension-free (a res/raw resource name).
val uri = Uri.parse("android.resource://$packageName/raw/$soundName")
val attrs = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.build()
channel.setSound(uri, attrs)
}
nm.createNotificationChannel(channel)
}Warning
chime → chime_v2) so a fresh channel is created.Full platform walkthrough: iOS setup and Android setup.
