Thermalink

ESC/POS, ZPL and TSPL cheat sheet

The printer commands you actually need for receipts and labels, with their bytes. Type in the box to filter.

used means my own agent, Thermalink, sends exactly these bytes and its tests check them. Its receipts print correctly on a BIXOLON SRP-352plusIII, but I have not checked every row on paper one by one. reference means standard Epson ESC/POS that my agent does not send. Cheaper printers skip some commands, so test on yours.

Paper widths

PaperResolutionPrintable dotsColumns, font AColumns, font B
80 mm203 dpi (8 dots/mm)576 (72 mm)4864
80 mm180 dpi5124256
58 mm203 dpi384 (48 mm)3242

These are nominal. My "576 dot" printer measured 568 usable dots, so print a ruler before trusting the spec sheet.

ESC/POS (receipt printers)

ESC is byte 1B, GS is 1D, DLE is 10. n is one byte you choose. Bytes are in hex.

Basics

CommandBytes (hex)What it does
ESC @1B 40Initialise the printer. Clears formatting set by earlier jobs. Send it first.used
LF0APrint the line buffer and feed one line.used
ESC d n1B 64 nPrint and feed n lines.used
ESC 21B 32Default line spacing.reference
ESC 3 n1B 33 nLine spacing of n dots.reference

Text style

CommandBytes (hex)What it does
ESC a n1B 61 nAlign: 0 left, 1 centre, 2 right.used
ESC E n1B 45 nBold: 1 on, 0 off.used
ESC - n1B 2D nUnderline: 0 off, 1 thin, 2 thick.used
GS B n1D 42 nWhite on black: 1 on, 0 off.used
GS ! n1D 21 nCharacter size. High 4 bits = width multiplier minus 1, low 4 bits = height multiplier minus 1. 00 normal, 11 double both, 10 double width, 01 double height.used
ESC M n1B 4D nFont: 0 = A (12x24), 1 = B (9x17, more columns).reference
ESC ! n1B 21 nOlder combined mode byte: bit 0 font B, bit 3 bold, bit 4 double height, bit 5 double width, bit 7 underline.reference

Characters

CommandBytes (hex)What it does
ESC t n1B 74 nSelect the code page. Epson numbering: 0 CP437, 2 CP850, 16 Windows-1252, 17 CP866, 19 CP858 (has the euro sign). Other brands number them differently, so check the self-test page.used
ESC R n1B 52 nInternational character set (changes a few ASCII symbols). 0 = USA.reference

Cut and cash drawer

CommandBytes (hex)What it does
GS V 01D 56 00Full cut at the current position. Feed a few lines first or you cut through the last line.used
GS V 11D 56 01Partial cut.used
GS V 65 n1D 56 41 nFeed to the cutter plus n extra steps, then full cut. Use n = 0 if unsure.reference
GS V 66 n1D 56 42 nFeed to the cutter plus n extra steps, then partial cut.reference
ESC p 0 t1 t21B 70 00 19 FAKick the cash drawer on pin 2. t1 and t2 are the pulse on and off times in 2 ms units.used
ESC p 1 t1 t21B 70 01 19 FAKick the cash drawer on pin 5.used

