For developers
Website integration
Print text, HTML or ESC/POS from a web page with one tap.
A page in Chrome on Android can print without a dialog by opening a rollcast://print link from a user gesture (a click). RollCast decodes the payload and prints on the chosen or default printer.
| type | What data contains |
|---|---|
| text | UTF-8 text. Printed with the printer's Text charset. |
| html | A complete UTF-8 HTML document. Laid out at the roll width and printed as an image. |
| raw | ESC/POS bytes, sent unchanged. This is the default when type is missing. |
Note
The user must turn on "Allow web prints" in RollCast. It is off by default, and links are rejected while it is off.
Print text
JavaScript
// UTF-8 -> base64, in chunks so long strings don't overflow the call stack.
function toBase64Utf8(str) {
const bytes = new TextEncoder().encode(str);
let binary = '';
for (let i = 0; i < bytes.length; i += 0x8000) {
binary += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
}
return btoa(binary);
}
// Chrome intent link: goes to the Play Store if RollCast is not installed.
function rollcastLink(type, base64, printerId) {
let url = 'intent://print?type=' + type + '&data=' + encodeURIComponent(base64);
if (printerId) url += '&printer=' + encodeURIComponent(printerId);
return url + '#Intent;scheme=rollcast;package=com.rollcast.app;end';
}
// Call from a click handler.
function printText(text, printerId) {
location.href = rollcastLink('text', toBase64Utf8(text), printerId);
}
// <button onclick="printText('Order #42\nTea x2 40.00\n\n')">Print</button>One-tap HTML print
This helper copies one element and the page's CSS into a standalone document, encodes it and hands it to RollCast. Outside Android it falls back to window.print().
JavaScript
/**
* paperMm: 48 for 58 mm rolls, 72 for 80 mm rolls.
* fallbackUrl: page to open when RollCast is not installed (optional).
*/
function rollcastPrint(element, { paperMm = 48, printerId = '', fallbackUrl = '' } = {}) {
if (!/Android/i.test(navigator.userAgent)) {
window.print();
return;
}
// 1. Collect readable CSS (inline <style> and same-origin sheets).
let css = '';
for (const sheet of document.styleSheets) {
try {
for (const rule of sheet.cssRules) css += rule.cssText + '\n';
} catch (e) {
// Cross-origin sheet: rules are not readable. Skip it.
}
}
// 2. Clone the element and make image URLs absolute.
const clone = element.cloneNode(true);
const originals = element.querySelectorAll('img');
clone.querySelectorAll('img').forEach((img, i) => {
img.setAttribute('src', originals[i].currentSrc || originals[i].src);
img.removeAttribute('srcset');
img.removeAttribute('loading'); // lazy images may never load offscreen
});
// 3. Build a complete document sized for the roll.
const html = `<!doctype html>
<html><head><meta charset="utf-8">
<style>
${css}
@page { size: ${paperMm}mm auto; margin: 0 }
html, body { margin: 0; padding: 0; background: #fff; color: #000; }
</style></head>
<body>${clone.outerHTML}</body></html>`;
// 4. UTF-8 -> base64 in chunks.
const bytes = new TextEncoder().encode(html);
let binary = '';
for (let i = 0; i < bytes.length; i += 0x8000) {
binary += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
}
const b64 = btoa(binary);
// 5. Hand it to RollCast.
let url = 'intent://print?type=html&data=' + encodeURIComponent(b64);
if (printerId) url += '&printer=' + encodeURIComponent(printerId);
url += '#Intent;scheme=rollcast;package=com.rollcast.app;';
if (fallbackUrl) url += 'S.browser_fallback_url=' + encodeURIComponent(fallbackUrl) + ';';
url += 'end';
location.href = url;
}
// <button onclick="rollcastPrint(document.getElementById('receipt'))">Print receipt</button>Tip
The HTML is rendered with JavaScript off. Send finished markup. Canvas content and typed form values are not copied.
Print raw ESC/POS
JavaScript
// Uses rollcastLink() from the text example. Keep raw text ASCII:
// the printer reads it with its own code page, not UTF-8.
function printRawReceipt(printerId) {
const ascii = (s) => Array.from(s, (c) => c.charCodeAt(0) & 0xFF);
const bytes = [
0x1B, 0x40, // ESC @ reset
0x1B, 0x45, 0x01, // ESC E 1 bold on
...ascii('MY SHOP\n'),
0x1B, 0x45, 0x00, // ESC E 0 bold off
...ascii('Tea x2 40.00\n'),
...ascii('TOTAL 40.00\n'),
0x1B, 0x64, 0x03, // ESC d 3 feed 3 lines
0x1D, 0x56, 0x01, // GS V 1 cut
];
const b64 = btoa(String.fromCharCode(...bytes));
location.href = rollcastLink('raw', b64, printerId);
}Receipt print CSS
HTML
<style>
@page { size: 48mm auto; margin: 0 } /* 72mm for 80 mm rolls */
#receipt {
width: 100%;
color: #000; /* black only: grey is dithered and looks fuzzy */
font: 500 10pt/1.3 sans-serif; /* weight 500 or more, 9pt or larger */
}
#receipt .total { font-weight: 700; }
#receipt img { width: 60%; } /* size in %, mm or pt, not px */
#receipt hr { border: 0; border-top: 1px dashed #000; }
@media print { .no-print { display: none } }
</style>
<div id="receipt">
<!-- Absolute https:// URLs only; relative and http:// URLs are blocked. -->
<img src="https://shop.example.com/logo-bw.png" alt="">
<p>Order #42</p>
<hr>
<p class="total">TOTAL 40.00</p>
</div>Limits
| Limit | Value |
|---|---|
| Link size | 2 MB of query string. Keep payloads to a few hundred KB; Android may drop bigger links. |
| Rate | 1 link per second. Extra links are dropped ("Too many print requests"). |
| User switch | "Allow web prints" must be on. |
| Gesture | Open the link from a click. Chrome blocks app links a page opens by itself. |
| HTML resources | https:// and data: only. Loading stops after 15 seconds. No cookies are sent. |