CLI tool
labbots/NiimPrintX avatar
labbots/NiimPrintX

NiimPrintX drives NiimBot label printers over Bluetooth from Python or Tkinter

NiimPrintX is a Python library designed to seamlessly interface with NiimBot label printers via Bluetooth. This library supports a range of models including D11/B21/B1, D110, and B18.

523 stars67 forksPythonGPL-3.0

At a glance

What is it?
NiimPrintX is a Python library for talking to NiimBot thermal label printers over Bluetooth, with a Click based command line for printing images and querying device info and a Tkinter GUI for designing labels to a device's size. It supports the D11, B21, B1, D110 and B18 models, and it needs ImageMagick alongside Python 3.12 or newer.
Who is it for?
Adopt NiimPrintX if you own a NiimBot printer and want to script your labelling from Python rather than through the vendor's phone app. Do not adopt it if you need a printer model outside the documented list, since the CLI only accepts a fixed set of model identifiers, and note that the GUI depends on pycairo and cairo, which is the part of the setup most likely to need system packages.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 159 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

What it covers: one vendor's printers, over Bluetooth, with two front ends

NiimPrintX is a Python library designed to seamlessly interface with NiimBot label printers via Bluetooth. It provides both a Command-Line Interface and a Graphical User Interface for users to design and print labels efficiently.

The scope is narrow by design, and that is the point. It is not a generic label printing framework with pluggable back ends; it speaks to one manufacturer's devices. What it offers instead is two ways of working with them, which is the axis the feature list emphasises: a CLI for scripting and automation, and a GUI for designing labels by hand.

The key features list names cross-platform compatibility on Windows, macOS and Linux, Bluetooth connectivity to NiimBot printers, and comprehensive model support for the D11, B21, B1, D110 and B18. The custom label design entry says the GUI app enables users to design labels tailored to specific devices and label sizes, and advanced print settings covers print density, quantity and image rotation.

That last group is what makes the CLI worth having. Print density is a NiimBot-specific setting, the range of which runs from 1 to 5, and rotation is offered in quarter turns. Those are properties of the printer protocol, not of a generic image pipeline, and they are the reason a wrapper around the vendor's Bluetooth protocol has a reason to exist rather than you writing the packets yourself.

The repository metadata gives Python as the primary language with the topics niimbot, python3 and tkinter, so the GUI's toolkit choice is visible in the topic tags. The licence is GPL-3.0, and the package is built with Poetry.

Installing: Poetry, ImageMagick and a Python version floor

The Requirements section lists three things you need installed: Python 3.12 or later, the ImageMagick library, and Poetry for dependency management.

ImageMagick is not optional decoration here. The dependency list includes Wand at 0.6.13, which is the Python binding for ImageMagick, and the README's install step starts by telling you to ensure that ImageMagick is installed and properly configured on your system, with a link to the download page.

The install sequence itself is three steps. Clone the repository:

bash
git clone https://github.com/labbots/NiimPrintX.git
cd NiimPrintX

Then create an environment and install the dependencies with Poetry:

bash
python -m venv venv
poetry install

There is a MacOS specific note for local development, and it is worth reading before you hit the error it prevents:

bash
brew install libffi
brew install glib gobject-introspection cairo pkg-config

export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
export LDFLAGS="-L/usr/local/opt/libffi/lib"
export CFLAGS="-I/usr/local/opt/libffi/include"

Those three export variables are the giveaway. cairo and gobject-introspection are native libraries that have to be found at build time, and pkg-config is the tool that locates them. libffi is the FFI binding layer, and it has its own pkgconfig path that the other two variables point at. This is the cost of the pycairo dependency, which appears in the dependency list at version 1.27.0.

So the install has two halves. The Python side is straightforward if Poetry is present. The native side is where the friction is, and on macOS it means installing system packages and setting build environment variables.

The project also ships a .python-version file and a poetry.lock at the repository root, along with requirements.txt and requirements-ci.txt for environments where a plain pip install is preferred, so the pinned versions are available in both formats.

The CLI: one command, one printer model, a handful of options

The command line interface is a Click application with two commands, info and print.

bash
Usage: python -m NiimPrintX.cli [OPTIONS] COMMAND [ARGS]...

Options:
  -v, --verbose  Enable verbose logging
  -h, --help     Show this message and exit.

Commands:
  info
  print

The print command is where the interesting options are:

bash
Usage: python -m NiimPrintX.cli print [OPTIONS]

