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 and Vue.js
Install dependencies:
npm install --save laravel-echo pusher-js
Create a Vue component DownloadProgress.vue:
<template>
<div>
<h2>Download Progress</h2>
<div>{{ progress }}%</div>
</div>
</template>
<script>
export default {
data() {
return {
progress: 0,
};
},
mounted() {
let userId = document.head.querySelector('meta[name="user-id"]').content;
window.Echo.private(`download-progress.${userId}`)
.listen('DownloadProgressUpdated', (e) => {
this.progress = e.progress;
});
},
};
</script>
Include the component in your main Vue app and register it:
import { createApp } from 'vue';
import DownloadProgress from './components/DownloadProgress.vue';
const app = createApp({});
app.component('download-progress', DownloadProgress);
app.mount('#app');
Add meta tag to Blade layout:
<meta name="user-id" content="{{ auth()->id() }}">
Add the component to your view:
<div id="app">
<download-progress></download-progress>
</div>
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.
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, Vue.js, 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