
Product
Introducing Reports: An Extensible Reporting Framework for Socket Data
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.
payload-notifications
Advanced tools
Generic notification infrastructure for Payload CMS with email, in-app, and external callback channels.
Multi-channel notification infrastructure for Payload CMS with document subscriptions and live messages.
Payload has no built-in way to notify users about events. This plugin provides a server-side notify() / subscribe() / getSubscribers() API that you wire into your own hooks, endpoints, and workflows. A single notify() call can store an in-app notification, send an email, and fire an external callback -- each channel independent and optional. Everything is user-scoped with strict access control.
Features
notify() call. Per-user preferences control which channels are active.getSubscribers() returns follower IDs for fan-out. Supports auto-subscribe (e.g. on first comment) and manual follows.t.actor, t.document('title'), t.meta('key')) that resolve against fresh data at read time. Renamed users and updated titles are reflected in existing notifications.onNotify hook for pushing to Slack, webhooks, queues, or anything else.pnpm add payload-notifications
// payload.config.ts
import { buildConfig } from "payload";
import { notificationsPlugin } from "payload-notifications";
export default buildConfig({
// ...
plugins: [
notificationsPlugin({
email: {
generateSubject: ({ notification }) =>
`Notification: ${notification.event}`,
generateHTML: ({ notification, recipient }) =>
`<p>Hi ${recipient.displayName}, ${notification.message}</p>`,
},
}),
],
});
import { notify } from "payload-notifications";
await notify(req, {
recipient: user.id,
event: "comment.created",
actor: commenter.id,
message: "Someone replied to your post",
documentReference: { entity: "collection", slug: "posts", id: post.id },
});
import {
subscribe,
getSubscribers,
notify,
createLiveMessage,
} from "payload-notifications";
const docRef = { entity: "collection", slug: "posts", id: post.id } as const;
await subscribe(req, { userId: commenter.id, documentReference: docRef });
const subscribers = await getSubscribers(req, docRef);
for (const recipientId of subscribers) {
await notify(req, {
recipient: recipientId,
event: "comment.created",
actor: commenter.id,
message: createLiveMessage(
(t) => t`${t.actor} commented on "${t.document("title")}"`,
),
documentReference: docRef,
});
}
Static strings go stale when users rename themselves or documents get updated. Live messages store tokens that resolve against fresh data at read time:
import { notify, createLiveMessage } from "payload-notifications";
await notify(req, {
recipient: user.id,
event: "post.updated",
actor: editor.id,
message: createLiveMessage(
(t) => t`${t.actor} edited "${t.document("title")}"`,
),
documentReference: { entity: "collection", slug: "posts", id: post.id },
});
t.actor -- actor's display name (from admin.useAsTitle on the user collection)t.document(field) -- a field from the referenced documentt.meta(key) -- a key from the notification's meta object| Option | Type | Default | Description |
|---|---|---|---|
email | NotificationEmailConfig | -- | generateSubject and generateHTML functions. Omit to skip email. |
onNotify | NotifactionCallback | -- | Callback for every notification (Slack, webhooks, queues, etc). |
notificationsSlug | string | "notifications" | Slug for the notifications collection. |
subscriptionsSlug | string | "subscriptions" | Slug for the subscriptions collection. |
pollInterval | number | 30 | Poll interval in seconds for the admin bell component. |
All functions are server-side and require a PayloadRequest:
| Export | Description |
|---|---|
notify(req, input) | Deliver a notification. Respects per-user channel preferences. |
subscribe(req, opts) | Subscribe a user to a document. Deduplicates automatically. |
unsubscribe(req, userId, ref) | Remove a subscription. |
getSubscribers(req, ref) | Return all user IDs subscribed to a document. |
createLiveMessage(fn) | Build a serializable message template with dynamic tokens. |
This plugin lives in the payload-plugins monorepo.
pnpm install
# watch this plugin for changes
pnpm --filter payload-notifications dev
# run the Payload dev app (in a second terminal)
pnpm --filter sandbox dev
The sandbox/ directory is a Next.js + Payload app that imports plugins via workspace:* -- use it to test changes locally.
fix(payload-notifications): ...).pnpm release.Bug reports and feature requests are welcome -- open an issue.
MIT
FAQs
Generic notification infrastructure for Payload CMS with email, in-app, and external callback channels.
We found that payload-notifications demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.