CPOS Web Printing

Print receipts and open the cash drawer from a web app on a CPOS device. CPOS Helper behaves as an Epson TM receipt printer at http://127.0.0.1:9100.

CPOS Helper 2.5.16+ ePOS-Print XML Raw ESC/POS
This page is a live test
Open it in Chrome on a CPOS device. Each Run button sends the snippet it belongs to, exactly as shown, to the printer.

Overview

Write your app against Epson's ePOS-Print XML specification, exactly as you would for a real Epson printer. This guide does not repeat that specification. It covers how to connect, and the places where the Helper deliberately differs from an Epson printer.

Every job goes through one print queue. The physical printer (built-in head, USB, Bluetooth or network) and the drawer mode are configured in the CPOS Helper app, so your app does not need to know which one it is talking to.

ePOS-Print XML is the supported route for web apps. A raw ESC/POS route exists for apps that already build ESC/POS themselves.

Requirements

CORS needs nothing from you: the Helper answers the OPTIONS preflight and echoes your Origin.

Quick start

Check the printer

GET /status is a CPOS addition, not part of ePOS-Print. See the fields.

JavaScript

Send a receipt

POST an ePOS-Print document with fetch(). A receipt can be sent as text or as one image you draw yourself.

Small requests that print fast and sharp. Use it unless you need something only an image can do. The sample is a full cafe receipt: a large heading, small and reversed text, Thai item names with prices aligned right, notes, rules, a CODE128 barcode, a QR code, the cut and the drawer.

Pad columns the way a Thai-mode printer counts them: a mark above or below a Thai letter shares that letter's column, which is what columns() in the sample does. The Helper draws Thai in the same grid, so the prices line up. <layout> centres a 58 mm receipt on 80 mm paper, so pick 58 mm below to try one on an 80 mm printer.

Whitespace inside <text> is printed, so do not indent the XML there. Use &#10; for a new line. Text attributes stay in effect until a later <text> changes them, which is why the sample switches each one back off.

The expected print is rendered from the Helper's own output. English text uses the printer's font, so its shape varies by printer.

The reply has the same shape as a real Epson printer's:

Response
<response xmlns="http://www.epson-pos.com/schemas/2011/03/epos-print"
          success="true" code="" status="6" battery="0"/>

Read the reply

success="true" means queued, not printed
The queue is stored on disk and retried until the printer accepts the job, so a busy or out-of-paper printer never blocks a sale. Read status for the printer's health.
Continues the snippet above
if (!queued) showError("Rejected: " + reply);
else if (status & 0x00000001) showWarning("Printer is not responding");
else if (status & 0x00080000) showWarning("Out of paper");
else if (status & 0x00000020) showWarning("Printer cover is open");

All bits are listed under Status bits.

Differences from an Epson printer

These change how you write your app:

All other differences

TopicEpson printerCPOS Helper
<layout> Label and black mark settings No printer command. Its width (0.1 mm units: 720 for 80 mm paper, 480 for 58 mm) sets the frame the Helper lays the document out in. Without it, the printer aligns against the paper it has.
Not supported - <vline-begin>/<vline-end>, and MaxiCode, Aztec and 2D GS1 DataBar in <symbol>. They are skipped and the rest of the receipt still prints.
<sound> Named buzzer patterns A plain beep (BEL), repeated.
Cuts on the M1/M10 built-in head As requested That head cuts wherever the paper stands, so the Helper always feeds it to the cutter first, no_feed included. Other printers get exactly the cut you asked for.
<page> on the built-in head Page mode Printed in standard mode instead.
devid, timeout Select the device and the job timeout Accepted and ignored. Any POST path other than /raw is treated as ePOS.
battery Battery level on mobile printers Always 0.
Request size Printer dependent Up to 12 MB. Larger requests get HTTP 413.

Reference

GET /status

Response
{"service":"cpos-helper","port":9100,"running":true,"output":"usb","printer":"USB:1155-30016",
 "drawerMode":"both","printableDots":576,"queuedJobs":0,"connected":true,
 "health":"Ready","status":4}
FieldMeaning
runningThe print service is up.
connectedThe Helper can reach the physical printer.
healthReadable state, such as Ready, Paper out, Cover open.
printableDotsPrintable width the Helper assumes when a document does not state one (384 = 58 mm, 576 = 80 mm).
queuedJobsJobs waiting in the queue.
statusThe ASB word, see Status bits.

Opening http://127.0.0.1:9100/ in a browser on the device shows the same information as a page.

Status bits

status is the Epson ASB word. These are the bits the Helper sets:

BitMeaning
0x00000001No response: the printer is not answering, or the Helper has no reading yet. Ignore the other bits.
0x00000002The job was accepted (print replies only).
0x00000004Drawer kick connector. Always set when the printer answers; carries no information.
0x00000008Offline. Set together with cover open, paper end or an error.
0x00000020Cover open.
0x00002000Unrecoverable error.
0x00020000Paper near end.
0x00080000Paper end.

A healthy printer gives 6 in a print reply and 4 from GET /status. The Helper does not report the cutter error bit.

Raw ESC/POS

POST /raw takes an ESC/POS byte stream. Use it only if your app already produces ESC/POS; otherwise use ePOS-Print. The bytes reach the printer unchanged, with two exceptions: the drawer kick (ESC p) follows the drawer mode set in the Helper, and status queries (DLE EOT, GS r) are answered by the Helper.

JavaScript
JavaScript
fetch(PRINTER_URL + "/raw?encoding=base64", { method: "POST", headers: { "Content-Type": "text/plain" }, body: btoa(binaryString) });
fetch(PRINTER_URL + "/raw?encoding=hex",    { method: "POST", headers: { "Content-Type": "text/plain" }, body: "1b40 48 49 0a 1d564200" });

The reply is JSON with the same status word. success: true again means queued.

Troubleshooting

fetch fails with TypeError: Failed to fetch and no detail
Cause
The Helper is not running, the URL is https://, the page is open on another machine, or the site was blocked from accessing apps and services on this device.
Fix
The browser console shows which check blocked it. Go through the Requirements.
success="true" but nothing prints
Cause
The job is waiting in the queue for the printer.
Fix
Read status in the reply and queuedJobs in GET /status, then clear the fault the printer reports.
The end of the receipt is cut through or appears on the next one
Fix
ePOS: use <cut type="feed"/> and CPOS Helper 2.5.16 or later. Raw: end with GS V 66 0.
Thai is garbled (raw route)
Cause
Printers have no Thai code page you can rely on.
Fix
Send it as an image, or use ePOS-Print.
The drawer does not open, or opens twice
Fix
Check the drawer mode in the CPOS Helper app (both, usb or telpo).

References