# ddgr: DuckDuckGo from the Terminal, Reviewed for Adoption

> ddgr is a Python 3.10+ command line client for DuckDuckGo's HTML endpoint, with bangs, a REPL and configurable results per page. It is a small, single-file tool for people who want search in the shell without a browser.

**jarun/ddgr** — :duck: DuckDuckGo from the terminal

- Repository: https://github.com/jarun/ddgr
- Stars: 3,558 · Forks: 168
- Language: Python
- License: GPL-3.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/jarun-ddgr

## What ddgr solves, and who it is actually for

Searching from a terminal usually means either opening a browser or writing a scraper. ddgr occupies the middle ground: it is a command line utility that queries DuckDuckGo's HTML version and prints results in the terminal. The README frames the origin directly, saying that while googler is popular among command line users, forums kept asking for the same thing for privacy-aware DuckDuckGo, and that DuckDuckGo Bangs are "super-cool too".

The audience is narrow and specific. Someone who lives in tmux or GNU Screen, wants to run a search without switching context, and prefers DuckDuckGo over Google. The README also notes that DuckDuckGo works over the Tor network, which it presents as an advantage over googler. That matters for people who route traffic through Tor and want search to go through the same path.

It is not a general search library. There is no documented API for embedding it in another program, and it is not affiliated with DuckDuckGo in any way, which the README states plainly.

## How ddgr talks to DuckDuckGo's HTML endpoint

The mechanism is a single executable script. The repository root contains a file named ddgr, and setup.py copies that file to ddgr.py at build time, then reads the version out of it with a regular expression on _VERSION_. The package exposes one console entry point, ddgr = ddgr:main. There is no package directory, no modules to import, and no service to run.

Requests go to the HTML version of DuckDuckGo, linked in the README as html.duckduckgo.com/html/. That means ddgr parses markup rather than calling a JSON API. It is the same shape of tool as googler, and it inherits the same failure mode: when the HTML changes, the parser is what breaks. The README does not describe a fallback path or a second endpoint.

Features that come out of that endpoint include instant answers, which the README lists as supported by the DDG html version, and DuckDuckGo Bangs. Bangs are the ! prefixes that redirect a query to a specific site, and ddgr adds completion for them. The tool also supports keywords such as filetype:mime and site:somesite.com, time-limited searches, region selection, and safe search control.

Output is designed around a different constraint than the web page. The README says the default interface is "carefully designed to use minimum space without sacrificing readability", and unlike the web interface you can pick how many results appear per page instead of skimming thirty-odd results. The -n flag takes 0 through 25, with 10 as the default; passing 0 shows the actual number of results fetched per page. That is a small feature, but it is the one that most changes how the tool feels in daily use.

## Installing ddgr and running a first search

The dependency list is short. ddgr requires Python 3.10 or later, and only the latest patch release of each minor version is supported. The requests library was required up to v1.1 and was removed in later releases, so a current install does not need it.

The quickest route on most systems is pip. The README lists PyPI under unlisted packagers with this command:

```bash
pip3 install ddgr
```

After that, ddgr is on your PATH through the console script entry point in setup.py. Running it with keywords performs a search and prints a numbered list of results. The help output is the authoritative reference for flags:

```bash
ddgr --help
```

The usage line in the README shows the positional argument as KEYWORD [KEYWORD ...], so a plain search looks like this:

```bash
ddgr python packaging
```

If pip is not how you install software, the README also lists snap install ddgr and, for Source Mage, cast ddgr. From a git clone, the Makefile installs to /usr/local by default and supports PREFIX for a different location:

```bash
sudo make install
```

The Makefile installs the script to $(PREFIX)/bin, gzips ddgr.1 into the man directory, and copies README.md into /usr/local/share/doc/ddgr. Removal is symmetric:

```bash
sudo make uninstall
```

ddgr is also a standalone executable, so from the containing directory ./ddgr runs it without installing anything. That path is what makes Termux workable, and the README lists Termux separately with pip3 install ddgr.

## The omniprompt, clipboard handling and where it breaks

After a search, ddgr drops into an interactive prompt rather than exiting. The README calls this a REPL for continuous searches, and the prompt is where navigation and browser integration happen. Copying a URL at that prompt depends on external programs: ddgr looks for wl-copy on Wayland, then xsel, then xclip, then termux-clipboard-set on Linux, and uses pbcopy on macOS, clip on Windows and clipboard on Haiku. GNU Screen and tmux copy-paste buffers are used when X11 is absent.

That lookup chain is the most likely source of confusion. If none of those binaries is installed, the copy action has nothing to call, and the README does not document a fallback or an error message for that case. On a minimal Linux container, xsel and xclip are both commonly missing. The fix is to install one of them, not to reconfigure ddgr.

The bigger limitation is structural. ddgr parses DuckDuckGo's HTML, so it covers what that page returns and nothing else. Image search, maps, and the richer result panels from the main interface are outside its scope. The README's feature list mentions instant answers, bangs, keywords, time limits, region and safe search, but says nothing about images or maps.

The --json flag exists, and appears in the usage block, but the README excerpt does not describe its schema or promise stability. Treating it as a supported interface for another program is a guess, not a documented contract. If you need a stable machine-readable search API, ddgr is the wrong tool; a search API with a versioned response format is the right one.

## ddgr versus googler: same author, different index

