Create Indie Notification Inbox

This guide covers how to use the getIndieNotificationInbox function to get indie push notification data to be used to create your Indie Notification Inbox.

This video walks through the setup guide below:

Indie Notification Inbox Preview

Here's how the Indie Notification Inbox creation process works:

  • Get Indie Notifications Sent: Use the native-notify getIndieNotificationInbox function to get the history of notifications a subscriber received — the indie pushes sent to them plus your mass pushes (kept for 365 days).
  • Use: Use the Indie Notification Inbox data from the getIndieNotificationInbox function to create an Indie Notification Inbox.

Prerequisites

1

Create a free Native Notify account

Create a free NativeNotify.com account to get your Native Notify App ID and App Token.

A Pro plan feature:

The notification inbox is included in the Free, Pro and Team plans. On Premium, every inbox endpoint answers 201 with an explanation instead of notifications ("Your current Native Notify membership cannot access notification inbox features…"), so the SDK shows an empty inbox and an unread count of 0. Notifications you send keep being recorded, so they appear once the account upgrades. See what each plan includes.

Setup and Use

1

Import

In your Indie Notification Inbox screen, include these imports:

import React, { useState, useEffect } from 'react';
import { getIndieNotificationInbox } from 'native-notify';
2

Check for Hook function

Make sure you are using a Hook function as your Notification Inbox function. Here is an example:

export default function NotificationInbox() {
    ...
}

This link explains Hooks in detail: https://react.dev/reference/react/hooks

3

Create a data Hook

Inside of your Indie Notification Inbox screen, create a useState to store your Indie Notification Inbox data. Here's an example:

const [data, setData] = useState([]);
4

Get notifications

Paste this code into your Notification Inbox function:

const [takeNumber, setTakeNumber] = useState(10);
const [skipNumber, setSkipNumber] = useState(0);

const fetchNotifications = async () => {
    try {
        const notifications = await getIndieNotificationInbox(
            "unique-user-id",
            "app-id-number",
            "app-token-string",
            takeNumber,
            skipNumber
        );
        console.log("notifications: ", notifications);
        setData(notifications);
    } catch (error) {
        console.error("Error fetching notifications: ", error);
    }
};

useEffect(() => {
  fetchNotifications();
}, []);

