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:

TypeGoes toWhen
admin_new_signupEvery adminA user record is created, except an account an app made (by: 'app', see App accounts)
admin_new_feedbackEvery adminSomeone sends feedback (see Feedback button)
admin_contact_messageEvery adminSomeone 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_failedEvery adminA customer's payment goes through or fails
payment_succeeded, payment_failedThe paying userTheir payment goes through or fails (see Payments)
account_securityThe userTheir email or phone number was verified on another account and removed from theirs
admin_account_detachedEvery adminAn account lost its only sign-in method to another account
admin_sign_in_setupEvery adminA phone sign-in failed because the Google Cloud setup is missing; at most once a day (see Sign-in methods)
announcementThe users an admin picks: everyone, a role, or listsAn admin sends an announcement, with the Email marketing feature on (see Email marketing)
Any typeThe event's userA 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:

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:

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:

  1. the sender asked for email (an announcement sent without Also send email stays in-app);
  2. the type is in the registry or is a built-in type, and its email channel is on;
  3. the person has an email address on their user record;
  4. the person has not turned that type's email off (types they may configure only);
  5. the Notification emails switch is on;
  6. the type's email template exists;
  7. 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

WhereHolds
NotificationsuserId, type, title, body, link, read, readAt, createdAt, createdBy, emailDelivery, and when set icon, announcementId, suppressEmail
Settings/notification_typesThe 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

WhoCan
Signed-in personRead their own notifications; change only read and readAt on them; read and save their own email choices through the callables
AdminRead every notification; read and write Settings/notification_types
Nobody from a browserCreate or delete a notification. Only Cloud Functions do.

Troubleshooting

You seeWhy, and what to do
The notification shows but no email cameRead 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 moreThe 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 emptyThe notification's userId must be their Firebase Auth uid, not their user record id.
No admin gets alertsThe Admin alerts switch under Email Features is off.