Designing and Building A Minimally Viable Notification System
When setting out to build Hikearound, I knew that a key part of the product would center around a notification system, the purpose of which would be to keep existing users up-to-date and as well as to re-engage them.
Because I chose to build Hikearound largely as a native product with a streamlined web presence, this also meant that its notification channels would primarily be either (a) emails, or (b) push notifications.
Establishing a baseline
Before building anything, I went through an exercise exploring what types of use-cases Hikearound’s notification system would need to support. Some of the candidate notifications I felt would be necessary to have ready when the product launched included:
- A welcome email which would be sent to users after they signed up and which would also be used to verify their email address
- A reset password email which would be sent to users locked out of their accounts
- A hiking digest email and paired push notification which would be sent to users on a scheduled basis to let them know about new hikes or content that had been added near them
- A ‘review like’ push notification which would be sent to users who had previously reviewed a hike which then received a like from another user
This list seemed like a good starting point which balanced both the functional needs of users as well as the need of the product to keep users engaged.
Under the hood
At a technical level, because Hikearound’s data is stored in a Firebase Cloud Firestore, this meant that I could build the notification system atop Firebase Cloud Functions. Cloud Functions, in a simplified definition, fire triggers in response to certain events within a database, and allow the subsequent execution of code using metadata associated with those events.
In the example below, every time a new document is created in Hikearound’s user table, Firebase grabs the ID of that new user account and then executes code which sends them a welcome email.
In addition to triggering notifications in response to an event, it’s also possible to set certain notifications to send on a scheduled basis. In the example below, the hike digest email and its paired push notification attempt to send every Friday morning at 9:00AM PST (assuming there have been new hikes or content added near a given user).
Defining a notification
Every Hikearound notification is, at its simplest, a function which specifies a unique notification type and which builds a data object in JavaScript with common fields. Depending on the type of notification, that data object is then either injected into an email template or chunked and sent to a user’s mobile app as a push notification using a series of common utility functions.
Additionally, push notifications sent to the mobile app are also saved to a separate Cloud Firestore notification table and can be viewed independently from the app’s Notification tab.
In the example below, which is the code block that builds a data object for Hikearound’s new user welcome email, you can see how simplistic the core of each notification really is.
Focusing on email
Having previously worked on email and notification systems at both Nextdoor and Quora, one thing I did want to focus on was ensuring that the email templates I used for Hikearound were able to utilize a common set of components. I’ve found myself in situations in the past where email systems become overly complex, difficult to maintain, and the templates for individual emails fall out of sync with one another. That was something I aimed to avoid here.
To solve for this, I utilized the MJML email framework to build a shared set of customizable components that all Hikearound emails draw from. What that looks like in practice is that all emails inherit from a base template which looks like this:
Within each email, unique components get compiled in a special type file unique to that notification while common components, like headers, remain the same across all emails:
Because email components are also customizable, it’s possible to configure them differently based on the type of email being sent. For example, emails can be configured with either a (a) global unsubscribe link, or (b) a global unsubscribe link paired with a specific type unsubscribe link.
For transactional emails like the one sent to new users, it doesn’t necessarily make sense to allow users to unsubscribe from that specific type of email since they’ll only receive it once. In cases like that, the unique unsubscribe link gets hidden in lieu of showing only the global unsubscribe link.
Empowering users
Relatedly, any good notification system should seek to provide users control over the types of notifications they receive. The Hikearound notification system is no exception, and takes into account a user’s notification preferences before sending any email or push notification.
In the example below, before any email is sent to a user, the system checks if (a) they have a verified email address, (b) whether they have disabled emails globally, and (c) if they disabled the type of email the system is attempting to send them.
Every push notification that gets sent to users routes through the same type of check. From the settings screen in the mobile app, users can always re-enable any email or push notification they previously disabled.
Returning to our email example from earlier, assuming a user has not unsubscribed from a specific type of email or from all emails, data from the notification’s data object is injected into an email template, the template is compiled into cross-client compatible HTML, and that HTML is sent to the user through the Mailgun API.
Targeting mobile
As for push notifications which are primarily text-based, building and sending them is a lot easier!
For Hikearound notifications that support push notifications, if a user has enabled notifications in the Hikearound app, the notification system takes that users notification token and sends a bundled data object via Expo’s Node.js SDK.
This is also the point where the system writes the notification to a separate Firebase Firestore table and aggregates the number of unread notifications for a given user so that the app’s iOS icon and the in-app notification tab icon can both be labeled with an unread notification badge.
Because Hikearound is a mobile first product, certain links embedded within emails are deep-linked directly into the Hikearound iOS app. In the hike digest email for example, if a user is on a mobile device with Hikearound installed, clicking on a link within the email will push them directly to the correct screen within the app rather than route them to the Hikearound website.
A little something extra
Not because I felt it would be necessary as a part of an MVP, but only because I thought it would be fun to build, all Hikearound emails also render in dark mode for supported email clients.
Wrapping it all up
More than anything, what I was trying to accomplish in building this system was to make it powerful without also making it overly complex, and to build it in such a way where it will be easy to expand in the future.
In terms of fulfilling a series of core use-cases as well as allowing users detailed control over the types of notifications they receive, I’m happy with how it turned out and excited to continue improving it.
Give Hikearound a try for yourself and download the app today by visiting tryhikearound.com. Happy trails!