Web-PDB: debugging a remote Python program through the browser
Web-based remote UI for Python's PDB debugger
At a glance
- What is it?
- Web-PDB puts a web front end on Python's built in PDB, so a program running on a server you cannot reach a terminal on can be paused and inspected from a browser. It is a small, dependency free tool in minimum maintenance mode, which tells you both what it is good for and how much to expect from it.
- Who is it for?
- Web-PDB suits someone debugging a long running script on a headless machine, where a terminal is not available, and it does not suit a production incident, because the debugger binds an HTTP port on the host and offers no authentication, so a machine reachable from the internet should not run it that way.
- Can I use it commercially?
- Yes. MIT 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 5 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
A debugger that lives on the machine you are debugging
Web-PDB is a web interface for Python's built in PDB debugger, and the readme states its purpose plainly: it allows you to debug Python scripts remotely in a web browser.
The problem it solves is narrow and real. PDB is a terminal debugger, and a terminal debugger is awkward when the program you are debugging is running on a server, in a container, or on a machine over SSH that you would rather not keep a session open against. Web-PDB pauses at your breakpoint and serves a debugger UI over HTTP from the same host, and you drive it from a browser tab.
What it is not is a different debugger. The readme says it supports all PDB features, and the web console is a full PDB command prompt with the standard commands, plus extras. The additional panels are what make it usable rather than merely possible.
There is a Current file box that tracks the current position in the file being executed, with red line numbers indicating breakpoints. There are Globals and Locals boxes showing the variables in the current scope, and the readme is specific about a detail that matters: special variables whose names start and end with the double underscore markers are excluded from those panels, and you can always view them using PDB commands.
There is command history storing up to the last ten unique PDB commands, reachable with the arrow up and down keys. And there is an inspect command, or i, which is not present in the original PDB. It outputs the list of an object's members along with their values, with the syntax inspect <object_name> or i <object_name>, and again the members with those markers are ignored.
The UI is Bootstrap based with light and dark modes, and the code is highlighted with Prism in the default and Okaida themes. The readme ships screenshots of both modes.
Installation is one pip command and one import
The install step is a single package install into your working Python environment.
pip install web-pdbThen you put one line in your program at the point where you want to stop.
import web_pdb; web_pdb.set_trace()The set_trace call suspends the program and opens a web UI at the default port 5555, and the port value can be changed. You then point your browser at the address http://<your Python machine hostname or IP>:5555, with the readme giving http://monty-python:5555 as the example.
The important operational detail is the warning attached to this: it is strongly recommended to work with the Web-PDB web UI only in one browser session, and with more than one browser window accessing it, it may display incorrect data in one or more sessions. That is a design consequence of a debugger server holding one program state, and it is much better to know it before you open three tabs trying to compare frames.
Subsequent set_trace calls can be used as hardcoded breakpoints, which is the intended way to use it: sprinkle the call at the points you care about and run the program.
If you would rather use the standard breakpoint function, the readme notes that Web-PDB is compatible with the breakpoint function added in Python 3.7, and that setting the environment variable PYTHONBREAKPOINT to web_pdb.set_trace launches Web-PDB with breakpoint(). That means you can leave plain breakpoint() calls in your code and switch the whole process between the terminal debugger and the web one by changing one environment variable, which is convenient when the same code runs in both places.
Catching an exception and landing straight in a post-mortem session
The second entry point is a context manager, and it is the one worth knowing about if you are chasing a crash rather than stepping through code.
Web-PDB provides catch_post_mortem, a context manager that can catch unhandled exceptions raised within its scope and automatically start a PDB post-mortem debugging session.
import web_pdb
with web_pdb.catch_post_mortem():
# Some error-prone code
assert foo == bar, 'Oops!'So the block is marked, and if something inside it raises and is not handled, the debugger opens on the traceback frame rather than the exception simply propagating out of the program. For a long running service that dies on an assertion at three in the morning, that turns a stack trace in a log into a state you can inspect interactively.
The alternative would be wrapping the call site in a try and except and calling set_trace in the handler, which is the manual version of the same idea. The context manager is a small convenience, and the readme is careful to point at the real documentation for the details: for more detailed info about the Web-PDB API, read the docstrings in the ./web_pdb/__init__.py file. The API is documented in docstrings rather than in a separate reference, which means the source is the reference.
One thing the readme does not describe is whether catch_post_mortem re-raises the exception after the session, or how it behaves when the exception is caught by something inside the block. The docstrings in the module would be the place to check that.
One debugger instance, one thread, and a port per process
The section on multithreading and multiprocessing is where the tool's real constraints are stated, and they are not the kind you find out by reading the feature list.
For multithreading, Web-PDB maintains one debugger instance that traces only one thread. You should not call set_trace from different threads to avoid race conditions, and each thread needs to be debugged separately, one at a time.
That is a genuine limitation rather than a caveat. A program with worker threads where you want to inspect the state of one of them will stop on whichever thread reaches the set_trace call first, and the web UI shows that thread's state. The readme's advice is to debug each thread separately, which in practice means arranging your test so only the thread you care about is running, or using process level parallelism instead.
For multiprocessing the situation is better but requires action from you. Each process can have its own debugger instance, provided you call set_trace with a different port value for each process. That way you can debug each process in a separate browser tab or window. And to simplify this you can use set_trace(port=-1) to select a random port between 32768 and 65536.
The random port option is a nice touch, because it removes the need to coordinate port numbers across a set of worker processes that you did not start by hand. It also means you have to find out which port each one took, since the browser URL depends on it.
Taken together, the threading and multiprocessing rules define the envelope: one debugged thread per process, one port per process, and a browser tab per process. That is enough for a lot of real debugging, but it is not a general purpose remote debugger for a running service.
No dependencies and an asyncio server in a thread
The implementation details section is short and both points matter.
Web-PDB uses a custom asynchronous HTTP server based on the asyncio library that runs in a separate thread. The readme asks you to take this into account when using Web-PDB in your environment.
A separate thread matters because of how the debugger suspends your program. The set_trace call blocks the calling thread while the server thread serves the HTTP requests that make up the web UI, so a program that has its own threads will have one of them blocked in the debugger and the others still running, and a program with an event loop of its own will find that loop paused rather than spinning. Neither is a bug, but both change the behaviour of the program you are debugging in ways that can look like the debugger caused the problem you are chasing.
The asyncio server is custom, which is the second point worth noting. The project does not use a web framework for the server side.
The second implementation detail is the dependency story. Starting from v2.0, the Web-PDB Python backend has no external dependencies except for the Python standard library. That is a genuinely important property for a debugging tool, because a debugger that pulls in a dependency tree is a debugger that can break in the environment where you most need it. The project is also compatible with Python 3.8 and above, and the readme says all modern browsers should work.
The repository layout supports that separation. There is a web_pdb/ directory for the Python package, a frontend/ directory for the browser side, a tests/ directory, a Makefile, a tox.ini, a .pylintrc and a uv.lock. The build uses setuptools with a plain setup.py that calls setup() with no arguments, so the metadata is in setup.cfg.
Minimum maintenance mode is the headline
The readme leads with an important notice, and it is worth reading before anything else.
The project is in a minimum maintenance mode. The maintainer will try to maintain compatibility with new Python versions and address critical issues if any arise, but at the moment has no time or resources to develop new features or properly review external contributions. Only pull requests with bug fixes will be prioritised, and other issues or pull requests may or may not be reviewed or accepted.
That is a clear statement of what will happen to your pull request, which is more than most projects in this position give you. It also tells you what to expect from the tool going forward: it will keep working with new Python versions, it will not grow, and it will not get the features you might want.
The repository reflects that state. The last push was on 2026-10-18, so the code is being touched. The repository has no GitHub releases, so there is no version history to track from the tag list, though there is a VERSION file and a Changelog.rst at the root. The requirements file is worth reading for a different reason: it lists uv, wheel, build, selenium 4.10.0 and ruff 0.15.12, which is the development toolchain, not the runtime requirements of the installed package, consistent with the no external dependencies claim from v2.0 onward.
The Makefile shows the whole workflow in one screen. test runs the test suite with uv run tests/tests.py, lint and lint-fix use ruff on the web_pdb Python files, build runs python -m build, and clean removes the build, dist and egg-info directories. There is a separate set of frontend targets, frontend-build-dev, frontend-build, frontend-watch and frontend-lint, each running an npm script inside the frontend directory, which confirms the split between the Python server and the browser client.
The configuration is modern in a small way. The pyproject file sets ruff to a line length of 100, a target version of py310, and enables the isort rule set, and the format settings use spaces and single quotes.
On the licence, the package is MIT with the terms in LICENSE.txt, and there is a separate note that the debugger icon is by Freepik from flaticon.com and licensed under CC 3.0 BY, so the icon carries its own attribution requirement alongside the MIT terms of the code.
Editorial conclusion
Web-PDB suits someone debugging a long running script on a headless machine, where a terminal is not available, and it does not suit a production incident, because the debugger binds an HTTP port on the host and offers no authentication, so a machine reachable from the internet should not run it that way. Before you rely on it, read the threading note, because one debugger instance traces only one thread and calling set_trace from two threads causes race conditions, and check the port when running under multiprocessing, since each process needs a different one.
Frequently asked questions
What is Web-PDB and what does it do?
Web-PDB is a web interface for Python's built in PDB debugger that lets you debug Python scripts remotely in a web browser. It supports all PDB features and adds panels for the current file, globals, locals, command history and an inspect command.
How do I install and start Web-PDB?
Run pip install web-pdb, then put import web_pdb; web_pdb.set_trace() in your program. The program suspends and serves a web UI on port 5555 by default, which you open at http://<hostname or IP>:5555.
Can I use Web-PDB with the standard breakpoint() function?
Yes. Set the environment variable PYTHONBREAKPOINT to web_pdb.set_trace and breakpoint() launches the web debugger, which lets you switch the same code between the terminal debugger and the web one.
What are the threading and multiprocessing limits of Web-PDB?
One debugger instance traces only one thread, so set_trace should not be called from different threads because of race conditions. For multiprocessing, each process needs a different port, and set_trace(port=-1) picks a random port between 32768 and 65536.
Does Web-PDB have any external dependencies?
Starting from v2.0 the Web-PDB Python backend has no external dependencies except the Python standard library, and the project requires Python 3.8 or above.
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/romanvm-python-web-pdb)Was this useful?