How to Wait for a File Download in Vibium
Wait for a file download in Vibium with Python — wrap the triggering click in capture.download(), which blocks until the file finishes downloading.
To wait for a file download in Vibium, wrap the click that triggers it in vibe.capture.download() — the call blocks until the download finishes, then returns a result you save with save_as(). This is the clean way to handle the classic race: a naive script clicks a download link and immediately tries to read the file before the browser has written it. capture.download() removes that race entirely. It registers a download listener first, runs your action, and only returns once the file is fully downloaded, so the result it hands back is itself the "download complete" signal. No polling the filesystem, no fixed sleep() that is too short on slow networks and wasteful on fast ones. You get the suggested filename, source URL, and temp path, and you copy the file wherever you want.
What is the download-wait script?
from vibium import browser
bro = browser.launch()
vibe = bro.page()
vibe.go("http://localhost:3000")
# Blocks until the file finishes downloading, then returns
result = vibe.capture.download(lambda: vibe.find("#dl-link").click())
print(result["suggested_filename"]) # hello.txt
result.save_as("/tmp/hello.txt")
bro.close()The lambda is the action that starts the download. Vibium begins listening, runs the click, waits for the file to finish, and returns the result. By the time the next line runs, the download is guaranteed complete.
How does each step work?
vibe.go(url)— open the page that has the download link or button.vibe.capture.download(action)— register a download listener, runaction, and block until the download completes. This is the wait — you do not add one yourself.result["suggested_filename"]— the name the server suggested via theContent-Dispositionheader.result.save_as(path)— copy the finished file to a permanent path you choose.bro.close()— close the browser.
In sync mode the result is a dict-like object: read result["url"], result["suggested_filename"], and result["path"], and it still exposes save_as().
Why does capture.download() remove the race?
The order of operations is what matters. capture.download() attaches the listener before your click fires, so even a download that completes almost instantly cannot slip past unnoticed. Then the call holds until the browser reports the file finished. Contrast that with the fragile alternative — click, time.sleep(2), hope — which fails on a slow connection and wastes time on a fast one. Because Vibium auto-waits on the element before clicking and capture.download() waits on the file after, the entire flow is deterministic without a single hardcoded delay.
How do I wait for many downloads at once?
When files can arrive at any time — say a button that exports several reports — register on_download() once and collect them as they complete, rather than wrapping a single action:
import time
downloads = []
vibe.on_download(lambda dl: downloads.append(dl))
vibe.find("#export-all").click()
time.sleep(2) # give the batch time to finish
for dl in downloads:
print(dl["suggested_filename"])
dl.save_as(f"/tmp/{dl['suggested_filename']}")Use capture.download() when you wait on one known action; use on_download() for ongoing monitoring of an unknown number of files.
Why isn't my download completing?
If capture.download() seems to hang, the browser most likely never started a download at all. A download only fires when the server responds with a Content-Disposition: attachment header — a plain link that navigates or opens a PDF inline will not trigger one, so the listener waits forever. For local testing, a tiny server that sets the header is enough to verify your script:
# server.py — run with: python server.py
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/file":
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Disposition", 'attachment; filename="hello.txt"')
self.end_headers()
self.wfile.write(b"hello world")
else:
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write(b'<a href="/file" id="dl-link">Download hello.txt</a>')
HTTPServer(("localhost", 3000), Handler).serve_forever()Run python server.py in one terminal, then run the download script in another and point go() at http://localhost:3000.
Tips for reliable download waits
- Always
save_as()— the temppathmay be cleaned up when the browser closes, so copy the file out explicitly. - Check
suggested_filenamebefore saving so you keep the correct extension. - Prefer
capture.download()for a single known action; reach foron_download()only when several files arrive unpredictably.
Next steps
Frequently asked questions
How do I wait for a file download in Vibium?
Wrap the click that starts the download in vibe.capture.download(). It registers a listener, runs your action, and blocks until the download finishes before returning the result. You never write a sleep — the call returns exactly when the file is ready to save.
How do I know when a Vibium download is complete?
capture.download() only returns once the download has finished, so the result it hands back is the signal of completion. From there you read suggested_filename, url, and path, then call save_as() to copy the finished file to a permanent location of your choosing.
Why is my Vibium download hanging or never finishing?
A download only fires when the server sends a Content-Disposition attachment header. If the link navigates or opens the file inline, no download event ever completes and capture.download() waits in vain. Point Vibium at an endpoint that returns the attachment header.
Vibium is created by Jason Huggins. This is an independent tutorial — see the official Vibium site and GitHub repo for canonical docs.
Related guides
How to Automate a Checkout Flow with Vibium
Automate an e-commerce checkout with Vibium in Python — add to cart, fill shipping and payment fields, place the order, and verify the confirmation page.
4 min read→How-To RecipesHow to Automate a Google Search with Vibium
Automate a Google search with Vibium in Python — open Google, type a query, submit it, and read the result titles in about ten lines of code.
3 min read→How-To RecipesHow to Automate a Multi-Tab Flow with Vibium
Automate a multi-tab flow with Vibium in Python — open new tabs with new_page(), switch with bring_to_front(), capture popups, and close tabs cleanly.
3 min read→How-To RecipesHow to Automate a Search Box with Vibium
Automate a search box with Vibium in Python — find the input, type your query, press Enter, wait for results to render, and read them back with findAll.
3 min read→