Building a Custom Label Printing System: From Loftware to GoDex
Our logistics department had been using Loftware's IoT label printing system for shipping labels. It's a solid, reliable system with one fatal flaw — it's expensive.
Between licensing fees and printer rentals, it was a significant annual expense. The operations team started wondering: since we have our own ERP system, couldn't we develop our own label printing feature with more affordable printers?
And so, this task landed on my desk.
Requirements and Hardware Selection
Operations chose the GoDex G530+ as our label printer. It's a desktop thermal printer at a reasonable price point, supporting 100mm wide label paper. Our shipping label spec is 100mm x 120mm, divided into an 80mm main label on top and a 40mm customer receipt section below, with a tear line in between.
For the technical approach, I decided on web printing. Compared to sending EZPL commands directly to the printer, web printing offers:
- HTML/CSS layout for faster development
- No additional printing software required
- Browser preview of print results
- Better cross-platform compatibility
Sounds great, right? Reality, as always, had other plans.
The Driver Rabbit Hole
The first problem appeared when setting up the printer. I connected the GoDex G530+ to my M4 MacBook Pro, and macOS detected it, but when selecting a driver, there was no GoDex option.
I downloaded and installed the macOS driver from GoDex's website, but still no GoDex driver appeared when adding the printer. Out of options, I chose what seemed most relevant — Zebra ZPL Label Printer.
The printer could print, but problems kept coming:
- Content wouldn't fill the label, always with large margins
- Paper size options didn't match actual labels
- Print orientation seemed wrong, requiring 180-degree rotation
I spent hours tweaking CSS, trying various @page settings, transform: rotate(180deg), different paper sizes. Sometimes content was completely blank, sometimes it overflowed, sometimes it crossed label boundaries.
Finding the Root Cause
Through repeated debugging, I started suspecting the issue wasn't CSS but the driver itself. ZPL is Zebra's printer language, while GoDex uses EZPL. Despite some compatibility, paper size definitions, print orientation, and margin calculations could all differ.
Checking system status via terminal:
lpstat -p -d
# lpstat: No destinations added.
system_profiler SPPrintersDataType
# Status: The printers list is empty.Strangely, the printer could print, but the system said there were no printers. This made me realize the printer might not be properly registered with CUPS.
The Real Problem
Checking where GoDex drivers were installed:
ls /Library/Printers/GoDEX/PPDs/
# godex-g530.ppd godex-g530+.ppd ...(bunch of PPD files)
ls /Library/Printers/PPDs/Contents/Resources/ | grep -i godex
# (empty)Found it! GoDex PPD files were installed to /Library/Printers/GoDEX/PPDs/, but macOS only reads PPD files from /Library/Printers/PPDs/Contents/Resources/.
PPD (PostScript Printer Description) files define paper sizes, resolution, feature options, and other printer parameters. Using the wrong PPD is like giving the printer someone else's manual — naturally, it won't work correctly.
The Solution
Create symbolic links so macOS can find the correct PPDs:
sudo ln -s /Library/Printers/GoDEX/PPDs/godex-g530.ppd \
/Library/Printers/PPDs/Contents/Resources/godex-g530.ppd
sudo ln -s /Library/Printers/GoDEX/PPDs/godex-g530+.ppd \
/Library/Printers/PPDs/Contents/Resources/godex-g530+.ppdRe-adding the printer, this time searching for "godex" in "Select Software" finally showed GODEX G530+, 1.1.14!
With the correct driver, previous issues vanished:
- ✅ Correct paper size
- ✅ No manual rotation needed
- ✅ Reasonable margins
CSS Print Controls
With the driver sorted, next came layout. Shipping labels need precise size control so the 80mm main label and 40mm receipt align exactly with the tear line.
@page vs body
CSS printing has two important concepts to distinguish:
@page {
margin: 2mm; /* Controls paper edge margins */
}
body {
margin: 0; /* Controls content distance from print area */
}Simply put, @page controls the "paper," body controls the "content." For label printing, @page margin determines the printer's actual printable area.
Fixed Height Division
For precise 80mm/40mm division, I used fixed-height divs:
.label-page {
width: 100%;
height: 116mm; /* 120mm - 4mm margins */
page-break-after: always;
page-break-inside: avoid;
}
.main-label {
height: 78mm; /* 80mm - 2mm margin */
overflow: hidden;
}
.receipt-label {
height: 38mm; /* 40mm - 2mm margin */
overflow: hidden;
}page-break-after: always ensures each label gets its own page, page-break-inside: avoid prevents content from splitting across pages.
Barcodes and QR Codes
Labels need barcodes (for scanner guns) and QR codes (for driver app scanning). I used milon/barcode, a Laravel package for generation.
Barcodes: PNG vs SVG
Initially using PNG format:
DNS1D::getBarcodePNG($delivery->number, 'C128', 1.5, 33)The printed barcode couldn't be scanned. The bars were too thin, and PNG gets blurry when scaled.
Switching to SVG solved it:
DNS1D::getBarcodeSVG($delivery->number, 'C128', 1.5, 28, 'black', false)SVG is vector-based, doesn't lose quality when scaled, has sharp bar edges, and scanners can read it correctly.
QR Code: Stick with PNG
Interestingly, QR codes had problems with SVG. SVG QR code size is dynamically generated based on content length, making it hard to control precisely with CSS — it easily overflows containers or gets clipped.
Final choices:
| Type | Format | Reason |
|---|---|---|
| Barcode (1D) | SVG | Fixed bar width, SVG is sharper |
| QR Code (2D) | PNG | Easier to control size with CSS |
// Barcode
{!! DNS1D::getBarcodeSVG($number, 'C128', 1.5, 28, 'black', false) !!}
// QR Code
<img src="data:image/png;base64,{{ DNS2D::getBarcodePNG($url, 'QRCODE', 4, 4) }}"
style="width: 12mm; height: 12mm;">Results and Takeaways
After much troubleshooting, the label printing system is finally in production. Compared to Loftware's annual fees, a GoDex G530+ costs about two or three months of licensing. More importantly, we now fully control label design and printing logic — future format changes or new fields are easy to implement.