pyzk drives ZKTeco attendance machines over a socket from Python
Unofficial library of zkteco fingerprint attendance machine
At a glance
- What is it?
- pyzk is an unofficial Python library for the zksoftware and zkteco family of fingerprint attendance terminals, covering user management, fingerprint templates, attendance records and live capture. It is a device integration library, not a vendor supported product, and it exposes destructive commands without confirmation.
- Who is it for?
- pyzk is the practical choice for a small team that owns zkteco terminals and needs to script user enrolment, template backups or attendance exports, because the protocol work is already done and the surface area is documented command by command.
- Can I use it commercially?
- Yes, with conditions. GPL-2.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 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An unofficial wrapper for the zksoftware attendance terminal protocol
pyzk is described as an unofficial library of the zksoftware, that is the zkteco family, attendance machine. Unofficial is the operative word, and it is not a throwaway remark. There is no vendor behind this repository, so there is no compatibility matrix, no support commitment and no guarantee that a firmware update on the device does not change what the library expects. What the library does provide is a complete Python surface for the device protocol, split across the zk package in the tree. The package keywords in setup.py list zk, pyzk, zksoftware, attendance machine, fingerprint, biometrics and security, which matches what you find in the code. The devices in question are the fingerprint attendance terminals that sit on a wall or a desk and record punches, so the user of this library is usually an administrator who wants to script enrolment, pull attendance records, or back up the biometric templates, rather than a general developer.
Connecting takes an address, a port, a timeout and a device password
Everything starts with a ZK object. The constructor takes the device address, the port, the timeout, the password and two flags, and the connection itself is made with a connect call.
zk = ZK('192.168.1.201', port=4370, timeout=5, password=0, force_udp=False, ommit_ping=False)
conn = zk.connect()
conn.disconnect()The default port shown in the test machine usage output is 4370, and the default address in that same usage text is 192.168.1.201. The force_udp flag selects the UDP transport, and the ommit_ping flag, spelled with a doubled letter as it appears in the source, controls whether a ping is sent on connect. A timeout of five seconds is a reasonable default for a device on a local network and a poor one for a terminal on a slow link across a building. The device password defaults to zero here, which is a hint worth checking on your own hardware, because terminals ship with a numeric communication password that has to match what you pass. The library is a client for a binary protocol rather than a wrapper around a vendor SDK, so the parameter list is the whole of your configuration surface.
Disabling and enabling the device is how a batch job avoids colliding with users
The pattern the documentation leads with is a lock around your work. Before running anything that changes the database, you disable the device, which the documentation says ensures no activity on the device while the process runs, and you re-enable it when the commands are finished.
# disable (lock) device, to ensure no user activity in device while some process run
conn.disable_device()
# re-enable the connected device and allow user activity in device again
conn.enable_device()This is the right idea, because an enrolment run that overlaps with a user punching in can leave half written records. It is also the most likely place to leave a terminal unusable, since a script that raises between the two calls leaves the device locked. The examples in the repository wrap this in a try and finally block, but the finally block there only disconnects, so the re-enable is not guaranteed by the pattern the documentation demonstrates. If you build tooling on top of this library, that is the specific failure you should design against, and a supervisor that reconnects and re-enables on start is worth more than a try and finally in your own code.
Users, fingerprint templates and attendance records cover the operational surface
The command list is broad and reads like a device manual. Users can be created with a uid, name, privilege, password, group and card, listed with get_users, and deleted either by uid or by user id. Fingerprint templates are read one at a time with a template id that selects which finger, from zero to nine, or listed in bulk, and saving a template requires a User object together with a list of fingers, with a maximum of ten in the list. Attendance records are read with get_attendance and can be cleared with clear_attendance. Device information is available in a wide set of getters covering the firmware version, serial number, platform, device name, face and fingerprint versions, the network parameters, the MAC address and the PIN width, and the usage counters report the number of users, fingers, records and their capacities. There is also a set_time and get_time pair, since a terminal with a wrong clock produces attendance data that no analysis can rescue, and a test_voice call that plays one of a list of built in sounds. A live_capture generator yields attendance objects as they arrive, with a ten second timeout, and can be broken out of gracefully by setting a flag on the connection or by interrupting it.
High rate transfer exists because template upload is the slow part
The documentation names a high rate mode for the case that dominates the runtime of a bulk job, uploading users and finger templates, and it needs the actual user and finger objects assembled in a nested list rather than one call at a time.
usertemplates = [
[user_1, [user_finger_1, user_finger_2]],
[user_2, [finger_3]],
...
]
conn.HR_save_usertemplates(usertemplates)That batching is the difference between a restore that takes minutes and one that takes hours, so any backup and restore tooling you write should use it. Remote fingerprint enrollment, where the device prompts the user to place a finger, is exposed as a single call on the ZK object, and the documentation carries an honest warning next to it: it does not work with some TCP ZK8 devices. That is the kind of caveat that matters more than a feature list, because it tells you the library covers some device families better than others, and it is the reason to test against your own hardware before promising a rollout.
The destructive commands are one call away and the documentation says so
The device maintenance section is where a reviewer should slow down. There is a call that erases all data on the device, including users, attendance reports and the finger database, and the documentation marks it with a DANGER comment in the same words.
# DANGER!!! This command will be erase all data in the device (incuded: user, attendance report, and finger database)
conn.clear_data()
# shutdown connected device
conn.poweroff()
# restart connected device
conn.restart()
# clear buffer
conn.free_data()Alongside those sit poweroff, restart and a buffer clear. A library that can shut down a terminal, wipe its database and restore it again is exactly what a backup and restore workflow needs, and equally what a buggy script needs at the wrong moment. The repository ships scripts for exactly these operations, including a test_backup_restore.py and a test_machine.py command line tool with flags for adding users, deleting users, enrolling users and reading a finger, plus a separate directory of small example scripts covering clearing data, reading device info, reading memory info, reading templates, reading users, live capture, powering off, restarting, setting a user and syncing the time. There is no confirmation prompt and no transaction, so any tool you build around this library should require an explicit flag to reach these calls.
Installation paths differ on modern Debian, and the package is pre 1.0
Installation is pip for most people, and the documentation also covers a manual route and a path based one for people who want to work straight from a clone.
pip install -U pyzkOn current Debian and Ubuntu releases, the documented failure is the externally-managed-environment error, which the attributes to PEP 668 protecting system Python packages, and the fix given is a virtual environment.
sudo apt install python3-venv -y
python3 -m venv venv
source venv/bin/activate
pip install pyzkThere is also a manual installation by running the setup script, and a documented pattern for adding a clone to the import path.
import sys
import os
sys.path.insert(1,os.path.abspath("./pyzk"))
from zk import ZK, constOn project status, the licence is GPL-2.0 with the terms in the LICENSE and LICENSE.txt files, the last push was on 2026-10-18, and the repository publishes no GitHub releases at all, so there is no tag to install from. The version in setup.py reads 0.9.1, which is the number you would see on the package index, and the full documentation lives on Read the Docs rather than in the repository. A changelog file and a repository directory called another tested device suggest the maintainer keeps notes on which hardware actually responds to which command, which is exactly the reference an unofficial library needs and exactly what a vendor would provide.
Editorial conclusion
pyzk is the practical choice for a small team that owns zkteco terminals and needs to script user enrolment, template backups or attendance exports, because the protocol work is already done and the surface area is documented command by command. It is the wrong choice for an environment that needs a supported contract, a versioned release train or a safety net around destructive calls, since it is explicitly unofficial, carries no GitHub releases and the package version in setup.py is 0.9.1. Before you script against a live terminal, check three things: that the disable and enable calls in your flow are balanced, because a process that exits between them leaves the device locked against users, that you know which voice index the firmware in your terminals supports, since the list is firmware dependent, and that a backup of the user and template database exists before you call clear_data. The licence is GPL-2.0, the last push was on 2026-10-18, and the full documentation is published on Read the Docs.
Frequently asked questions
How do I connect to a zkteco attendance machine with pyzk?
Create a ZK object with the device address, port, timeout, password and transport flags, then call connect. The documented defaults are port 4370 and address 192.168.1.201, and the constructor also takes force_udp and ommit_ping. A disconnect call closes the connection.
Why should I disable the device before running a batch job?
The disable_device call locks the terminal so that no user activity happens on it while your process runs, and enable_device restores normal operation afterwards. The library does not restore it automatically, so a script that fails between the two calls leaves the device locked.
Does pyzk support remote fingerprint enrollment?
Yes, through an enroll_user call on the ZK object, with the caveat that the documentation says it does not work with some TCP ZK8 devices. Bulk transfers of users and templates are handled separately with the high rate mode.
How do I install pyzk on a modern Debian or Ubuntu system?
The plain pip install may fail with the externally-managed-environment error, which the documentation attributes to PEP 668. The recommended fix is to install python3-venv, create a virtual environment, activate it and then install pyzk inside that environment.
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/fananimi-pyzk)Was this useful?