Skip to content

atefe-aa/silent-print

Repository files navigation

🖨️ silent-print-service

A lightweight Windows background service that exposes a local HTTP API, enabling web apps to print HTML silently — no browser print dialog, no user interruption.

Platform Go Version License: MIT


The Problem

When a user hits Print in a web app, the browser always opens a print dialog. For most cases that's fine — but for high-frequency, repetitive printing (barcode label scanning, receipt printing, shipping labels) it becomes a serious friction point. Every scan → every print → dismiss dialog. Over hundreds of prints a day, this is painful.

The Solution

silent-print-service runs as a Windows Service on the user's machine. Your web app calls its local HTTP API instead of triggering the browser's print dialog. The service routes the job directly to the right physical printer based on paper size — no dialog, no clicks, just print.

Web App  ──POST /api/print──▶  silent-print-service  ──▶  Windows Printer
         { html, paper_size }        (localhost)              (silent)

Features

  • Silent printing — HTML content is sent directly to a configured Windows printer
  • Paper size routing — map each paper size (A4, A6, Label, etc.) to a specific printer
  • Runs as a Windows Service — starts automatically on boot, no console window
  • Built-in settings UI — configure printer mappings via a browser at http://localhost:8123
  • REST API — simple JSON API for health checks, printer discovery, config, and printing
  • CORS enabled — call from any web origin

Requirements

  • Windows 10 / Windows Server 2016 or newer
  • PowerShell 5.1+ (included in Windows)
  • Internet Explorer COM object (present on all standard Windows installs)
  • Go 1.21+ (only if building from source)

Quick Start

Option 1 — Download Pre-built Binary (Recommended)

  1. Go to Releases and download the latest silent-print-service.exe
  2. Place it in a permanent folder, e.g. C:\PrintService\
  3. Open PowerShell as Administrator in that folder and run:
.\silent-print-service.exe -service install
.\silent-print-service.exe -service start
  1. Open your browser at http://localhost:8123 to configure your printer mappings.

Option 2 — Install via go install

go install github.com/yourusername/silent-print-service@latest

Then run the same install / start commands above.

Option 3 — Build from Source

git clone https://github.com/yourusername/silent-print-service.git
cd silent-print-service
go build -o silent-print-service.exe .

Service Management

All commands require Administrator privileges.

Command Description
-service install Register as a Windows Service (auto-start)
-service uninstall Remove the service
-service start Start the service
-service stop Stop the service
-service restart Restart the service
# Example — stop and uninstall
.\silent-print-service.exe -service stop
.\silent-print-service.exe -service uninstall

Configuration

On first run, a config.json file is created next to the executable:

{
  "port": 8123,
  "printer_mappings": {
    "A4": "HP LaserJet Pro M404n",
    "A6": "Zebra ZD421 (Label Printer)"
  }
}

You can edit this file directly or use the web UI at http://localhost:8123.

Supported Paper Sizes

Key Dimensions
A3 297 × 420 mm
A4 210 × 297 mm
A5 148 × 210 mm
A6 105 × 148 mm
Letter 216 × 279 mm
Legal 216 × 356 mm

API Reference

Base URL: http://localhost:8123

All endpoints return JSON in the format:

{ "success": true, "data": { ... } }

GET /api/health

Returns service status and uptime.

curl http://localhost:8123/api/health
{
  "success": true,
  "data": {
    "status": "healthy",
    "uptime": "3h12m4s",
    "version": "1.0.0",
    "platform": "windows/amd64"
  }
}

GET /api/printers

Lists all printers installed on the machine.

curl http://localhost:8123/api/printers
{
  "success": true,
  "data": [
    {
      "name": "Zebra ZD421",
      "driver_name": "ZDesigner ZD421-300dpi ZPL",
      "port_name": "USB001",
      "status": "Ready",
      "is_default": false
    }
  ]
}

GET /api/config

Returns current port and printer mappings.


POST /api/config

Updates printer mappings. Send an empty string to remove a mapping.

curl -X POST http://localhost:8123/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "mappings": {
      "A4": "HP LaserJet",
      "A6": "Zebra ZD421",
      "A3": ""
    }
  }'

POST /api/print

