How we are sending notifications easy with Novu
Midday is all about being on top of your business. Stay informed about your business insights, track when you get paid, receive updates on new transactions, and access general information how your business actually are doing. And that includes well-timed notifications via emails and push notifications, carefully curated for your convenience.
The challenge: Implementing a unified infrastructure for notifications
From the beginning, we knew the importance of a unified approach to managing our notifications. From past experiences of stitching together different solutions to support various notification needs, we were determined to create a system that could seamlessly support web, desktop, and mobile applications. Our goal is to ensure that our notification system can scale alongside our growth.
The solution: Novu
While we tried a bunch of different providers we decided to go with Novu based on our requirements:
- Support Resend, Expo
- In App notifications
- User Preferences
Novu not only ticked every box they also got a huge bonus for being open source and you get 30K events/month for free.
Implementation and SDKs
We started with created our own package @midday/notifications
where
we installed @novu/node
dependency, where we register our notification
types for convenience:
// Our notification templates
export enum Templates {
Transaction = "transaction",
Transactions = "transactions",
Inbox = "inbox",
Match = "match",
}
// Our notification types (email|in-app)
export enum Events {
TransactionNewInApp = "transaction_new_in_app",
TransactionsNewInApp = "transactions_new_in_app",
TransactionNewEmail = "transaction_new_email",
InboxNewInApp = "inbox_new_in_app",
MatchNewInApp = "match_in_app",
}
And using our New Transactions email as an example, which is sent from a background job using Trigger.dev when you have new transactions.
import { Notifications, Types, Events } from "@midday/notifications";
// Generate html from react-email
const html = await renderAsync(
TransactionsEmail({
fullName: user.full_name,
transactions,
locale: user.locale,
})
);
await Notifications.trigger({
name: Events.TransactionNewEmail,
payload: {
type: Types.Transaction,
subject: t("transactions.subject"),
html,
},
user: {
subscriberId: user.id,
teamId: team_id,
email: user.email,
fullName: user.full_name,
avatarUrl: user.avatar_url,
},
});
Because we are sending the email with the variables subject
and html
with the generated content we are just adding those to Novu and then we're done.
And to send In App Notifications it's just a matter of changing the Events
and
Types
.
import { Notifications, Types, Events } from "@midday/notifications";
await Notifications.trigger({
name: Events.TransactionNewInApp,
payload: {
recordId: transaction.id,
type: Types.Transaction,
description: t("notifications.transaction", {
from: transaction.name,
}),
},
user: {
subscriberId: user.id,
teamId: team_id,
email: user.email,
fullName: user.full_name,
avatarUrl: user.avatar_url,
},
});
The results: Beautiful In App Notificaitons and Emails
Thanks to the SDK @novu/headless
we implemented the notification center for Midday
in a matter of hours to match our branding exacly like we wanted while Novu delivers
the notifications in realtime.
And for user preferences we just use their API together with a simple server action.
The future of Midday x Novu
We are really happy that we chose to use Novu, We have several smart notifications planned that will offer valuable business insights. Plus, Novu will integrate smoothly with our upcoming mobile app, allowing us to send push notifications effortlessly via Expo by just connecting a new provider.
GitHub
While this is just a draft on how we are using Novu in production you can dig deeper into the codebase in our repository.