# How to Use Phoenix Channels: Real-Time Chat with Elixir

Phoenix Channels enable developers to build scalable, real-time applications in Elixir. Backed by the concurrency power of the BEAM, Channels allow you to create chat apps, live dashboards, games, and more with low latency and high throughput.

In this article, we’ll explore:

* What are Phoenix Channels?
    
* When to use them
    
* Step-by-step implementation
    
* Key functions with explanations
    
* Real-time communication in action
    
* Best practices
    
* Final thoughts and CTA
    

---

## 🔁 What Are Phoenix Channels?

Phoenix Channels provide a simple yet powerful abstraction over WebSockets. They are designed for **bi-directional communication** between clients (like web browsers) and the server, using a **topic-based** pattern.

* Channels are **mounted on a Socket**
    
* Each Channel handles **a topic** (e.g., `"room:lobby"`, `"user:42"`)
    
* One socket connection can handle multiple topics
    

---

## 💡 When to Use Phoenix Channels

Use Channels when your app needs:

* Real-time updates (chat, notifications, dashboards)
    
* Multiplayer collaboration
    
* Interactive interfaces (live auctions, stock updates)
    
* Background broadcasting of messages to clients
    

---

## ⚙️ Step-by-Step: Create a Real-Time Chat with Phoenix Channels

Let’s implement a real-time chat room.

### 1\. Create a Phoenix Project

```bash
mix phx.new chat_app --no-ecto
cd chat_app
mix deps.get
```

---

## 🔌 Server-Side: Understanding Channel Functions

### File: `lib/chat_app_web/channels/room_channel.ex`

```elixir
defmodule ChatAppWeb.RoomChannel do
  use ChatAppWeb, :channel

  def join("room:lobby", _payload, socket) do
    {:ok, socket}
  end

  def handle_in("new_msg", %{"body" => body}, socket) do
    broadcast(socket, "new_msg", %{body: body})
    {:noreply, socket}
  end
end
```

---

### 🔍 Explanation:

### 🔹 `join(topic, payload, socket)`

* **What it does**: Called when a client tries to join a topic like `"room:lobby"`.
    
* **Purpose**: Authenticate, authorize, and allow/deny access to a topic.
    
* **Returns**:
    
    * `{:ok, socket}` if the client can join
        
    * `{:error, reason}` if access should be denied
        

```elixir
def join("room:lobby", _payload, socket) do
  if authorized?(socket) do
    {:ok, socket}
  else
    {:error, %{reason: "unauthorized"}}
  end
end
```

---

### 🔹 `handle_in(event, params, socket)`

* **What it does**: Handles an **incoming message** (pushed by the client).
    
* **Example**: When a client pushes `"new_msg"` with body `"Hi"`, this function is triggered.
    

```elixir
def handle_in("new_msg", %{"body" => body}, socket) do
  broadcast(socket, "new_msg", %{body: body})
  {:noreply, socket}
end
```

---

### 🔹 `broadcast(socket, event, payload)`

* **What it does**: Sends the `payload` to **all other clients** connected to the same topic.
    
* Used to notify all participants of a change or message.
    

```elixir
broadcast(socket, "new_msg", %{body: "Hello, all!"})
```

### Connect the Channel

In `lib/chat_app_web/channels/user_socket.ex`:

```elixir
channel "room:*", ChatAppWeb.RoomChannel
```

This tells Phoenix to route any topic starting with `"room:"` to the `RoomChannel`.

### 🔍 Explanation of `user_socket.ex`:

This file acts as the **entry point for all WebSocket connections**. It defines:

---

### 🔸 `connect(params, socket, connect_info)`

```elixir
def connect(_params, socket, _connect_info) do
  {:ok, socket}
end
```

* **Authenticates users** when they first open the WebSocket.
    
* You can use tokens or session info to verify users.
    

---

### 🔸 `id(socket)`

```elixir
def id(_socket), do: nil
```

* **Purpose**: Assigns a unique identifier for each socket.
    
* Useful when you want to **push a message to a specific user**.
    

Example with ID:

```elixir
def id(socket), do: "user_socket:#{socket.assigns.user_id}"
```

Then you can broadcast to a specific user like:

```elixir
ChatAppWeb.Endpoint.broadcast("user_socket:123", "new_notification", %{msg: "Hello!"})
```

---

## 🌐 Client-Side: JavaScript Integration

### 1\. Import and Connect

```js
import {Socket} from "phoenix"

let socket = new Socket("/socket", {params: {userToken: "123"}})
socket.connect()
```

### 2\. Join a Channel

```js
let channel = socket.channel("room:lobby", {})
channel.join()
  .receive("ok", resp => console.log("Joined successfully", resp))
  .receive("error", resp => console.log("Unable to join", resp))
```

---

### 3\. Push Data to Server

```js
channel.push("new_msg", {body: "Hello from client!"})
```

This triggers the `handle_in("new_msg", ...)` on the server.

---

### 4\. Receive Broadcasts

```js
channel.on("new_msg", payload => {
  const message = document.createElement("p")
  message.innerText = `[New] ${payload.body}`
  document.querySelector("#messages").appendChild(message)
})
```

---

## 🗣 Broadcasting from Server

Broadcast from anywhere in the app using:

```elixir
ChatAppWeb.Endpoint.broadcast("room:lobby", "new_msg", %{body: "Hello from server!"})
```

This doesn't need a client push; it works independently — perfect for admin messages or system events.

---

## 🔐 Authorization Example

```elixir
defp authorized?(socket) do
  # Validate token or user role
  true
end
```

Use this pattern inside `join/3` to limit access to sensitive channels.

---

## ✅ Best Practices

* **Validate join requests** to prevent unauthorized access.
    
* **Use topic conventions** (`"user:123"`, `"room:lobby"`) for scalability.
    
* **Avoid large payloads** to keep WebSocket communication fast.
    
* **Log channel events** in production for debugging.
    
* **Use** `Presence` module if you need to track online users.
    

---

## 🚀 What Can You Build?

* Live chat apps
    
* Multiplayer games
    
* Real-time dashboards
    
* Notification systems
    
* Collaborative editors (Google Docs style)
    

---

## 🔚 Conclusion

Phoenix Channels make it easy to build real-time, scalable applications with a clean and efficient API. By leveraging Elixir’s concurrency model, you can build fast, reliable systems that handle thousands of connections with minimal resource usage.

---

## 🤝 Work with the Experts

Looking to build a real-time app with Phoenix Channels?

[**ElixirMasters**](https://elixirmasters.com/) (powered by [BetaMize](https://betamize.com/)) can help you:

✅ Build scalable real-time web apps  
✅ Develop reliable backends using Phoenix  
✅ Maintain and optimize Elixir applications

👉 [Let's Talk – elixirmasters.com](https://elixirmasters.com/)
