オンライン人数と視聴者数
オンライン・視聴中の人数を表示し、プレゼンスでユニークユーザーを数え、HTTP API と Webhook でサーバーから各ルームの人数を読み取ります。
「1,284 人がオンライン」「38 人が視聴中」「満室」:リアルタイムの人数はプロダクトににぎわいを与え、同じ数字がチームに、どのルームが盛り上がっているか、いつモデレーターを増やすべきか、夜のピークがどれほどだったかを教えてくれます。接続を自分で数える必要はありません。Hibira は各チャンネルに誰が購読しているかをすでに把握しており、Pusher プロトコルにはそれを問い合わせる方法が 4 つあります。
ユーザーが得られるもの
- 人の出入りに合わせて動く「オンライン」や「視聴中」の人数。
- アバターの列と「ほか 120 人」。タブを 2 つ開いている人も 1 人として数えます。
- 誰かが入ろうとする前に「満室」と表示されるルーム。
- チーム向けに、最もにぎわっているルームの管理画面と、ピークの履歴。

使う機能
- 購読者数(
pusher:subscription_count):パブリック・プライベートチャンネルの人数をブラウザで受け取ります。 - プレゼンスチャンネル(
presence-)でユニークユーザーを数え、大規模プレゼンスチャンネル(presence-large-)なら最大 100,000 メンバー。 - HTTP API(
GET /channels):サーバーからいつでも人数を読み取れます。 - Webhook(
member_added、member_removed、subscription_count):人数が変わったときに通知され、履歴を残せます。
ブラウザで
pusher:subscription_countサーバーが問い合わせる
GET /channels?info=user_countサーバーが通知を受ける
member_added接続数か、人数か
これは別々の数字なので、意識して選びましょう:
subscription_countは接続を数えます。タブを 3 つ開いた人は 3 と数えられます。サインインなしでパブリック・プライベートチャンネルで使えるので、公開ページの「視聴中」カウンターに向いています。user_countはプレゼンスチャンネル上のユニークユーザーを、サーバーが署名したuser_idで数えます。タブ 2 つでも、スマホとノート PC でも 1 人です。座席の上限やオンライン一覧など「人」が大事な場面ではこちらを使います。
ステップ 1:ブラウザで人数を表示する
アプリの設定で 購読者数を送信 をオンにします。パブリック・プライベートチャンネルの購読者全員が、人数が変わる間は最大 1 秒に 1 回、現在の人数を受け取ります:
const stream = pusher.subscribe('stream-42');
stream.bind('pusher:subscription_count', ({ subscription_count }) => {
watching.textContent = subscription_count.toLocaleString();
});コードを書かなくても、1 行の埋め込みスクリプトで同じことができます:<span data-hibira-online="stream-42">0</span> 人が視聴中。
ステップ 2:プレゼンスで人を数える
プレゼンスチャンネルでは全員がメンバー一覧を受け取るので、人数はすでにブラウザにあります:
const room = pusher.subscribe('presence-room-' + roomId);
const show = () => online.render(room.members.count, room.members);
room.bind('pusher:subscription_succeeded', show);
room.bind('pusher:member_added', show);
room.bind('pusher:member_removed', show);プレゼンスチャンネルは最大 100 メンバーです。メンバー全員がすべての参加通知を受け取るためです。サイト全体や大きなイベントなら、すべてのページで 1 つの大規模プレゼンスチャンネルに @hibira-io/large-presence で参加させます。最大 100,000 メンバーまで扱え、正確な人数とその場にいる人のサンプルを 1 秒に 1 回送ります:
import { LargePresence } from '@hibira-io/large-presence';
const site = LargePresence.subscribe(pusher, 'presence-large-site', { maxMembers: 12 });
site.on('ready', ({ count }) => badge.render(count, site.members));
site.on('change', ({ count }) => badge.render(count, site.members));ステップ 3:サーバーから問い合わせる
サーバーは HTTP API で同じ数字を読み取れます。Pusher 互換のサーバーライブラリならどれでも使えます。1 つのチャンネル:
const res = await pusher.get({
path: '/channels/presence-room-42',
params: { info: 'user_count,subscription_count' },
});
const { occupied, user_count, subscription_count } = await res.json();すべてのルームを一度に、にぎわっている順に:
const res = await pusher.get({
path: '/channels',
params: { filter_by_prefix: 'presence-room-', info: 'user_count' },
});
const { channels } = await res.json();
// { "presence-room-7": { "user_count": 42 }, "presence-room-9": { "user_count": 17 } }
const busiest = Object.entries(channels)
.map(([name, { user_count }]) => ({ name, users: user_count }))
.sort((a, b) => b.users - a.users);購読に署名する前に座席の上限を確認するには、チャンネル認可ルートでルームの人数を読み、満員なら拒否します:
app.post('/pusher/auth', requireLogin, async (req, res) => {
const { socket_id, channel_name } = req.body;
const room = await pusher.get({ path: `/channels/${channel_name}`, params: { info: 'user_count' } });
const { user_count } = await room.json();
if (user_count >= 8) return res.status(403).json({ error: 'room_full' });
res.json(pusher.authorizeChannel(socket_id, channel_name, { user_id: req.user.id, user_info: { name: req.user.name } }));
});また、配信するときに、その瞬間に何接続が購読していたかを問い合わせれば、イベントが何人に届いたかがわかります:
const sent = await pusher.trigger('stream-42', 'goal', { minute: 81 }, { info: 'subscription_count' });
const { channels } = await sent.json();
console.log(`reached ${channels['stream-42'].subscription_count} viewers`);user_count はプレゼンスチャンネルでのみ指定でき、チャンネル一覧では filter_by_prefix=presence- が必要です。複数のルームの人数を足すと、2 つのルームに同時にいる人を二重に数えます。サイト全体のユニークな人数には、代わりに GET /channels/presence-large-site?info=user_count を読みましょう。
ステップ 4:Webhook で履歴を残す
夜のピークをグラフにしたり、ルームが空になったらアラートを出したりするには、Hibira からサーバーに通知させます。ポータルで、member_added と member_removed(プレゼンスチャンネル)、subscription_count(パブリック・プライベートチャンネル、カウントがオンのとき)、または channel_occupied と channel_vacated の Webhook を追加します:
app.post('/hibira/webhooks', express.text({ type: '*/*' }), async (req, res) => {
const webhook = pusher.webhook({ headers: req.headers, rawBody: req.body });
if (!webhook.isValid()) return res.sendStatus(401);
for (const e of webhook.getEvents()) {
if (e.name === 'member_added') await db.online.add(e.channel, e.user_id);
if (e.name === 'member_removed') await db.online.remove(e.channel, e.user_id);
if (e.name === 'subscription_count') await db.viewers.record(e.channel, e.subscription_count);
}
res.sendStatus(200);
});ヒント
- 人数の読み取りはメッセージ枠を使いません。メッセージとして数えるのは配信したイベントだけです。それでも、ページ表示ごとに問い合わせるのではなく、HTTP API の結果をサーバーで数秒キャッシュしましょう。
- Webhook は遅れて届いたり、2 回届いたりすることがあります。履歴とアラートに使い、今の正確な数字が必要なときは HTTP API を読みます。
- にぎわう公開ページでは丸めた数字(「1.2k オンライン」)を表示しましょう。動きが落ち着き、それでも活気は伝わります。
- 人数はアプリ単位です。ステージングと本番の 2 つのアプリがあれば、それぞれ自分の接続だけが見えます。
- プランが制限するのは同時接続数で、人数ではありません。各プランのピーク上限は料金をご覧ください。