DEVELOPERS / GO / ZPL
Print ZPL Labels From Go
Two ways to print labels from Go: raw ZPL over net.Dial to port 9100, or the LabelInn Go SDK — print to any printer from any server, with queueing, status and templates.
conn, err := net.DialTimeout("tcp", "192.168.1.50:9100", 5*time.Second)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("^XA^FO50,50^A0N,40,40^FDHello from LabelInn^FS^XZ"))THE PROBLEM
You need Go code to put a label on a thermal printer: a shipping label when an order is paid, a product label when a batch is finished. There are two ways to do it. This page shows both, with code you can paste.
01 / GO
The quick way: raw ZPL to port 9100
Zebra printers, and most printers that emulate ZPL, accept raw ZPL on TCP port 9100. If your code runs on the same network as the printer, this is all it takes:
conn, err := net.DialTimeout("tcp", "192.168.1.50:9100", 5*time.Second)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("^XA^FO50,50^A0N,40,40^FDHello from LabelInn^FS^XZ"))02 / ZPL
Why not just open a socket?
Writing ZPL to port 9100 works on the bench. In production it leaves you with problems the printer will not solve for you:
- Your server has to reach the printer. A cloud-hosted Go app cannot open a socket to a printer on a warehouse LAN without a VPN or port forwarding.
- Nothing tells you it printed. Port 9100 accepts the bytes whether or not the ribbon is out or the head is open.
- Nothing queues. If the printer is off, the job is gone.
- One language per printer. ZPL works on Zebra; TSC wants TSPL, Toshiba wants TPCL.
LabelInn puts a small runtime next to the printer that connects out to the cloud. Your code calls one HTTPS API from anywhere; the job is queued, delivered in the printer's own language, and its status comes back.
📦 go get github.com/labelinn/labelinn-go/v3, one API key, and your Go code prints to any registered printer, anywhere. Get a key →
03 / ZEBRA
Install the SDK
go get github.com/labelinn/labelinn-go/v304 / API
Find the printer
Register the printer once in the LabelInn app on the computer it is connected to. Then list your printers to get the id:
import labelinn "github.com/labelinn/labelinn-go/v3"
client := labelinn.New("sk_live_...")
printers, err := client.Fleet.List(nil)
if err != nil {
log.Fatal(err)
}
for _, p := range printers {
fmt.Println(p.ID, p.Name, p.Status)
}05 / GO
Print ZPL
job, err := client.Print.Create(&labelinn.CreateJobRequest{
PrinterID: "prt_abc123",
PayloadType: "zpl",
PayloadData: "^XA^FO50,50^A0N,40,40^FDHello from LabelInn^FS^XZ",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(job.ID, job.Status)06 / ZPL
Print a designed label with data
Raw ZPL means your code owns the layout. With a template, the label is designed visually in LabelInn and your code sends only the data. Fields fill by name, and LabelInn converts the design to ZPL, TSPL or TPCL for whichever printer you choose.
job, err := client.Print.Create(&labelinn.CreateJobRequest{
PrinterID: "prt_abc123",
PayloadType: "template",
DesignID: "dsg_shipping",
Data: map[string]string{"order_id": "ORD-9876", "customer": "Jane Doe", "barcode": "TR123456789"},
Copies: 2,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(job.ID)07 / ZEBRA
Print many labels in one call
Batch up to 100 jobs per request. Each job is accepted or rejected on its own, so one bad row does not sink the rest.
var jobs []labelinn.CreateJobRequest
for _, sku := range []string{"A-1001", "A-1002", "A-1003"} {
jobs = append(jobs, labelinn.CreateJobRequest{
PrinterID: "prt_abc123", PayloadType: "template",
DesignID: "dsg_product", Data: map[string]string{"sku": sku},
})
}
result, err := client.Print.Batch(jobs)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d of %d accepted\n", result.Succeeded, result.Total)08 / API
Never print the same label twice
Retries happen: a timeout, a redeploy, a queue redelivery. Send an idempotency key and a repeated call returns the original job instead of printing again.
job, err := client.Print.Create(&labelinn.CreateJobRequest{
PrinterID: "prt_abc123",
PayloadType: "template",
DesignID: "dsg_shipping",
Data: map[string]string{"order_id": "ORD-9876"},
}, labelinn.WithIdempotencyKey("order-ORD-9876-label"))
if err != nil {
log.Fatal(err)
}
fmt.Println(job.ID)Printing through the API is part of the Pro plan, and the free trial includes it. Keys that start with sk_test_ run against a sandbox that never prints, so you can build and test before going live. See pricing.
09 / GO
Same thing, other languages
QUESTIONS / FAQ
Frequently asked questions
How do I print a ZPL label from Go?
On the same network, write the ZPL to the printer's TCP port 9100. From anywhere else, install the LabelInn SDK, register the printer once, and call print.create with payload_type "zpl" and the printer id.
Can my cloud-hosted Go app print to a printer in a warehouse?
Yes. The LabelInn runtime next to the printer connects out to LabelInn, so your server calls an HTTPS API and never needs network access to the printer itself.
Does it only work with Zebra printers?
No. Raw ZPL needs a ZPL printer, but templates are converted to the printer's own language, including TSPL for TSC and TPCL for Toshiba.
How do I avoid printing duplicates when a request is retried?
Send an idempotency key with the job. Repeating the call with the same key returns the original job instead of printing again.
KEEP GOING
Related
NEXT STEP / LABELINN
Print from Go without touching a printer driver
Get an API key, register a printer, and send your first label in minutes. · Official SDK · ZPL or visual templates · Queue, status and retries handled