Reliable ESC/POS Bluetooth printing for React Native on iOS and Android. The library owns discovery, connection lifecycle, image rasterization, command generation, write serialization, and Bluetooth backpressure without a closed vendor SDK.
- Pure React Native TurboModule with autolinking
- Android Bluetooth Classic (RFCOMM/SPP) support
- iOS Bluetooth Low Energy support through writable GATT characteristics
- Paired-printer discovery on Android and timed BLE scanning on iOS
- Text printing with CP850 and Windows-1252 code pages
- Base64 image printing at the native 58 mm (384 px) or 80 mm (576 px) width
- Proportional image resizing without stretching
- Serialized native operations, connection timeouts, chunked writes, and BLE backpressure
- No Expo dependency and no proprietary printer SDK
| Platform | Requirement | Transport |
|---|---|---|
| React Native | 0.76 or newer | New Architecture/TurboModule |
| Android | API 24 or newer | Bonded Bluetooth Classic device with SPP/RFCOMM |
| iOS | The minimum supported by the host React Native version | BLE peripheral with a writable GATT characteristic |
The printer must understand ESC/POS. iOS does not expose arbitrary Bluetooth Classic SPP devices, so the printer must offer BLE unless it is part of Apple's MFi program with a dedicated integration.
npm install rn-escpos-printeror:
yarn add rn-escpos-printerInstall CocoaPods after adding the package:
cd ios && pod installThis package contains native code. It works with bare React Native apps and Expo development builds/prebuilds, but it cannot run inside Expo Go.
The library manifest declares the Bluetooth permissions. On Android 12 (API 31) and newer, request BLUETOOTH_CONNECT before calling the library:
import { PermissionsAndroid, Platform } from 'react-native';
if (Platform.OS === 'android' && Platform.Version >= 31) {
await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT
);
}Pair the printer in Android system settings before discovery. getPrinters() intentionally returns bonded devices only; v1 does not request location or perform broad Android device discovery.
Add a Bluetooth usage description to Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Bluetooth is used to connect to your receipt printer.</string>iOS returns a stable peripheral UUID as the printer id. Persist that value if the app should reconnect without scanning after a restart.
import { EscPosPrinter, type PrinterDevice } from 'rn-escpos-printer';
await EscPosPrinter.initialize();
const printers: PrinterDevice[] = await EscPosPrinter.getPrinters({
scanDurationMs: 4_000,
});
const printer = printers[0];
if (!printer) {
throw new Error('No ESC/POS printer found');
}
await EscPosPrinter.connect(printer, { timeoutMs: 12_000 });
await EscPosPrinter.printText('Pedido 123\nTotal: R$ 42,90', {
codePage: 'cp850',
feedLines: 5,
cut: true,
});
await EscPosPrinter.printImageBase64(receiptPngBase64, {
paperWidth: 80,
threshold: 160,
feedLines: 5,
cut: true,
});
await EscPosPrinter.disconnect();printImageBase64 accepts either a raw base64 payload or a data:image/...;base64,... URI.
Validates Bluetooth availability and permission. Call it before discovery or connection so configuration failures are reported early.
On Android, returns bonded Bluetooth devices immediately. On iOS, scans for named BLE peripherals for scanDurationMs (default: 4000 ms).
type PrinterDevice = {
id: string;
name: string;
address: string;
transport: 'bluetooth-classic' | 'ble';
connected: boolean;
};Accepts a PrinterDevice or its id. The default timeout is 12 seconds. The promise resolves only after Android opens the SPP socket or iOS discovers a writable characteristic.
Closes the active connection and clears native transport state.
Returns whether a usable native printer transport is active.
| Option | Type | Default |
|---|---|---|
codePage |
'cp850' | 'cp860' | 'windows1252' |
'cp850' |
feedLines |
integer from 0 to 10 | 5 |
cut |
boolean |
true |
The printer's configured character table must match the selected code page. CP850 remains the backward-compatible default. For Portuguese receipts, use CP860 when the printer supports the standard ESC/POS page 3 mapping:
await EscPosPrinter.printText('Não autorizado: ação e preço', {
codePage: 'cp860',
});Character-table support and page numbers can vary on non-Epson-compatible firmware, so validate the selected code page on every printer model used in production.
| Option | Type | Default |
|---|---|---|
paperWidth |
58 | 80 |
80 |
threshold |
integer from 0 to 255 | 160 |
feedLines |
integer from 0 to 10 | 5 |
cut |
boolean |
true |
Images are decoded and rasterized natively. They are resized to 384 or 576 pixels with the original aspect ratio, converted to monochrome, and sent with the widely supported ESC * 24-dot bit-image command.
Rejected native promises expose one of these stable error codes through error.code:
ERR_BLUETOOTH_DISABLEDERR_BLUETOOTH_PERMISSIONERR_CONNECTION_FAILEDERR_CONNECTION_LOSTERR_CONNECTION_TIMEOUTERR_INVALID_ARGUMENTERR_INVALID_IMAGEERR_NOT_CONNECTEDERR_PRINTER_NOT_FOUNDERR_SCAN_FAILEDERR_WRITE_FAILED
try {
await EscPosPrinter.connect(printer);
} catch (error) {
const code =
error instanceof Error && 'code' in error ? error.code : undefined;
console.error(code, error);
}Version 1 is intentionally limited to the production needs that motivated the package:
- Bluetooth transport only
- ESC/POS printers only
- Text and base64 images only
- 58 mm and 80 mm paper
USB, TCP/IP, QR codes, barcodes, cash drawers, printer status queries, and vendor-specific protocols are not part of v1.
ESC/POS describes the print command language, while each printer also chooses a Bluetooth profile, GATT service, characteristic, buffer size, cutter, and character-table mapping. The library uses standard SPP on Android and dynamically discovers writable GATT characteristics on iOS, with conservative chunking and flow control.
For a production rollout, validate every printer model and firmware revision used by the business. When reporting a compatibility issue, include the platform, OS version, printer model, firmware, advertised BLE services/characteristics (iOS), and a minimal print payload.
See CONTRIBUTING.md for the local workflow and docs/architecture.md for implementation details.
yarn
yarn verifyMIT © HighSoft Sistemas