Every setting can be passed as an option to PusherServer.start_link/1 (or as {PusherServer, opts} in a supervision tree) or set as an environment variable. An explicit option wins over the environment variable.

OptionEnv varDefaultNotes
:app_idPUSHER_APP_ID"app-id"Must match the client SDK / Laravel. Also namespaces Redis keys.
:app_keyPUSHER_APP_KEY"app-key"Public; used in the WebSocket URL /app/:app_key.
:app_secretPUSHER_APP_SECRET"app-secret"Keep private. The default is public and logs a warning.
:portPORT6001Plain HTTP/WS. Put TLS in front.
:webhook_urlPUSHER_WEBHOOK_URLnoneWhere webhooks are POSTed.
:client_messages_enabledPUSHER_ENABLE_CLIENT_MESSAGEStruefalse rejects all client-* events.
:redis_urlPUSHER_REDIS_URLnoneEnables multi-server mode. rediss:// for TLS.
:redis_optsnone[]Extra Redix options, e.g. ssl: true.
:webhook_retriesPUSHER_WEBHOOK_RETRIES3Retries after the first attempt. 0 turns retries off.
:webhook_retry_base_msnone1000First retry delay; doubles each time.
:rest_rate_limitPUSHER_REST_RATE_LIMITnoneMax REST API requests per second for the instance.
:client_event_rate_limitPUSHER_CLIENT_EVENT_RATE_LIMITnoneMax client events per second, per connection.
:max_connectionsPUSHER_MAX_CONNECTIONSnoneMax WebSocket connections on this node.
:batch_limitPUSHER_BATCH_LIMIT10Max events in one batch_events request. Pusher's own limit is 10.
:metricsPUSHER_METRICSfalseServe Prometheus metrics at GET /metrics.
:metrics_tokenPUSHER_METRICS_TOKENnoneRequire Authorization: Bearer <token> on /metrics.
:namenonePusherServerEmbedded only. Unique per instance.

One app per instance

An instance serves exactly one app (one id, key and secret). To serve several apps, embed several named instances on different ports; see the Embedding guide.

Client events

Clients can send client-* events on private and presence channels, only to channels they are subscribed to, and never on public channels. Set PUSHER_ENABLE_CLIENT_MESSAGES=false to refuse them all (the client receives error 4301).

Webhooks

With PUSHER_WEBHOOK_URL set, the server POSTs JSON for these events:

  • channel_occupied, channel_vacated
  • member_added, member_removed (presence channels)
  • client_event

Each request carries X-Pusher-Key and X-Pusher-Signature (HMAC-SHA256 of the raw body with your app secret), the same as Pusher's webhooks. Verify the signature before trusting a request.

Delivery runs in the background and never blocks a connection. A failed delivery (network error, timeout, HTTP 5xx, 408 or 429) is retried up to PUSHER_WEBHOOK_RETRIES times (default 3) with a doubling delay: 1 s, 2 s, 4 s. Other 4xx responses are not retried, because the receiver rejected the payload. Two things to design for:

  • Retries are held in memory. If the node stops while a retry is pending, that webhook is lost.
  • Retried events can arrive after later events, so make your receiver idempotent and don't rely on order.

Rate limits and capacity

All are off by default.

  • PUSHER_REST_RATE_LIMIT=100 allows 100 REST API requests per second for the whole instance (the health check and /metrics are exempt). Extra requests get 429 with Retry-After: 1. Laravel treats that as a failed broadcast, so set it above your real peak.
  • PUSHER_CLIENT_EVENT_RATE_LIMIT=10 allows each connection 10 client events per second. Extra events are dropped and the client gets pusher:error 4301.
  • PUSHER_MAX_CONNECTIONS=10000 refuses new WebSocket connections on this node beyond that count with pusher:error 4004. Clients reconnect, and with a load balancer they may land on another node.

The limits are per instance and per node. With several nodes, each node applies its own limit.

Metrics

Set PUSHER_METRICS=true and scrape GET /metrics (Prometheus text format). Counters are per node and reset on restart; scrape every node.

MetricType
pusher_server_connectionsgauge: open WebSocket connections on this node
pusher_server_channelsgauge: channels with a subscriber on this node
pusher_server_connections_total, pusher_server_connections_rejected_totalcounter
pusher_server_subscriptions_totalcounter
pusher_server_events_triggered_totalcounter: events delivered via the REST API, one per channel
pusher_server_client_events_total, pusher_server_client_events_rate_limited_totalcounter
pusher_server_rest_requests_total, pusher_server_rest_rate_limited_totalcounter
pusher_server_webhooks_sent_total, pusher_server_webhook_retries_total, pusher_server_webhooks_failed_totalcounter

Set PUSHER_METRICS_TOKEN to require Authorization: Bearer <token>. Without a token anyone who can reach the port can read /metrics, so block that path at your proxy.

Redis

See Multi-server. Redis is used only when :redis_url is set.