Laravel Show Download File Progress with Reverb and HTTP Client

Author: Manoj Damor

When handling large file downloads in a Laravel application, it’s essential to provide feedback to users in real-time. With Laravel Reverb (WebSocket) and Laravel’s powerful HTTP Client, we can create a seamless user experience by showing download progress. This guide walks you through the full implementation.


Prerequisites

Before starting, ensure you have:

  • Laravel 11+
  • Laravel Reverb installed and running
  • Laravel Echo and Pusher JS (for frontend broadcasting)
  • A working Redis setup (default for broadcasting)

Step 1: Install and Start Laravel Reverb

Laravel Reverb is now bundled with Laravel 11+. To install:

php artisan install reverb

Start the WebSocket server:

php artisan reverb:start

Set the following in your .env file:

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=reverb
PUSHER_APP_KEY=reverb
PUSHER_APP_SECRET=reverb
PUSHER_HOST=127.0.0.1
PUSHER_PORT=6001
PUSHER_SCHEME=http

Clear config cache:

php artisan config:clear

Step 2: Set Up Frontend with Laravel Echo

Install dependencies:

npm install --save laravel-echo pusher-js

Update resources/js/app.js:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'reverb',
    wsHost: window.location.hostname,
    wsPort: 6001,
    forceTLS: false,
    disableStats: true,
});

Run the build:

npm run dev

Step 3: Create a Broadcast Event

Create a new event:

php artisan make:event DownloadProgressUpdated

Edit app/Events/DownloadProgressUpdated.php:

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class DownloadProgressUpdated implements ShouldBroadcast
{
    use SerializesModels;

    public $userId;
    public $progress;

    public function __construct($userId, $progress)
    {
        $this->userId = $userId;
        $this->progress = $progress;
    }

    public function broadcastOn(): Channel
    {
        return new PrivateChannel('download-progress.' . $this->userId);
    }

    public function broadcastWith(): array
    {
        return ['progress' => $this->progress];
    }
}

Step 4: Secure the Private Channel

Update routes/channels.php:

Broadcast::channel('download-progress.{userId}', function ($user, $userId) {
    return (int) $user->id === (int) $userId;
});

Step 5: Create the File Download Logic

You can create a job or use a controller to handle downloads. Here’s a simple function that uses Laravel’s HTTP client:

use Illuminate\Support\Facades\Http;
use App\Events\DownloadProgressUpdated;

function downloadLargeFile($fileUrl, $savePath, $userId)
{
    $resource = fopen($savePath, 'w');

    Http::withOptions([
        'progress' => function ($total, $downloaded) use ($userId) {
            if ($total > 0) {
                $percent = round(($downloaded / $total) * 100);
                broadcast(new DownloadProgressUpdated($userId, $percent));
            }
        },
        'sink' => $resource,
    ])->get($fileUrl);

    fclose($resource);
}

You can call this function from a controller or dispatch it as a job for background processing.


Step 6: Show Progress on Frontend

In your Blade or Vue component:

<div id="progress">Download Progress: <span id="percentage">0%</span></div>
window.Echo.private(`download-progress.${userId}`)
    .listen('DownloadProgressUpdated', (e) => {
        document.getElementById("percentage").innerText = `${e.progress}%`;
    });

Replace userId with the authenticated user’s ID in your Blade template:

<script>
    let userId = {{ auth()->id() }};
</script>

Optional: Use Job for Background Downloads

You can offload the download to a queue:

php artisan make:job DownloadFileWithProgress

Inside the job, move the downloadLargeFile() logic.


Conclusion

Using Laravel Reverb and the built-in HTTP client, you can build a responsive download tracking system. With minimal setup, users can view real-time progress updates, leading to better UX and improved transparency in your application processes.

This solution can also be extended to monitor uploads, long-running reports, and any background tasks.


Author: Manoj Damor


Leave a Reply

Your email address will not be published. Required fields are marked *