Options:
  -m, --model [b1|b18|b21|d11|d11_h|d110]
                                  Niimbot printer model  [default: d110]
  -d, --density INTEGER RANGE     Print density  [default: 3; 1<=x<=5]
  -n, --quantity INTEGER          Print quantity  [default: 1]
  -r, --rotate [0|90|180|270]     Image rotation (clockwise)  [default: 0]
  --vo INTEGER                    Vertical offset in pixels  [default: 0]
  --ho INTEGER                    Horizontal offset in pixels  [default: 0]
  -i, --image PATH                Image path  [required]
  -h, --help                      Show this message and exit.

Two details in that help output are worth noting. The model list is a fixed set of choices, b1, b18, b21, d11, d11_h and d110, and the default is d110. The density option is an integer range rather than a plain integer, constrained to 1 through 5, which tells you the printer rejects anything outside that range and the CLI stops it before the device does.

The rotation and offset options exist because of a physical constraint. A label printer has a fixed printable area and a fixed origin, and an image that is the wrong size or the wrong orientation has to be adjusted, so the CLI exposes rotation in quarter turns and pixel offsets in both axes.

A complete print invocation looks like this:

bash
python -m NiimPrintX.cli print -m d110 -d 3 -n 1 -r 90 -i path/to/image.png

And the info command, which queries the printer rather than sending it a job:

bash
Usage: python -m NiimPrintX.cli info [OPTIONS]

Options:
  -m, --model [b1|b18|b21|d11|d110]
                                  Niimbot printer model  [default: d110]
  -h, --help                      Show this message and exit.

Compare the two model lists and you find a real inconsistency. The print command accepts d11_h and the info command does not, and the README's feature list mentions a D11, B21, B1, D110 and B18 while the CLI carries an extra d11_h variant. The d11_h name suggests a distinct hardware variant, and the info command's model list appears not to have been updated alongside the print one.

That is the kind of small gap worth knowing about before you script against it, because the failure mode is a rejected choice rather than a clear error message.

The GUI, and what the dependency list says about it

The graphical interface is started with a module invocation:

bash
python -m NiimPrintX.ui

The README describes it as allowing users to design labels based on the label device and label size, which is the differentiating feature against the CLI. The CLI sends an image you already have; the GUI is for producing that image to the dimensions of a specific label, which is a task the CLI cannot do at all.

The dependency list in pyproject.toml explains the shape of the GUI. pycairo at 1.27.0 provides the Cairo drawing surface, Pillow at 11.0.0 handles images, click at 8.1.7 is the CLI framework, bleak at 1.0.0 is the Bluetooth stack, loguru handles logging, rich at 13.7.1 handles terminal output, and appdirs locates configuration directories on each platform. Wand at 0.6.13 is the ImageMagick binding, and it is the piece that ties the project to the ImageMagick system requirement.

bleak is the detail that explains the Bluetooth half. It is a cross-platform Bluetooth stack with no external dependencies, and it is the library that lets the same code talk to a printer on macOS, on Windows and on Linux, which is what makes the cross-platform claim work rather than being three separate implementations.

The Python constraint is stated twice and it is narrow. The pyproject requires python = ">=3.12,<3.14", so Python 3.12 or 3.13, and the README's requirements list says Python 3.12 or later. The upper bound is the one to notice, since a machine on 3.14 will not install this.

The development dependencies are devtools at 0.12.2 and pyinstaller at 6.6.0, and PyInstaller explains the presence of the bin/ directory at the repository root and the requirements.txt full of macOS-specific packages such as pyobjc-framework-CoreBluetooth, pyobjc-framework-Cocoa and pyobjc-framework-libdispatch. The requirements.txt is the frozen output of a packaging run, not a hand-maintained list.

Where NiimPrintX is the wrong choice

The first limit is the vendor lock-in, and it is complete. The model option is a closed list and the Bluetooth protocol implementation is NiimBot's. There is no generic path here, so if you later switch to a printer from another manufacturer you are starting over rather than changing a setting.

The second limit is the Python version window. The pyproject caps it below 3.14, so on a current interpreter the install either fails or you need a separate environment pinned to 3.13. For a library meant to be dropped into someone else's tooling, that is a real constraint, and it is the kind that ages badly.

The third limit is the two heavyweight native dependencies for what is fundamentally a Bluetooth protocol client. cairo and gobject-introspection have to be present and discoverable at build time, and the macOS setup section is a list of Homebrew installs and exported build flags. If you are deploying this into a locked down environment, or onto a machine where you cannot install system packages, that is the part that breaks first, and the pycairo dependency is why.

The fourth is that the CLI model list and the info model list disagree, as described above. It is a small thing in isolation, and it is a symptom of a project where the device variants are still being mapped out rather than settled.

The alternative to weigh is the vendor's own application. NiimBot ships its own mobile app, and the practical difference is that it needs no Python, no ImageMagick, no cairo and no Bluetooth stack on the machine. If your use is printing an occasional label, the app is a shorter path. NiimPrintX earns its keep when you need to print as part of a script or a service, when you need to place the image exactly, or when you need to drive a specific density and quantity from code.

The other alternative is talking to the printer directly. Bluetooth label printers from this vendor use a documented protocol over a serial-like Bluetooth service, and a print job is a payload of image data plus settings. Writing that yourself is a weekend of work for one model, and it is what this library has already done, which is the argument for using it.

One more consideration for a headless deployment: the GUI is Tkinter based and needs a display. The CLI is the part that works over SSH or in a container, and the Bluetooth connection itself needs either a Bluetooth adapter on the machine or a dongle passed through.

Maintenance, licensing and the state of the repository

The maintenance record is recent but the release history is not moving fast. The last push was on 2026-05-17 and the repository is not archived. The recent releases are v0.0.47 from 2024-06-01, v0.0.46 from 2024-05-30 and v0.0.45 from 2024-05-30, three releases inside two days two years ago.

There is a discrepancy worth noting between those tags and the package metadata. The pyproject version field says 0.1.0, while the latest published release tag is v0.0.47. That suggests the project moved to a different versioning scheme, most likely switching from the 0.0.x tag series to a 0.1.x line, and the older tags were left behind.

Either way, a version number in the 0.0.x or 0.1.x range signals an API that is not promised to be stable, and for a library whose whole surface is a handful of Click commands and a GUI, that is a mild rather than severe risk.

The licence is GPL-3.0, recorded in the pyproject as GNU GPLv3, with a LICENSE file at the repository root. That is a materially different grant from the permissive licences common in this ecosystem, and it is the one thing to check before you adopt it. GPL-3.0 carries copyleft obligations when you distribute a derivative work, and for a library that you import into an application the question of whether that makes the application a derivative work is the kind of legal question this article cannot answer. Treat it as a licensing note rather than legal advice, and read the licence text with your own counsel if you plan to ship something proprietary that imports it.

The repository layout is a normal Python package. There is a NiimPrintX/ directory holding the package itself, a .python-version file, a poetry.lock, pyproject.toml, requirements.txt and requirements-ci.txt, plus assets/, bin/, docs/, runtime_hooks/ and spec_files/. The runtime_hooks/ directory is the PyInstaller packaging output and spec_files/ holds the PyInstaller specification, which matches the pyinstaller dev dependency.

The credits list is a long run of Flaticon contributors, Dave Gandy, Pixel perfect, Freepik and a dozen others, which tells you the GUI icons are not the author's own work and that the icon set came from a stock library.

Editorial conclusion

Adopt NiimPrintX if you own a NiimBot printer and want to script your labelling from Python rather than through the vendor's phone app. Do not adopt it if you need a printer model outside the documented list, since the CLI only accepts a fixed set of model identifiers, and note that the GUI depends on pycairo and cairo, which is the part of the setup most likely to need system packages. Verify first which model identifier your printer uses, since the print command accepts d11_h while the info command does not, and that ImageMagick is present since image handling goes through Wand.

Frequently asked questions

Which NiimBot printer models does NiimPrintX support?

The README names the D11, B21, B1, D110 and B18. The CLI print command accepts b1, b18, b21, d11, d11_h and d110 with d110 as the default, while the info command accepts the shorter list without d11_h.

How do I install NiimPrintX?

Install ImageMagick first, then clone the repository, run python -m venv venv and poetry install. You need Python 3.12 or later, with the pyproject requiring python >=3.12,<3.14. On macOS, local development also needs brew install libffi and brew install glib gobject-introspection cairo pkg-config, plus PKG_CONFIG_PATH, LDFLAGS and CFLAGS exported for libffi.

How do I print an image from the command line?

Use the print command with a model, density, quantity, rotation and image path, for example python -m NiimPrintX.cli print -m d110 -d 3 -n 1 -r 90 -i path/to/image.png. Density is an integer range from 1 to 5, rotation takes 0, 90, 180 or 270, and vertical and horizontal pixel offsets are available as options.

What does the NiimPrintX GUI add over the CLI?

The GUI lets you design labels based on the label device and label size, so you can produce an image sized to a specific label, which the CLI cannot do since it only sends an existing image file. It is started with python -m NiimPrintX.ui and is built on Tkinter with pycairo for drawing.

What licence is NiimPrintX released under?

GPL-3.0, recorded in pyproject.toml as GNU GPLv3, with a LICENSE file at the repository root. The last push was on 2026-05-17, the latest release tag listed is v0.0.47 from 2024-06-01, and the package version in the metadata is 0.1.0.

Official sources

  1. Issues
  2. labbots/NiimPrintX on GitHub
  3. License: GPL-3.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/labbots-niimprintx.svg)](https://hysenlabs.com/projects/labbots-niimprintx)

Was this useful?