# mss lists the native screenshot API it calls on each platform

> mss is a screenshot module written in pure Python using ctypes, with no dependencies and a Python 3.10 floor. The keyword list in its packaging metadata is the most honest description of the project available, because it names the native calls on each platform: BitBlt and EnumDisplayMonitors on Windows, XGetImage and XRRGetScreenResourcesCurrent on X11, CGGetActiveDisplayList on macOS, and screencapture.

**BoboTiG/python-mss** — An ultra fast cross-platform multiple screenshots module in pure Python using ctypes.

- Repository: https://github.com/BoboTiG/python-mss
- Website: https://python-mss.readthedocs.io
- Stars: 1,290 · Forks: 117
- Language: Python
- License: MIT
- Published: 2026-10-17 · Updated: 2026-10-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/bobotig-python-mss

## The keyword list is the architecture

The most informative thing in this repository is the keyword list in the packaging metadata, and it is worth reading as a design document.

Among the general terms, `BitBlt`, `ctypes`, `EnumDisplayMonitors`, `CGGetActiveDisplayList`, `CGImageGetBitsPerPixel`, `XGetImage`, `XGetWindowAttributes` and `XRRGetScreenResourcesCurrent` appear alongside the obvious ones like monitor, screen and screenshot.

That list is three operating systems described in API calls. `EnumDisplayMonitors` and `BitBlt` are Windows. `XGetImage`, `XGetWindowAttributes` and `XRRGetScreenResourcesCurrent` are X11, and the RandR call in particular is how you enumerate monitors on a system with dynamic displays. `CGGetActiveDisplayList` and `CGImageGetBitsPerPixel` are macOS. And `screencapture` is the command-line tool.

So the module is not wrapping a single abstraction. It has a backend per platform, each talking to the API that platform actually offers, and the shared surface is small enough that the differences fit inside it.

That is what the ctypes choice buys. There is no C extension to compile, no wheel per platform and per Python version, and the install is one pure-Python package with no dependencies. The cost is that the differences between platforms are handled by hand.

The stated characteristics follow from that: Python 3.10 and later, PEP8 compliant, no dependency, thread-safe.

The classifiers list both CPython and PyPy, and Python 3.10 through 3.14, with a development status of 5, Production/Stable.

## The whole API in five lines, and the context manager matters

The usage example is the entire README in code.

```python
from mss import MSS

# The simplest use, save a screenshot of the 1st monitor
with MSS() as sct:
    sct.shot()
```

Five lines, and three of them are setup. The context manager is doing real work rather than decoration, because grabbing screen content allocates native buffers on each platform and the context manager is how they are released.

`MSS` is the class and it stands for Multiple ScreenShots, as the README notes.

What that example does not show is the part that matters for anything nontrivial, which is the per-monitor iteration. The README describes the module as very basic: it grabs one screenshot by monitor, or a screenshot of all monitors, and saves it to a PNG file.

Saving PNG by default is a small decision with consequences. It means the common case needs no image library at all, which is the point of having no dependencies. But it also means the screenshot is encoded to a compressed image format before you ever see the pixels.

For computer vision work that is usually wrong. You want the raw buffer, and mss returns one; the README says it integrates well with NumPy and OpenCV, and that you can use PIL to benefit from all its formats or add your own.

So the design has two layers: a convenient one that saves a PNG and a raw one that hands you pixels. Which you use depends on whether you want a picture or data.

The example itself should not be copied for anything performance sensitive. The README's justification for the module is embedding it into games and other software requiring fast, platform optimised screenshot methods, such as AI and computer vision, and the context-managed single call is the demonstration of the API rather than the fast path.

## Import mss first, or your screenshot will be the wrong size

The last paragraph of the README is the single most useful thing in it for anyone who has debugged a capture library.

