Asynchronous File Downloads from Within VBA Excel
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
VBA is fundamentally single-threaded, but you can still perform non-blocking HTTP downloads by using COM objects that support asynchronous requests and event callbacks. The important distinction is that Excel itself is not becoming multi-threaded; instead, the HTTP component performs work in the background and notifies VBA when progress changes.
The Basic Approach
For asynchronous downloads in Excel VBA, a practical pattern is:
- create a class module with
WithEvents - use
MSXML2.XMLHTTP60in async mode - handle the
onreadystatechangeevent - save the
responseBodywhen the request completes
This gives you a responsive workbook while the request is in flight. Users can still interact with Excel, though you should avoid starting dozens of downloads at once unless you also manage state carefully.
Class Module Example
Create a class module named CDownloadJob and paste this code into it:
The key detail is the third argument to Open. Passing True requests asynchronous behavior.
Standard Module Code
Now add a standard module so Excel can create and retain the download object. Keeping a reference is important because the class must stay alive long enough to receive the callback.
Run StartDownload from the macro dialog or attach it to a button in the sheet.
What Makes This Asynchronous
The macro that starts the request returns almost immediately. The HTTP request continues after control goes back to Excel. When the component changes state, the event handler runs. That is why this technique feels asynchronous to the user even though VBA itself is not using await or threads in the modern sense.
This also means your workbook must remain open and the object reference must remain valid. If the class instance goes out of scope, the events will stop and the download callback will never arrive.
Handling Multiple Downloads
If you need several downloads, store several CDownloadJob objects in a collection instead of a single module-level variable. Remove each job from the collection when it completes. That prevents it from being garbage collected too early while avoiding leaked references after the request is done.
You may also want to report progress in cells or a status form instead of showing MsgBox dialogs. The event-based model supports that cleanly once the basic download flow is working.
Why Synchronous Code Feels Worse in Excel
A synchronous download blocks the Excel UI until the request finishes. During a slow network call, the workbook can appear frozen, formulas do not recalculate visibly, and users may think the application crashed.
That is why async download patterns are valuable in VBA even if the language itself is older. The network wait is usually the expensive part, and handing that wait to a COM component makes the workbook much more usable.
Common Pitfalls
The most common mistake is letting the download object go out of scope. If you create it inside a procedure and do not store it anywhere, the event handler may never run.
Another issue is forgetting required references. MSXML2.XMLHTTP60 needs the Microsoft XML library available on the machine, and writing binary data cleanly is easiest with ADODB.Stream.
Developers also assume asynchronous means parallel-safe. It does not. Event callbacks can still modify workbook state at awkward times, so shared state should be updated carefully.
Finally, do not ignore HTTP status codes. A request that finishes with 404 or 500 still reaches ready state 4, but it did not succeed. Always inspect Status before saving the response.
Summary
- VBA can support non-blocking downloads by using asynchronous COM HTTP objects with events.
- '
MSXML2.XMLHTTP60plus aWithEventsclass is a practical pattern for Excel automation.' - Keep the download object alive or the completion callback will never fire.
- Use
ADODB.Streamto save binary response data safely to disk. - Treat ready state
4as “request finished,” not automatically as “download succeeded.”

