Realtime on every site you build.

WPSignal is a hosted WebSocket relay for WordPress. Publish an event from any action hook with one PHP call and every browser on the site hears it within milliseconds. No server to run, no polling to tune, and event payloads are encrypted before they leave WordPress.

< How it works />

Three hops, one connection

  1. 1. WordPress publishes

    A trigger on any action hook, or one WPS::publish() call, sends an HMAC-signed POST to the relay. The payload is encrypted before it leaves WordPress.

  2. 2. The relay fans out

    WPSignal delivers the event to every browser subscribed to that site's channels, over WebSocket with SSE as the fallback. Tokens decide who may read and write which channels.

  3. 3. The browser reacts

    WordSocket's client holds one connection per page and dispatches a native CustomEvent per event. Listen with plain JavaScript or any framework.

< Code />

Example

Readable, developer focused API

Publish on any WordPress action hook using the fluent builder API. Add a condition, custom channel, or transform the payload: all optional.

Listen for events

The browser client auto-connects and dispatches native CustomEvents, listen with plain JavaScript or integrate with any frontend framework.

See the full guide
wp-content/plugins/{plugin}/plugin.php
add_action('wpsignal_loaded', function () {
  WPS::trigger('order.status_changed')
    ->on('woocommerce_order_status_changed', 10, 3)
    ->channel('events')
    ->data(
      fn ($order_id, $old_status, $new_status) => [
        'order_id' => $order_id,
        'old_status' => $old_status,
        'new_status' => $new_status,
        'total' => wc_get_order($order_id)->get_total(),
      ])
    ->register();
});
wp-content/plugins/{plugin}/src/main.js
WPS.on('order.status_changed', (data) => {
  const {
    order_id,
    new_status,
    total
  } = data;
  triggerFlashNotification(order_id, new_status, total);
});

< Capabilities />

Built for WordPress developers

Build on WordSocket

ShopSocket is built on nothing the public API does not offer. An extension reserves a channel namespace with its own read and write grants, publishes from PHP, holds connection-scoped presence from the browser, and adds a card or a whole tab to WordSocket's settings page. One connection per page, shared by everything on it.

my-extension.php
add_action('wpsignal_loaded', function () {
  $wps   = WPS::instance();
  $staff = 'manage_woocommerce';

  // Staff read it, only PHP writes to it.
  $wps->channels()->reserve('shop:orders', $staff, '__return_false');

  // Every shopper announces presence, only staff may listen.
  $wps->channels()->reserve('shop:carts', $staff, '__return_true');

  // A card on WordSocket's Extensions tab.
  $wps->extensions()->register('my-extension', [
    'title'    => 'My Extension',
    'version'  => '1.0.0',
    'docs_url' => 'https://example.com/docs',
    'file'     => plugin_basename(__FILE__),
  ]);
});

WPS::publish('shop:orders:feed', 'order.placed', ['id' => $order_id]);
storefront.js
// Who is here right now; gone the instant the tab closes.
WPS.setPresence('shop:carts:live', { cart: cartId });

// Staff side: joins, leaves, and a sync on subscribe.
WPS.on('wps.presence', (data, channel) => {
  if (!WPS.onChannel(channel, 'shop:carts:live')) return;
  render(data.action, data.id, data.state, data.members);
});
settings.js
// Your own tab on WordSocket's settings page (0.28+).
window.wordsocket.registerTab({
  name: 'my-extension',
  title: 'My Extension',
  render: SettingsTab,
});

< Reference />

Documentation

Push your first event

Connect a site and see an event land in the Explorer in minutes.

Get started Getting started guide