Sends an HTML document to the printer configured for the given paper size.

curl -X POST http://localhost:8123/api/print \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Order #1042</h1><p>Ship to: John Doe</p>",
    "paper_size": "A6"
  }'

Request body:

Field Type Required Default Description
html string Full HTML content to print
paper_size string A4 One of the supported paper sizes

Success response:

{
  "success": true,
  "message": "Print job sent successfully",
  "data": {
    "printer": "Zebra ZD421",
    "paper_size": "A6"
  }
}

Web App Integration

Vanilla JavaScript

async function silentPrint(html, paperSize = 'A4') {
  const res = await fetch('http://localhost:8123/api/print', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ html, paper_size: paperSize }),
  });

  const data = await res.json();
  if (!data.success) throw new Error(data.error);
  return data;
}

// Usage
await silentPrint('<h1>Label</h1><p>SKU: 00123</p>', 'A6');

React Hook

import { useState, useCallback } from 'react';

const PRINT_SERVICE_URL = 'http://localhost:8123';

export function useSilentPrint() {
  const [printing, setPrinting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const print = useCallback(async (html: string, paperSize = 'A4') => {
    setPrinting(true);
    setError(null);
    try {
      const res = await fetch(`${PRINT_SERVICE_URL}/api/print`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ html, paper_size: paperSize }),
      });
      const data = await res.json();
      if (!data.success) throw new Error(data.error);
      return data;
    } catch (err: any) {
      setError(err.message);
      throw err;
    } finally {
      setPrinting(false);
    }
  }, []);

  return { print, printing, error };
}
// In your component
function BarcodeScanner() {
  const { print, printing, error } = useSilentPrint();

  const handleScan = async (barcode: string) => {
    const label = `
      <div style="font-family: monospace; padding: 8px;">
        <h2 style="margin: 0;">Item Received</h2>
        <p>Barcode: <strong>${barcode}</strong></p>
        <p>${new Date().toLocaleString()}</p>
      </div>
    `;
    await print(label, 'A6');
  };

  return (
    <div>
      {printing && <span>Printing...</span>}
      {error && <span style={{ color: 'red' }}>{error}</span>}
      {/* your scanner UI */}
    </div>
  );
}

Graceful Fallback

If the service is not running, fall back to the browser print dialog:

async function printWithFallback(html, paperSize = 'A4') {
  try {
    const health = await fetch('http://localhost:8123/api/health', { signal: AbortSignal.timeout(500) });
    if (health.ok) {
      return silentPrint(html, paperSize);
    }
  } catch {
    // service unavailable — fall back
  }

  // Browser fallback
  const win = window.open('', '_blank');
  win.document.write(html);
  win.print();
  win.close();
}

Settings UI

Navigate to http://localhost:8123 in any browser on the machine to:

  • View all installed printers and their status
  • Map each paper size to a specific printer
  • Send test print jobs

Architecture

silent-print-service/
├── main.go          # Windows Service lifecycle (install/start/stop)
├── server.go        # HTTP server and route registration
├── handlers.go      # API request handlers
├── printer_windows.go  # Windows-specific printer enumeration & printing
├── config.go        # Config load/save (config.json)
├── models.go        # Shared types (PaperSize, PrinterInfo)
└── web/
    └── templates/
        └── settings.html

Printing is implemented via PowerShell's Internet Explorer COM object, which sends the job directly to the Windows print spooler without any UI.


Limitations & Roadmap

Current limitations:

  • Windows only (uses winspool.drv and IE COM object)
  • Printing relies on Internet Explorer COM — may be affected on systems with IE fully removed

Planned / community welcome:

  • macOS support (lp / CUPS)
  • Linux support
  • Replace IE COM with a headless Chromium/WebView2 backend
  • Per-printer CSS page size injection
  • Print job queue and status tracking
  • Authentication / API key support for multi-user environments

License

MIT — see LICENSE


Contributing

Issues and PRs are welcome. If you're adding support for a new OS, see printer_windows.go for the interface to implement.

About

A lightweight Windows background service that exposes a local HTTP API so web apps can print HTML silently — no browser print dialog, no user interruption. Perfect for barcode label printing, receipt workflows, and any high-frequency print scenario.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors