Laravel×Pusherの使い方|Laravel 13対応の設定手順とReverbとの使い分け
Pusher(プッシャー)は、WebSocketサーバーを自前で運用せずにリアルタイム通信を追加できるマネージドサービスです。LaravelのBroadcasting機能が公式にPusherドライバーを備えているため、チャットや通知の即時更新は数十行のコードで動きます。一方でLaravel 11以降は設定方法が大きく変わり、古い記事どおりに書くと接続できません。ここではLaravel 13時点の正しい手順と、無料枠の範囲、そして自前ホストのLaravel Reverbとどちらを選ぶかまでを整理します。
まとめ:Laravel 13のPusher導入で押さえる4点
- 導入は
php artisan install:broadcasting --pusherの一発。config/broadcasting.phpはLaravel 11以降デフォルトでは存在せず、このコマンドが生成する。 - 環境変数は
BROADCAST_CONNECTION=pusher。旧称のBROADCAST_DRIVERは使わない。 - フロント側のキーは
VITE_PUSHER_APP_KEY。Laravel Mix時代のMIX_PUSHER_APP_KEYは Vite では読み込まれず、これが「キーがundefinedで接続できない」の最頻原因。 - 無料のSandboxプランは100同時接続・1日20万メッセージ。これを超え続けるなら、Startup(月49ドル)に上げるか、自前運用のLaravel Reverbへ切り替えるかの分岐に入る。
Pusherとは:WebSocketをマネージドで提供するリアルタイム通信サービス
Pusherは2010年にロンドンで生まれたリアルタイム通信基盤で、WebSocket接続の維持・スケール・フェイルオーバーを肩代わりします。サーバーがイベントを発行すると、Pusherが接続中のブラウザへ即座に配信する「パブリッシュ/サブスクライブ」型です。本記事で扱うのはWebSocket製品のChannelsで、モバイルプッシュ通知のBeamsは別製品です。なお2020年12月にMessageBird(現Bird)が買収しており、ドキュメントもBirdのサイトへ移行しています。長期の採用可否を検討するなら、この体制変更を踏まえて後述のReverbと比較してください。
アプリケーション側はPusherのAPIキーを設定するだけで、WebSocketサーバーの常駐プロセスもRedisも用意しません。ポーリング(一定間隔でのHTTPリクエスト)と違い、サーバー発の変化がそのまま画面に反映されるため、チャット・通知バッジ・進捗バー・共同編集のカーソル表示などに向きます。
料金プラン:無料Sandboxの上限と有料プランの分岐点
2026年7月時点の公開プランは以下のとおりです(最新はPusher公式の料金ページで確認してください)。
| プラン | 月額 | 同時接続 | メッセージ/日 |
|---|---|---|---|
| Sandbox(クレカ登録不要) | 無料 | 100 | 20万 |
| Startup | 49ドル | 500 | 100万 |
| Pro | 99ドル | 2,000 | 400万 |
| Business | 299ドル | 5,000 | 1,000万 |
| Premium | 499ドル | 10,000 | 2,000万 |
| Growth | 699ドル | 15,000 | 4,000万 |
| Plus | 899ドル | 20,000 | 6,000万 |
| Growth Plus | 1,199ドル | 30,000 | 9,000万 |
| Enterprise | 個別 | 個別 | 個別 |
課金はドル建てのため、円換算額は為替で変動します。判断の目安は「同時接続100」です。社内ツールや管理画面の通知なら無料枠で足りますが、一般ユーザー向けサービスで常時100人がページを開いているなら即座に有料プランになります。メッセージはpublish 1回+購読者数ぶんの配信=1+Nで数えます。50人が購読するチャンネルへ1回送れば51メッセージです。参加者が増えるほど消費が跳ね上がる点に注意してください。
Laravel 13でのPusher導入手順
パッケージ導入とinstall:broadcasting
まずPHP側のSDKを入れ、ブロードキャスト機能を有効化します。Laravel 11以降はconfig/broadcasting.phpもroutes/channels.phpも初期状態では存在せず、次のコマンドが生成します。
composer require pusher/pusher-php-server
php artisan install:broadcasting --pusher
このコマンドはフロント側のresources/js/echo.jsと、laravel-echo・pusher-jsのnpmインストールまで面倒を見ます。手動で入れる場合はnpm install --save-dev laravel-echo pusher-jsです。
.envの設定:BROADCAST_CONNECTIONとVITE_プレフィックス
Pusherダッシュボードで作成したアプリのApp ID・Key・Secret・Clusterを.envに書きます。Laravelの雛形はPUSHER_APP_CLUSTERがmt1(米バージニア)になっているため、東京リージョンでアプリを作ったならap3への書き換えが必須です。ここが実際のアプリと違うと接続が確立しません。
BROADCAST_CONNECTION=pusher
PUSHER_APP_ID="your-app-id"
PUSHER_APP_KEY="your-app-key"
PUSHER_APP_SECRET="your-app-secret"
PUSHER_APP_CLUSTER="ap3"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
App SecretはPHP側だけが使います。VITE_を付けた変数はビルド成果物に埋め込まれてブラウザから読めるため、SecretにVITE_を付けてはいけません。
MIX_PUSHER_APP_KEYが効かない原因とVITE_への移行
古い記事や既存プロジェクトにはprocess.env.MIX_PUSHER_APP_KEYが残っています。Laravel 9でビルドツールがLaravel MixからViteへ変わったため、この書き方はViteでは値を解決できずundefinedになり、Pusherへの接続が「キー不正」で失敗します。JS側はimport.meta.env.VITE_PUSHER_APP_KEYへ、.env側はMIX_接頭辞をVITE_へ置き換えてください(Viteへ移行する理由と手順はLaravelでViteを使用する理由とその利点について詳しく解説で扱っています)。.envを書き換えたらnpm run buildをやり直さないと古い値がバンドルに残ります。
イベントのブロードキャストとEchoでの受信
ShouldBroadcastイベントの実装
ブロードキャストされるのはShouldBroadcastインターフェースを実装したイベントだけです。broadcastOn()で配信先チャンネルを、broadcastAs()でフロントが受け取るイベント名を決めます。
php artisan make:event MessageSent
// app/Events/MessageSent.php
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Message $message) {}
public function broadcastOn(): Channel
{
return new PrivateChannel('chat.' . $this->message->room_id);
}
public function broadcastAs(): string
{
return 'message.sent';
}
}
あとはコントローラーでbroadcast(new MessageSent($message));と発火するだけです。publicなプロパティがそのままJSONペイロードとしてクライアントへ届きます。ここで見落としやすいのが、ShouldBroadcastは常にキュー経由で送信される点です(同期送信したいときだけShouldBroadcastNowを使います)。Laravel 11以降の既定はQUEUE_CONNECTION=databaseなので、php artisan queue:workを動かしていなければイベントはジョブテーブルに溜まったまま配信されません。「コードは正しいのに届かない」ときは最初にここを疑ってください。
Echo側の受信設定
install:broadcastingが生成するresources/js/echo.jsは、Echoの初期化だけを行う次の形です。encrypted: trueは古いオプションで、現在はforceTLS: trueを使います。
// resources/js/echo.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true,
});
購読はコンポーネント側で書きます。チャットルームのIDを持っている画面なら次のようになります。
const roomId = 12;
window.Echo.private(`chat.${roomId}`)
.listen('.message.sent', (e) => {
console.log(e.message.body);
});
broadcastAs()で名前を付けた場合、listen()の引数は先頭にドットを付けた'.message.sent'になります。ドットを落とすとLaravelは名前空間付きのクラス名(App\Events\MessageSent)を探すため、イベントを取りこぼします。ReactやVueを使うなら@laravel/echo-react・@laravel/echo-vueのconfigureEcho()とフックが用意されています(構成の考え方はLaravelとReactの連携ガイド|環境構築・SPA・認証・デプロイと選び方を参照)。
プライベートチャンネルの認可
PrivateChannelを使うと、クライアントは接続時に/broadcasting/authへ認可リクエストを送ります。ここで許可を返すルールをroutes/channels.phpに書きます。
// routes/channels.php
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
return $user->rooms()->whereKey($roomId)->exists();
});
ここでtrueを返さないと403となり、チャンネルの購読が失敗します。ログイン状態でしか動かないため、セッションCookieが送られないクロスドメイン構成(APIを別ドメインに置くSPAなど)では、withCredentialsやSanctumのステートフルドメイン設定を先に整える必要があります。
PusherかReverbか:外部サービスと自前運用の判断基準
2024年のLaravel 11でファーストパーティのWebSocketサーバーLaravel Reverbが加わり、「Pusher一択」ではなくなりました。ReverbはPusherプロトコル互換なので、Echo側はbroadcasterを'reverb'に変えるだけで、イベントや認可のコードはそのまま動きます。
結論を言えば、常時接続が100を超えず、サーバー運用の手を増やしたくないならPusher、接続数が数千規模に伸びる見込みがあり、常駐プロセスの監視・再起動を自分たちで回せるならReverbです。Pusherの費用は接続数に比例して階段状に上がりますが、Reverbは自前のVPS代しかかからない代わりに、プロセス監視・スケールアウト・TLS終端・再接続時の負荷が運用側の責任になります。月数万円の課金を惜しんで、常駐プロセスの死活監視を新設するほうが高くつくケースは珍しくありません。監視の作り込みが必要になったときはLaravelでPrometheusとGrafana監視を実装:メトリクス収集・可視化・アラート設定が参考になります。
逆に採用すべきでないのは、Sandboxの無料枠で本番の一般公開サービスを賄おうとする場合です。100接続はページを開いているユーザー数であってアクティブユーザー数ではないため、告知直後のアクセス集中であっさり上限に触れます。Sandboxは上限で即座に打ち切られ、超過分の接続はWebSocketのエラーコード4004で拒否され、publishは403を返します(有料プランは接続上限の120%までは許容されます)。無料枠は検証と社内利用までと割り切るのが安全です。
laravel-echo-server:新規採用を外す理由
かつての自前ホスト定番だったSocket.io製のlaravel-echo-serverは、2023年11月15日にGitHubリポジトリがアーカイブされ、読み取り専用になりました。新規採用は避け、自前運用を選ぶならReverbにしてください。既存プロジェクトで動いている場合も、Node.jsやSocket.ioの脆弱性修正が来ない以上、移行計画を立てるべき状態です。同じくスターターキット周辺も入れ替えが進んでいるので、古い構成を引きずっているならLaravel Breeze・Jetstreamはなぜ非推奨に?スターターキット(React/Vue/Livewire)への移行と代替案もあわせて確認してください。
接続できないときの切り分け
Pusher連携の不具合は、原因の切り分け順を決めておくと早く終わります。
- ブラウザのコンソールに何も出ない:Echoが初期化されていない。
app.jsでecho.jsをimportしているか、npm run build後のバンドルが配信されているかを確認する。 - キーがundefined/接続直後に切断:
MIX_接頭辞のまま、またはVITE_変数を追加した後にビルドし直していない。 - WebSocketは張れるがイベントが来ない:Clusterの不一致、
listen()のドット漏れ、キューワーカー停止のいずれか。Pusherダッシュボードの「Debug console」にイベントが届いているかを見れば、サーバー側とクライアント側のどちらの問題か一目でわかる。 - 403が返る:
routes/channels.phpの認可がfalseを返している、または未ログイン。 - 接続がエラーコード4004で切られる:プランの同時接続上限に達している。Sandboxなら100接続を超えた分がここで落ちる。
- 全体的に不安定:自社コードを疑う前にstatus.pusher.comでChannelsのREST API・WebSocket client APIの稼働状況を確認する。
よくある質問
Pusherの読み方は?
「プッシャー」です。英語のpush(押す)に由来し、サーバーからクライアントへデータを押し出す動作を表しています。同名の一般語(押す人、コイン落としゲームの押し出し機構)とは無関係で、開発文脈ではPusher社のリアルタイム通信サービスを指します。
Pusherは無料で使える?
Sandboxプランがクレジットカード登録なしの無料で、100同時接続・1日20万メッセージまで使えます。期間制限はないため、開発・検証・社内ツールならこのまま運用できます。上限を超えると接続が拒否されるので、一般公開サービスでは有料プラン(Startup 月49ドル〜)を前提にしてください。
BROADCAST_DRIVERを設定しても動きません
Laravel 11以降、この環境変数はBROADCAST_CONNECTIONに改名されました。古い名前は読まれないため、既定値のnullドライバーが選ばれ、イベントがどこにも送信されません。.envを書き換えたうえでphp artisan config:clearを実行してください。
pusher-php-serverとpusher-jsの違いは?
pusher/pusher-php-serverはComposerで入れるPHP側のSDKで、Laravelがイベントを送信するときに使います。pusher-jsはnpmで入れるブラウザ側のクライアントで、Laravel EchoがWebSocket接続を張るために内部で利用します。役割が違うため、Pusherを使う構成では両方必要です。
PusherからReverbへ移行するとコードはどれだけ変わる?
ReverbはPusherプロトコル互換のため、イベントクラス・routes/channels.php・listen()の書き方は変わりません。変更は.envの接続設定と、Echo初期化のbroadcaster: 'reverb'およびwsHost/wsPort指定、そしてサーバーでphp artisan reverb:startを常駐させる運用の追加です。アプリケーションコードよりインフラ側の作業が主になります。