Axios Progress Events — Complete Guide with Examples
In this tutorial, you'll learn about Axios download progress tracking. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Axios onDownloadProgress callback lets you track download progress in real time, displaying percentage, speed, estimated time remaining, and building custom progress indicators for large file downloads.
What You'll Learn
By the end of this tutorial, you'll use onDownloadProgress to track download completion, calculate download speed and ETA, build progress bars, and handle streams with progress.
Why It Matters
Users abandon downloads that show no progress. A progress bar builds trust and sets expectations. Tracking download speed helps diagnose slow connections and gives users actionable feedback.
Real-World Use
DodaZIP shows a detailed download progress bar when downloading update packages. It displays percentage, MB/s speed, time remaining, and total size. This transparency keeps users informed during large downloads.
Where This Fits in Your Learning Path
flowchart LR
A["Cancellation"] --> B["**Progress Events**"]
B --> C["Upload Progress"]
C --> D["Cookies & Auth"]
D --> E["Axios Advanced"]
style B fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
Basic Download Progress
The onDownloadProgress callback receives a ProgressEvent with loaded and total properties.
const response = await axios.get('/api/large-file', {
responseType: 'blob',
onDownloadProgress: function(progressEvent) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
console.log(`Downloaded: ${percentCompleted}%`)
}
})
Expected output: The console logs progress from 0% to 100% as the file downloads.
Progress Bar UI
Build a visual progress bar that updates in real time.
const progressBar = document.querySelector('#progress-bar')
const progressText = document.querySelector('#progress-text')
await axios.get('/api/large-file', {
responseType: 'blob',
onDownloadProgress: function(e) {
const percent = Math.round((e.loaded * 100) / e.total)
progressBar.style.width = percent + '%'
progressBar.textContent = percent + '%'
progressText.textContent = `Downloaded ${formatBytes(e.loaded)} of ${formatBytes(e.total)}`
}
})
function formatBytes(bytes) {
if (bytes < 1024) return bytes + ' B'
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
return (bytes / 1048576).toFixed(1) + ' MB'
}
<div style="width:100%;background:#e0e0e0;border-radius:4px;overflow:hidden">
<div id="progress-bar" style="width:0%;height:24px;background:#4ecdc4;text-align:center;color:white;line-height:24px;font-size:12px">0%</div>
</div>
<p id="progress-text" style="font-size:14px;color:#666">Starting download...</p>
Expected output: A progress bar fills from 0% to 100% with a formatted byte display beneath it.
Download Speed and ETA
Calculate transfer speed and estimated time remaining.
let startTime = Date.now()
let lastLoaded = 0
const response = await axios.get('/api/large-file', {
responseType: 'blob',
onDownloadProgress: function(e) {
const now = Date.now()
const elapsed = (now - startTime) / 1000
const speed = e.loaded / elapsed // bytes per second
const remaining = (e.total - e.loaded) / speed
const percent = Math.round((e.loaded * 100) / e.total)
console.log(`${percent}% | ${formatSpeed(speed)} | ETA: ${formatTime(remaining)}`)
lastLoaded = e.loaded
}
})
function formatSpeed(bytesPerSec) {
if (bytesPerSec < 1024) return bytesPerSec.toFixed(0) + ' B/s'
if (bytesPerSec < 1048576) return (bytesPerSec / 1024).toFixed(1) + ' KB/s'
return (bytesPerSec / 1048576).toFixed(1) + ' MB/s'
}
function formatTime(seconds) {
if (seconds < 60) return Math.round(seconds) + 's'
return Math.round(seconds / 60) + 'm ' + Math.round(seconds % 60) + 's'
}
Expected output: Console shows a live update of percentage, download speed, and estimated time remaining.
Downloading with Response Type Blob
When downloading binary data, set responseType to blob and get a downloadable URL.
const { data } = await axios.get('/api/report.pdf', {
responseType: 'blob',
onDownloadProgress: function(e) {
console.log(`Downloading report: ${Math.round((e.loaded * 100) / e.total)}%`)
}
})
// Create a download link
const url = URL.createObjectURL(data)
const link = document.createElement('a')
link.href = url
link.download = 'report.pdf'
link.click()
URL.revokeObjectURL(url)
Expected output: The file downloads with a progress log, then triggers a browser download of the PDF.
Common Mistakes
1. Forgetting responseType: 'blob' for binary downloads
Without blob responseType, Axios tries to parse binary data as JSON, causing corruption and incorrect total size detection.
2. Assuming progressEvent.total is always available
total is null for responses without Content-Length header. Handle the case where total is undefined.
3. Not throttling progress updates in the UI
onDownloadProgress fires frequently. Throttle UI updates to every 100ms to avoid layout thrashing.
4. Using progress events in Node.js without proper streams
Node.js progress events work differently. Use the onDownloadProgress in Axios or manually track progress with streams.
5. Calculating ETA incorrectly early in the download
Early ETA estimates fluctuate wildly. Wait for at least 10% progress before displaying ETA.
Practice Questions
Which config option enables download progress tracking? onDownloadProgress callback in the request config.
What properties does the progress event contain? loaded (bytes completed) and total (total bytes). Total may be null without Content-Length.
How do you calculate download speed? Divide loaded bytes by elapsed time in seconds since the download started.
Why use responseType: 'blob' for downloads? It ensures binary data is returned as a Blob instead of being parsed as text/JSON.
Can you track progress for requests without Content-Length? Partially. loaded updates but total is null. Show indeterminate progress or downloaded bytes only.
Challenge
Build a download manager that tracks multiple simultaneous downloads, each with its own progress bar, speed display, and ETA. Auto-retry failed downloads up to 3 times.
FAQ
Mini Project
Build a complete download dashboard. Enter a URL, click download, and see a real-time progress bar with speed, ETA, percentage, and total size. When complete, show a success animation and offer to open the file.
async function startDownload(url) {
const startTime = Date.now()
const statusEl = document.querySelector('#status')
const progressEl = document.querySelector('#progress-fill')
const detailsEl = document.querySelector('#details')
try {
const response = await axios.get(url, {
responseType: 'blob',
onDownloadProgress: function(e) {
const now = Date.now()
const elapsed = (now - startTime) / 1000
const percent = e.total ? Math.round((e.loaded * 100) / e.total) : 0
const speed = e.loaded / elapsed
const eta = e.total ? ((e.total - e.loaded) / speed) : 0
progressEl.style.width = percent + '%'
statusEl.textContent = `${percent}%`
detailsEl.textContent = `Downloaded: ${formatBytes(e.loaded)}${e.total ? ' of ' + formatBytes(e.total) : ''} | Speed: ${formatSpeed(speed)} | ETA: ${formatTime(eta)}`
}
})
progressEl.style.width = '100%'
statusEl.textContent = 'Complete!'
detailsEl.textContent = `File size: ${formatBytes(response.data.size)}`
// Trigger download
const blobUrl = URL.createObjectURL(response.data)
const a = document.createElement('a')
a.href = blobUrl
a.download = url.split('/').pop()
a.click()
URL.revokeObjectURL(blobUrl)
} catch (error) {
statusEl.textContent = 'Failed'
detailsEl.textContent = error.message
}
}
What's Next
Learn about upload progress tracking:
| Tutorial | What You'll Learn |
|---|---|
| Upload Progress | Track file upload progress for form data |
| Cookies and Auth | Manage cookies and authentication with Axios |
Related topics: Blob and File objects, URL.createObjectURL.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro