PyBoy: a Game Boy emulator in Python that doubles as an AI training harness
Game Boy emulator written in Python
At a glance
- What is it?
- PyBoy is a Game Boy emulator written in Python, installable with pip, with a scriptable API for reading memory, sending button presses and capturing screens. It is built for people who want to automate games, not just play them.
- Who is it for?
- Adopt PyBoy if you need programmatic access to a Game Boy: memory reads, synthetic button presses, frame skipping and parallel instances, all from Python. Do not adopt it if you want an accurate, low-latency emulator for playing on a desktop or handheld, or if you need Game Boy Advance support, which the README does not claim.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 3 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 September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What PyBoy is for, and who should reach for it
PyBoy is a Game Boy emulator written in Python. The distinction that matters is not the emulation itself but the surface it exposes: a Python object with methods for ticking frames, pressing buttons, reading memory addresses and pulling the current screen as an image. That makes it a harness for reinforcement learning, bot scripts and tool-assisted exploration rather than a desktop player.
The README points at exactly this audience. It links to PokemonRedExperiments for training RL agents on Pokemon Red, to PokemonPinballRL for building your own AI, and to PyBrosAI for teaching Mario to win. The wiki carries example pages for Kirby, Tetris and Super Mario Land, plus a page on using PyBoy with Gym. If your goal is to run a game and watch it, a conventional emulator is simpler. If your goal is to have code decide what the game does next, the API is the product.
The tick loop, memory access and the rendering switch
The core mechanism is a single loop. You construct a PyBoy instance with a ROM path, then call pyboy.tick() repeatedly. Each call advances emulation by one frame by default and returns a value that the README's example uses as a loop condition: while pyboy.tick(): pass. Game logic, timers and audio all keep running inside that call.
Input is synthetic. pyboy.button('down') and pyboy.button('a') queue a press, and the README notes you must process at least one frame with pyboy.tick() for the game to register it. State is readable directly: pyboy.memory[0xC345] returns the byte at that address, which is how a script turns game state into a reward signal or a feature vector. The screen is available as a PIL image via pyboy.screen.image, so screenshots are a save call away.
The performance section describes the trade-off that shapes most training setups. tick() accepts a frame count and a rendering flag. Rendering every frame is the slow path; the README's own table compares full rendering at x124 realtime, frame-skip 15 at x344 realtime and no rendering at x395 realtime, with the caveat that results depend on the game. The corresponding calls are pyboy.tick() in a loop, pyboy.tick(15) inside a shorter loop, and pyboy.tick(target, False) to run a batch with rendering off. The README also recommends running multiple instances in parallel and estimates that an 8-core machine could reach roughly 3160 hours of gameplay per hour. Those numbers come from the project's own documentation, not from independent measurement.
Installing PyBoy and running a first script
The README gives a one-line install. PyBoy is published on PyPI under the name pyboy, and the package declares dependencies on numpy, pysdl2 and pysdl2-dll, so the SDL2 binaries arrive with the install on the platforms pysdl2-dll supports.
pip install pyboyAfter that, the README shows two entry points. The first is the command line, which launches the emulator on a ROM file.
pyboy game_rom.gbThe second is the Python API, which is where PyBoy differs from a normal emulator. This is the README's own minimal example: construct the object, tick until the game stops, then stop.
from pyboy import PyBoy
pyboy = PyBoy('game_rom.gb')
while pyboy.tick():
pass
pyboy.stop()To drive the game rather than watch it, the README shows the API in use. Setting the emulation speed to 0 removes the speed limit so the loop runs as fast as the host allows, then buttons are queued and a frame is processed so the game sees them.
pyboy.set_emulation_speed(0) # No speed limit
pyboy.button('down')
pyboy.button('a')
pyboy.tick() # Process at least one frame to let the game register the input
value_of_interest = pyboy.memory[0xC345]
pil_image = pyboy.screen.image
pil_image.save('screenshot.png')What you should see: the emulator window appears when you launch from the terminal, and in the scripted case the values you read from memory change as the game state changes. The README notes that the wiki covers installation details, and that the API documentation lives at baekalfen.github.io/PyBoy. There are more examples under extras/examples in the repository. If you intend to build from source rather than install the wheel, the repository ships a Makefile with build, install and test targets, and setup.py compiles the Cython extensions on CPython; on PyPy the setup script skips Cython entirely and runs the pure-Python path.
Where PyBoy is the wrong tool
The honest limitation is the same thing that makes the API pleasant: it is Python. The README treats performance as a priority and leans on frame skipping and parallel instances to reach usable throughput, which tells you that single-instance, fully rendered emulation is not the fast path. If you need cycle-accurate timing for hardware research, or a handheld-grade experience with low input latency, a C or Rust emulator will be a better fit.
The scope is also narrow. The README and the project metadata describe a Game Boy emulator. There is no claim of Game Boy Color or Game Boy Advance support in the documentation, so do not assume it. People searching for PyBoy GBA or PyBoy Advance are looking for something the documentation does not promise.
Finally, the README does not document rollback of emulator state, save-state compatibility guarantees, or what happens when a ROM uses unsupported mappers. The contributing section says known problems are tracked in the Issues tab and lists Link Cable and debugger support as areas people can work on, which is a fair signal that those are not finished features. Treat any workflow that depends on them as unverified until you test it yourself.
How PyBoy differs from SameBoy and other accuracy-first emulators
The comparison that comes up in search data is SameBoy, a well-known Game Boy emulator. The difference is the axis each project optimizes. SameBoy is written in C and targets accuracy and a polished playing experience: you load a ROM and play it. PyBoy targets programmability: you load a ROM and script it.
That changes what you can do. In PyBoy, the game state is a Python object you can index by memory address, the screen is a PIL image you can save, and the frame loop is something you control, including skipping rendering entirely. A C emulator can be wrapped from Python, but the wrapper is a project of its own. Conversely, PyBoy's Python-first design means its ceiling on raw emulation speed is lower than a native implementation, and the project's answer is parallelism and frame skipping rather than a rewrite.
There is a practical consequence for training runs. The README's advice to run multiple PyBoy instances in parallel assumes your environment can afford one process per game, each holding its own emulator state. That is a memory and CPU planning question, not just a code question.
Maintenance, versioning and what the licence files actually say
The repository is not archived, and the last push was on 2026-09-22, one day before this writing. Releases are frequent enough to track: v2.6.1 on 2025-11-20, v2.7.0 on 2026-01-24 and v2.7.1 on 2026-05-05. The version in pyproject.toml matches the latest release, 2.7.1. The project requires Python 3.9 or newer and classifies itself as supporting both CPython and PyPy, with Cython extensions compiled only on CPython.
Upgrade cost is mostly the usual pip upgrade, but two things are worth checking on each bump. First, the optional extras group named all pulls in pyopengl, glfw, PyOpenAL, markdown, pdoc3 and gym; if you use the Gym wrapper, a gym version change is the most likely source of breakage. Second, because the Cython extensions are built from source in the sdist path, a Python version bump can mean waiting for a matching wheel or compiling locally.
On licensing, the two files disagree and you should resolve that before shipping anything. The repository metadata reports the licence as NOASSERTION, while pyproject.toml declares license = "LGPL-3.0-only". The repository also ships a LICENSE.md file. LGPL has implications for how you link and distribute, and those implications depend on your use case; read LICENSE.md and, if you are distributing a product, get proper advice rather than inferring from the metadata field.
Editorial conclusion
Adopt PyBoy if you need programmatic access to a Game Boy: memory reads, synthetic button presses, frame skipping and parallel instances, all from Python. Do not adopt it if you want an accurate, low-latency emulator for playing on a desktop or handheld, or if you need Game Boy Advance support, which the README does not claim. Before committing, verify the licence text in LICENSE.md, since the repository metadata says NOASSERTION while pyproject.toml declares LGPL-3.0-only, and check that your target games run at the speed you need with rendering disabled.
Frequently asked questions
How do Game Boy emulators work?
PyBoy advances emulation one frame per call to pyboy.tick(), running game logic, timers and audio inside that call. Scripts read state through pyboy.memory and send input with pyboy.button(), then tick again so the game registers the press.
How do I get games for the PyBoy emulator?
The README does not cover where to obtain ROM files. It only shows how to point PyBoy at one, either as pyboy game_rom.gb on the command line or as PyBoy('game_rom.gb') in Python.
Why is it called a Game Boy?
The documentation does not explain the origin of the name. PyBoy refers to the Game Boy hardware it emulates, and the README gives no naming history.
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/baekalfen-pyboy)