If you’ve ever used a Thermal printer on a website like Fedex.com, you know it can be kind of ugly to get your label to print. As of this writing, FedEx.com still relies on a Java plugin to do the dirty work of sending the data to your locally-connected printer. I have a couple of applications that integrate with FedEx web services and in the past, I too have relied on Java applets (jZebra, which became qzPrint) to do the work of sending a print job via a web browser.

After searching around, I found a better way to do it: use a simple POST request to send to a network printer. This article is what really got me started: Label And Receipt Printing – Printing from Websites part 2

The sample code shows how you can create a simple XmlHttpRequest object and send it the EPL/ZPL you want. Here is a barebones sample:

var zpl = "^XA^PW400^LL200^FO20,20^A0N,30,30^FDTest^FS^XZ"; //some zpl to send to the printer
var zebraPrinterUrl = ""; //ip address of the printer
var request = new XMLHttpRequest();
request.onload = function () {
  //take some action
request.onerror = function () {
  //take some action
request.open("POST", zebraPrinterUrl, true); 
request.setRequestHeader("Content-Length", zpl.length);

That’s really all there is to it.

A couple of caveats – as the article I linked above notes, CORS can be a bit of a problem. The zebra printer does not return the necessary Access-Control-Allow-Origin header, so I found this to be disruptive when I tried to use the AngularJS (1.0) $http service. Sending the post using $http would result in a response coming back with status 0, which indicates a CORS problem.

Therefore, I ended up using the XMLHttpRequest object in my application, which can significantly impact testability, unless you wrap the instantiation of XMLHttpRequest objects in another component that you inject into your controller or service.

Finally, because I’m using promises and asynchronous requests, I had to make sure that all of the labels being printed complete before resolving or rejecting the promise.

This solution obviously isn’t very scalable, but I do think it provides much greater flexibility than the old way of using java or some browser plugin to do the job.