In this post we'll look at how you can easily get up and running with our pre-built notification feed component and what the advantages are of using Knock to power your notifications.

What's an in-app notification feed and why would you want one?

An in-app notification feed lets your users see activity that's relevant to them, surfaced within the product itself. You've probably seen or used a notifications feed in a product in the past, and typically it looks like a badge letting you know how many unread items you have, and a feed in reverse chronological order (with newest items first) describing an action that occurred and who performed the action.

An example of an in-app notifications feed component in Notion

Notification feeds are essential in collaboration or workflow based products, but they are also broadly applicable in any product where work can happen asynchronously and your customers should be made aware of things they have missed.

However, building your own feed is a time consuming endeavor for a team, especially when you're concerned with delivering a best-in-class experience for your customers. You'll need to setup real-time socket infrastructure, build out API endpoints, and put together a great UI. That's where Knock can help: we have a pre-built in-app feed component and a backend to power your feed experience to accelerate the time to market for your notifications build.

Why use Knock?

Knock provides you an out-of-the-box experience for in-app and out-of-app notifications across push, SMS, and email (with more to come!). Leveraging our notification engine and pre-built components gives you:

  • Centralized templating. With Knock your notification templates don't need to live in your backend codebase. They are editable via our template editor and are completely version controlled so changes can be confidently made and tested before being pushed to production. No more JIRA tickets for notification copy updates!
  • A best-in-class notifications experience. We support advanced notification use-cases like batching ("Chris, Sam, and 3 others commented on ...") as well as delays and channel fallbacks (send to email if they didn't see the in-app message). It's your entire notification roadmap, delivered for you and ready to go.
  • Real-time out-of-the-box. We use web sockets to provide real-time updates to your users, including delivering new notifications and updating the badge count for the number of unread messages. All of this is taken care of for you.
  • A robust, pre-built notifications model and API. We've already done all the hard work of designing and creating a robust notifications model, complete with read, seen, and archive statuses, available via a RESTful API and SDKs in all major languages.
  • Entirely customizable. You can use our components as they come to get up and running quickly, or you can use us in a "headless" capacity to power a completely customized notifications experience.
  • Typed and ready to integrate. Our feed component ships with a full set of types so that you can easily integrate into your existing TypeScript project. It's written using React, Zustand, and Axios.

Getting up and running

Here's an example of what the Knock in-app feed component looks like, taken from the Knock dashboard where we use the in-app component to power notifications within Knock.

An example of the Knock notifications feed, within the Knock dashboard

Install the component

The first step is to install the component:

yarn add @knocklabs/react-notification-feed

Add to your application

Next we need to add the feed component to our application, typically in the application-wide header or layout file.

import {
  KnockFeedProvider,
  NotificationIconButton,
  NotificationFeedPopover,
} from "@knocklabs/react-notification-feed";

// Import the default CSS styles
import "@knocklabs/react-notification-feed/dist/index.css";

const YourAppLayout = () => {
  const [isVisible, setIsVisible] = useState(false);
  const notifButtonRef = useRef(null);

  return (
    <Header>
      <KnockFeedProvider
        apiKey={process.env.KNOCK_PUBLIC_API_KEY}
        feedId={process.env.KNOCK_FEED_ID}
        userId={currentUser.id}
      >
        <NotificationIconButton
          ref={buttonRef}
          onClick={(e) => setIsVisible(!isVisible)}
        />
        <NotificationFeedPopover
          buttonRef={buttonRef}
          isVisible={isVisible}
          onClose={() => setIsVisible(false)}
        />
      </KnockFeedProvider>
    </Header>
  );
};

You can see here that we need 3 pieces of information in order for the feed to render:

  1. apiKey: The public API key found in your Knock dashboard
  2. feedId: The ID of the feed channel configured to receive in-app notifications, again can be found in your Knock dashboard
  3. userId: The ID of the current, logged in user so we know which feed to fetch (note: this ID must match what you're passing to Knock in your notify and identify calls)

Triggering notifications

Knock needs two things to be able to send notifications to your users:

  1. Information about your users (via identify calls)
  2. Notification triggers (notify calls) to tell Knock when to trigger a workflow, and who to send the notification to

Both of these need to be integrated into the backend of your codebase. You'll find SDKs available for Ruby, Python, NodeJS, and Elixir. Or, alternatively you can get started by using our Postman collection and calling the API directly.

For an example of identifying a user and triggering a notification, see below:

const { Knock } = require("@knocklabs/node");
const knock = new Knock(process.env.KNOCK_API_KEY);

// Identify the user to Knock, upserting them if they don't already exist
await knock.users.identify(user.id, {
  name: user.name,
  email: user.email,
  avatar: user.avatar_url,
});

// Trigger the workflow which will send notifications for one or more recipients
await knock.notify("new-user-invited", {
  // The user who performed the action
  actor: user.id,
  // The list of recipient user ids
  recipients: recipientUserIds,
  // Data to be passed to the template
  data: {
    inviteeNme: "Jane Doe",
    inviteeEmail: "jane.doe@example.com",
    inviteeRole: "member",
  },
});

You can read more about the work involved in integrating Knock in our documentation.

Securing the feed 🔐

To ensure a user's feed can only be accessed by the user who owns the feed, we require that you secure your calls with a JWT signed against a specially generated private key that only you have (we keep the public key) to be used in the Knock JS client.

Sign a JWT for the current user

You'll first need to generate an application signing key from your Knock dashboard and you'll need to pass the private key as the signing key token for the JWT algorithm:

// Signing a JWT for the user in a NodeJS backend using express-style middleware
const jwt = require("jsonwebtoken");

app.use((req, res, next) => {
  const currentTime = Math.floor(Date.now() / 1000);

  res.locals({
    knockToken: jwt.sign(
      {
        // The user we're signing the token for
        sub: req.user.id,
        iat: currentTime,
        // The expiration of the token (24 hours)
        exp: currentTime + 60 * 60 * 24,
      },
      process.env.KNOCK_SIGNING_KEY,
      {
        algorithm: "RS256",
      }
    ),
  });
  next();
});

Pass the user token to the feed provider

Next, once you've generated the JWT you'll need to pass it to your client and use it within the feed provider:

// Passing to the Knock feed provider
<KnockFeedProvider userToken={currentUser.knockUserToken}>

You're now ready to go to production with a secure, real-time notification feed!

Customizing the feed

Out of the box the Knock in-app feed looks great, but you'll often want to ensure that this component matches your visual identity and that means customizing the component's look and feel. Fortunately, you have a few options here for how to make the component feel truly at home in your product:

  • Customize the theme variables. The component uses CSS variables for colors, sizes, and typography which you're able to override to better match your styles.
  • Override the CSS. When customizing the CSS variables alone isn't enough, you can opt to override the styles associated with the component entirely. It's probably easiest here to follow the stylesheet generated with the component so you can see the class names to target
  • Render custom components. If you need an extra degree of control with the component, you can opt-out of Knock's components partially or entirely and take rendering into your own hands. If you're opting the do the latter here, we expose a state store based on Zustand which you can use to power your notification feed.

If you're looking for some design help for your notification feed, our Figma community component is a great place to start.

Advanced use cases

From here it's easy to start building the ideal notifications experience for your customers, all available within Knock:

  • Multi-channel fallbacks. User didn't see the in-app notification in the last hour? Escalate to different channels like push, SMS, or email (with chat support for Slack and MS Teams coming soon).
  • Preferences. We manage your users' notification preferences for you and automatically apply preferences when executing notifications for a user. Read more in our documentation.
  • Batched notifications. Often seeing multiple notifications being fired together? Easily add batching to your messages so that multiple notifications get grouped as one.

Read more

And if you're looking to integrate a notification feed into your product immediately, sign up for the Knock waitlist below and we'll get you setup.