# gdown: downloading public Google Drive files when curl and wget fail

> gdown is a Python CLI and library for pulling public Google Drive files and folders, exporting Docs formats, and resuming interrupted transfers. It is a narrow tool with a clear boundary: public links only, and no upload path.

**wkentaro/gdown** — Google Drive public file downloader when curl/wget fails.

- Repository: https://github.com/wkentaro/gdown
- Stars: 5,440 · Forks: 433
- Language: Python
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/wkentaro-gdown

## The problem gdown solves is a confirmation page, not a protocol

The README states the motivation plainly: downloading public files from Google Drive with curl or wget does not work, because Google serves a confirmation page for large files and the URL formats are inconsistent. That is the whole premise. A plain HTTP client follows the share URL, receives an HTML interstitial rather than bytes, and writes a few kilobytes of markup to disk with an exit code of zero. Scripts that check the exit code conclude the download succeeded.

gdown exists to skip that virus-scan confirmation step so large downloads actually finish. The intended audience is developers who receive Drive links from collaborators, dataset authors, or paper repositories and need a reproducible fetch in a build script or notebook. It is not a general-purpose Drive client. There is no upload command anywhere in the README, and the project description is explicit that this is a public file and folder downloader.

The secondary value is URL tolerance. The README notes that URL formats are a mess, and gdown accepts several shapes for the same file: a uc?id= URL, a bare file ID, or a full /file/d/.../view?usp=sharing share link. That normalization is small but it removes a class of copy-paste bugs.

## How gdown resolves a share link into bytes

For Google Drive URLs, the README says gdown automatically extracts the file ID and downloads the actual file, and adds a note that you should use curl or wget if you want the raw HTML page instead. So the first stage is parsing: the tool recognizes the URL shapes above, isolates the identifier, and constructs the request that returns content rather than the interstitial.

Folder handling is a second stage. Folder URLs are detected automatically, but a bare folder ID requires --folder, because file and folder IDs share the same format and cannot be told apart by shape alone. That is a real design constraint rather than an oversight: the ambiguity is in Google's identifier scheme, not in gdown.

For Google Docs, Sheets, and Slides, the tool performs an export rather than a download. The README lists the default export formats as Docs to docx, Sheets to xlsx, and Slides to pptx, with --format pdf as an override. This is a different code path from a binary file fetch, and it is worth knowing which one you are triggering, because the output is a converted rendering and not the original document bytes.

Everything else flows through a requests-based HTTP layer. The dependency list in pyproject.toml includes requests[socks], urllib3, beautifulsoup4, filelock, and tqdm. BeautifulSoup is consistent with parsing HTML responses, and tqdm is the progress bar. The filelock dependency is not explained in the README, but its presence alongside a default cookie path of ~/.cache/gdown/cookies.txt suggests the cookie jar is treated as shared mutable state.

## Installing gdown and downloading your first folder

gdown requires Python 3.10 or later, per both the README and the requires-python field in pyproject.toml. The documented install is a plain pip install, with uv as an alternative.

```bash
pip install gdown
```

After that, the gdown console script is on your PATH. The README also documents the uv route, which installs it as an isolated tool rather than into a project environment:

```bash
uv tool install gdown
```

If the shell reports gdown: command not found after a pip install, the usual cause is that pip wrote the script into a user-level bin directory that is not on PATH. The README does not cover this case, so it is worth checking where pip placed the entry point before assuming the install failed.

A first real download is a single argument. The README's quick start says to just paste a Google Drive URL:

```bash
gdown 'https://drive.google.com/file/d/0B9P1L--7Wd2vU3VUVlFnbTgtS2c/view?usp=sharing'
```

The tool resolves the ID, skips the confirmation page, and writes the file under the name Drive reports. If you want to control the name while keeping the original extension, --json resolves the filename without downloading. Note the README's caveat that --json is in beta and its output format may change, and that --quiet suppresses the beta warning in scripts:

```bash
url="https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c"
filename=$(gdown "$url" --json | jq -r '.[0].path')
gdown "$url" -O "my_name.${filename##*.}"
```

The output is an array of objects with url and path keys. For folders, the same flag lists contents instead of downloading, and the README shows filtering that list with jq and piping matches back into gdown one at a time:

```bash
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --json \
  | jq -r '.[] | select(.path | test("shad")) | .url' \
  | xargs -n1 gdown
```

That pattern is the most useful thing in the README for anyone maintaining a data pipeline, because it separates discovery from transfer and lets you cache or skip individual files.

## Resume, throttling, and the failure modes the README admits

The README documents --continue for resuming a partially downloaded file, --speed for a transfer cap, --proxy for an HTTP proxy, and --timeout to give up when the server sends nothing for a stated number of seconds. Those are the knobs that matter on unreliable links, and their existence tells you the maintainer expects long transfers over flaky connections.

The most consequential limitation is throttling. The FAQ states that Google throttles downloads when too many people access the same file, but lets a signed-in account through. The documented workaround is --cookies-from-browser, which reuses a browser's session:

```bash
gdown --cookies-from-browser firefox https://drive.google.com/uc?id=FILE_ID
```

The README lists supported browsers as brave, chrome, chromium, edge, firefox, opera, safari, vivaldi, and wh. This is a real operational constraint, not a bug: a popular dataset link can simply stop working for anonymous clients, and your options are to authenticate or to mirror the file somewhere else. If you are building an unattended CI job, keep in mind that cookie reuse means a credential material dependency, and the default cookie file lives at ~/.cache/gdown/cookies.txt unless you override it with --cookies or disable it with --no-cookies.

