Biometric Attendance for ERPNext: Complete Integration Guide
Connect ZKTeco fingerprint and face scanners to ERPNext with real-time webhooks. Full code walkthrough β from device setup to Auto Attendance, no pyzk required.
Why Biometric Attendance in ERPNext Breaks at Scale
You have ZKTeco fingerprint scanners at your offices and ERPNext managing HR. The official Frappe Biometric Attendance Sync Tool uses pyzk to poll devices over your LAN. One office, one device, one network β it works.
Add a second location and everything falls apart.
pyzk requires a Python script running on the same local network as every device. If ERPNext runs on Frappe Cloud, you cannot install pyzk on their servers. If you have branch offices, each needs its own sync machine. If a device gets a new IP via DHCP, the connection breaks silently β and you discover it when payroll runs with missing records.
PunchConnect eliminates this entire architecture. Devices push attendance data to a cloud API. ERPNext receives it via webhook in real time. No local scripts. No LAN dependency. No cron jobs polling stale data.
This guide walks you through the complete integration: device configuration, webhook receiver, employee mapping, Auto Attendance, and production hardening. Every code block is copy-paste ready.
Architecture: How the Integration Works
The traditional pyzk approach and the PunchConnect approach solve the same problem differently:
Traditional (pyzk):
- Requires shared network
- 10β30 minute sync delay
- Breaks across sites
PunchConnect (cloud webhook):
- Works from any network
- Real-time (1β3 seconds)
- Single endpoint for all sites
The device pushes punches to PunchConnect's cloud infrastructure. PunchConnect normalizes the data across firmware versions and forwards it as a clean JSON webhook to your ERPNext instance. ERPNext creates an Employee Checkin record, and the built-in Auto Attendance module converts checkins into Attendance entries automatically.
No middleware server. No VPN tunnels. No per-site infrastructure.
Device β [LAN] β pyzk script β [cron] β ERPNext API β Employee Checkin
Prerequisites
Before starting, you need:
- ERPNext v14+ or v15+ with the HRMS app installed
- A ZKTeco device with cloud connectivity (SpeedFace V5L, ProFace X, uFace 800, MB460, iClock 680, K-series, or similar)
- A PunchConnect account β start a free 7-day trial, no credit card required
- HTTPS on your ERPNext instance β webhooks require a valid SSL certificate
Step 1: Create Your PunchConnect Account and Register a Device
Sign up at punchconnect.com/signup. After email verification, you land on the dashboard.
Click Add Device and enter your device's serial number. PunchConnect generates a cloud configuration for your device β apply it through the PunchConnect dashboard. The entire process takes about 5 minutes per device.
Once configured, the device appears as "Online" in your dashboard within 60 seconds.
Managing multiple sites? Register all devices under one account. PunchConnect handles 50+ sites and hundreds of devices from a single dashboard. Each device is identified by its serial number, and you can organize them by location.
Step 2: Build the Webhook Receiver in ERPNext
PunchConnect sends a POST request to your ERPNext instance every time someone punches. You need a whitelisted API method to receive it.
Option A: Quick Setup with the PunchConnect ERPNext App
Install the official PunchConnect ERPNext app for zero-code setup:
After installation:
1. Navigate to PunchConnect Settings β enter your API key and webhook secret
2. Click Test Connection to verify
3. In the PunchConnect dashboard, add your webhook URL:
The app handles everything: HMAC signature verification, duplicate detection, employee mapping, sync logs, and a monitoring dashboard.
# From your bench directorybench get-app https://github.com/punchconnect/erpnext-punchconnect.gitbench --site your-site.local install-app punchconnectbench --site your-site.local migrate
Option B: Custom Webhook Receiver (Full Control)
If you prefer building your own receiver, create a whitelisted API method in your custom Frappe app:
Add the URL to your site's site_config.json:
Register the endpoint in PunchConnect's dashboard:
# your_app/api.pyimport frappeimport hmacimport hashlibfrom frappe import _WEBHOOK_SECRET = frappe.conf.get("punchconnect_webhook_secret", "")@frappe.whitelist(allow_guest=True)def punchconnect_webhook():"""Receive attendance events from PunchConnect."""# 1. Verify HMAC signaturepayload = frappe.request.datasignature = frappe.request.headers.get("X-PunchConnect-Signature", "")expected = hmac.new(WEBHOOK_SECRET.encode(),payload,hashlib.sha256).hexdigest()if not hmac.compare_digest(signature, expected):frappe.throw(_("Invalid webhook signature"), frappe.AuthenticationError)# 2. Parse the eventdata = frappe.parse_json(payload)event_type = data.get("event")if event_type != "attendance":# Acknowledge non-attendance events (device_status, heartbeat)return {"status": "ok", "message": f"Event {event_type} acknowledged"}# 3. Find the employee by device user IDdevice_user_id = str(data.get("user_id"))employee = frappe.db.get_value("Employee",{"attendance_device_id": device_user_id, "status": "Active"},["name", "employee_name", "company"],as_dict=True)if not employee:frappe.log_error(f"No employee found for device user ID: {device_user_id}","PunchConnect Webhook")return {"status": "error", "message": "Employee not found"}# 4. Check for duplicates (same employee, same timestamp)timestamp = data.get("timestamp")existing = frappe.db.exists("Employee Checkin", {"employee": employee.name,"time": timestamp})if existing:return {"status": "ok", "message": "Duplicate, skipped"}# 5. Create Employee Checkincheckin = frappe.get_doc({"doctype": "Employee Checkin","employee": employee.name,"employee_name": employee.employee_name,"time": timestamp,"device_id": data.get("device_serial"),"log_type": map_punch_direction(data.get("punch_direction"))})checkin.insert(ignore_permissions=True)frappe.db.commit()return {"status": "ok","checkin": checkin.name,"employee": employee.employee_name}def map_punch_direction(direction):"""Map PunchConnect direction to ERPNext log type."""mapping = {"IN": "IN","OUT": "OUT","0": "IN", # Some devices use numeric codes"1": "OUT",}return mapping.get(str(direction).upper(), "")
Step 3: Map Employees to Device User IDs
Every employee who uses a biometric device needs their attendance_device_id set. This field links the biometric user ID stored on the device to the ERPNext Employee record.
Manual Mapping
1. Open the Employee doctype
2. Scroll to Attendance and Leave Details
3. Set Attendance Device ID to match the user ID on the biometric device
Bulk Mapping via Data Import
For organizations with hundreds of employees, use ERPNext's Data Import:
Upload via Settings β Data Import β Employee (update existing records).
name,attendance_device_idHR-EMP-00001,101HR-EMP-00002,102HR-EMP-00003,103
Mapping via API
Automate mapping with a script that pulls users from PunchConnect and matches by name:
import requestsimport frappeAPI_KEY = "your_punchconnect_api_key"def sync_employee_ids():"""Pull device users from PunchConnect and map to ERPNext employees."""response = requests.get("https://api.punchconnect.com/v1/users",headers={"Authorization": f"Bearer {API_KEY}"})device_users = response.json()["data"]for user in device_users:# Match by employee name (adjust matching logic as needed)employee = frappe.db.get_value("Employee",{"employee_name": user["name"], "status": "Active"},"name")if employee:frappe.db.set_value("Employee", employee,"attendance_device_id", str(user["user_id"]))frappe.db.commit()print(f"Mapped {len(device_users)} device users to employees")
Step 4: Configure Auto Attendance
ERPNext v14+ includes Auto Attendance β it converts Employee Checkin records into Attendance entries automatically. This is the final piece of the pipeline.
Enable Auto Attendance
1. Go to HR Settings β enable Auto Attendance
2. Navigate to Shift Type β create or edit a shift
3. Configure the shift timing:
4. Assign shifts to employees: Go to Shift Assignment β create assignments linking employees to shift types
Shift Name: Morning ShiftStart Time: 08:00End Time: 17:00Enable Auto Attendance: βDetermine Check-in and Check-out: AlternatingWorking Hours Threshold for Half Day: 4Working Hours Threshold for Absent: 2
How Auto Attendance Processes Checkins
The Auto Attendance job runs periodically (configurable in Scheduled Job Type). It:
1. Picks up Employee Checkin records that haven't been processed
2. Matches them against the employee's assigned Shift Type
3. Calculates working hours (first IN to last OUT)
4. Creates an Attendance record with status: Present, Half Day, or Absent
5. Marks the checkins as processed
No manual intervention at any step. Device β Cloud β ERPNext β Attendance β fully automated.
# The full pipeline in action:## 08:02 β Device captures fingerprint (User ID: 101)# 08:02 β PunchConnect receives punch# 08:03 β Webhook fires to ERPNext (1-3 second delay)# 08:03 β Employee Checkin created (HR-EMP-00001, IN, 08:02)# ...# 17:05 β Same employee punches OUT# 17:05 β Employee Checkin created (HR-EMP-00001, OUT, 17:05)# ...# Auto Attendance runs β Attendance record: Present, 9h 3m worked
Step 5: Monitor and Troubleshoot
Using the PunchConnect ERPNext Dashboard
If you installed the official app, navigate to /punchconnect-dashboard for a real-time overview:
- Device count: total, online, offline
- Today's checkins: running count
- Sync success/failure rate: last 24 hours
- Recent activity log: every webhook processed
Using PunchConnect Sync Logs
Every webhook event is recorded in the PunchConnect Sync Log doctype. Filter by status to find failures:
# Find failed syncs in the last 24 hoursfailed = frappe.get_all("PunchConnect Sync Log",filters={"status": "Failed","creation": [">", frappe.utils.add_days(frappe.utils.now(), -1)]},fields=["name", "error_message", "device_serial", "raw_payload"])for log in failed:print(f"Device {log.device_serial}: {log.error_message}")
Common Issues and Fixes
Employee Checkin not created?
- Verify the employee's attendance_device_id matches the device user ID
- Check PunchConnect Sync Logs for the error message
- Enable "Log Raw Payloads" in PunchConnect Settings for debugging
Webhook returning 401 or 403?
- Confirm the webhook secret matches in both PunchConnect and ERPNext
- Check that the API method is whitelisted with allow_guest=True
- Verify your SSL certificate is valid (webhooks require HTTPS)
Auto Attendance not creating records?
- Confirm Auto Attendance is enabled in HR Settings
- Verify employees have Shift Assignments for the correct date range
- Check the Scheduled Job Type for process_auto_attendance β it must be active
Duplicate checkins?
- The PunchConnect app includes built-in duplicate detection
- If using a custom receiver, check for existing records before inserting (see Step 2 code)
Deployment Models: Which Setup Fits You?
Frappe Cloud
You cannot install pyzk on Frappe Cloud servers. PunchConnect webhooks are the only viable path for biometric integration. The webhook receiver runs as a standard Frappe API endpoint β no special server access required.
Self-Hosted / Docker
You could use pyzk, but PunchConnect is faster to deploy and more reliable. No cron jobs to maintain, no device IP tracking, no firmware compatibility issues. One webhook endpoint handles all devices.
Multi-Site Organizations
This is where PunchConnect delivers the most value. 100 devices across 20 offices? One PunchConnect account, one webhook endpoint, one ERPNext instance. No per-site infrastructure. No VPN tunnels. No per-location sync scripts.
Currently powering attendance for 24,000+ active employees across 50+ sites in production. Read the AgriWise case study for a real-world deployment at scale.
Security Considerations
Biometric attendance data flows through three points: device, PunchConnect cloud, and your ERPNext instance. Here's how each leg is secured:
Device β PunchConnect: TLS-encrypted connection. Devices authenticate with their registered serial number.
PunchConnect β ERPNext: HTTPS with HMAC-SHA256 signature verification. Every webhook includes an X-PunchConnect-Signature header. Your receiver validates this before processing (see the code in Step 2).
Data at rest: PunchConnect processes attendance events in real time and forwards them. It does not store biometric templates (fingerprints, face data). Only metadata β user ID, timestamp, device serial β passes through the API.
For a deeper dive into securing biometric data pipelines, read our guide on securing biometric data in transit.
Pricing
$200 per device β one-time license. No monthly fees. No per-employee charges.
Compare that to the hidden cost of pyzk infrastructure: a sync server per site, VPN configuration, developer time for firmware debugging, and ongoing maintenance. For most organizations, PunchConnect pays for itself in the first month of reduced DevOps overhead.
Start your free 7-day trial β no credit card required.
Frequently Asked Questions
Does biometric attendance for ERPNext work with Frappe Cloud?
Yes. PunchConnect sends data via webhook to a standard Frappe API endpoint. No software installation on Frappe Cloud servers is required.
Which ZKTeco devices are supported?
Any model with cloud connectivity: SpeedFace V5L, ProFace X, uFace 800, MB460, iClock 680, K-series, and more. Contact us to verify your specific model.
How fast does attendance data reach ERPNext?
1β3 seconds via webhook. Compare that to 10β30 minutes with pyzk cron-based polling.
Can I run PunchConnect alongside the existing Frappe sync tool?
Yes. Both create Employee Checkin documents. Run them in parallel during migration, then disable the cron-based script once you verify webhook delivery.
What happens if ERPNext is temporarily down?
PunchConnect retries failed webhook deliveries with exponential backoff. No attendance data is lost during brief outages.
Do I need a static IP for my ERPNext server?
No. You need a domain name with a valid SSL certificate. PunchConnect sends webhooks to your URL β DNS handles the rest.
How does this work with ERPNext's permission model?
The webhook receiver uses allow_guest=True because PunchConnect authenticates via HMAC signature, not ERPNext user sessions. The Employee Checkin is created with ignore_permissions=True by the server-side handler.
Can I track which verification method was used (fingerprint vs. face vs. card)?
Yes. The webhook payload includes a verify_mode field. You can store this in a custom field on Employee Checkin for audit purposes.
---
Ready to connect your biometric devices to ERPNext? Start your free 7-day trial β register your first device, configure the webhook, and see real-time Employee Checkins in ERPNext within 30 minutes. No credit card. No pyzk. No local infrastructure.
Questions? Contact us β we've integrated with every ERPNext deployment model and every ZKTeco firmware variant.