TL;DR
Clients join a simple topic like "daily_agent_stats:total_inbound_calls".
On the server I expand it using workspace_id + agent_id from params.
But Phoenix still subscribes them to the raw topic too → I want to stop that and only keep the expanded subscription.
Hey folks ![]()
I’m building a Phoenix channel for agent analytics stats.
Here’s a simplified version of my use case:
What I want
-
Clients connect with
workspace_idandagent_idas query params. -
Then they only subscribe with a simplified topic (no need to repeat IDs).
-
On the server, I expand that simplified topic into the full PubSub key and subscribe internally.
Example
Channel:
defmodule MyAppWeb.AgentChannel do
use Phoenix.Channel
# Client joins something like: "daily_agent_stats:total_inbound_calls"
def join("daily_agent_stats:" <> stat_key, _payload, socket) do
workspace_id = socket.assigns[:workspace_id]
agent_id = socket.assigns[:agent_id]
# Expand topic internally
full_topic = "agent/analytics/daily_agent_stats:#{workspace_id}:#{agent_id}:#{stat_key}"
IO.puts("Subscribing to #{full_topic}")
Phoenix.PubSub.subscribe(MyApp.PubSub, full_topic)
{:ok, socket}
end
def join(topic, _payload, _socket) do
{:error, %{reason: "Invalid topic #{topic}"}}
end
end
UserSocket:
defmodule MyAppWeb.UserSocket do
use Phoenix.Socket
channel "daily_agent_stats:*", MyAppWeb.AgentChannel
def connect(%{"workspace_id" => ws_id, "agent_id" => agent_id}, socket, _connect_info) do
{:ok, assign(socket, :workspace_id, ws_id) |> assign(:agent_id, agent_id)}
end
def id(_socket), do: nil
end
Client connection (via wscat):
wscat -c "ws://localhost:4000/v1/agent/websocket?workspace_id=c8f4a3a0-835d-4ee2-9c71-0c18550680e5&agent_id=47dbbab6-1abf-4392-a42f-dbde107c2793"
Join a topic without IDs:
{"topic":"daily_agent_stats:total_inbound_calls","event":"phx_join","payload":{},"ref":1}
The Issue:
Even though I subscribe manually inside join/3, Phoenix still also assigns the socket to the original "daily_agent_stats:total_inbound_calls" topic.
So the socket ends up listening on two topics:
-
"daily_agent_stats:total_inbound_calls" -
"agent/analytics/daily_agent_stats:<workspace_id>:<agent_id>:total_inbound_calls"
I want to disable the first (auto) subscription and only rely on the expanded one.
My Question:
Is there a way to tell Phoenix not to subscribe the socket to the raw topic passed in by the client, so I can fully control subscriptions in join/3?
Any guidance on best practices here would be super helpful.




