QR code (GS ( k)

CommandBytes (hex)What it does
Model1D 28 6B 04 00 31 41 32 00Select QR model 2.used
Module size1D 28 6B 03 00 31 43 nDot size of one module, n = 1 to 16.used
Error correction1D 28 6B 03 00 31 45 nn = 48 L, 49 M, 50 Q, 51 H.used
Store data1D 28 6B pL pH 31 50 30 d1...dkpL + pH x 256 = k + 3, where k is the number of data bytes.used
Print1D 28 6B 03 00 31 51 30Print the stored symbol.used

Barcodes (GS k)

CommandBytes (hex)What it does
GS h n1D 68 nBarcode height in dots.used
GS w n1D 77 nModule width, n = 2 to 6.used
GS H n1D 48 nHuman-readable text: 0 none, 1 above, 2 below, 3 both.used
CODE1281D 6B 49 n d1...dnStart the data with 7B 42 ("{B") to select code set B.used
EAN-131D 6B 43 n d1...dnn = 12 or 13 digits.used
EAN-81D 6B 44 n d1...dnn = 7 or 8 digits.used
UPC-A1D 6B 41 n d1...dnn = 11 or 12 digits.used
CODE391D 6B 45 n d1...dnDigits, capitals and a few symbols.used

Images

CommandBytes (hex)What it does
GS v 01D 76 30 00 xL xH yL yH d1...dkRaster image. xL + xH x 256 = width in bytes (dots / 8). yL + yH x 256 = height in dots. One bit per dot, 1 = black, most significant bit on the left. Send tall images in bands.used

Status

CommandBytes (hex)What it does
DLE EOT n10 04 nReal-time status: 1 printer, 2 offline cause, 3 error cause, 4 paper sensor. The printer answers with one byte, so you need a two-way connection.reference
GS r 11D 72 01Paper sensor status.reference

A whole receipt in bytes

const ESC = 0x1b, GS = 0x1d;
const text = s => [...new TextEncoder().encode(s)];   // ASCII only; see the code page row above

const bytes = new Uint8Array([
  ESC, 0x40,                      // initialise
  ESC, 0x61, 1,                   // centre
  GS, 0x21, 0x11,                 // double width and height
  ...text('BLUE DOOR CAFE\n'),
  GS, 0x21, 0x00,                 // normal size
  ESC, 0x61, 0,                   // left
  ...text('Flat white x2        8.00\n'),
  ESC, 0x45, 1,                   // bold on
  ...text('TOTAL                8.00\n'),
  ESC, 0x45, 0,                   // bold off
  ESC, 0x64, 3,                   // feed 3 lines so the cut clears the text
  GS, 0x56, 0x00                  // full cut
]);

Getting those bytes from a web page to the printer is the hard part. Thermalink does that, and builds the bytes from JSON so you do not write this by hand.

ZPL (Zebra label printers)

Plain text commands. Positions are in dots: 203 dpi is 8 dots per mm. I have not printed these on a Zebra; they follow Zebra's programming guide.

CommandWhat it does
^XA ... ^XZStart and end of a label. Everything goes between them.
^PW nLabel width in dots.
^LL nLabel length in dots.
^LH x,yLabel home: moves the origin for every field.
^FO x,yField origin: where the next field goes, in dots from the top left.
^FD text ^FSField data, then field separator. Every field ends with ^FS.
^CF0,hDefault font 0 at height h dots.
^A0N,h,wFont 0, normal rotation, height h and width w, for the next field.
^FB w,lines,,alignField block: wrap text to width w. Align is L, C, R or J.
^BY w,r,hBarcode defaults: module width, wide to narrow ratio, height.
^BCN,h,Y,N,NCode 128 barcode, height h, with the text printed below.
^BQN,2,mQR code, model 2, magnification m. The data starts with a prefix: ^FDQA,your-data^FS.
^GB w,h,tBox or line: width, height, line thickness.
^FRReverse the next field (white on black where it overlaps).
^CI28Read field data as UTF-8.
^PQ nPrint n copies.
^XA
^CF0,40
^FO40,40^FDShip to: Jane Doe^FS
^CF0,30
^FO40,90^FD221B Baker Street, London^FS
^FO40,150^BY3^BCN,120,Y,N,N^FD1Z999AA10123456784^FS
^FO40,320^BQN,2,6^FDQA,https://example.com/track/1Z999AA10123456784^FS
^XZ

TSPL (TSC, 4BARCODE, Xprinter label printers)

One command per line, each line ending with CR LF. I have not printed these on a label printer; they follow the TSPL manual.

CommandWhat it does
SIZE 50 mm, 30 mmLabel width and height.
GAP 2 mm, 0 mmGap between labels and its offset.
DIRECTION 1Print direction, 0 or 1.
CLSClear the image buffer. Send it before drawing each label.
TEXT x,y,"font",rot,xmul,ymul,"content"Text at x,y in dots. Fonts "1" to "8" are built in; rot is 0, 90, 180 or 270.
BARCODE x,y,"128",h,human,rot,narrow,wide,"content"Barcode. human = 1 prints the text below.
QRCODE x,y,ECC,cell,mode,rot,"content"QR code. ECC is L, M, Q or H; cell is the module size 1 to 10; mode A is automatic.
BAR x,y,w,hFilled bar or line.
BOX x,y,xend,yend,thicknessRectangle outline.
DENSITY nDarkness, 0 to 15.
SPEED nPrint speed in inches per second.
PRINT sets,copiesPrint the label. Always the last line.
SIZE 50 mm, 30 mm
GAP 2 mm, 0 mm
DIRECTION 1
CLS
TEXT 20,20,"3",0,1,1,"Organic Honey 500g"
TEXT 20,60,"2",0,1,1,"Price: 9.99"
BARCODE 20,100,"128",70,1,0,2,2,"SKU-000123"
PRINT 1,1

Last checked 11 October 2026. Found a mistake? Tell me through the Gumroad page.