Chrome Extension Downloads Management — Best Practices
5 min readDownloads Management Patterns
This guide covers patterns for managing downloads in Chrome extensions using the Downloads API.
Starting Downloads
Use chrome.downloads.download() to initiate downloads:
async function startDownload(url, filename) {
const downloadId = await chrome.downloads.download({
url: url,
filename: filename,
saveAs: true,
method: 'GET'
});
return downloadId;
}
Options:
url: The URL to downloadfilename: Custom filename (optional, auto-generated if omitted)saveAs: Show “Save As” dialog (true/false)method: HTTP method (default: ‘GET’)
Monitoring Progress
Listen to chrome.downloads.onChanged to track download progress:
chrome.downloads.onChanged.addListener((downloadDelta) => {
if (downloadDelta.state) {
console.log(`State: ${downloadDelta.state.current}`);
}
if (downloadDelta.bytesReceived) {
const progress = (downloadDelta.bytesReceived / downloadDelta.totalBytes) * 100;
updateProgressBar(downloadDelta.id, progress);
}
});
Download States
Downloads transition through these states:
in_progress: Download is actively downloadinginterrupted: Download was interrupted (checkerrorfor reason)complete: Download finished successfully
Progress UI in Popup
Display download progress in your extension popup:
function updateProgressBar(downloadId, percent) {
const progressBar = document.getElementById('download-progress');
progressBar.style.width = `${percent}%`;
progressBar.textContent = `${Math.round(percent)}%`;
}
Filename Generation
Generate dynamic filenames with timestamps:
function generateFilename(baseName, extension) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const sanitized = baseName.replace(/[^a-z0-9]/gi, '_').toLowerCase();
return `${sanitized}_${timestamp}.${extension}`;
}
File Type Handling
Set appropriate MIME types and extensions:
const fileTypes = {
json: { mime: 'application/json', ext: 'json' },
csv: { mime: 'text/csv', ext: 'csv' },
png: { mime: 'image/png', ext: 'png' }
};
Batch Downloads
Queue multiple downloads with concurrency control:
async function batchDownload(urls, concurrency = 3) {
const queue = [...urls];
const active = [];
while (queue.length > 0 || active.length > 0) {
while (active.length < concurrency && queue.length > 0) {
const url = queue.shift();
const promise = chrome.downloads.download({ url }).then(id => {
active.splice(active.indexOf(promise), 1);
});
active.push(promise);
}
await Promise.race(active);
}
}
Download from Generated Data
Create downloads from Blob URLs for generated content:
async function downloadDataAsFile(data, filename, mimeType) {
const blob = new Blob([data], { type: mimeType });
const url = URL.createObjectURL(blob);
await chrome.downloads.download({ url, filename });
URL.revokeObjectURL(url);
}
Cancel, Pause, Resume
chrome.downloads.cancel(downloadId); // Cancel download
chrome.downloads.pause(downloadId); // Pause download
chrome.downloads.resume(downloadId); // Resume paused download
Open and Show Files
chrome.downloads.open(downloadId); // Open downloaded file
chrome.downloads.show(downloadId); // Show in file manager
Download History
Query past downloads:
async function getDownloadHistory() {
const downloads = await chrome.downloads.search({ limit: 50 });
return downloads.filter(d => d.state === 'complete');
}
Shelf Control
Control the download shelf (bottom bar):
chrome.downloads.setShelfEnabled(false); // Hide download shelf
chrome.downloads.setShelfEnabled(true); // Show download shelf
Related Documentation
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.