How to Detect Printer Status (Online, Offline, Paper Out, or Errors) in Node.js with Kiosk Nov 18, 2025 | 13 minutes read 8 Likes Printer Status Monitoring with Node.jsWhen managing kiosks, retail terminals, or POS systems, it is essential to know whether your printer is online, offline, or out of paper. We’ll build a Node.js-based printer status monitor using SNMP, ESC/POS commands, and Express.js to expose a simple API. What We’ll BuildAutomatically discovers printers via SNMPUses ESC/POS status commands to detect:○ Online/offline state○ Paper out / paper near the end○ Cover open○ Mechanical or cutter errorsServes a REST API endpoint (/) that returns real-time printer information in JSON. Project Setup:1. Environment VariablesCreate a .env file # Printer SNMP settings PRINTER_SNMP_COMMUNITY=public PRINTER_IP=192.168.10.148 PRINTER_INTERVAL=60000 PRINTER_START_INTERVAL=15000 PORT=9100 2. Printer Discovery via SNMP File: printers/discovery.js const snmp = require('net-snmp'); const { getEscPosStatus, getEscPosInfo } = require('./status'); let printers = []; // ---------------------- // Helper: Add or update printer (deduplicate by IP + port) // ---------------------- function addOrUpdatePrinter(newPrinter) { const existing = printers.find(p => p.ip === newPrinter.ip && p.port === newPrinter.port); if (existing) { // Prefer Bonjour info if available if (newPrinter.protocol === "Bonjour") { existing.name = newPrinter.name || existing.name; existing.protocol = newPrinter.protocol; } existing.model = newPrinter.model || existing.model; existing.firmware = newPrinter.firmware || existing.firmware; } else { printers.push(newPrinter); } } function discoverSNMP(printerIp = process.env.PRINTER_IP) { return new Promise((resolve) => { const found = []; let completed = 0; // SNMP OIDs const OIDS = { sysName: "1.3.6.1.2.1.1.5.0", // Hostname sysDescr: "1.3.6.1.2.1.1.1.0", // System description (model/firmware) sysLocation: "1.3.6.1.2.1.1.6.0", // Location string prtGeneralPrinterName: "1.3.6.1.2.1.43.5.1.1.16.1", // Printer name prtGeneralSerialNumber: "1.3.6.1.2.1.43.5.1.1.17.1", // Serial number }; const ip = printerIp; const session = snmp.createSession(ip, process.env.PRINTER_SNMP_COMMUNITY); session.get(Object.values(OIDS), (err, varbinds) => { if (!err && varbinds && varbinds.length > 0) { const printer = { id: `${ip}:9100`, ip, port: process.env.PORT, protocol: "SNMP", name: varbinds[0]?.value?.toString() || "", // sysName model: varbinds[1]?.value?.toString() || "", // sysDescr location: varbinds[2]?.value?.toString() || "", // sysLocation printerName: varbinds[3]?.value?.toString() || "", // prtGeneralPrinterName serialNumber: varbinds[4]?.value?.toString() || "", // prtGeneralSerialNumber }; addOrUpdatePrinter(printer); found.push(printer); } session.close(); completed++; if (completed >= 254) resolve(found); }); // Safety timeout setTimeout(() => resolve(found), 8000); }); } // ---------------------- // Periodic discovery & cleanup (keep only online printers) // ---------------------- function discoverPrintersPeriodic(interval = process.env.PRINTER_INTERVAL, ip = process.env.PRINTER_IP) { async function discover() { // await discoverBonjour(); await discoverSNMP(ip); // Check status for all printers and remove offline ones for (let i = printers.length - 1; i >= 0; i--) { const p = printers[i]; try { const status = await getEscPosStatus(p); if (!status.online) printers.splice(i, 1); } catch { printers.splice(i, 1); } } setTimeout(discover, interval); } discover(); } module.exports = { printers, discoverPrintersPeriodic, addOrUpdatePrinter }; 3. Checking Printer Status via ESC/POS CommandsFile: printers/status.js const net = require('net'); // ESC/POS commands const STATUS_COMMANDS = { printer: Buffer.from([0x10, 0x04, 0x01]), offline: Buffer.from([0x10, 0x04, 0x02]), error: Buffer.from([0x10, 0x04, 0x03]), paper: Buffer.from([0x10, 0x04, 0x04]), }; const GS_I_MODEL = Buffer.from([0x1D, 0x49, 0x01]); const GS_I_FIRMWARE = Buffer.from([0x1D, 0x49, 0x02]); async function queryEscPos(ip, port, command) { return new Promise((resolve, reject) => { const client = new net.Socket(); let buffer = Buffer.alloc(0); client.setTimeout(2000, () => { client.destroy(); reject(new Error("Timeout")); }); client.connect(port, ip, () => client.write(command)); client.on('data', data => { buffer = Buffer.concat([buffer, data]); client.destroy(); resolve(buffer.toString().trim()); }); client.on('error', reject); }); } async function getEscPosInfo(printer) { try { const model = await queryEscPos(printer.ip, printer.port, GS_I_MODEL); const firmware = await queryEscPos(printer.ip, printer.port, GS_I_FIRMWARE); return { model, firmware }; } catch { return {}; } } async function getEscPosStatus(printer) { const commands = [STATUS_COMMANDS.printer, STATUS_COMMANDS.offline, STATUS_COMMANDS.error, STATUS_COMMANDS.paper]; const results = []; try { for (const cmd of commands) { const res = await queryEscPos(printer.ip, printer.port, cmd); results.push(res.charCodeAt(0) || 0); } const [printerB, offline, error, paper] = results; const status = { online: !(offline & 0x08), coverOpen: !!(error & 0x04), paperOut: !!(paper & 0x60), paperNearEnd: !!(paper & 0x0C), mechanicalError: !!(error & 0x40), cutterError: !!(error & 0x08), unrecoverableError: !!(error & 0x20), }; status.error = status.coverOpen || status.paperOut || status.mechanicalError || status.cutterError || status.unrecoverableError; return status; } catch { return { online: false, error: true }; } } module.exports = { getEscPosInfo, getEscPosStatus }; 4. Logging Printer EventsFile: printers/events.js function logPrinterStatus(printer, status) { const symbol = status.error ? '✖' : '✔'; const color = status.error ? '\x1b[31m' : '\x1b[32m'; console.log(`${color}${symbol} [${printer.protocol}] ${printer.name}: ${status.error ? 'ERROR' : 'OK'}\x1b[0m`); } module.exports = { logPrinterStatus }; 5. Creating the Express API EndpointFile: routes/printers.js const express = require('express'); const router = express.Router(); const { printers } = require('../printers/discovery'); const { getEscPosStatus, getEscPosInfo } = require('../printers/status'); const { logPrinterStatus } = require('../printers/events'); const fs = require('fs'); const path = require('path'); router.get('/', async (req, res) => { const debug = req.query.debug === 'true'; const enriched = []; const configPath = path.join(__dirname, '../config.json'); const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); const kioskName = config.KIOSK_NAME; for (const p of printers) { try { // Get printer status const status = await getEscPosStatus(p); if (!status.online) continue; // Get ESC/POS info (model, firmware) const escposInfo = await getEscPosInfo(p); // Build enriched printer object const printerData = { id: p.id, ip: p.ip, port: p.port, protocol: p.protocol, name: p.name || p.printerName || "", model: escposInfo.model && escposInfo.model.length > 2 ? escposInfo.model : p.model || p.printerName || "Unknown", firmware: escposInfo.firmware && /^[\x20-\x7E]+$/.test(escposInfo.firmware) ? escposInfo.firmware : undefined, serialNumber: p.serialNumber || "", kioskId: kioskName, location: p.location || "", online: status.online, coverOpen: status.coverOpen || false, paperOut: status.paperOut || false, paperNearEnd: status.paperNearEnd || false, mechanicalError: status.mechanicalError || false, cutterError: status.cutterError || false, unrecoverableError: status.unrecoverableError || false, error: status.error || false, }; if (debug) logPrinterStatus(p, status); enriched.push(printerData); } catch (e) { console.error("Failed to enrich printer:", p.ip, e); } } res.json(enriched); }); module.exports = router; 6. Starting the ServiceFile: server.js require('dotenv').config(); const express = require('express'); const http = require('http'); const cors = require('cors'); const { discoverPrintersPeriodic } = require('./printers/discovery'); const printersRoute = require('./routes/printers'); const paymentRoute = require('./routes/payment'); const printRoute = require('./routes/print'); const { startWebSocket, startMonitoring } = require('./printers/monitor'); const app = express(); const PORT = 3001; const server = http.createServer(app); app.use(cors()); app.use(express.json()); app.use('/api/printers', printersRoute); // Start periodic network discovery (removes offline printers automatically) discoverPrintersPeriodic(process.env.PRINTER_INTERVAL); // Start WebSocket server startWebSocket(server); // Start real-time monitoring startMonitoring(5000); server.listen(PORT, () => console.log(`Server running at http://localhost:${PORT}`)); Run it:node server.jsVisit: http://localhost:3000/printers 7. Example Output: [ { "id": "192.168.10.148:9100", "ip": "192.168.10.148", "protocol": "SNMP", "name": "EPSON_TM_T88VI", "model": "EPSON TM-T88VI Receipt Printer", "firmware": "1.02", "serialNumber": "AB12345678", "kioskId": "Kiosk-001", "online": true, "coverOpen": false, "paperOut": false, "paperNearEnd": false, "mechanicalError": false, "cutterError": false, "unrecoverableError": false, "error": false } ] Printer Status insights for real-time kiosk monitoringCheck NowThe Way ForwardIntegrating Apple Pay and Google Pay using Stripe in React Native is a powerful way to deliver seamless and secure payment experiences to users worldwide. With a few lines of configuration and careful setup, you can enable one-tap payments and boost conversion rates.This guide covered the end-to-end process from SDK setup and backend creation to testing React Native apps online and deployment, giving you a solid foundation for handling mobile payments confidently.Next step: Explore advanced flows like saving payment methods, handling subscriptions, or integrating 3D Secure authentication for maximum protection.Free Consultation Node.js DevelopersNode.jsNode js Service ProvidersHire Dedicated Node js DeveloperNode.js ApplicationHire Node.js DeveloperMayur DosiNov 18 2025I am Assistant Project Manager at iFlair, specializing in PHP, Laravel, CodeIgniter, Symphony, JavaScript, JS frameworks ,Python, and DevOps. With extensive experience in web development and cloud infrastructure, I play a key role in managing and delivering high-quality software solutions. I am Passionate about technology, automation, and scalable architectures, I am ensures seamless project execution, bridging the gap between development and operations. I am adept at leading teams, optimizing workflows, and integrating cutting-edge solutions to enhance performance and efficiency. Project planning and good strategy to manage projects tasks and deliver to clients on time. Easy to adopt new technologies learn and work on it as per the new requirments and trends. When not immersed in code and project planning, I am enjoy exploring the latest advancements in AI, cloud computing, and open-source technologies.You may also like How to Print Order Receipts from a Kiosk Machine Using Node.js and ESC/POS Read More Nov 25 2025 Database Simplified: TypeORM in Node.js Read More Nov 19 2025 Network Discovery for JCC Terminals in Node.js – Best Practices & Code Samples Read More Nov 18 2025 Next JS Development Services Driving Innovation in Modern Web Architecture Read More Sep 11 2025 Scaling SaaS Platforms Using SSR Strategies with Hire Next.js Developers Read More Aug 12 2025 Implementing Microservices Architecture with Node.js and MongoDB Read More Jun 13 2025