Skip to main content

In-App Messaging

Add a notification inbox to your web or mobile application. Users can view, read, and manage their notifications directly in your app. You can send in-app notifications via the API and manage them through the Dashboard or the React component.

Features

  • Drop-in React Component - Ready-to-use inbox UI
  • Real-time Updates - WebSocket-powered live notifications
  • Customizable - Style to match your brand
  • Preferences - Users control their notification settings
  • Persistence - Notifications stored until read/archived

Quick Start

1. Install the React Component

npm install @zyphr/inbox-react

2. Get Your Public Key

Your public key is available in the Dashboard under Applications → [Your App] → API Keys. It starts with za_pub_ and is safe to use in client-side code.

3. Add to Your App

import { ZyphrInbox, ZyphrProvider } from '@zyphr/inbox-react';

function App() {
return (
<ZyphrProvider
publicKey="za_pub_your_public_key"
subscriberId="user_123"
>
<ZyphrInbox />
</ZyphrProvider>
);
}

4. Send a Notification

// From your backend
await zyphr.inbox.send({
subscriberId: 'user_123',
title: 'New Comment',
body: 'John commented on your post',
actionUrl: '/posts/123#comments',
});

React Component

Everything you need to integrate the inbox into your frontend.

Live Preview

Try the inbox component below — click the bell, mark notifications as read, archive, and switch between views.

Basic Usage

import { ZyphrInbox, ZyphrProvider } from '@zyphr/inbox-react';

function App() {
return (
<ZyphrProvider
publicKey="za_pub_your_key"
subscriberId={currentUser.id}
>
<Header>
<ZyphrInbox />
</Header>
</ZyphrProvider>
);
}

Customization

<ZyphrInbox
// Appearance
theme="dark"
position="bottom-right"

// Behavior
showUnreadBadge={true}
playSound={true}

// Callbacks
onNotificationClick={(notification) => {
router.push(notification.actionUrl);
}}
onUnreadCountChange={(count) => {
document.title = count > 0 ? `(${count}) My App` : 'My App';
}}
/>

Custom Rendering

Build your own inbox UI using the useZyphrInbox hook:

import { useZyphrInbox } from '@zyphr/inbox-react';

function CustomInbox() {
const {
notifications,
unreadCount,
markAsRead,
markAllAsRead,
archive,
} = useZyphrInbox();

return (
<div className="my-inbox">
<h2>Notifications ({unreadCount})</h2>
{notifications.map(n => (
<div
key={n.id}
className={n.readAt ? 'read' : 'unread'}
onClick={() => markAsRead(n.id)}
>
<h3>{n.title}</h3>
<p>{n.body}</p>
</div>
))}
</div>
);
}

Preference UI

Let users manage their notification preferences with a drop-in component:

import { ZyphrPreferences } from '@zyphr/inbox-react';

<ZyphrPreferences
categories={[
{ id: 'social', label: 'Social Updates' },
{ id: 'billing', label: 'Billing & Payments' },
{ id: 'product', label: 'Product Updates' },
]}
/>

Real-time Updates

The inbox automatically connects via WebSocket for real-time updates:

<ZyphrProvider
// Connection options
wsEndpoint="wss://realtime.zyphr.dev"
reconnectAttempts={5}
reconnectDelay={1000}
>

Events

Listen for incoming notifications to trigger custom behavior:

import { useZyphrEvents } from '@zyphr/inbox-react';

function NotificationToast() {
useZyphrEvents({
onNotification: (notification) => {
toast.show(notification.title);
},
});

return null;
}

Styling

CSS Variables

:root {
--zyphr-primary: #4a90d9;
--zyphr-background: #ffffff;
--zyphr-text: #1a1a1a;
--zyphr-border: #e5e5e5;
--zyphr-unread: #e8f4fd;
--zyphr-badge: #ef4444;
}

Custom Class Names

<ZyphrInbox
classNames={{
container: 'my-inbox-container',
notification: 'my-notification',
unread: 'my-unread',
badge: 'my-badge',
}}
/>

Server-Side API

Everything for sending and managing notifications from your backend.

Send a Notification

curl -X POST https://api.zyphr.dev/v1/inbox/send \
-H "X-API-Key: zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"subscriber_id": "user_123",
"title": "New Comment",
"body": "John commented on your post",
"action_url": "/posts/123#comments",
"category": "comments",
"priority": "normal"
}'

Batch Send

Send up to 100 notifications in a single request:

curl -X POST https://api.zyphr.dev/v1/inbox/send/batch \
-H "X-API-Key: zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"notifications": [
{ "subscriber_id": "user_1", "title": "Update", "body": "New features!" },
{ "subscriber_id": "user_2", "title": "Update", "body": "New features!" }
]
}'
await zyphr.inbox.sendBatch({
notifications: [
{ subscriberId: 'user_1', title: 'Update', body: 'New features!' },
{ subscriberId: 'user_2', title: 'Update', body: 'New features!' },
// ... up to 100
],
});

Notification Parameters

ParameterTypeRequiredDescription
subscriber_idstringYesThe subscriber to notify
titlestringYesNotification title
bodystringNoNotification body text
action_urlstringNoURL to navigate to on click
action_labelstringNoButton label for action
image_urlstringNoImage to display
iconstringNoIcon name or URL
categorystringNoCategory for filtering/preferences
prioritystringNolow, normal, high, urgent
dataobjectNoCustom data payload
expires_atstringNoISO 8601 expiration datetime

Subscriber Management

Subscribers are automatically created when you send their first notification, or create explicitly:

curl -X POST https://api.zyphr.dev/v1/subscribers \
-H "X-API-Key: zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"external_id": "user_123",
"email": "user@example.com",
"name": "John Doe"
}'
await zyphr.subscribers.create({
externalId: 'user_123', // Your user ID
email: 'user@example.com',
name: 'John Doe',
});

Generate Subscriber Token

For authenticated inbox access, generate a token on your backend:

// Backend endpoint
app.get('/api/inbox-token', async (req, res) => {
const token = await zyphr.inbox.createToken({
subscriberId: req.user.id,
});
res.json({ token });
});

// Frontend
<ZyphrProvider
publicKey="za_pub_your_key"
tokenEndpoint="/api/inbox-token"
>

API Reference

MethodEndpointDescription
POST/v1/inboxSend notification
POST/v1/inbox/batchSend batch
GET/v1/inboxList notifications
GET/v1/inbox/:idGet notification
POST/v1/inbox/:id/readMark as read
POST/v1/inbox/read-allMark all as read
POST/v1/inbox/:id/archiveArchive notification
DELETE/v1/inbox/:idDelete notification
GET/v1/inbox/unread/countGet unread count

Concepts

Notification Lifecycle

  1. Created - Notification sent and visible in inbox
  2. Read - User clicked or marked as read
  3. Archived - Hidden from default view
  4. Expired - Past expiration date (auto-archived)
  5. Deleted - Permanently removed

Categories & Preferences

Organize notifications by category so users can control what they receive:

// Send with category
await zyphr.inbox.send({
subscriberId: 'user_123',
title: 'New follower',
category: 'social',
});

// User can disable categories
await zyphr.subscribers.updatePreferences({
subscriberId: 'user_123',
inApp: {
categories: {
social: false, // Disable social notifications
billing: true, // Keep billing enabled
},
},
});

Managing via Dashboard

  1. Navigate to Inbox in the sidebar
  2. View all in-app notifications with their read/unread status
  3. Filter and search messages
  4. View individual message details