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
| Parameter | Type | Required | Description |
|---|---|---|---|
subscriber_id | string | Yes | The subscriber to notify |
title | string | Yes | Notification title |
body | string | No | Notification body text |
action_url | string | No | URL to navigate to on click |
action_label | string | No | Button label for action |
image_url | string | No | Image to display |
icon | string | No | Icon name or URL |
category | string | No | Category for filtering/preferences |
priority | string | No | low, normal, high, urgent |
data | object | No | Custom data payload |
expires_at | string | No | ISO 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
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/inbox | Send notification |
POST | /v1/inbox/batch | Send batch |
GET | /v1/inbox | List notifications |
GET | /v1/inbox/:id | Get notification |
POST | /v1/inbox/:id/read | Mark as read |
POST | /v1/inbox/read-all | Mark all as read |
POST | /v1/inbox/:id/archive | Archive notification |
DELETE | /v1/inbox/:id | Delete notification |
GET | /v1/inbox/unread/count | Get unread count |
Concepts
Notification Lifecycle
- Created - Notification sent and visible in inbox
- Read - User clicked or marked as read
- Archived - Hidden from default view
- Expired - Past expiration date (auto-archived)
- 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
- Navigate to Inbox in the sidebar
- View all in-app notifications with their read/unread status
- Filter and search messages
- View individual message details