> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Broadcasting

> Explicamos cómo implementar comunicación en tiempo real por WebSocket con el broadcasting de Laravel y Laravel Reverb.

## ¿Qué es broadcasting?

Con WebSocket puedes enviar datos en tiempo real del servidor al cliente.
El broadcasting de Laravel es el mecanismo para hacer llegar eventos del lado del servidor al JavaScript del frontend mediante WebSocket.

Por ejemplo, cuando cambia el estado de un pedido, la actualización se muestra al instante en el navegador sin recargar la página.
La gran ventaja del broadcasting de Laravel es que compartes tal cual el nombre del evento y sus datos entre servidor y cliente.

<Info>
  El broadcasting se construye sobre el sistema de eventos de Laravel.
  Se recomienda entender primero [eventos y listeners](/es/events).
</Info>

```mermaid theme={null}
flowchart LR
    A["Servidor<br>Emite el evento<br>dispatch()"] --> B["Driver de<br>broadcasting<br>(Reverb, etc.)"]
    B --> C["Servidor<br>WebSocket"]
    C --> D["Verificación de<br>autorización del canal"]
    D --> E["Cliente<br>Laravel Echo"]
    E --> F["Actualización de la UI<br>en tiempo real"]
```

## Configuración

En una aplicación nueva el broadcasting está deshabilitado por defecto.
Actívalo con el comando Artisan `install:broadcasting`.

```shell theme={null}
php artisan install:broadcasting
```

El comando te pedirá que elijas el servicio de broadcasting y generará `config/broadcasting.php` y `routes/channels.php`.

## Laravel Reverb

Desde Laravel 11 se recomienda usar **Laravel Reverb**, el servidor WebSocket oficial.
Reverb es auto-hospedado y permite tiempo real sin depender de servicios externos.

### Instalación

Con la opción `--reverb`, `install:broadcasting` instala los paquetes de Composer y NPM que necesita Reverb y configura `.env` de una sola vez.

```shell theme={null}
php artisan install:broadcasting --reverb
```

Si prefieres instalarlo manualmente, añade el paquete con Composer y luego ejecuta el comando de instalación.

```shell theme={null}
composer require laravel/reverb

php artisan reverb:install
```

### Valores clave en .env

```ini theme={null}
BROADCAST_CONNECTION=reverb

REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
```

### Arrancar el servidor Reverb

```shell theme={null}
php artisan reverb:start
```

En producción, gestiónalo como daemon con un gestor de procesos como Supervisor.

<Tip>
  Los eventos de broadcast se procesan a través de la cola.
  Debes arrancar también un worker de cola aparte del servidor Reverb.

  ```shell theme={null}
  php artisan queue:work
  ```
</Tip>

## Crear eventos de broadcast

### Generar la clase del evento

```shell theme={null}
php artisan make:event OrderShipmentStatusUpdated
```

En la clase generada, implementa la interfaz `ShouldBroadcast`.

```php theme={null}
<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
    ) {}

    /**
     * Devuelve el canal al que se emite el evento
     */
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.' . $this->order->id);
    }
}
```

Con solo implementar `ShouldBroadcast`, cuando se despacha el evento se emite automáticamente a través de la cola.

### Personalizar los datos emitidos

Por defecto, todas las propiedades `public` de la clase se incluyen en el payload.
Para limitar los datos, define `broadcastWith`.

```php theme={null}
public function broadcastWith(): array
{
    return [
        'order_id' => $this->order->id,
        'status'   => $this->order->status,
    ];
}
```

### Personalizar el nombre del evento

Por defecto se usa el nombre de la clase.
Cámbialo con `broadcastAs`.

```php theme={null}
public function broadcastAs(): string
{
    return 'order.status.updated';
}
```

Al escuchar en el frontend, antepón un `.` para desactivar el prefijo del namespace de la aplicación.

```js theme={null}
Echo.private(`orders.${orderId}`)
    .listen('.order.status.updated', (e) => {
        console.log(e);
    });
```

## Tipos de canal

| Canal        | Clase             | Descripción                                                 |
| ------------ | ----------------- | ----------------------------------------------------------- |
| **Public**   | `Channel`         | No requiere autenticación. Cualquiera puede suscribirse     |
| **Private**  | `PrivateChannel`  | Solo usuarios autenticados. Requiere lógica de autorización |
| **Presence** | `PresenceChannel` | Extensión de Private. Puedes conocer los miembros del canal |

```php theme={null}
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;

// Canal público
public function broadcastOn(): Channel
{
    return new Channel('posts');
}

// Canal privado
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.' . $this->order->id);
}

// Canal presence
public function broadcastOn(): Channel
{
    return new PresenceChannel('rooms.' . $this->room->id);
}
```

Para emitir a varios canales, devuelve un array.

```php theme={null}
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.' . $this->order->id),
        new Channel('admin.orders'),
    ];
}
```

## Autorización de canales

Los canales Private y Presence se verifican en el servidor antes de que el cliente pueda suscribirse.

### routes/channels.php

Define los callbacks de autorización en `routes/channels.php`, generado por `install:broadcasting`.

```php theme={null}
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});
```

El primer argumento del callback es el usuario autenticado; los demás son los comodines del nombre del canal.
Devuelve `true` o un valor truthy para autorizar, o `false` para denegar.

<Info>
  También se puede usar route model binding.
  Con el nombre `orders.{order}` se recibe una instancia del modelo `Order`.
</Info>

```php theme={null}
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
```

### Autorización mediante clases de canal

Cuando hay muchos canales puedes organizarlos con clases dedicadas.

```shell theme={null}
php artisan make:channel OrderChannel
```

