Introducing Puppygram, Powered through Courier Inbox, Subsequent.js, and Inngest


An in-app notification middle is a vital part of any trendy app, however they are time-consuming and sophisticated to construct from scratch. What if you wish to release one thing temporarily and simply? The place do you get started?  

I determined to make use of Courier Inbox to construct one thing mild years clear of a product inbox. I assumed hard and long about what to construct and, most likely sensing my ingenious block, my canine Otto got here up and requested for his afternoon stroll.

Otto photo

And identical to that, Puppygram used to be born! Puppygram is an Instagram clone this is constructed for iOS and is powered through Courier Inbox, Subsequent.js, and Inngest. On this weblog publish we’re going to hide:

  • Making a recent Subsequent.js internet software
  • Configuring Courier to ship Inbox notifications
  • Fetching random photos of lovely canines the use of the random.canine API
  • The usage of Inngest to ship a brand new canine notification to our Inbox each and every minute
  • Growing the Puppygram iOS revel in the use of the Courier iOS SDK

There are a couple of necessities for finishing this instructional:

  • Node.js
  • Xcode for Mac
  • Courier and Inngest accounts

After we’re completed, we will have an app that appears like this:

Puppygram screenshot

You’ll to find the whole supply code for the Puppygram Server and Puppygram iOS app on GitHub and a are living demo of this app hosted on Vercel.

Making a Subsequent.js Internet Utility

With a purpose to construct a Subsequent.js app, you’ll want to have Node.js put in. My choice in this day and age is to make use of NVM (Node Model Supervisor) to put in Node.js. It makes it simple to put in a couple of variations of Node.js and turn between them for your tasks.

If you’ve put in Node.js, open up a terminal and run the next command to put in Subsequent.js:

npx create-next-app@newest

You’ll be induced to respond to a number of questions, nevertheless it’s effective to stick with the defaults. As soon as this procedure is entire, a brand new listing will likely be created and loaded with all the default information for this app.

Turn out to be this new listing and create a .env.native report to retailer secrets and techniques for Courier and Inngest. We’ll populate this report whilst we’re development and trying out on localhost, and also you’ll simply want to bear in mind to duplicate those setting variables to no matter platform or infra you deploy your app to.

Get Courier API Credentials

Log in in your Courier account, click on at the tools icon, after which API Keys. Whilst you create a Courier account, two Workspaces are routinely created for you: one for trying out and one for manufacturing. Each and every workspace has its personal set of information and API keys.

For simplicity, we’re going to stick with the “manufacturing” workspace. Reproduction the “revealed” manufacturing API Key and paste into into .env.native the use of the next key:


Configure Your Courier Inbox Supplier

Click on on “Channels” within the left nav. Channels constitute the other mediums {that a} person can obtain a notification on. Courier helps all the most well liked channels, together with SMS, e-mail, cell push, and others. For each and every channel, you’ll see a listing of Suppliers. For example, Courier helps a couple of SMS suppliers, together with Twilio, MessageBird, and Vonage simply to call a couple of.

In our case, scroll down and choose the “Courier Inbox” supplier. When the web page opens, scroll to the ground and click on “set up”. You at the moment are in a position to ship notifications to the “inbox” channel the use of the “Courier Inbox” supplier.

Making a Public Inbox

Courier Inbox is basically designed to show notifications to person customers, however in our case, the Inbox and its content material will likely be seen through somebody the use of the app. Nonetheless, we want to create a “person” to ship those notifications to, so click on on “Customers” within the left navigation and create a brand new person.

The one required box is user_id, so simply cross forward and input puppygram and click on “Save”. On your .env.native, create the next variable:


Get Inngest Credentials

Inngest is a workflow-as-code carrier that makes it simple to construct dependable serverless workflows for your present codebase, with none new infrastructure. We’re going to make use of Inngest to create a cron activity that sends pet pics to our app as soon as each and every minute.

