bitdreamit / laravel-qz-tray
Enterprise silent printing with QZ Tray for Laravel - Zero configuration, automatic certificate, browser caching
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Language:JavaScript
pkg:composer/bitdreamit/laravel-qz-tray
Requires
- php: ^8.1
- ext-openssl: *
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
README
🎯 What is This Package?
Laravel QZ Tray is a complete silent printing solution that connects your Laravel application to desktop printers via QZ Tray. It allows you to print directly from the browser without print dialogs, with smart caching, printer memory, and automatic fallback.
Perfect for: POS systems, receipt printing, label printing, invoices, reports, and any application needing silent, automated printing.
📁 FINAL PACKAGE STRUCTURE
laravel-qz-tray/
├── composer.json # Package configuration
├── LICENSE # MIT License
├── README.md # This documentation
├── config/
│ └── qz-tray.php # Package configuration
├── database/
│ └── migrations/
│ └── 2024_01_01_000000_create_qz_print_jobs_table.php
├── routes/
│ ├── web.php # Web routes for QZ Tray
│ └── api.php # API routes (optional)
├── resources/
│ ├── js/
│ │ ├── smart-print.js # Main printing library (23KB)
│ │ ├── smart-print.min.js # Minified version (12KB)
│ │ ├── printer-switcher.js # UI for switching printers
│ │ ├── printer-status.js # Status indicator component
│ │ └── adapters/
│ │ ├── escpos.js # ESC/POS thermal printer commands
│ │ ├── zpl.js # ZPL label printer commands
│ │ └── raw-print.js # Generic raw printing
│ └── installers/ # QZ Tray installers
│ ├── qz-tray-windows.exe # Windows installer
│ ├── qz-tray-linux.deb # Linux installer
│ └── qz-tray-macos.pkg # macOS installer
├── src/
│ ├── QzTrayServiceProvider.php # Laravel service provider
│ ├── Console/
│ │ └── Commands/
│ │ ├── InstallQzTray.php # Installation command
│ │ └── GenerateCertificate.php
│ └── Http/
│ └── Controllers/
│ └── QzSecurityController.php
└── storage/
└── qz/
├── certificate.pem # Auto-generated SSL certificate
└── private-key.pem # Auto-generated private key
🚀 Step-by-Step Installation Guide
Step 1: Install via Composer
# Install the package
composer require bitdreamit/laravel-qz-tray
Step 2: Run the Installer
# This does everything automatically: # - Publishes config # - Generates SSL certificate # - Publishes JavaScript files # - Sets up routes php artisan qz-tray:install
What the installer does:
- ✅ Creates
config/qz-tray.php - ✅ Generates SSL certificate in
storage/qz/ - ✅ Publishes JS files to
public/vendor/qz-tray/ - ✅ Sets up all necessary routes
- ✅ Optional: Runs migrations
Step 3: Include JavaScript in Your Layout
Add to resources/views/layouts/app.blade.php:
<!DOCTYPE html> <html> <head> <!-- CSRF Token --> <meta name="csrf-token" content="{{ csrf_token() }}"> <!-- QZ Tray Library (REQUIRED) --> <script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.5/qz-tray.min.js"></script> <!-- Laravel QZ Tray (REQUIRED) --> <script src="{{ asset('vendor/qz-tray/smart-print.min.js') }}"></script> <!-- Optional Components --> <script src="{{ asset('vendor/qz-tray/printer-status.min.js') }}"></script> <script src="{{ asset('vendor/qz-tray/adapters/escpos.min.js') }}"></script> <script src="{{ asset('vendor/qz-tray/adapters/zpl.min.js') }}"></script> </head> <body> <!-- Your content --> <!-- Optional: Printer status indicator --> <div data-qz-status='{"position": "bottom-right"}'></div> </body> </html>
Step 4: Install QZ Tray on Client Computers
Users need QZ Tray installed on their computers. Provide download links:
<!-- In your settings page or help section --> <div class="card"> <div class="card-header">Install Printer Software</div> <div class="card-body"> <p>Download and install QZ Tray for silent printing:</p> <a href="{{ route('qz.installer', 'windows') }}" class="btn btn-primary"> <i class="fas fa-download"></i> Download for Windows </a> <a href="{{ route('qz.installer', 'linux') }}" class="btn btn-primary"> <i class="fas fa-download"></i> Download for Linux </a> <a href="{{ route('qz.installer', 'macos') }}" class="btn btn-primary"> <i class="fas fa-download"></i> Download for macOS </a> <p class="text-muted mt-2"> <small>After installation, restart your browser and this page.</small> </p> </div> </div>
🖨️ COMPLETE USAGE GUIDE
1. Basic Print Buttons
<!-- Simple print button --> <button class="btn btn-primary" data-qz-print="{{ route('invoice.pdf', $id) }}"> <i class="fas fa-print"></i> Print Invoice </button> <!-- With specific printer --> <button class="btn btn-success" data-qz-print="{{ route('label.pdf', $id) }}" data-qz-printer="Label Printer" data-qz-copies="2"> Print 2 Copies </button> <!-- With delay (useful for chaining prints) --> <button data-qz-print="{{ route('report.pdf', $id) }}" data-qz-delay="2000"> Print with 2-second delay </button>
2. Auto-Print on Page Load
<!-- Auto-print when page loads (great for receipts) --> @if(session('print_receipt')) <div data-qz-auto-print="{{ route('receipt.pdf', session('receipt_id')) }}" data-qz-printer="Receipt Printer" data-qz-delay="1000"> </div> @endif
Controller example for auto-print:
public function storeOrder(Request $request) { // Process order... $order = Order::create($request->all()); return redirect()->route('order.confirmation', $order->id) ->with([ 'success' => 'Order placed successfully!', 'auto_print' => true, 'receipt_id' => $order->id, ]); } public function confirmation($id) { $order = Order::find($id); return view('orders.confirmation', [ 'order' => $order, 'auto_print' => session('auto_print', false), ]); }
3. Advanced Printing Options
<!-- Multiple data attributes --> <button class="btn btn-info" data-qz-print="{{ route('document.pdf', $id) }}" data-qz-printer="Laser Printer" data-qz-copies="3" data-qz-type="pdf" data-qz-delay="500"> <i class="fas fa-copy"></i> Print 3 Copies </button> <!-- Print on click with JavaScript --> <button class="btn btn-warning" onclick="printMyDocument()"> Custom Print </button> <script> function printMyDocument() { smartPrint('/documents/123.pdf', { printer: 'Receipt Printer', copies: 2, onComplete: function(job) { alert('Printed successfully!'); } }); } </script>
4. Raw Printing (Thermal Printers & Labels)
<!-- ESC/POS Thermal Receipt --> <button class="btn btn-dark" onclick="printThermalReceipt()"> <i class="fas fa-receipt"></i> Print Thermal Receipt </button> <!-- ZPL Label --> <button class="btn btn-secondary" onclick="printShippingLabel()"> <i class="fas fa-tag"></i> Print Shipping Label </button> <script> // Thermal receipt (ESC/POS) function printThermalReceipt() { const receiptData = { storeName: "My Store", receiptNumber: "12345", items: [ { name: "Item 1", price: "10.00", quantity: 2 }, { name: "Item 2", price: "15.00", quantity: 1 }, ], subtotal: "35.00", tax: "3.50", total: "38.50" }; const commands = ESCPOS.createReceipt(receiptData); smartPrintESC(commands, 'Thermal Printer'); } // Shipping label (ZPL) function printShippingLabel() { const labelData = { fromName: "John Doe", fromAddress: "123 Street", toName: "Jane Smith", toAddress: "456 Avenue", trackingNumber: "TRK123456789" }; const zpl = ZPL.createShippingLabel(labelData); smartPrintZPL(zpl, 'Label Printer'); } </script>
5. Programmatic API Usage
// Check if QZ Tray is connected if (SmartPrint.isConnected()) { console.log('Ready to print!'); } // Get current printer const currentPrinter = await SmartPrint.getCurrentPrinter(); console.log('Current printer:', currentPrinter); // Get all available printers const printers = await SmartPrint.getPrinters(); console.log('Available printers:', printers); // Set printer for current page await SmartPrint.setPrinter('Label Printer'); // Print with options const jobId = await SmartPrint.print('/documents/invoice.pdf', { printer: 'Office Printer', copies: 2, type: 'pdf' }); // Listen for events SmartPrint.on('connected', () => { console.log('Connected to QZ Tray!'); }); SmartPrint.on('job-completed', (event) => { console.log('Print job completed:', event.job); alert('Document printed successfully!'); }); SmartPrint.on('job-failed', (event) => { console.error('Print job failed:', event.error); alert('Printing failed. Please try again.'); });
6. Hotkey Feature
Default: Ctrl + Shift + P
When pressed, shows a dialog to switch printers for the current page. The selection is remembered permanently for that URL.
7. Printer Status Indicator
<!-- Add anywhere in your layout --> <div data-qz-status='{ "position": "bottom-right", "showPrinterName": true, "showConnection": true, "autoHide": true, "clickToSwitch": true }'></div>
Options:
position:top-left,top-right,bottom-left,bottom-right,top-center,bottom-centershowPrinterName: Show current printer nameshowConnection: Show connection statusautoHide: Automatically hide after delayclickToSwitch: Click to open printer switcher
🔧 Configuration Reference
After publishing config (php artisan vendor:publish --tag=qz-config):
config/qz-tray.php
<?php return [ /* |-------------------------------------------------------------------------- | Certificate Settings |-------------------------------------------------------------------------- */ 'cert_path' => storage_path('qz/certificate.pem'), 'key_path' => storage_path('qz/private-key.pem'), 'cert_ttl' => 3600, // Cache certificate for 1 hour /* |-------------------------------------------------------------------------- | Printer Settings |-------------------------------------------------------------------------- */ 'default_printer' => env('QZ_DEFAULT_PRINTER', 'Receipt Printer'), 'allow_printer_switch' => true, 'remember_printer_per_page' => true, 'printer_cache_duration' => 86400, // Remember for 24 hours /* |-------------------------------------------------------------------------- | WebSocket Settings |-------------------------------------------------------------------------- */ 'websocket' => [ 'host' => env('QZ_WEBSOCKET_HOST', '127.0.0.1'), 'port' => env('QZ_WEBSOCKET_PORT', 8181), 'retries' => 3, 'timeout' => 30, ], /* |-------------------------------------------------------------------------- | Browser Fallback |-------------------------------------------------------------------------- */ 'fallback' => [ 'enabled' => true, // Fallback to browser printing if QZ fails 'open_in_new_tab' => true, 'show_warning' => true, ], /* |-------------------------------------------------------------------------- | Hotkey Settings |-------------------------------------------------------------------------- */ 'hotkey' => [ 'enabled' => true, 'combination' => 'ctrl+shift+p', 'require_confirmation' => false, ], /* |-------------------------------------------------------------------------- | Route Settings |-------------------------------------------------------------------------- */ 'routes' => [ 'prefix' => 'qz', 'middleware' => ['web'], 'throttle' => '60,1', // 60 requests per minute ], /* |-------------------------------------------------------------------------- | Logging |-------------------------------------------------------------------------- */ 'logging' => [ 'enabled' => env('QZ_LOGGING_ENABLED', false), 'channel' => env('QZ_LOGGING_CHANNEL', 'stack'), 'level' => env('QZ_LOGGING_LEVEL', 'info'), ], /* |-------------------------------------------------------------------------- | Installer Settings |-------------------------------------------------------------------------- */ 'installers' => [ 'windows' => 'qz-tray-windows.exe', 'linux' => 'qz-tray-linux.deb', 'macos' => 'qz-tray-macos.pkg', ], ];
Environment Variables (.env)
# Default printer QZ_DEFAULT_PRINTER="Receipt Printer" # WebSocket settings (if QZ Tray is on different machine) QZ_WEBSOCKET_HOST=192.168.1.100 QZ_WEBSOCKET_PORT=8181 # Logging QZ_LOGGING_ENABLED=true QZ_LOGGING_CHANNEL=stack QZ_LOGGING_LEVEL=info
📊 API Endpoints Reference
| Endpoint | Method | Description | Example |
|---|---|---|---|
GET /qz/certificate |
GET | Get SSL certificate | curl /qz/certificate |
POST /qz/sign |
POST | Sign data for QZ Tray | {"data": "string to sign"} |
GET /qz/printers |
GET | Get available printers | curl /qz/printers |
GET /qz/printer/{path} |
GET | Get printer for path | curl /qz/printer/invoices |
POST /qz/printer |
POST | Set printer for path | {"printer": "HP", "path": "/invoices"} |
POST /qz/print |
POST | Log print job | {"url": "/invoice.pdf", "printer": "HP"} |
GET /qz/status |
GET | System status | curl /qz/status |
GET /qz/health |
GET | Health check | curl /qz/health |
GET /qz/installer/{os} |
GET | Download installer | /qz/installer/windows |
🎨 JavaScript API Reference
Global Functions
// Print PDF/HTML from URL smartPrint(url, options); // Print ZPL commands smartPrintZPL(zplCommands, printer); // Print ESC/POS commands smartPrintESC(escposCommands, printer);
SmartPrint Object
// Access the full API const api = window.SmartPrint; // Print methods api.print(url, options); // Print document api.printRaw(data, type, printer); // Print raw data api.printZPL(zpl, printer); // Print ZPL api.printESC(escpos, printer); // Print ESC/POS // Printer management api.getPrinters(); // Get all printers api.getCurrentPrinter(); // Get current printer api.setPrinter(printer, path); // Set printer for path api.showPrinterSwitcher(); // Show printer switcher // Connection api.connect(); // Connect to QZ Tray api.disconnect(); // Disconnect api.isConnected(); // Check connection // Queue management api.getQueue(); // Get print queue api.clearQueue(); // Clear queue // Settings api.getSettings(); // Get current settings api.updateSettings(newSettings); // Update settings // Events api.on(event, callback); // Listen to event api.off(event, callback); // Remove listener // Utility api.clearCache(); // Clear localStorage cache
Options Object
{ printer: 'Printer Name', // Specific printer type: 'pdf', // pdf, zpl, escpos, raw copies: 1, // Number of copies rawData: null, // Raw data for type='raw' delay: 0, // Delay before printing (ms) onComplete: function(job) {}, // Callback on success onError: function(error) {} // Callback on error }
Events
// Connection events SmartPrint.on('connected', () => {}); SmartPrint.on('disconnected', () => {}); SmartPrint.on('connection-failed', (data) => {}); // Printer events SmartPrint.on('printers-loaded', (data) => {}); SmartPrint.on('printer-saved', (data) => {}); SmartPrint.on('printers-error', (data) => {}); // Print job events SmartPrint.on('job-queued', (data) => {}); SmartPrint.on('job-processing', (data) => {}); SmartPrint.on('job-completed', (data) => {}); SmartPrint.on('job-failed', (data) => {}); SmartPrint.on('fallback-print', (data) => {}); // System events SmartPrint.on('ready', (data) => {}); SmartPrint.on('init-failed', (data) => {}); SmartPrint.on('queue-cleared', () => {}); SmartPrint.on('cache-cleared', () => {}); SmartPrint.on('settings-updated', (data) => {});
🔌 Adapters Reference
ESC/POS Adapter (Thermal Receipt Printers)
// Create receipt const receipt = ESCPOS.createReceipt({ storeName: "My Store", receiptNumber: "12345", items: [...], subtotal: "35.00", total: "38.50" }); // Print receipt ESCPOS.printReceipt(receiptData, 'Receipt Printer'); // Open cash drawer ESCPOS.openDrawer('Receipt Printer'); // Global shortcuts printReceipt(data, printer); // Print receipt printLabel(data, printer); // Print label openCashDrawer(printer); // Open cash drawer
ZPL Adapter (Zebra Label Printers)
// Create shipping label const zpl = ZPL.createShippingLabel({ fromName: "John Doe", toName: "Jane Smith", trackingNumber: "TRK123456789" }); // Print label ZPL.printShippingLabel(labelData, 'Label Printer'); // Create product label ZPL.printProductLabel(productData, 'Label Printer'); // Create QR code label ZPL.printQRLabel(qrData, 'Label Printer'); // Global shortcuts printShippingLabel(data, printer); printProductLabel(data, printer); printQRLabel(data, printer);
Raw Print Adapter (Generic Printing)
// Print formatted text RawPrint.printText("Hello World", { printer: 'Printer', align: 'center', bold: true, fontSize: 'large' }); // Print table RawPrint.printTable(data, { printer: 'Printer', columns: [ { title: 'Name', key: 'name', width: 20 }, { title: 'Price', key: 'price', width: 10 } ] }); // Print barcode RawPrint.printBarcode('123456789', 'CODE128', 'Printer'); // Cut paper RawPrint.cutPaper('Printer'); // Full cut RawPrint.cutPaper('Printer', true); // Partial cut // Test printer RawPrint.testPrinter('Printer'); // Global shortcuts printText(text, options); printTable(data, options); printBarcode(data, type, printer); cutPaper(printer, partial); openCashDrawer(printer); testPrinter(printer);
🚨 Troubleshooting Guide
Problem: QZ Tray Not Connecting
Symptoms:
- "Connecting to QZ Tray..." message stays
- Print buttons don't work
- Console shows WebSocket errors
Solutions:
-
Check if QZ Tray is installed and running
- Look for QZ Tray icon in system tray
- Right-click → About to check version
- If not installed: Download from
/qz/installer/windows
-
Check WebSocket connection
// In browser console SmartPrint.connect().then(connected => { console.log('Connected:', connected); });
-
Check certificate
# Regenerate certificate php artisan qz-tray:generate-certificate --force -
Check firewall/antivirus
- Allow port 8181
- Add exception for QZ Tray
Problem: Certificate Errors
Error messages:
- "Invalid certificate"
- "Certificate not trusted"
- Security warnings
Solutions:
-
Clear browser cache:
// In console SmartPrint.clearCache(); localStorage.clear(); sessionStorage.clear();
-
Regenerate certificate:
php artisan vendor:publish --tag=qz-certificate --force
-
Restart everything:
- Restart QZ Tray
- Restart browser
- Clear DNS cache
Problem: Printing Fails
Symptoms:
- Print job starts but nothing prints
- Printer not found errors
- Timeout errors
Solutions:
-
Check printer status:
// Check if printer is available const printers = await SmartPrint.getPrinters(); console.log('Available printers:', printers);
-
Try fallback printing:
<!-- Add fallback attribute --> <button data-qz-print="/document.pdf" data-qz-fallback="true"> Print with Fallback </button>
-
Check printer configuration:
- Verify printer is online
- Check paper/ink levels
- Test print from OS
-
Enable debug mode:
<script> window.QZ_CONFIG = { debug: true, endpoint: '/qz' }; </script>
Problem: Auto-Print Not Working
Check:
- Is
data-qz-auto-printdiv present in HTML? - Is there any JavaScript error in console?
- Is QZ Tray connected? (
SmartPrint.isConnected()) - Is the delay too short? Try
data-qz-delay="2000"
Common Error Messages:
| Error | Solution |
|---|---|
| "QZ Tray library not loaded" | Add <script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.5/qz-tray.min.js"></script> |
| "Cannot connect to QZ Tray" | Install QZ Tray, check it's running |
| "No printer selected" | Set default printer in config or use data-qz-printer |
| "PDF download timeout" | Check PDF generation route, increase timeout |
| "Response is not a PDF" | Ensure route returns proper PDF content-type |
📋 Best Practices
1. User Experience
<!-- Show loading state --> <button class="btn btn-primary" data-qz-print="/document.pdf" onclick="this.innerHTML='<i class=\'fas fa-spinner fa-spin\'></i> Printing...'"> <i class="fas fa-print"></i> Print </button> <!-- Provide feedback --> <script> SmartPrint.on('job-completed', () => { showNotification('Document printed successfully!', 'success'); }); SmartPrint.on('job-failed', () => { showNotification('Printing failed. Please try again.', 'error'); }); </script>
2. Error Handling
async function safePrint(url, options) { try { const jobId = await smartPrint(url, options); return { success: true, jobId }; } catch (error) { console.error('Print failed:', error); // Try fallback if (options.fallback !== false) { window.open(url, '_blank'); return { success: true, fallback: true }; } return { success: false, error }; } }
3. Batch Printing
<!-- Print multiple documents --> <button onclick="printBatch()">Print Batch</button> <script> async function printBatch() { const documents = [ '/documents/invoice-1.pdf', '/documents/invoice-2.pdf', '/documents/receipt-1.pdf' ]; for (let i = 0; i < documents.length; i++) { await smartPrint(documents[i], { printer: 'Laser Printer', delay: i * 1000 // 1 second between prints }); } } </script>
4. Printer Selection UI
<!-- Custom printer selector --> <div class="printer-selector"> <select id="printerSelect" class="form-select"> <option value="">Default Printer</option> <option value="Receipt Printer">Receipt Printer</option> <option value="Label Printer">Label Printer</option> <option value="Office Printer">Office Printer</option> </select> <button class="btn btn-sm btn-primary" onclick="setPrinterFromSelect()"> Set Printer </button> </div> <script> async function setPrinterFromSelect() { const select = document.getElementById('printerSelect'); const printer = select.value; if (printer) { await SmartPrint.setPrinter(printer); alert(`Printer "${printer}" set for this page`); } } </script>
🔄 Migration from Other Printing Solutions
From: Browser Print Dialog
<!-- BEFORE: Browser print --> <button onclick="window.print()">Print</button> <!-- AFTER: Silent print --> <button data-qz-print="{{ route('document.pdf', $id) }}">Print</button>
From: Raw PHP Printing
// BEFORE: Direct printing $printer = "\\\\server\\printer"; $handle = printer_open($printer); printer_write($handle, "Receipt content"); printer_close($handle); // AFTER: Client-side printing // Controller remains the same, just return PDF return PDF::loadView('receipt', $data)->stream();
From: JavaScript Print Libraries
// BEFORE: window.print() window.print(); // AFTER: Smart Print smartPrint('/document.pdf', { printer: 'Default' });
📈 Performance Optimization
1. Cache Printers
// Printers are cached for 5 minutes // Clear cache if printers change SmartPrint.clearCache();
2. Optimize PDF Generation
// Use caching for frequently printed documents public function pdf($id) { return Cache::remember("document.{$id}.pdf", 300, function() use ($id) { $data = Document::find($id); return PDF::loadView('document', $data)->stream(); }); }
3. Batch Processing
// Process print queue efficiently const queue = []; let isProcessing = false; function addToQueue(url, options) { queue.push({ url, options }); processQueue(); } async function processQueue() { if (isProcessing || queue.length === 0) return; isProcessing = true; const job = queue.shift(); try { await smartPrint(job.url, job.options); } catch (error) { console.error('Queue error:', error); } finally { isProcessing = false; processQueue(); } }
🔐 Security Considerations
1. Certificate Security
- Certificates auto-generated with 4096-bit RSA
- Stored in
storage/qz/directory - Regenerate periodically with
php artisan qz-tray:generate-certificate
2. Rate Limiting
- Routes are rate-limited (60 requests/minute)
- Adjust in config:
'throttle' => '60,1'
3. CSRF Protection
- All POST routes protected with CSRF tokens
- Automatically included with Laravel
4. Access Control
// Add middleware to routes Route::middleware(['auth', 'can:print'])->group(function () { Route::post('/qz/print', [QzSecurityController::class, 'print']); Route::post('/qz/printer', [QzSecurityController::class, 'setPrinter']); });
🎯 Real-World Examples
1. POS System Receipt
<!-- POS System --> <div class="pos-receipt"> <h4>Order #{{ $order->id }}</h4> <button class="btn btn-success" data-qz-print="{{ route('pos.receipt', $order->id) }}" data-qz-printer="Thermal Printer"> <i class="fas fa-receipt"></i> Print Receipt </button> <button class="btn btn-info" data-qz-print="{{ route('pos.kitchen', $order->id) }}" data-qz-printer="Kitchen Printer"> <i class="fas fa-utensils"></i> Print Kitchen </button> <!-- Auto-print on order completion --> @if($order->status === 'completed') <div data-qz-auto-print="{{ route('pos.receipt', $order->id) }}" data-qz-printer="Thermal Printer" data-qz-delay="500"> </div> @endif </div>
2. Shipping Label System
<!-- Shipping System --> <div class="shipping-label"> <h5>Shipment #{{ $shipment->tracking_number }}</h5> <button class="btn btn-primary" onclick="printShippingLabel({{ $shipment->id }})"> <i class="fas fa-tag"></i> Print Label </button> <button class="btn btn-secondary" onclick="printPackingSlip({{ $shipment->id }})"> <i class="fas fa-clipboard-list"></i> Packing Slip </button> </div> <script> async function printShippingLabel(shipmentId) { const response = await fetch(`/api/shipments/${shipmentId}/label-data`); const data = await response.json(); const zpl = ZPL.createShippingLabel(data); smartPrintZPL(zpl, 'Zebra Printer'); } async function printPackingSlip(shipmentId) { smartPrint(`/shipments/${shipmentId}/packing-slip.pdf`, { printer: 'Laser Printer', copies: 2 }); } </script>
3. Report Generation System
<!-- Report System --> <div class="report-actions"> <button class="btn btn-primary" data-qz-print="{{ route('reports.daily.pdf') }}" data-qz-printer="Report Printer"> <i class="fas fa-print"></i> Print Daily Report </button> <button class="btn btn-success" onclick="printReportBatch()"> <i class="fas fa-copy"></i> Print All Reports </button> <!-- Auto-print scheduled reports --> @if($autoPrintReports) <div id="report-batch"> @foreach($reports as $index => $report) <div data-qz-auto-print="{{ route('reports.view', $report->id) }}" data-qz-printer="Report Printer" data-qz-delay="{{ $index * 5000 }}"> </div> @endforeach </div> @endif </div>
📞 Support & Community
Getting Help
- Check Troubleshooting Guide above
- Enable Debug Mode:
<script> window.QZ_CONFIG = { debug: true }; </script>
- Check Console: Browser developer tools
Reporting Issues
# Include debug information SmartPrint.getStatus(); SmartPrint.getSettings();
Feature Requests
Visit GitHub repository issues section
🚀 Quick Start Cheat Sheet
1-Line Installation
composer require bitdreamit/laravel-qz-tray && php artisan qz-tray:install
Minimal Setup
<!-- In layout --> <script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.5/qz-tray.min.js"></script> <script src="{{ asset('vendor/qz-tray/smart-print.min.js') }}"></script> <!-- Print button --> <button data-qz-print="/document.pdf">Print</button>
Common Use Cases
<!-- Receipt --> <button data-qz-print="/receipt/123.pdf" data-qz-printer="Thermal">Receipt</button> <!-- Label --> <button onclick="smartPrintZPL('^XA...^XZ')">Label</button> <!-- Auto-print --> <div data-qz-auto-print="/invoice/123.pdf" data-qz-delay="1000"></div>
✅ Final Checklist Before Production
- QZ Tray installed on all client machines
- SSL certificate properly generated
- Default printer set in config
- JavaScript files included in layout
- Fallback printing enabled
- Error handling implemented
- User permissions configured
- Rate limiting appropriate for usage
- Logging enabled for debugging
- Backup/restore procedure for certificates
🎉 Congratulations!
Your Laravel application now has enterprise-grade silent printing capabilities.
Key Benefits:
- ✅ Zero configuration setup
- ✅ Automatic certificate management
- ✅ Per-page printer memory
- ✅ Smart browser caching
- ✅ Hotkey printer switching
- ✅ Fallback to browser printing
- ✅ ZPL/ESC-POS support
- ✅ Production-ready with monitoring
Start printing:
<button data-qz-print="{{ route('your.pdf.route') }}">Print Now</button>
Need help? Check the troubleshooting guide or create an issue on GitHub.
Happy Printing! 🖨️✨