```php theme={null}
<?php

namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    public function join(User $user, Order $order): bool
    {
        return $user->id === $order->user_id;
    }
}
```

Regístrala en `routes/channels.php`.

```php theme={null}
use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{order}', OrderChannel::class);
```

## Emisión del evento

Los eventos que implementan `ShouldBroadcast` se disparan como cualquier otro.

```php theme={null}
use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);
```

Para emitir solo a los demás usuarios excluyendo el emisor, usa `toOthers`.

```php theme={null}
broadcast(new OrderShipmentStatusUpdated($order))->toOthers();
```

<Warning>
  Para usar `toOthers`, la clase del evento debe usar el trait `InteractsWithSockets`.
</Warning>

## Recepción en el frontend

### Configuración de Laravel Echo

Con Reverb, configura una instancia de Echo en `resources/js/bootstrap.js`.

```shell theme={null}
npm install --save-dev laravel-echo pusher-js
```

```js theme={null}
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});
```

### Escuchar eventos

```js theme={null}
// Canal público
Echo.channel('posts')
    .listen('PostPublished', (e) => {
        console.log(e.post);
    });

// Canal privado
Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

// Canal presence
Echo.join(`rooms.${roomId}`)
    .here((users) => {
        console.log('Miembros actuales:', users);
    })
    .joining((user) => {
        console.log(user.name, 'se ha unido');
    })
    .leaving((user) => {
        console.log(user.name, 'ha salido');
    })
    .listen('MessagePosted', (e) => {
        console.log(e.message);
    });
```

### Uso de hooks para React / Vue

Si usas starter kits de React o Vue, los hooks dedicados simplifican el código.

```js theme={null}
import { useEcho } from "@laravel/echo-react";

// Canal privado
useEcho(
    `orders.${orderId}`,
    "OrderShipmentStatusUpdated",
    (e) => {
        console.log(e.order);
    },
);

// Canal público
import { useEchoPublic } from "@laravel/echo-react";

useEchoPublic("posts", "PostPublished", (e) => {
    console.log(e.post);
});
```

El hook `useEcho` deja automáticamente el canal al desmontar el componente.

<Tip>
  Antes de compilar los assets del frontend, comprueba que las variables `VITE_REVERB_*` de `.env` estén bien configuradas.

  ```shell theme={null}
  npm run build
  ```
</Tip>

## Ejemplo práctico: actualización en tiempo real del estado del pedido

<Steps>
  <Step title="Activar broadcasting">
    ```shell theme={null}
    php artisan install:broadcasting --reverb
    ```

    Arranca el servidor Reverb y el worker de cola.

    ```shell theme={null}
    php artisan reverb:start
    php artisan queue:work
    ```
  </Step>

  <Step title="Crear la clase del evento">
    ```shell theme={null}
    php artisan make:event OrderShipmentStatusUpdated
    ```

    Edita `app/Events/OrderShipmentStatusUpdated.php`.

    ```php theme={null}
    <?php

    namespace App\Events;

    use App\Models\Order;
    use Illuminate\Broadcasting\Channel;
    use Illuminate\Broadcasting\InteractsWithSockets;
    use Illuminate\Broadcasting\PrivateChannel;
    use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
    use Illuminate\Queue\SerializesModels;

    class OrderShipmentStatusUpdated implements ShouldBroadcast
    {
        use InteractsWithSockets, SerializesModels;

        public function __construct(
            public Order $order,
        ) {}

        public function broadcastOn(): Channel
        {
            return new PrivateChannel('orders.' . $this->order->id);
        }

        public function broadcastWith(): array
        {
            return [
                'order_id' => $this->order->id,
                'status'   => $this->order->status,
            ];
        }
    }
    ```
  </Step>

  <Step title="Definir la autorización del canal">
    Añade la lógica en `routes/channels.php`.

    ```php theme={null}
    use App\Models\Order;
    use App\Models\User;
    use Illuminate\Support\Facades\Broadcast;

    Broadcast::channel('orders.{order}', function (User $user, Order $order) {
        return $user->id === $order->user_id;
    });
    ```
  </Step>

  <Step title="Disparar el evento">
    Dispáralo en el controlador o job que actualiza el estado del pedido.

    ```php theme={null}
    use App\Events\OrderShipmentStatusUpdated;

    $order->update(['status' => 'shipped']);

    OrderShipmentStatusUpdated::dispatch($order);
    ```
  </Step>

  <Step title="Escuchar en el frontend">
    Escucha con script inline en Blade o desde un componente React/Vue.

    ```js theme={null}
    Echo.private(`orders.${orderId}`)
        .listen('OrderShipmentStatusUpdated', (e) => {
            document.getElementById('status').textContent = e.status;
        });
    ```
  </Step>
</Steps>

## Próximos pasos

<Card title="Laravel Reverb" href="/es/reverb">
  Consulta los detalles de configuración, operación en producción y escalado del servidor Reverb.
</Card>

<Card title="Colas y jobs" href="/es/queues">
  El broadcasting se procesa a través de la cola. Revisa la configuración y operación de las colas.
</Card>

<Card title="Eventos y listeners" href="/es/events">
  Aprende los detalles del sistema de eventos de Laravel, la base del broadcasting.
</Card>


## Related topics

- [Laravel AI SDK](/es/ai-sdk.md)
- [FAQ de la nueva estructura de aplicación de Laravel 11 y posteriores](/es/advanced/app-structure-faq.md)
- [Streaming](/es/packages/laravel-copilot-sdk/streaming.md)
- [SessionEvent](/es/packages/laravel-copilot-sdk/session-event.md)
- [Estructura de aplicación en Laravel 11 y posteriores](/es/advanced/app-structure.md)