The second failure mode is the permission error. The FAQ's first entry says a Permission Denied error means the file sharing is not set to Anyone with the link. gdown cannot fix that, and no flag will. The third is a boundary rather than a failure: gdown is the wrong tool when you want the raw HTML of a Drive page, when you need to upload, or when you cannot add a Python dependency to the environment at all. For plain HTTP and HTTPS URLs the README does present gdown as a curl/wget replacement, but if your target is not Google Drive you are paying a Python dependency for behavior curl already provides.

## gdown against curl, wget, and the Drive API

The honest comparison is not gdown versus another downloader. It is gdown versus writing the interstitial-handling logic yourself, or versus going through Google's own API.

curl and wget are the baseline the project defines itself against, and for ordinary HTTP they are strictly simpler: no Python runtime, no dependency tree, present by default on most images. The README acknowledges this by noting that gdown also works with regular URLs, which is a convenience rather than a reason to switch. Where curl and wget genuinely fail is the specific case in the project description: a large public Drive file behind a confirmation page. Reproducing gdown's parsing and confirmation handling in a shell script is possible but is exactly the kind of code that silently breaks when Google changes a response.

Against the Google Drive API, the difference is authentication and scope. The API expects OAuth credentials and works with files your account can see, including private ones. gdown targets public links and, when throttled, borrows a browser session through --cookies-from-browser rather than running an OAuth flow. If your access pattern is private files, service accounts, or anything under a shared drive, the API is the right layer and gdown is not.

A third option is simply mirroring. If a dataset is fetched by hundreds of CI runs, copying it to object storage once removes the throttling problem entirely. gdown is the tool that gets you the bytes for that first copy.

## Release cadence, licence, and what upgrading costs

The repository is not archived, and the last push was on 2026-09-18. Recent releases are close together: v6.2.0 on 2026-09-06, v6.3.0 on 2026-09-16, and v6.4.0 on 2026-09-17. That cadence means pinning a version is worth the effort if you depend on exact CLI behavior.

The release process is visible in the repository layout. There is a changelog.d directory and a towncrier configuration in pyproject.toml with fragment types for added, changed, deprecated, removed, fixed, and security, plus a justfile recipe named release that computes the next version from git tags and checks fragments for a Breaking marker. In practice that means breaking changes are meant to be announced in the changelog rather than discovered at runtime, and CHANGELOG.md is the file to read before bumping a pin.

The licence is MIT, declared both in the README badge and in the license field of pyproject.toml, with the LICENSE file at the repository root. MIT is permissive and imposes no copyleft obligation on your own code, but gdown bundles third-party work: the justfile has a vendor target that regenerates a vendored yt-dlp cookie module, and the lint recipe excludes gdown/_vendor from one of the checks. If you redistribute gdown inside a product, read the vendored files' own terms rather than assuming the top-level MIT text covers everything. That is a packaging question, not legal advice.

Upgrade cost is mostly the beta surface. The README flags --json as beta with a format that may change, so any script parsing its output is exposed to churn on a minor release. Using --quiet keeps the beta warning out of your logs but does not stabilize the schema.

## Conclusion

Adopt gdown if your pipeline pulls public Google Drive artifacts: datasets, model weights, shared release folders. Skip it if you need uploads, private-team-drive access, or a dependency-free shell script, since it is a Python package with six runtime dependencies. Before relying on it in automation, verify three things on your own links: that --json resolves the filename you expect, that --continue resumes cleanly against the specific file, and that the MIT licence text in LICENSE matches your redistribution terms.

## FAQ

### How do I install gdown?

Run pip install gdown; it requires Python 3.10 or later. The README also documents uv tool install gdown as an alternative that installs it as an isolated tool.

### How do I install gdown on Ubuntu?

The README gives no Ubuntu-specific instructions. The documented install is pip install gdown against a Python 3.10 or later interpreter, or uv tool install gdown.

### How do I use gdown to download a Google Drive file?

Pass the share link, a uc?id= URL, or a bare file ID as the single argument, as in gdown 'https://drive.google.com/file/d/0B9P1L--7Wd2vU3VUVlFnbTgtS2c/view?usp=sharing'. gdown extracts the file ID and downloads the actual file rather than the HTML page.

### How do I download an entire Google Drive folder with gdown?

Pass the folder URL and gdown detects it automatically; a bare folder ID needs --folder because file and folder IDs have the same format. The README shows -O /tmp/folder to choose the destination and --json to list contents instead of downloading.

### How do I download large files from Google Drive with gdown?

gdown skips the virus-scan confirmation page that curl and wget hit on large public files, and --continue resumes a partial download. If Google throttles the file, the README suggests reusing a browser session with --cookies-from-browser.

### Can I download from a Google Drive link with gdown?

Yes, as long as the file sharing is set to Anyone with the link. The README notes that a Permission Denied error means the sharing setting is still restricted.

## Sources

- [Issues](https://github.com/wkentaro/gdown/issues)
- [License: MIT](https://github.com/wkentaro/gdown/blob/main/LICENSE)
- [README](https://github.com/wkentaro/gdown/blob/main/README.md)
- [Releases](https://github.com/wkentaro/gdown/releases)
- [wkentaro/gdown on GitHub](https://github.com/wkentaro/gdown)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wkentaro-gdown