Log in in your Inngest account and click on on “Organize” within the best nav. Click on on “Tournament Keys” within the subnav.

Tournament Keys are used to package an identical occasions. This is helping when navigating the Inngest dashboard, debugging, and so on. The advice is that you simply create a brand new Tournament Key for each and every aggregate of setting and alertness. In our case, we’re simply going to make use of the “Default ingest key”, however you’ll simply create new Tournament Keys to make use of. Reproduction the price for this key and paste it into your app’s .env.native report:

Subsequent, click on on “Signing Key.” The Signing Secret is utilized by the Inngest SDK to safely be in contact along with your software. Reproduction the price for this key and paste it into your app’s .env.native report:


Let’s Get started Coding!

K, now that we have got our products and services and configuration out of the way in which, let’s dive into the code. We’re going to begin through development the server-side internet software this is accountable for sending photos of domestic dogs to our iOS app. Our internet software will likely be designed to:

  • Get up as soon as a minute
  • Make a selection a random image of a canine
  • Ship an inbox notification with the URL of the image of the random canine

The usage of Inngest To Time table Jobs

With only some strains of code, we’re going to twine up our internet software to Inngest in order that the carrier can name into our software as soon as a minute to cause a brand new notification to our Courier Inbox. We’re going to breeze via their Fast get started, which you’ll overview in additional element later.

Within the root of your undertaking, run the next command to put in the Inngest SDK:

Create a brand new listing referred to as inngest for your undertaking root. Create a report referred to as shopper.js on this new listing:

import { Inngest } from "inngest";

// Create a consumer to ship and obtain occasions
export const inngest = new Inngest({ identify: "Puppygram Subsequent.js" });

Now create a direction handler to take care of the /api/inngest direction. Create a listing in app referred to as api and a listing in api referred to as inngest. Create a report referred to as direction.js:

import { serve } from "inngest/subsequent";
import { inngest } from "../../../inngest/shopper";

export const { GET, POST, PUT } = serve(inngest, []);

In any case, let’s create an Inngest serve as that prints “Hi Puppygram” each and every minute. Edit direction.js and paste this serve as slightly below the imports:

export const sendNotification = inngest.createFunction(
    { identify: "Puppygram Ship Notification" },
    { cron: "* * * * *" },
    async () => {       
      console.log(“Hi Puppygram!”)

Now, replace the serve name on the backside of the report to incorporate this new Inngest serve as that has been created:

export const { GET, POST, PUT } = serve(inngest, [

On your terminal, cross forward and get started your internet software:

Open up some other terminal and run:

npx inngest-cli@newest dev

This will likely execute a localhost model of the Inngest carrier. This will likely attach in your internet software (working on port 3000) and start executing your cron activity. Return to the terminal you introduced your internet app in, and each and every minute you must see this printout:

Getting Footage of Random Canine

Due to our buddies on the Random Canine API, we’ve a carrier that we will be able to use to get photos of very lovely, very random canines. The API helps 3 other endpoints:

  • /woof – Go back the ID of a random canine
  • /woof.json – Go back a JSON payload of a random canine
  • /doggos – Go back JSON array of all canine IDs

Since our carrier goes to get up as soon as a minute to ship a notification with an image of a random canine, we didn’t wish to burden this unfastened carrier with all the ones API calls. So as a substitute we invoked the /doggos endpoint and copied that knowledge right into a report in our undertaking.

Create a listing on the undertaking root referred to as records and a report in it referred to as doggos.json. Paste the next into that report:


Now, let’s replace our sendNotification serve as in app/api/inngest/routes.js to select a random symbol and print it out to the console. Upload the next import to the highest of the report:

import doggos from '../../../records/doggos.json' assert { kind: 'json' }

Replace the serve as to choose a random symbol from the array and print it out:

export const sendNotification = inngest.createFunction(
    { identify: "Puppygram Ship Notification" },
    { cron: "* * * * *" },
    async () => {       
        // get random canine photograph
        const randomIndex = Math.ground(Math.random() * doggos.period)
        const symbol = doggos[randomIndex]

Reset your Subsequent.js dev server, and also you must see random symbol filenames being revealed out as soon as a minute. Now it’s time to ship the ones to Courier Inbox!

Sending Random Canine Pics to Courier Inbox

The overall a part of the server-side element of Puppygram is the code to ship the random canine % to Courier Inbox. 

First, let’s upload the Courier Node.js SDK to our undertaking:

npm i @trycourier/courier

Subsequent, import the module and initialize the API shopper on the best of direction.js:

import { CourierClient } from '@trycourier/courier'

const courier = CourierClient()

In any case, within the frame of our sendNotification serve as, make the API name to Courier:

export const sendNotification = inngest.createFunction(
    { identify: "Puppygram Ship Notification" },
    { cron: "* * * * *" },
    async () => {       
        // get random canine photograph
        const randomIndex = Math.ground(Math.random() * doggos.period)
        const symbol = doggos[randomIndex]
        // ship a notification with the URL to the random symbol
        look ahead to courier.ship({
            message: {
                to: {
                   user_id: procedure.env.NEXT_PUBLIC_COURIER_USER
               content material: {
                    name: "",
                    frame: "Meet my fluffy and playful spouse in crime, all the time in a position for some mischief! :heart_eyes: :paw_prints: #AdorableTroublemaker"
                records: {
                    image_url: `https://random.canine/${symbol}`
                routing: {
                   approach: "unmarried",
                    channels: [

You’re completed! Now, all you want to do is deploy this internet app (there are lots of choices for deploying a Subsequent.js software) and deploy your serverless serve as to Inngest. Be sure your internet software is totally deployed and are living earlier than you deploy the serve as to Inngest.

Now, let’s flip our consideration to development the iOS app.

Growing an iOS App

With a purpose to construct an iOS app, you’ll want to set up Xcode. I’ll wait…

< 2 hours later >

Hi there, welcome again! Good enough, now that you simply’ve downloaded a number of gigabytes of IDE, let’s get started development an iOS app!

Create a New App

  • Create a brand new Undertaking, choose “iOS” and “App,” and click on “Subsequent”.
  • Give it the identify “Puppygram”, be sure that “SwiftUI” is chosen, and click on “Subsequent”.
  • Create a brand new folder to your undertaking after which click on “Create”.

Set up the Courier iOS SDK

Now that you’ve got created your undertaking, let’s set up the Courier iOS SDK.

Make a selection the “Puppygram” undertaking within the best left of your software nav and click on “Bundle Dependencies” at the proper. Click on the “+” signal on the backside and you’ll be able to be induced so as to add a dependency. Paste this hyperlink in:

Click on “Upload Bundle” so as to add this in your undertaking. That is it! You currently have the ability of Courier at your fingertips.

Development the View

For the aim of this weblog publish, we are going to construct a single-screen app that has a listing view that updates in actual time to show the notifications we’re sending the app.

On your undertaking, open up the ContentView report. On the best of the report, import the Courier iOS SDK:

Beneath the ContentView declaration, create a messages example variable to carry the Inbox messages that we obtain from Courier:

1struct ContentView: View {2    @State non-public var messages: [InboxMessage] = []3    var frame: some View {

Instantly following the .padding() name, upload an onAppear match handler with the next code.

1.padding()2.onAppear{3  Job {4    check out await5      // Signal-in to Courier6      Courier.shared.signIn(accessToken:"<JWT TOKEN>",clientKey:"<COURIER_CLIENT_KEY>",userId:"<NEXT_PUBLIC_COURIER_USER>")7      // Upload an Inbox listener8      Courier.shared.addInboxListener(9        onInitialLoad: { },10        onError: { error in },11        onMessagesChanged: { messages, unreadMessageCount, totalMessageCount, canPaginate in12          // replace the messages array when new messages come in13          self.messages = messages14        }15      )16  }17}

This code indicators the person into Courier and wires up an match handler to replace the messages example variable when new messages are available. With a purpose to get the Courier.shared.signIn name operating correctly, you want to exchange the ones 3 values. Let’s cross one at a time.

Authenticating the iOS SDK

Exchange <NEXT_PUBLIC_COURIER_USER> with the to price you might be the use of for your internet app whilst you ship a notification the use of Courier. In our case, the price is puppygram.

Exchange<COURIER_CLIENT_KEY> with the price of the Courier Public Key to your Courier Inbox Supplier. This secret is utterly secure to make use of at the shopper, in each internet and cell apps.

In any case, we want to set the accessToken belongings. With a purpose to do that safely, it’s endorsed that builders generate JWTs for his or her customers that explain scope and expiration knowledge. For the needs of this instructional, we are going to use the Courier API to generate a JWT at the command line. Open up a terminal, and run the next command substituting your values for <NEXT_PUBLIC_COURIER_USER> and <COURIER_AUTH_TOKEN>:

1curl --request POST 2     --url 3     --header 'Settle for: software/json' 4     --header 'Authorization: Bearer <COURIER_AUTH_TOKEN>' 5     --header 'Content material-Kind: software/json' 6     --data '7{8  "scope": "user_id:<NEXT_PUBLIC_COURIER_USER> learn:messages",9  "expires_in": "2 days"10}11'

You can get again some JSON that appears like this:

Reproduction the price of the token belongings and paste it into the authToken parameter for Courier.shared.signIn. You’re completely authenticated!

Showing the Messages

Now that we are authenticated, the final step for our app is to show the messages. Delete the code beneath:

1Image(systemName: "globe")2  .imageScale(.massive)3  .foregroundColor(.accentColor)4Text("Hi, international!")

Exchange it with this:

1List {2  ForEach(messages, identity: .self) { message in3    AsyncImage(url: URL(string: message.imageUrl)){ symbol in4      symbol.resizable()5    } placeholder: {6      ProgressView()7    }8    .body(width: 300, top: 300)9    .clipShape(RoundedRectangle(cornerRadius: 25))              10    VStack {11      Textual content(message.subtitle ?? "")12    }13  }14}

That is the most straightforward approach to outline a Record and the weather inside it. For now, we are simply going to simply show the picture (handed in by means of the customized records box of the REST API name) and the picture description which we’re passing within the frame box of the REST API name.

Necessary Notice: Within the iOS SDK, the subtitle belongings of the message object maps to the price of frame within the REST API name.

Now, if you happen to attempt to construct this it is going to fail. It is because we want to inform the iOS SDK that we are passing in a customized box within the REST API name. You’ll do that through extending the InboxMessage magnificence. Simply paste this code on the best of your report, slightly below the imports:

1extension InboxMessage {2    var imageUrl: String {3        get {4            go back (records?["image_url"] as? String) ?? ""5        }6    }7}

If all is going smartly, you’ll press “play” and also you must see one thing like this working within the simulator.

Wrapping Issues Up

K, we lined a LOT of territory development an Instagram clone for lovely canines. We realized easy methods to:

  • Create a recent Subsequent.js internet software
  • Configure Courier to ship Inbox (in-app) notifications
  • Fetch random photos of lovely canines the use of the random.canine API
  • Use Inngest to ship a brand new canine notification to our Inbox each and every minute
  • Create a recent iOS app
  • Use the Courier iOS SDK to customized render notifications

With a little bit UI polish, you’ll render the knowledge and finally end up with an app that appears and seems like this:

Whether or not you are development Kittygram, Bunnygram, or a contemporary software inbox, Courier Inbox, supplies a versatile set of APIs and UI elements that can assist you construct precisely what you want. And do not omit, whilst we curious about iOS, Inbox UI elements are to be had for each internet and Android packages too.



0 0 votes
Article Rating
Notify of
Inline Feedbacks
View all comments
Back To Top
Would love your thoughts, please comment.x