What It Does
KwickPython is a tiny Python CGI script that bridges the gap between your web application and local printers. It runs as a local HTTP server on port 9100 and accepts AJAX requests from your webpage — enabling silent, direct printing to any attached printer.
List Printers
Enumerate all local and network printers available on the client machine.
Check Status
Query printer status — online, offline, or paused — before sending print jobs.
Silent Printing
Send RAW data (ESC/POS, PCL, etc.) directly to printers. No dialogs, no previews.
Any Printer
Works with USB, serial, parallel, LAN, and Windows shared printers.
JavaScript API
Get List of Printers
$.ajax({
url: 'http://127.0.0.1:9100/htbin/kp.py',
success: function(printers) {
console.log(printers); // JSON object of all printers
}
});
Check Printer Status
$.ajax({
url: 'http://127.0.0.1:9100/htbin/kp.py',
data: { p: 'Kitchen_Printer' },
success: function(status) {
console.log(status); // "Kitchen_Printer Ready"
}
});
Send Print Job
$.ajax({
url: 'http://127.0.0.1:9100/htbin/kp.py',
data: {
p: 'Receipt_Printer',
d: btoa(rawEscPosData) // Base64 encoded ESC/POS data
},
success: function(bytes) {
console.log(bytes + ' bytes sent');
}
});
Setup (5 Minutes)
Requirements: Windows + Python 3 + pywin32
- Create directory:
C:\KwickPython\htbin - Save kp.py to
C:\KwickPython\htbin\kp.py - Start the server:
# Start KwickPython on port 9100 cd C:\KwickPython python -m http.server --cgi 9100
Your web app can now print to any local printer via AJAX calls to http://127.0.0.1:9100/htbin/kp.py
Port Configuration
Port 9100 is the standard raw printing port. You can use any port — just update both the server command and your AJAX URLs to match:
# Use a custom port python -m http.server --cgi 1234
Security
By default, KwickPython accepts requests from any origin (Access-Control-Allow-Origin: *). For production, lock it down to your domain:
# In kp.py, change:
print('Access-Control-Allow-Origin: *')
# To:
print('Access-Control-Allow-Origin: https://yourdomain.com')
Full Source Code
The entire script — under 50 lines:
# KwickPython [FREE TO USE FOR ANY PROJECT, NO WARRANTY]
# Link back to https://kwickpos.com if it works for you
import cgi, os, sys, win32print, pywintypes
print("Access-Control-Allow-Origin: *")
print("Content-Type: text/plain\n")
form = cgi.FieldStorage()
p = form.getvalue('p')
if p:
data = form.getvalue('data')
if data:
import base64
raw_data = base64.b64decode(data)
if raw_data:
h = win32print.OpenPrinter(p)
hJob = win32print.StartDocPrinter(h, 1,
("KwickPOS Ticket", None, "RAW"))
win32print.StartPagePrinter(h)
b = win32print.WritePrinter(h, raw_data)
win32print.EndPagePrinter(h)
win32print.EndDocPrinter(h)
win32print.ClosePrinter(h)
print(b)
sys.exit()
else:
try:
h = win32print.OpenPrinter(p)
d = win32print.GetPrinter(h, 2)
win32print.ClosePrinter(h)
a = d['Attributes']
hex_val = hex(a)
if hex_val[-3] == '6':
print(p + ' Offline')
sys.exit()
s = d['Status']
if s == 1:
print(p + ' Paused')
sys.exit()
print(p + ' Ready')
except pywintypes.error:
print(p + ' No Such Printer')
else:
import json
p = {}
lst = win32print.EnumPrinters(2)
for f, d, n, c in lst:
p[n] = {'d': d, 'c': c}
print(json.dumps(p))
Need a Full Restaurant POS System?
KwickPython powers the local printing in KwickPOS — the smart POS system trusted by 5,000+ merchants.
Get a Free Demo →