Message pusher
Message Pusher sends real-time notifications from Drupal's Message entities to subscribed clients using Pusher or compatible services. It integrates with Message Notify to allow various use cases like activity streams, chat, and live dashboards, with flexible channel routing based on message content. This module requires the Message and Message Notify modules, and can be enhanced with Pusher User for automatic client subscriptions.
What it does
Message Pusher delivers Message Stack entities to subscribed clients in real time, using Pusher or any Pusher-protocol compatible server such as Soketi or pws.
It hooks into Message Notify as a Notifier plugin (id: pusher), so it slots in next to the email notifier and inherits all the standard message_notify behavior — save on success, save on fail, rendered view-modes, MessageNotifierBase::postSend().
Use cases
The transport is generic; anything that can be modeled as a Message entity can ride it:
- Notifications — mentions, replies, system alerts on
private-user.{uid}, rendered as bell popups. - Activity streams / timelines — "Alice posted on group X" on
group-{linked_entity_id}. - Chat / threads — chat lines on
thread-{linked_entity_id}. - Live dashboards — metric events on
dashboard-{uid}. - Broadcast announcements — owner-less Messages on a static channel like
announcements. Access checks adapt:{uid}is only required when the channel pattern actually uses it.
How it works
Channel resolution is token-driven. Default pattern is private-user.{uid} (matches the Pusher User convention). Available tokens:
{uid}— recipient user id{template}— message template machine name{linked_entity_type}/{linked_entity_id}— when those base fields exist on the Message entity
You can fan out one Message to multiple channels in a single trigger via additional_channels. The Pusher event name defaults to the message template machine name, but can be overridden per send. Optionally include the rendered pusher view-mode HTML in the payload (off by default — Pusher caps payloads at ~10kB and rendered HTML may leak privileged content into a channel).
Server side:
$message = Message::create([ 'template' => 'mention_news', 'uid' => $recipientUid, 'linked_entity_type' => 'node', 'linked_entity_id' => $node->id(), ]); $message->save(); \Drupal::service('message_notify.sender')->send($message, [], 'pusher');
Client side (with pusher_user installed, every authenticated page subscribes the current user to their own private-user.{uid} channel and re-broadcasts each event):
$(document).on('pusherUser:event', (e, eventName, data) => { if (eventName.startsWith('mention_')) { // Update bell counter, prepend to feed, refetch endpoint, etc. } });
For native clients (React Native, iOS, Android) subscribe to the same channel through your Pusher SDK after authenticating against pusher_api's /admin/pusher-api/authentication endpoint.
Requirements
- Message
- Message Notify
- Pusher API — must be configured via
$settings['pusher_api']insettings.php.
Recommended companion modules
- Pusher User — auto-subscribes logged-in Drupal users to their
private-user.{uid}channel on the web, so no extra JS is needed to receive notifications.
Installation
composer require drupal/message_pusher drush en message_pusher
See the bundled README.md for the full configuration reference, payload shape, and test instructions.
Self-hosting tip
Pusher.com works out of the box, but for in-house / EU-hosted real-time you can swap in Soketi — it speaks the Pusher protocol, runs in Docker, and requires no code changes on either the Drupal side or the client side. Just point $settings['pusher_api']['default']['options'] at your Soketi host.
Status
1.0.0-alpha1 — first release. Production-shaped but the API may still shift before 1.0.0 stable. Issue reports, MRs and feedback very welcome.
Related issues upstream
A couple of pusher_api issues are open that affect this module's robustness:
- pusher_api #3591837:
PusherService::trigger()should returnboolso callers can detect delivery failure. Once merged, this module'sdeliver()will pass real success/failure back toMessageNotifierBase::postSend()andsave on failwill behave correctly. - pusher_api #3591832: self-hosted servers via
js_options— needed if you're running Soketi instead of pusher.com and want the browser to connect to your own host.