In case of scaling and high DPI issues for external monitors, some packages, and the three named are `mouseinfo`, `pyautogui` and `pyscreeze`, incorrectly call `SetProcessDpiAware()` during their import process. To prevent that, import `mss` first.

The mechanism is worth understanding rather than memorising. On Windows, a process is either DPI aware or it is not, and that is a process-wide setting set once. A screenshot library that is not DPI aware gets coordinates and pixels in the scaled space the system reports to legacy applications, which is why a capture can come back at the wrong resolution on a high-DPI display with multiple monitors.

The failure is silent and it is order-dependent. Import pyautogui first and it wins the race; import mss first and it does. Both libraries work, and the same code produces correct output on one machine and a wrong-size image on another depending on what was imported before.

That is a genuine fragility in the ecosystem, not a bug in mss. The workaround is a one-line ordering rule, but it is the kind of rule that survives for years because nothing enforces it.

If you hit it, the symptom is a capture whose dimensions do not match the monitor, typically on a scaled display with an external monitor attached, and the fix is the import order rather than any setting in mss.

## Two installs, a pinned build backend and a uv lockfile

Installation is a pip line and a conda line, and the pip form has a flag worth noticing.

```shell
python -m pip install -U --user mss
```

The `--user` flag installs the package into the user site-packages. The conda form is `conda install -c conda-forge python-mss`, and there are badges for both PyPI and Anaconda.

The build system is pinned exactly. `requires` is `hatchling==1.32.4` with the `hatchling.build` backend, which is unusual. The exact version pin fixes the build backend version used for a build.

The repository root shows the rest of the tooling: `check.sh` and `check.ps1` as the two entry points for whatever the project runs, a `uv.lock` at the root meaning dependencies are locked with uv, `pyproject.toml` with dynamic fields for version and dependencies, `src/` for the package, `docs/` for the documentation and `demos/`.

There is a `.devcontainer/`, a `.readthedocs.yml` for the documentation build, a `CONTRIBUTORS.md`, a `CODE_OF_CONDUCT.md`, an `AGENTS.md`, and a `.well-known/` directory.

The documentation is on Read the Docs with a page of examples, and support is through the issue tracker and a Stack Overflow tag named `python-mss`.

The release history is a major version every year or so: v10.0.0 in November 2024, v10.1.0 in August 2025 and v10.2.0 in April 2026, with the last push on 2026-10-13.

## Conclusion

Adopt mss when you need screen capture inside a Python process and want no image library in the dependency tree, since it calls the native API directly and returns a buffer. Skip it if you need annotated or composited output, because it grabs what is on screen and nothing more. Verify first that you import `mss` before any other screen-related library, because the DPI awareness conflict described in the README silently changes your capture dimensions.

## FAQ

### How do I take a screenshot with mss?

Import `MSS` from `mss` and use it as a context manager, calling `sct.shot()` to capture the first monitor and save it as a PNG. The README describes it as very basic: one screenshot by monitor or a screenshot of all monitors, saved to a PNG file.

### Why does mss need to be imported before other libraries?

Packages such as mouseinfo, pyautogui and pyscreeze call `SetProcessDpiAware()` when they are imported, which is incorrect and causes scaling and high DPI problems with external monitors. The README says to import `mss` first to prevent that, since the DPI awareness setting is process-wide and set once.

### Does mss have any dependencies?

No. It is a pure Python module using ctypes to call the native screenshot API on each platform, with no dependencies, a Python 3.10 minimum, and classifiers for both CPython and PyPy. PIL, NumPy and OpenCV are optional and only for formats and image processing.

## Sources

- [BoboTiG/python-mss on GitHub](https://github.com/BoboTiG/python-mss)
- [License: MIT](https://github.com/BoboTiG/python-mss/blob/main/LICENSE)
- [Project website](https://python-mss.readthedocs.io)
- [README](https://github.com/BoboTiG/python-mss/blob/main/README.md)
- [Releases](https://github.com/BoboTiG/python-mss/releases)

---

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