The obvious alternative is googler, by the same author, which the README names directly as the popular command line search utility that prompted ddgr's existence. They share a design lineage: both are single-file Python command line search clients with a prompt, browser integration, completion scripts and a similar flag vocabulary. If you have used one, the other will feel familiar.

The difference is the index behind them and what that implies. googler queries Google; ddgr queries DuckDuckGo's HTML endpoint. The README states that a big advantage of ddgr over googler is that DuckDuckGo works over the Tor network. For a user whose traffic already goes through Tor, that is the deciding factor, because the search request follows the same path as everything else.

The second difference is bangs. DuckDuckGo's ! shortcuts are a first-class feature in ddgr, with keyword and option completion scripts for Bash, Fish and Zsh kept under auto-completion/. Google has no equivalent, so this is not a feature you can port. If your workflow depends on typing !w or !gh to jump straight to a site, ddgr is the only one of the two that gives you that.

Neither tool is a library. Choosing between them is choosing a search index and a set of shortcuts, not an architecture.

## Maintenance, licensing and the upgrade cost

The last push to the repository was on 2026-08-16, so the project is not dormant. The most recent tagged release, however, is v2.2 from 2023-12-29, followed by v2.1 in 2022 and v2.0 in 2022. That gap between commits and releases is worth noticing: fixes may land on main before they reach a tag, and package managers typically track tags. If you install from a distribution repository and the version there looks dated, the README's own advice is to try an alternative installation method rather than wait.

Upgrade cost is low by design. There is no daemon, no database and no migration step. Upgrading means replacing one script and, at most, re-reading the man page. The real upgrade risk is the Python floor: python_requires is >=3.10 and setup.py classifies 3.10 through 3.14, so an environment pinned below 3.10 cannot run current ddgr at all.

The licence is GPL-3.0, declared in the LICENSE file and in setup.py as GPLv3. For a command line tool you install and run, that is unremarkable. It becomes relevant if you intend to copy ddgr's code into your own program, because GPL-3.0 carries distribution obligations that permissive licences do not. That is a statement about the licence text, not legal advice; check with someone qualified before embedding it.

One more maintenance note: because ddgr depends on DuckDuckGo's HTML structure, an upstream markup change can break it without any commit to this repository. The README does not document a compatibility policy for that scenario.

## What to check before you commit to ddgr

The package manager version is the first thing to verify. Run ddgr --help and compare the flags you see against the usage block in the README, which lists options including -n, -r, --colorize, --colors, -j, -t, -w, -x, -p, --unsafe, --noua, --json, --gb, --np, --url-handler, --show-browser-logs, -v and -d. If your installed version predates a flag you need, install from PyPI or from source instead.

Second, check the clipboard chain on your machine. On Linux, confirm that wl-copy, xsel, xclip or termux-clipboard-set is present, depending on your display server. Without one of them, the copy action at the prompt has nothing to invoke.

Third, decide whether you need shell completion. The scripts live in subdirectories of auto-completion/ for Bash, Fish and Zsh, and the README defers to your shell's manual for installation. They are not installed by the Makefile, so completion is a separate step you have to take deliberately.

Finally, be honest about the scope. ddgr gives you text results from DuckDuckGo's HTML page, plus bangs and instant answers. It does not give you images, maps or a documented JSON contract. If those are requirements, this is the wrong tool, and no amount of configuration will change that.

## Conclusion

Adopt ddgr if you already work in a terminal and want DuckDuckGo results, bangs and a REPL without leaving the shell; pip3 install ddgr or snap install ddgr gets you there in one step. Skip it if you need the main DuckDuckGo web interface, image or map results, or a stable machine-readable API, because ddgr scrapes the HTML endpoint and its --json output is not documented as a supported interface. Before relying on it, check that your Python is 3.10 or later, that your package manager's version is not dated, and whether you need a clipboard helper such as xsel or xclip installed for the copy action at the prompt.

## FAQ

### Can I use ddgr on Linux?

Yes. The README lists Linux clipboard helpers (wl-copy under Wayland, then xsel, xclip or termux-clipboard-set) and describes GNU Screen and tmux copy-paste buffers as fallbacks when X11 is unavailable. It also lists snap install ddgr and pip3 install ddgr as installation routes.

### Is ddgr free to use?

ddgr is released under GPL-3.0, declared in the LICENSE file and in setup.py, so there is no cost to install or run it. It is not affiliated with DuckDuckGo in any way, as the README states.

### What Python version does ddgr need?

ddgr requires Python 3.10 or later, and the README says only the latest patch release of each minor version is supported. setup.py sets python_requires to >=3.10 and classifies 3.10 through 3.14.

### How do I install ddgr from source?

Clone the repository and run sudo make install, which installs to /usr/local by default. The Makefile supports PREFIX if you want a different location, and sudo make uninstall removes the script, the man page and the docs directory.

### How many results can ddgr show per page?

The -n flag takes a value from 0 to 25 and defaults to 10. Setting N to 0 shows the actual number of results fetched per page, according to the usage text in the README.

## Sources

- [Issues](https://github.com/jarun/ddgr/issues)
- [jarun/ddgr on GitHub](https://github.com/jarun/ddgr)
- [License: GPL-3.0](https://github.com/jarun/ddgr/blob/main/LICENSE)
- [README](https://github.com/jarun/ddgr/blob/main/README.md)
- [Releases](https://github.com/jarun/ddgr/releases)

---

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