Notes:

  • Replace "unique-user-id" with the unique user ID you registered with Native Notify.
  • If you omit the take count, native-notify v5+ asks for 20 rows (v4, and a raw REST call without take, get the server's default of 10).
  • Skip count defaults to 0.
  • Each row's pushData is the JSON string you sent — JSON.parse(row.pushData) to read it.
  • Fetching marks every notification of that subscriber as read.
  • This link explains how 'useEffect' works in detail: https://react.dev/reference/react/useEffect
5

Create your Indie Notification Inbox

Create your Indie Notification Inbox using the data received by running your getIndieNotificationInbox function.

Complete example

import React, { useState, useEffect } from 'react';
import { getIndieNotificationInbox } from 'native-notify';

export default function NotificationInbox() {
    const [data, setData] = useState([]);
    const [takeNumber, setTakeNumber] = useState(10);
    const [skipNumber, setSkipNumber] = useState(0);

    const fetchNotifications = async () => {
        try {
            const notifications = await getIndieNotificationInbox(
                "unique-user-id",
                "app-id-number",
                "app-token-string",
                takeNumber,
                skipNumber
            );
            console.log("notifications: ", notifications);
            setData(notifications);
        } catch (error) {
            console.error("Error fetching notifications: ", error);
        }
    };

    useEffect(() => {
      fetchNotifications();
    }, []);

    return (
      ... // create an Indie Notification Inbox using getIndieNotificationInbox data
    )
}

Exact pagination: getIndieNotificationInboxPage

getIndieNotificationInboxPage(subId, appId, appToken, take, skip) returns one page of rows plus the server's total row count, read from the X-Total-Count response header — so "load more" can be exact instead of a guess:

import { getIndieNotificationInboxPage } from 'native-notify';

const { rows, total } = await getIndieNotificationInboxPage(
  "unique-user-id",
  "app-id-number",
  "app-token-string",
  20, // take
  0   // skip
);

console.log(rows.length, "of", total); // total is null when the server doesn't send the header

Heads-up:

On the indie endpoint the X-Total-Count header reports your subscriber's own row total, so total is exact and page math can rely on it. getIndieNotificationInbox(...) returns the same rows without the total.

Per-notification read state

Requires native-notify v5.2+. The page function takes an optional sixth argument: { perNotification: true } — it adds ?perNotification=true to the request, so each row keeps its own read flag and the server no longer marks the whole inbox read on fetch:

import { getIndieNotificationInboxPage, markIndieNotificationRead } from 'native-notify';

const { rows, total } = await getIndieNotificationInboxPage(
  "unique-user-id",
  "app-id-number",
  "app-token-string",
  20, // take
  0,  // skip
  { perNotification: true }
);

rows[0].read; // this subscriber's own read state

// Mark ONE row read when it is opened (best-effort — resolves false, never throws).
// Pass the ids unless you set them once with NativeNotify.init():
await markIndieNotificationRead(rows[0].notification_id, "unique-user-id", "app-id-number", "app-token-string");

Read state is tracked per subscriber (subId), so — unlike mass — it works on simulators, in Expo Go, and on web. Without the option the request is byte-identical to previous SDK versions.

markIndieNotificationRead(notificationId, subId, appId?, appToken?) resolves true when the server accepted the mark, and false — never throwing — on any failure. Without a notificationId it resolves false and sends nothing (the endpoint's id-less form marks the whole inbox read).

The useNotificationInbox() hook and the prebuilt components expose the same feature as the perNotificationRead prop.

Query the endpoint directly (REST / Postman)

Every inbox screen ultimately calls the public indie inbox endpoint behind getIndieNotificationInbox — you can call it yourself from Postman, curl, or any HTTP client when you need to verify what a subscriber's inbox actually contains:

# List a subscriber's notifications (newest first)
GET https://app.nativenotify.com/api/indie/notification/inbox/{subId}/{appId}/{appToken}?take=10&skip=0

# Unread count for the same subscriber
GET https://app.nativenotify.com/api/indie/notification/inbox/read/{subId}/{appId}/{appToken}

Replace {subId} with the unique user id you registered, and {appId} / {appToken} with your app's id number and app token — the same values you pass to getIndieNotificationInbox. take (default 10) and skip (default 0) paginate; add perNotification=true to keep each row's own read flag instead of the legacy mark-all-read on fetch. You can also mark read explicitly with POST /api/indie/notification/inbox/read and a JSON body of { "appId": …, "appToken": …, "subId": …, "notificationId": … } (notificationId optional — without it, everything for the subscriber is marked read).

Success is 201 with a JSON array (pushData is the JSON string you sent):

[
  {
    "notification_id": 12345678,
    "date": "9-17-2026 7:24PM",
    "title": "New comment",
    "message": "Someone commented on your post",
    "pushData": "{\"postId\":\"a1b2c3\"}",
    "read": true
  }
]

A plain GET keeps the legacy behavior — it marks every notification of the subscriber read before listing, so each row comes back "read": true. Add perNotification=true to list the real read state without marking anything.

The unread endpoint answers 201 with { "unreadCount": 3 }.

On a Premium account these endpoints (and the mark-read call) answer 201 with this text instead — nothing is listed, counted or marked:

Your current Native Notify membership cannot access notification inbox features. You must upgrade to a higher membership to access notification inbox features.

Check the body is a JSON array before using it. The inbox is a Pro plan feature — see what each plan includes.

Responses are never cached — every fetch returns the current rows.

Troubleshooting an empty inbox: the list contains the notifications sent to that exact subId plus the app's mass notifications sent after it registered — an empty array [] means nothing has reached that subscriber yet (compare the id you registered with the one you send to). A 401 with "The App ID and App Token do not match any app registered with Native Notify…" means the appId / appToken pair is wrong — re-copy both from your app's dashboard.