Notifications
Notifications are short in-app messages to one signed-in person, shown under the bell in the admin and member areas. Each type can also go out by email, and people can turn that email off for the types that allow it.
What it is
A notification is one document in Notifications, addressed to one person by their Firebase Auth uid. It has a type, a title, a body and an optional link. Arc CMS creates them for these moments:
| Type | Goes to | When |
|---|---|---|
admin_new_signup | Every admin | A user record is created, except an account an app made (by: 'app', see App accounts) |
admin_new_feedback | Every admin | Someone sends feedback (see Feedback button) |
admin_contact_message | Every admin | Someone writes with the contact form on the site; at most ten an hour, and none for possible spam (see Contact form) |
admin_payment_received, admin_payment_failed | Every admin | A customer's payment goes through or fails |
payment_succeeded, payment_failed | The paying user | Their payment goes through or fails (see Payments) |
account_security | The user | Their email or phone number was verified on another account and removed from theirs |
admin_account_detached | Every admin | An account lost its only sign-in method to another account |
admin_sign_in_setup | Every admin | A phone sign-in failed because the Google Cloud setup is missing; at most once a day (see Sign-in methods) |
announcement | The users an admin picks: everyone, a role, or lists | An admin sends an announcement, with the Email marketing feature on (see Email marketing) |
| Any type | The event's user | A rule in Automations creates one |
The type registry in Settings/notification_types describes each type: its label and description, its category (transactional or marketing), whether it is also emailed, and whether people can turn its email off.
Turn it on or off
Notifications are always on: they are core, not a switchable feature. The in-app part cannot be turned off. The email part can, in three places:
- per type, with the Email switch on the Notification types tab of Email, Announcements, then Save types (that page comes with the Email marketing feature; without it, set
defaultChannels.emailon the type inSettings/notification_types); - for every type at once, with the Notification emails switch under Email Features on Admin, Settings, Email Settings (see Email engine);
- for admin alerts only, with the Admin alerts switch on the same page, which stops the admin notifications themselves, in-app as well.
Set it up
Nothing to set up. The type registry is filled with the built-in types the first time someone opens their notification preferences, or when an admin opens Email, Announcements (Email marketing feature). Until then, the built-in defaults apply. The email copy needs a working Email engine.
Use it
The bell
The bell sits at the right of the page header on admin pages and on the member pages. Its badge counts the unread notifications among the 30 most recent, and shows 9+ above nine. Click it to open a panel with the 10 most recent:
- Click a notification to mark it read and open its link.
- Mark all read marks the unread notifications read, up to 200 at a time.
- View all notifications opens the full list:
/admin/notificationsfor admins,/notificationsfor members.
The notifications page
The page lists the 100 most recent notifications. Under Email preferences, below the list, each type whose email people may turn off has a switch: turn it off and click Save preferences, and that type stops coming by email (it still shows in the app). The same page serves admins and members.
When a notification is also emailed
When a notification is created, the onNotificationCreate function decides whether to email it. It is emailed only when all of these hold:
- the sender asked for email (an announcement sent without Also send email stays in-app);
- the type is in the registry or is a built-in type, and its email channel is on;
- the person has an email address on their user record;
- the person has not turned that type's email off (types they may configure only);
- the Notification emails switch is on;
- the type's email template exists;
- the email engine lets it through: the master switch, an active template, the contact not disabled, consent for marketing types, and the suppression list (see Email engine).
The email uses the notification_generic_email template, filled with the title, body and link. The outcome is written on the notification as emailDelivery, with a skippedReason when it was not sent.
People's email choices are stored on their contact record (Contacts, field notificationPrefs), which only Cloud Functions can write. The page reads and saves them through the getMyNotificationPrefs and updateMyNotificationPrefs functions.
Extend it
Create a notification from your Cloud Functions in functions/src/custom/. The browser cannot create one.
import { createNotification } from '../email-core/notifications.js';
await createNotification({
userId: uid, // the person's Firebase Auth uid
type: 'order_shipped', // a type in the registry
title: 'Your order has shipped',
body: 'It should arrive on Friday.',
link: '/user/dashboard', // optional
});
A new type needs an entry under types in Settings/notification_types, or it stays in-app only (its email is skipped as unknown_type):
"order_shipped": {
"label": "Order shipped",
"description": "Your order is on its way.",
"category": "transactional",
"defaultChannels": { "inApp": true, "email": true },
"userConfigurable": true,
"enabled": true
}
Set emailTemplateType on the type to email it with your own template instead of notification_generic_email. To send to every admin, use notifyAdmins(type, { title, body, link }) from functions/src/email-core/adminAlerts.ts. It creates nothing while the Admin alerts switch is off.
If an admin, not your code, should decide whether something notifies people, emit an event and let them add a rule in Automations.
What it stores
| Where | Holds |
|---|---|
Notifications | userId, type, title, body, link, read, readAt, createdAt, createdBy, emailDelivery, and when set icon, announcementId, suppressEmail |
Settings/notification_types | The type registry |
Contacts (notificationPrefs) | Each person's per-type email choices |
A user's notifications are deleted with their account. The functions: onNotificationCreate (Firestore trigger), getMyNotificationPrefs and updateMyNotificationPrefs (callables, signed in). See Data model and Cloud Functions.
Who can do what
| Who | Can |
|---|---|
| Signed-in person | Read their own notifications; change only read and readAt on them; read and save their own email choices through the callables |
| Admin | Read every notification; read and write Settings/notification_types |
| Nobody from a browser | Create or delete a notification. Only Cloud Functions do. |
Troubleshooting
| You see | Why, and what to do |
|---|---|
| The notification shows but no email came | Read emailDelivery.skippedReason on the notification: suppressed_by_sender (an announcement sent without email), unknown_type, type_channel_off, no_email, user_pref_off, feature_disabled, no_template, or an email engine reason (email_disabled, template_inactive, contact_disabled, unsubscribed, suppressed). With emailLogId, the email log has the rest. |
| The bell badge says 9+ but there are more | The badge counts only the 30 most recent notifications and stops at 9+. The notifications page lists up to 100. |
| A member's notification list is empty | The notification's userId must be their Firebase Auth uid, not their user record id. |
| No admin gets alerts | The Admin alerts switch under Email Features is off. |