Push settings
An app's offline push is configured in the "Push" tab of app details, in three parts:
- Push credentials: upload credentials for APNs, FCM and each phone maker's channel, and send test pushes.
- Notification templates: change notification titles and text, or add templates for more languages.
- Push stats: see push counts by date, channel, category and result.
To find out why a user isn't getting pushes, open the user in "IM users" and look at their "Push" tab; see A user's push devices and settings. For offline push rules (which devices get pushes, Do Not Disturb, badges and so on), see Offline push.
Upload credentials before releasing the app
An app with no credentials sends no offline pushes at all. When the app registers a push token it names a credential, and registration fails if the name doesn't exist, so upload credentials in the console first, then configure their names in the app.
Roles and permissions
| Action | owner | admin | developer |
|---|---|---|---|
| View push credentials (without secrets), notification templates and push stats | ✓ | ✓ | ✓ |
| Send test pushes | ✓ | ✓ | ✓ |
| Change and restore notification templates | ✓ | ✓ | ✓ |
| View users' push devices, push settings and conversation Do Not Disturb; change users' push settings, lift conversation Do Not Disturb, unbind push devices | ✓ | ✓ | ✓ |
| Add credentials, replace a credential's secret, delete credentials (needs identity verification) | ✓ | ✓ | |
| Change a credential's public parameters, disable and enable credentials | ✓ | ✓ |
Holding a credential means being able to push anything to every user of that app, so uploading, replacing and deleting credentials require identity verification within the last 10 minutes. These write actions and test pushes are recorded in the operation log, without secrets: push_credential.create, push_credential.update, push_credential.disable, push_credential.enable and push_credential.delete for credentials; push_template.update and push_template.delete for templates; and push.settings_update, push.conversation_setting_update, push.device_unbind and push.test for users' push settings, conversation Do Not Disturb, unbinding devices and test pushes.
Push credentials
"Push credentials" lists all of the app's credentials, sorted by name:
| Column | Description |
|---|---|
| Name | The credential's name, which the app uses to name it when registering push tokens |
| Channel | The push channel. APNs credentials also show the environment (production or development), and ones that can send VoIP pushes are marked "VoIP" |
| Package | The iOS Bundle ID, or the Android or HarmonyOS package name |
| Secret | A hint to recognize it, not the secret itself: the Key ID for an APNs .p8 key; for a .p12 certificate, the certificate name and days until it expires (red within 30 days); the service account email for FCM; the key ID for HarmonyOS; the last 4 characters of the secret for other channels |
| Status | Enabled or disabled. Ones disabled by the platform are also marked "Disabled by platform"; paused ones show the reason, and hovering shows until when; see Paused credentials |
| Last success | The last time a push through this credential succeeded, updated at most once a minute |
| Last error | The error code of the last credential-type error (authentication failure, expired certificate, package mismatch, a surge of invalid tokens, the maker's daily quota used up and so on); hover for the description and time. Network errors aren't recorded here |
Add a credential
owner or admin clicks "Add credential", fills in the following, clicks "Save", and verifies their identity again as prompted:
| Field | Description |
|---|---|
| Name | Letters, digits, _, - and ., 1 to 64 characters, case-sensitive, such as ios-prod or xiaomi-main. Unique within the app; can be reused after deletion |
| Channel | One of apns, fcm, huawei, harmony, xiaomi, oppo, vivo, honor, meizu |
| Bundle ID or package | The client app's Bundle ID (iOS, macOS) or package name (Android, HarmonyOS), which must match the app, such as com.example.chat. Contains at least one . |
| Environment | APNs only: production (production) or development (sandbox); see Apple APNs |
| Public parameters | Each channel's App ID, message category, notification channel and so on; see Credentials for each channel. Each up to 64 characters |
| Secret | Each channel's secret, certificate or service account; paste the content, or click "Read from file" to choose a file |
Saving checks the secret's format: whether a .p8 key parses, whether a .p12 certificate's password is right, it hasn't expired, and it includes the Bundle ID entered, and whether a service account's private key parses. If not, it says "The credential's secret is invalid" without saying which part is wrong.
Secrets are stored encrypted and never shown again on any page or API after saving; only the recognition hint shows. Channel, environment and package can't be changed after creation: for a different app or environment, previously registered tokens no longer work, so create a new credential.
Each app can have up to 20 credentials, several per channel. When one IM app has several client apps (such as a main app and a lite version), upload a credential for each, and have each app register tokens with its own credential name.
Credentials for each channel
Apple APNs
APNs has two ways to authenticate; the .p8 key is recommended:
.p8key (recommended): in Certificates, Identifiers & Profiles on the Apple Developer site, create a key with Apple Push Notifications service (APNs) enabled, download the.p8file (only possible once), and note its Key ID; the Team ID is in your developer account's membership details. Enter the Key ID and Team ID and paste the.p8file's content..p8keys don't expire, one key works for several apps in the developer account, and it can send VoIP pushes..p12certificate: in Certificates, Identifiers & Profiles, create an Apple push certificate for the app, import it into Keychain, export it with its private key as a.p12file, choose the file and enter the password set when exporting. Certificates expire; from 30 days before, the system reminds the tenant's owner and admins by email or SMS, so replace it in time. Only certificates that also register{Bundle ID}.voipcan send VoIP pushes, marked "VoIP" in the list.
Environment: apps installed straight from Xcode for debugging use the development environment (sandbox); App Store, TestFlight and enterprise distribution builds use production (production). Tokens don't work across environments: sending a development build's token with a production credential is reported as an invalid token. Upload a credential for each of the app's development and production builds (the same .p8 key can be used), such as ios-dev and ios-prod, and have the app register with the name matching its build type.
Optional parameters:
| Parameter | Description |
|---|---|
Sound sound | The sound for messages and notices: the name of a sound file in the app, the system default by default |
Allow notification extensions to modify content mutable_content | When on, notifications carry mutable-content, so the app can rewrite the content in a Notification Service Extension, such as showing the sender with a local friend remark |
Google FCM
In the Firebase console, open the app's project, generate a new private key under "Service accounts" in "Project settings", download the service account JSON file, and paste its content or choose the file. The package is the Android app's package name (applicationId), and the Firebase config built into the app must belong to the same project.
Optional parameters:
| Parameter | Description |
|---|---|
Notification channel ID android_channel_id | The Android notification channel (Android 8 and later) for messages and notices; the app must create a channel with the same ID at startup |
Silent channel ID silent_channel_id | The channel for updating a notification after a recall; the app creates it with low importance so replacing a notification doesn't ring again. Without it, the notification channel ID is used and may ring again |
Incoming and missed calls sent through FCM are data messages displayed by the app itself, with nothing extra to configure.
Chinese phone makers and HarmonyOS
After turning on push for the app on each maker's developer platform, fill in the following:
| Channel | Where to get it | Required | Optional parameters |
|---|---|---|---|
Huawei huawei | App information in Huawei AppGallery Connect | App ID, App Secret | Message category category |
HarmonyOS harmony | Huawei AppGallery Connect: the project ID; create a service account key in project settings and download the JSON file | Project ID, service account key JSON | Message category category |
Honor honor | Push service information for the app on the Honor developer platform | App ID, Client ID, Client Secret | Notification importance importance, using Honor push's values |
Xiaomi xiaomi | App information in push service on the Xiaomi open platform | App Secret | Channel ID channel_id; silent channel ID silent_channel_id |
OPPO oppo | App information in push service on the OPPO open platform | App Key, Master Secret | Notification channel ID channel_id; message category category; silent channel ID silent_channel_id |
vivo vivo | App information in push service on the vivo open platform | App ID, App Key, App Secret | Message category category |
Meizu meizu | App information in push service on the Meizu open platform | App ID, App Secret | — |
- Message categories and notification channels: Chinese makers require applying for message categories by content (such as instant messaging or private messages); pushes without one are treated as the maker's default category and may be throttled or rejected. Apply for an instant messaging category in the maker's console, and enter the category value and notification channel ID in the credential exactly; they're sent with each push.
- Silent channels: when Xiaomi or OPPO credentials have a silent channel, it's used to update a notification after a recall; the app creates it with low importance.
- The "call category", "call channel ID" and "call notification channel ID" fields in Huawei, HarmonyOS, Xiaomi and OPPO credentials can be filled in, but calls on these channels are currently sent as ordinary high-priority notifications and don't use them yet.
- The Huawei channel works on both Android and HarmonyOS devices, the HarmonyOS channel only on HarmonyOS devices, and the other Chinese makers only on Android devices.
Edit a credential
owner or admin clicks a credential's "Edit":
- Public parameters can be changed directly; saving replaces them as a whole and needs no identity verification.
- Replacing the secret: open "Replace secret" and upload the new secret, certificate or service account, which needs identity verification. When an APNs credential switches authentication method (between
.p8key and.p12certificate), the new secret must be uploaded at the same time. - Name, channel, environment and package can't be changed.
Changes apply to later pushes immediately, and the credential's "Last error" is cleared. If it says "The content was changed, refresh and try again", someone changed the credential after you opened it; refresh and edit again.
Disable and enable
owner or admin clicks "Disable", optionally with a reason. The credential immediately stops being used for sending (including calls), and tokens registered with it are kept: devices with tokens for other credentials switch to the next one, and those without get no pushes. Click "Enable" to restore it. While disabled, the app can still register tokens with it, usable as soon as it's enabled.
Disabled by the platform: when the platform disables a credential (such as for pushing violating content), the status shows "Disabled by platform" and hovering shows the reason, and the tenant's owner and admins are notified by email or SMS. Credentials disabled by the platform can't be edited, enabled or deleted; only the platform can enable them, which also triggers a notification.
Delete a credential
owner or admin clicks "Delete" and verifies their identity again as prompted. The credential immediately stops being used for sending, and tokens registered with it are cleaned up in the background. The same name can be added again afterward, but the old registered tokens don't come back; devices get pushes again only after the app re-registers on its next start. Credentials disabled by the platform can't be deleted.
Paused credentials
When a push channel hits one of the following, the system temporarily stops using the credential and shows the reason next to its status. While paused, pushes switch to the device's next token, and those without one count as channel_paused; it resumes automatically when the time is up, with nothing for you to do:
| Reason | Description | Paused for |
|---|---|---|
| Channel rate limit | The channel says requests are too frequent | The time the channel asks for, or 60 seconds if none, up to 1 hour |
| Daily quota used up | The maker's daily push quota for this app is used up; also recorded under "Last error" | Until 0:00 Beijing time the next day |
| Repeated authentication failures | 20 credential-type errors in a row within 1 minute, such as a wrong secret or expired certificate | 1 minute |
| Surge of invalid tokens | At least 50 sends within 1 minute with more than half reported as invalid tokens, usually because the credential's environment or package doesn't match the app | 10 minutes. Tokens reported invalid during it aren't deleted, so all of the credential's tokens aren't wiped at once |
When a credential keeps failing for an hour (with no success in between), the system notifies the tenant's owner and admins by email or SMS; one continuous failure is only notified once, and counting restarts after a success. Check the credential's secret, environment and package; editing the credential clears "Last error".
Test pushes
Click a credential's "Test" to send a test push with it, choosing:
- Username: sends to each of this user's devices that registered a token with this credential, one push per device.
- Token: sends straight to one token, for example copying a token from debug logs before releasing the app to check the credential is set up right. APNs uses the credential's environment.
Test pushes have the title "Test push" and the text "This is a test push; receiving it means push is set up correctly", in the device's registered language (pushes straight to a token use the app's default language), and can't be customized. They ignore Do Not Disturb and online state, carry no badge, don't count toward the app's push quota, and don't use VoIP tokens.
After sending, it waits up to 10 seconds for the channel's result and lists it per device:
| Column | Description |
|---|---|
| Device | The device's platform and session ID; "Token" for pushes straight to a token |
| Credential | The credential and channel used |
| Token | The masked token, showing only the first 6 and last 4 characters |
| Result | The push result, plus the channel's error code on failure; see Troubleshooting missing pushes |
- When sending to a user, devices that didn't register a token with this credential are listed too, with the result "Credential unavailable" (
credential_unavailable). - When the channel reports a token invalid, that token is deleted (pushes straight to a token delete nothing).
- Test pushes aren't retried on network errors and show
faileddirectly. - Each app can send up to 20 test pushes a minute and 5 per user per minute; beyond that it says "Too many test pushes, try again later". Apps that are disabled or suspended can't send.
Notification templates
Notification titles and text come from templates, with built-in Simplified Chinese (zh-CN), Traditional Chinese (zh-TW) and English (en). "Notification templates" lists every template key with the placeholders it can use, its built-in Simplified Chinese content and existing overrides. For how templates are chosen and the language lookup order, see Notification titles and content.
Override a template
Click "Override" on a template key's row and fill in:
| Field | Description |
|---|---|
| Language | A BCP 47 language tag such as zh-CN, en or ja, saved in lowercase. You can override a built-in language or add another |
| Title | Up to 64 characters, can be empty; when empty, the system shows the app name in the title position |
| Text | 1 to 256 characters |
- Only the template key's own placeholders (the "Placeholders" column) can be used; other placeholders or unbalanced braces can't be saved. To show a brace itself, write it twice.
- No control characters (such as newlines).
- Up to 300 overrides per app.
- Existing overrides show as language tags; click a tag to edit, or its close button to delete the override and restore the built-in template.
- Changes apply to later pushes immediately; notifications already sent don't change.
For example, to override message.group for Japanese users, set the title to {group} and the text to {sender}:{content}. Group messages to Japanese devices then use this template, while other template keys without overrides follow the language lookup order to the default language.
Template keys
| Template key | Use | Placeholders | Built-in title | Built-in text |
|---|---|---|---|---|
message.single | One-to-one message | {sender}, {content} | {sender} | {content} |
message.single_merged | One-to-one, several merged | {sender}, {count}, {content} | {sender} | [{count}条] {content} |
message.group | Group message | {group}, {sender}, {content} | {group} | {sender}: {content} |
message.group_merged | Group message, several merged | {group}, {count}, {sender}, {content} | {group} | [{count}条] {sender}: {content} |
message.group_mention | Group message mentioning the user | {group}, {sender}, {content} | {group} | [有人@我] {sender}: {content} |
message.group_system | Group message sent as the system | {group}, {content} | {group} | {content} |
message.single_sender_only | One-to-one message with preview mode "sender only" | {sender} | {sender} | 发来一条新消息 |
message.group_sender_only | Group message with preview mode "sender only" | {group}, {sender} | {group} | {sender} 发来一条新消息 |
message.hidden | Message with preview mode "none" | None | Empty | 你收到了一条新消息 |
content.image, content.voice, content.video | Summary of image, voice and video messages, i.e. {content} | None | — | [图片], [语音], [视频] |
content.file | Summary of file messages | {file_name} | — | [文件] {file_name} |
content.location | Summary of location messages | {location_name} | — | [位置] {location_name} |
content.custom, content.unknown | Summary of custom and other messages | None | — | [消息] |
name.deleted_user | {sender} when the sender was deleted | None | — | 已删除的用户 |
name.unnamed_group | {group} when the group has no name | None | — | 群聊 |
name.system | {sender} when sent as the system | None | — | 系统 |
recall.single | Notification after the sender recalls a one-to-one message | {sender} | {sender} | 撤回了一条消息 |
recall.group | Notification after the sender recalls a group message | {group}, {sender} | {group} | {sender} 撤回了一条消息 |
recall.removed | A message recalled by someone else, or preview mode "none" | None | Empty | 一条消息已被撤回 |
friend.request | Friend request received | {sender} | {sender} | 请求添加你为好友 |
friend.accepted | Friend request accepted | {sender} | {sender} | 已同意你的好友申请 |
friend.added | Added as a friend directly | {sender} | {sender} | 已添加你为好友 |
group.application | Someone requests to join | {group}, {target} | {group} | {target} 申请加入群聊 |
group.invite_review | A member's invitation awaits approval | {group}, {inviter}, {target} | {group} | {inviter} 邀请 {target} 加入群聊,等待审批 |
group.invitation | Group invitation received | {group}, {inviter} | {group} | {inviter} 邀请你加入群聊 |
group.removed | Removed from a group | {group} | {group} | 你已被移出群聊 |
group.dismissed | Group dissolved | {group} | {group} | 群聊已解散 |
notice.hidden | Friend and group notices with preview mode "none" | None | Empty | 你收到了一条新通知 |
call.audio, call.video | One-to-one voice and video calls | {sender} | {sender} | 邀请你语音通话, 邀请你视频通话 |
call.group_audio, call.group_video | Group call invitations | {group}, {sender} | {group} | {sender} 邀请你加入语音通话, {sender} 邀请你加入视频通话 |
call.missed, call.canceled | Missed call, caller cancelled | {sender} | {sender} | [未接来电], 对方已取消通话 |
call.hidden | Incoming call with preview mode "none" | None | Empty | 你有一个新的来电 |
call.missed_hidden | Missed or cancelled call with preview mode "none" | None | Empty | 你有一个未接来电 |
test | Test push | None | 测试推送 | 这是一条测试推送,收到说明推送配置正确 |
The built-in text above is the Simplified Chinese version; English and Traditional Chinese are also built in. Placeholders: {sender} is the nickname of the sender (or requester, or caller), or the username if there's no nickname; {group} is the group name; {content} is the message summary; {count} is how many were merged; {inviter} and {target} are the nicknames of the inviter and of the person invited or requesting to join; {file_name} and {location_name} are the file name and location name. Extra whitespace around placeholders that end up empty is removed. content.* and name.* only use the text, which is substituted into other templates' placeholders.
Titles and text your server gives in push when sending a message don't use templates; see The push field when sending messages.
Push stats
"Push stats" counts pushes by date, channel, category and result:
- Range: choose a date range within the last 180 days, up to 92 days at a time. Dates follow Beijing time, and the page shows the statistics time zone; today's data updates continuously.
- Filters: by channel and category. Categories are messages, friend and group notices, calls, clearing call notifications, updates after recall, and test pushes.
- Summary: the top shows totals for the main results in the range: accepted by channel, failed, invalid token, credential paused, over push quota, online in foreground, Do Not Disturb, and no devices.
- Details: each row is the count for one date, channel, category and result; combinations with no pushes aren't shown. Results where no token was chosen (such as online in foreground, Do Not Disturb, no devices) show
-as the channel.
For what each result means and how it's counted, see Push stats and troubleshooting. A few ratios worth watching:
- A sudden rise in invalid token usually means a newly uploaded credential doesn't match the app's environment or package.
- Persistent failed results: check the matching credential's last error, or send a test push to see the channel's error code.
- Over push quota means the app reached its per-minute push limit; contact us if you need it raised.
- A clearly low share of online in foreground may mean the app doesn't report its state when going to the background; a clearly high share while users say they get no alerts may mean the background report isn't arriving.
A user's push devices and settings
Open a user in "IM users"; the "Push" tab shows:
Devices registered for push:
| Column | Description |
|---|---|
| Device | The platform and device ID |
| Online | Online in foreground, background or offline. Devices online in the foreground aren't pushed to |
| Tokens | Each token's position (#1 and #2 are the order of regular tokens, VoIP the VoIP token), its credential and channel, the masked token, and the credential's status: available, credential disabled, credential paused or credential deleted |
| Language | The language the device registered; "Default" if none, using the app's default language |
| Badge | The device's current badge count |
| Signed in | When this sign-in happened |
- Unbind: deletes the device's push registration, so it stops getting this user's pushes immediately. The sign-in isn't affected, and the app re-registers on its next start. Use it for issues like "this phone got someone else's pushes", or to make the app re-register while troubleshooting; to stop a device getting pushes for good, sign it out under "Devices".
- Send test push: sends a test push to every device of this user registered for push, using each device's first available token, with the same rules as Test pushes.
An empty device list means the app hasn't registered push on any device: the app doesn't call registration, the user turned off notifications in the app or system settings, they're signed out, or they only sign in on platforms that can't register push, such as the Web.
Push settings: global Do Not Disturb (off, until a time, or always on), night Do Not Disturb (hours and time zone) and preview mode (showing the app's default when the user hasn't chosen). Click "Edit" to change them for the user:
| Item | Description |
|---|---|
| Global Do Not Disturb | Off; for a while (hours from now); always on |
| Night Do Not Disturb | Off, or on with start and end times (HH:MM) and a time zone |
| Preview mode | App default, show sender and content, show sender only, show nothing |
Conversation Do Not Disturb: one-to-one chats and groups the user muted, how (no push, or push only when mentioned) and when it expires. Click "Lift" to restore normal pushes for that conversation.
After a change, the user's online devices sync the new settings immediately. Servers can also manage these settings and devices through OpenAPI; see Push devices and settings.
Troubleshooting missing pushes
When a user says they're not getting pushes, check in this order:
- Devices: look at their devices in the user's "Push" tab. If there are none, see the reasons above; if a device shows "Online in foreground" while the app is actually in the background, the app isn't reporting the background state; if a token's credential status isn't "available", look at that credential under "Push credentials".
- Do Not Disturb: check push settings and conversation Do Not Disturb, minding the night Do Not Disturb time zone.
- Test push: click "Send test push" and look at each device's result.
- Credential: check the matching credential's last error and paused state under "Push credentials".
- Stats: look at the distribution of pushes over the period by channel and result under "Push stats".
Common results in test pushes and stats:
| Result | Common causes | What to do |
|---|---|---|
Accepted by channel sent | The channel accepted the push, but whether the device shows it is up to the device | If it doesn't show, check whether the app's notifications are off in system settings, whether Android created the notification channel configured in the credential, whether the Chinese maker's message category was applied for, and whether today's quota is used up |
Invalid token invalid_token | The app was uninstalled or the token expired; or the token doesn't match the credential: an iOS development build's token sent with a production credential (or the reverse), a package or Bundle ID different from the credential's, or a token from another Firebase project | Check the credential's environment and package, and have the app re-register with the right credential name |
Failed failed, error code network_error or timeout | The server failed to reach the push channel | Usually a temporary network problem; real pushes are retried twice automatically; contact us if it persists |
Failed failed, other error codes | The channel rejected this push, with an error code from the channel, such as APNs's BadDeviceToken | Follow the channel's docs; for authentication errors, check the secret and whether the certificate expired |
Credential unavailable credential_unavailable | All credentials of the device's tokens are disabled or deleted; or, when testing with a credential, the device didn't register a token with it | Enable the credential, or have the app re-register with an available credential |
Credential paused channel_paused | The credential is paused for a channel rate limit, a used-up daily quota or similar | See Paused credentials |
Do Not Disturb skipped_dnd | The user's Do Not Disturb blocked the push | Confirm it's the user's own setting |
Online in foreground skipped_online | The device is in the foreground and the message arrived over the connection | Nothing to do |
Push disabled skipped_disabled | The platform turned off the global "maker offline push" switch in the platform console, so all maker pushes stopped | Ask the platform admin to turn it back on |
