httpdbg shows you the HTTP traffic a Python program makes, and where it came from
A tool for Python developers to easily debug the HTTP(S) client and server requests in a Python program.
At a glance
- What is it?
- httpdbg is a Python debugging tool that records HTTP and HTTPS client and server requests and shows them in a local web interface, grouped by the function that triggered them. You run your program with pyhttpdbg instead of python, and the tool captures requests from requests, urllib3, httpx, aiohttp, Flask and FastAPI.
- Who is it for?
- httpdbg earns a place in a debugging session when you need to know not only which requests a Python program makes but which call site made each one, because the initiator and group model is something request logging middleware and an HTTP client log level do not give you. Skip it if you need distributed tracing across services, if your traffic is not going through one of the listed client libraries, or if HTTP/2 matters and the h2 library is not in play.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 26 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
pyhttpdbg replaces python on the command line
The problem httpdbg solves is a specific kind of confusion: a Python program makes an HTTP request, something goes wrong, and the stack trace or the library log tells you a request happened but not which line of your own code asked for it. In a program that calls an API client from a dozen places, that is the difference between an afternoon and a morning.
The tool is a wrapper. Instead of running python yourprogram.py you run pyhttpdbg yourprogram.py, and the process records the HTTP traffic that the program performs, both outbound calls and inbound requests to a server it is hosting. The result is displayed in a web interface served on port 4909, so you open a browser and look at the requests as a list you can inspect.
The audience is Python developers, and the surface area is deliberately narrow. The project is classified as production or stable in its package metadata, works on Python 3.9 through 3.14, is OS independent, and ships under Apache-2.0. Full documentation lives at httpdbg.readthedocs.io. The tool supports HTTP/1.0, HTTP/1.1 and HTTP/2, which is the first place where a caveat appears: HTTP/2 is supported only through the h2 library.
There is also an interactive console mode, which is the default. That matters because the zero-configuration claim in the documentation means you can start it and type Python at a prompt with the recording already active, with no script, no wrapper and no code change.
Initiators and groups are what make the request list readable
The mechanism that gives httpdbg its value is the pair of concepts called initiators and groups, and it is worth understanding them precisely, because the two tables in the documentation use them differently on purpose.
An initiator is the function or method at the origin of the HTTP requests. On the client side, the initiator is the highest-level method used to make the request through the client, and the group is identical to the initiator. On the server side, the initiator is the low-level socket method that receives the data, while the group is the endpoint method used to handle the request. A client request made inside a server endpoint method is included in that server group, which is how an outbound call triggered by an inbound request stays attached to the handler that caused it.
For clients, the group is a set rather than a single call. If a request to a URL produces multiple requests, as happens with redirection, all of them are grouped together, so a redirect chain reads as one entry instead of three confusing ones.
This model is the practical payoff. A raw request log is a flat list of URLs, and the question you actually have is which of the forty calls in your code produced the one that failed. With groups, the browser view answers that directly. The grouping is also a work queue in disguise: each group represents a call site, so the tool can show you how many distinct call sites made requests and which of them produced the most traffic.
Three ways to run a program under the recorder
The command line has three execution modes and the usage text makes them explicit:
usage: pyhttpdbg [-h] [--host HOST] [--port PORT] [--version]
[--initiator INITIATOR] [--only-client]
[--console | --module MODULE | --script SCRIPT]The default is an interactive console, which starts a Python REPL with the recorder running. The console banner tells you where the requests will appear:
httpdbg - HTTP(S) requests available at http://localhost:4909/For a script, the --script flag takes the file name and passes the rest of the arguments through:
pyhttpdbg --script filename.py [arg1 --arg2 ...]For a module, the -m argument behaves like python -m and passes the remaining arguments to the module. The documentation gives a deliberately revealing example, tracing the requests that pip itself makes:
pyhttpdbg -m pip install hookdns --upgradeThat example is a good demonstration of the tool's reach, because pip is not a project you wrote and does not use a supported client library, so the value of seeing the traffic is that the tool records at a lower level than your own code.
The third mode is test suites. The -m flag with pytest or unittest groups the requests by test, and requests made inside a fixture or in the setup and teardown methods are tagged so you can tell them apart:
pyhttpdbg -m pytest [arg1 --arg2 ...]This is the mode that turns httpdbg from a debugging toy into a test tool, since a per test view of outbound calls is something you can assert on in CI, which is what the test frameworks supported table in the documentation is pointing at.
The web interface on port 4909 is the entire inspection surface
Everything is viewed in a browser, and the defaults are chosen so that nothing has to be configured. The interface listens on localhost:4909, the port can be changed with --port or -p, and the host address with --host.
Two flags control the lifetime of the server, and they exist because the tool is designed for a short session rather than a long lived service. By default the server stops once the requests have been read. --keep-up keeps it up even after the requests have been read, and --force-quit stops it even if the requests have not been read. The first is what you want when you are stepping through your program in the console and want the list to survive between interactions. The second is what you want in a script that ends abruptly.
Two more options shape the output. The --export-html flag takes the path to an export file, which is the way to keep a record of a session worth discussing with a colleague. The --no-banner flag suppresses the banner in the console, useful when the banner is getting in the way of output you are trying to read.
The interface has to be reached in a browser, which is a real dependency in a headless environment. The server requests are recorded server side as well, and the documentation shows the Flask example where the same port serves the tool while the application under test runs on its own port:
pyhttpdbg -m flask --app demoflask runThat example prints the Flask startup lines alongside the tool banner, with the application on 127.0.0.1:5000 and the recorder on 4909, so both the incoming and the outgoing traffic land in the same view.
What is covered, and what a custom initiator buys you
The documentation is explicit about the supported matrix, and the asymmetry between clients and servers is the part to note.
Four client packages are listed as supported: requests, urllib3, httpx and aiohttp. For all four the initiator and the group are both available, and each is marked as supported for both. Then there is a row for your own package, with the argument needed to enable it. The --initiator flag, short form -i, adds a package to the initiator list:
pyhttpdbg -i api_client_pck --script my_script.pyThe documentation notes that any package can be an initiator and that this is not limited to HTTP requests, so the same mechanism can attribute non-HTTP side effects to a call site.
Servers are narrower. Flask and FastAPI are both supported, but with a dash in the initiator column and a yes in the group column, because on the server side the initiator is the low-level socket receive and the group is the endpoint method. A client request made within that endpoint method is included in the same group.
Test frameworks are grouped too: pytest and unittest are both listed as supported for grouping. And on the protocol side, HTTP/1.0, HTTP/1.1 and HTTP/2 are supported, with the HTTP/2 line qualified as supported only through the h2 library. That qualification is the single most important coverage fact in the tables.
Where httpdbg is the wrong instrument
Three cases rule it out.
First, HTTP/2 without the h2 library. The support table says so directly, and there is no configuration switch listed that changes it. A project on HTTP/2 through a different stack will see partial or no coverage, and the danger is that partial coverage looks like a working result.
Second, distributed tracing. httpdbg runs inside one Python process. It has no notion of trace context, no span propagation and no collector, so a request that leaves your process and comes back cannot be correlated with other services. A tracing setup that already answers which service made which call does a different job better, though it does not tell you which line of your code made the call.
Third, anything where the request never passes through a supported client library or a supported server. The pip example shows the tool can still record traffic in that case, but the initiator and group columns are exactly where that value is lost, and the groups are the part worth having.
The alternative approach, worth naming precisely, is instrumenting at the HTTP middleware or proxy level. A proxy sees the bytes on the wire and applies to any client, at the cost of TLS trust configuration, a separate process and no knowledge of the calling function. httpdbg takes the opposite approach: it stays inside the process, so it can attribute traffic to the exact method that made it, including for libraries that would never be configured to trust a local certificate authority. For a single process that is the more informative choice, and for a whole system it is the weaker one.
Apache-2.0, weekly releases, and Python 3.9 to 3.14
The licence is Apache-2.0, with the terms in the LICENSE file at the repository root and the same identifier recorded in the package metadata. The documentation makes no claim about warranty or support beyond that, and the practical reading is that you are relying on the community for fixes rather than on a vendor.
Maintenance is active by the obvious measures. The repository is not archived, the last push was on 2026-09-27, and the releases are frequent: v2.2.1 on 2026-09-27, v2.2.0 on 2026-09-20 and v2.1.8 on 2026-07-11. The version number is dynamic in the package metadata, read from the httpdbg.__version__ attribute rather than written into the configuration, so the installed version and the source version cannot drift apart.
The project structure shows the testing investment. The Makefile has separate targets for linting, typing, unit tests and coverage, with mypy configured to check the httpdbg package and black and flake8 for formatting and lint rules, and tox environments for several pytest versions. There is a selenium target that starts a standalone Chrome container and a testui target that runs the browser tests, with the ui tests marked separately from the rest and excluded from the default test run. The package is split into httpdbg, httpdbg.hooks and httpdbg.webapp, with static assets for the web interface shipped as package data, and the package metadata marks it as production or stable with the version left dynamic.
So the cost of adopting it is low: one pip install, an Apache-2.0 licence, and a tool whose main upgrade risk is a change in how a supported client library is instrumented rather than any breaking change in your own code.
Editorial conclusion
httpdbg earns a place in a debugging session when you need to know not only which requests a Python program makes but which call site made each one, because the initiator and group model is something request logging middleware and an HTTP client log level do not give you. Skip it if you need distributed tracing across services, if your traffic is not going through one of the listed client libraries, or if HTTP/2 matters and the h2 library is not in play. Before you adopt it, run pyhttpdbg --script on the smallest reproduction you have, check that the groups it shows match the call sites you expect, and confirm the Apache-2.0 terms suit how you plan to ship it.
Frequently asked questions
How do I install and start httpdbg?
Install it with pip install httpdbg, then run your program with the pyhttpdbg command instead of python, for example pyhttpdbg --script filename.py. Open a browser at http://localhost:4909 to inspect the recorded requests.
What are initiators and groups in httpdbg?
An initiator is the function or method at the origin of the requests. For client packages the initiator is the highest-level method that made the request and the group is identical, while for servers the initiator is the low-level socket method and the group is the endpoint method that handled it.
Can httpdbg trace requests made during a pytest run?
Yes. Running pyhttpdbg -m pytest groups the recorded requests by test, and requests made inside a fixture or in the setup and teardown methods are identified by a tag so they can be told apart.
Does httpdbg support HTTP/2?
Yes, but the support table qualifies it as supported only through the h2 library. HTTP/1.0 and HTTP/1.1 are supported without that qualification.
How do I add support for my own HTTP client package in httpdbg?
Use the --initiator argument, short form -i, naming the package, for example pyhttpdbg -i api_client_pck --script my_script.py. The documentation notes that any package can be an initiator and that this is not limited to HTTP requests.
What licence is httpdbg released under?
Apache-2.0. The terms are in the LICENSE file in the repository root, and the package metadata records the same Apache-2.0 identifier.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cle-b-httpdbg)Was this useful?