CapacitorJS wrapper for ESC POS (native) printers.
npm install @fedejm/capacitor-esc-pos-printerCapacitorJS wrapper for ESC POS (native) printers.
- Bluetooth printing - Connect to Bluetooth ESC/POS printers (Android, iOS)
- USB printing - Connect to USB ESC/POS printers via USB Host API (Android only)
- Raw data sending - Send raw ESC/POS commands for full control
- Bi-directional communication - Read responses from printer
- Permission management - Built-in USB permission request flow
``bash`
npm install @fedejm/capacitor-esc-pos-printer
npx cap sync
| Feature | Android | iOS | Web |
|------------|---------|---------|---------|
| Bluetooth | Yes | Yes | Limited |
| USB | Yes | No | No |
| Network | Planned | Planned | Planned |
- Bluetooth: Requires BLUETOOTH_CONNECT and BLUETOOTH_SCAN permissions (Android 12+)android.hardware.usb.host
- USB: Requires feature (automatically declared as optional)
- Bluetooth printing is supported via CoreBluetooth framework
- USB printing is not available on iOS
`typescript
import { EscPosPrinter, BluetoothPrinter } from '@fedejm/capacitor-esc-pos-printer';
// Request Bluetooth enable (Android)
await EscPosPrinter.requestBluetoothEnable();
// Get paired Bluetooth printers
const { devices } = await EscPosPrinter.getBluetoothPrinterDevices();
console.log('Found printers:', devices);
// Create and connect to a printer
const printer = new BluetoothPrinter(devices[0].address);
await printer.link();
await printer.connect();
// Send ESC/POS commands
await printer.send([0x1B, 0x40]); // Initialize printer
await printer.send([0x48, 0x65, 0x6C, 0x6C, 0x6F]); // "Hello"
await printer.send([0x0A]); // Line feed
// Disconnect
await printer.disconnect();
await printer.dispose();
`
`typescript
import { EscPosPrinter, UsbPrinter } from '@fedejm/capacitor-esc-pos-printer';
// Get connected USB printers
const { devices } = await EscPosPrinter.getUsbPrinterDevices();
console.log('Found USB printers:', devices);
// Find a device and check permission status
const device = devices[0];
if (!device.hasPermission) {
// Request USB permission
const { value: granted } = await EscPosPrinter.requestUsbPermission({
address: device.id
});
if (!granted) {
console.log('USB permission denied for:', device.name);
return;
}
}
// Create and connect to a USB printer
const printer = new UsbPrinter(device.id);
await printer.link();
await printer.connect();
// Send ESC/POS commands (same as Bluetooth)
await printer.send([0x1B, 0x40]); // Initialize printer
await printer.send([0x48, 0x65, 0x6C, 0x6C, 0x6F]); // "Hello"
await printer.send([0x0A]); // Line feed
// Disconnect
await printer.disconnect();
await printer.dispose();
`
The printer connection follows this lifecycle:
``
┌─────────┐ link() ┌────────┐ connect() ┌───────────┐
│ Created ├───────────────►│ Linked ├─────────────────►│ Connected │
└─────────┘ └────────┘ └───────────┘
│
disconnect()
│
▼
┌─────────┐ dispose() ┌────────────┐
│Disposed │◄──────────────┤Disconnected│
└─────────┘ └────────────┘
1. Create - Instantiate BluetoothPrinter or UsbPrinter with device addresslink()
2. Link - Register with native plugin ()connect()
3. Connect - Open connection to physical device ()send()
4. Send/Read - Perform I/O operations (, read())disconnect()
5. Disconnect - Close connection ()dispose()
6. Dispose - Unregister from plugin ()
* requestBluetoothEnable()
* getBluetoothPrinterDevices()
* getUsbPrinterDevices()
* requestUsbPermission(...)
* createPrinter(...)
* disposePrinter(...)
* isPrinterConnected(...)
* connectPrinter(...)
* disconnectPrinter(...)
* sendToPrinter(...)
* readFromPrinter(...)
* Interfaces
* Enums
`typescript`
requestBluetoothEnable() => Promise
Returns: Promise<ValueResult<boolean>>
--------------------
`typescript`
getBluetoothPrinterDevices() => Promise
Returns: Promise<BluetoothDevicesResult>
--------------------
`typescript`
getUsbPrinterDevices() => Promise
Discovers USB devices that could be ESC/POS printers.
Returns devices with bulk OUT endpoints that may be suitable for printing.
Returns: Promise<UsbDevicesResult>
--------------------
`typescript`
requestUsbPermission(options: WithAddress) => Promise
Requests USB permission for a specific device.
Note: May require user interaction via system UI.
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithAddress |
Returns: Promise<ValueResult<boolean>>
--------------------
`typescript`
createPrinter(options: CreatePrinterOptions) => Promise
| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| options | CreatePrinterOptions |
Returns: Promise<ValueResult<string>>
--------------------
`typescript`
disposePrinter(options: WithHashKey) => Promise
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithHashKey |
Returns: Promise<ValueResult<boolean>>
--------------------
`typescript`
isPrinterConnected(options: WithHashKey) => Promise
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithHashKey |
Returns: Promise<ValueResult<boolean>>
--------------------
`typescript`
connectPrinter(options: WithHashKey) => Promise
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithHashKey |
--------------------
`typescript`
disconnectPrinter(options: WithHashKey) => Promise
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithHashKey |
--------------------
`typescript`
sendToPrinter(options: SendToPrinterOptions) => Promise
| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| options | SendToPrinterOptions |
--------------------
`typescript`
readFromPrinter(options: WithHashKey) => Promise
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | WithHashKey |
Returns: Promise<ValueResult<number[]>>
--------------------
#### ValueResult
| Prop | Type |
| ----------- | -------------- |
| value | T |
#### BluetoothDevicesResult
| Prop | Type |
| ------------- | ------------------------------------------------------------------------------------------------------------------- |
| devices | { address: string; alias?: string; name: string; bondState: number; type: number; uuids: string[]; }[] |
#### UsbDevicesResult
Result from USB device discovery.
Contains list of USB devices that could be ESC/POS printers.
| Prop | Type |
| ------------- | ---------------------------- |
| devices | UsbDeviceInfo[] |
#### UsbDeviceInfo
Information about a discovered USB device.
| Prop | Type | Description |
| ---------------------- | -------------------- | -------------------------------------------------------------------------- |
| id | string | Stable identifier for the device (format: "vendorId:productId:deviceName") |
| name | string | Human-readable name (product name or fallback) |
| vendorId | number | USB Vendor ID |
| productId | number | USB Product ID |
| deviceClass | number | USB Device Class |
| deviceSubclass | number | USB Device Subclass |
| deviceName | string | System device name/path |
| manufacturerName | string | Manufacturer name if available |
| hasPermission | boolean | Whether the app has USB permission for this device |
#### WithAddress
| Prop | Type |
| ------------- | ------------------- |
| address | string |
#### CreatePrinterOptions
| Prop | Type | Description |
| -------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connectionType | PrinterConnectionType | |
| address | string | Address/identifier for the printer: - Bluetooth: MAC address (e.g., "00:11:22:33:44:55") - USB: Device identifier (e.g., "1234:5678:002") - Network: IP address and optional port (e.g., "192.168.1.100:9100") |
#### WithHashKey
| Prop | Type |
| ------------- | ------------------- |
| hashKey | string |
#### SendToPrinterOptions
| Prop | Type |
| ----------------- | --------------------- |
| data | number[] |
| waitingTime | number |
#### PrinterConnectionType
| Members | Value |
| --------------- | ------------------------ |
| Bluetooth | 'bluetooth' |
| Usb | 'usb' |
| Network | 'network' |
All printer operations may throw a PrinterError with a specific error code:
`typescript
import { PrinterError, PrinterErrorCode } from '@fedejm/capacitor-esc-pos-printer';
try {
await printer.connect();
} catch (error) {
if (error instanceof PrinterError) {
switch (error.code) {
case PrinterErrorCode.Connect:
console.log('Connection failed');
break;
case PrinterErrorCode.NotConnected:
console.log('Printer not connected');
break;
case PrinterErrorCode.Send:
console.log('Failed to send data');
break;
case PrinterErrorCode.Read:
console.log('Failed to read data');
break;
case PrinterErrorCode.Permissions:
console.log('Permission denied');
break;
case PrinterErrorCode.DeviceNotFound:
console.log('Device not found');
break;
}
}
}
`
| Code | Name | Value | Description |
|------|----------------|-------|---------------------------------------------------------------|
| 1 | Connect | 1 | Failed to establish connection to the printer |
| 2 | NotConnected | 2 | Attempted operation on disconnected printer |
| 3 | Send | 3 | Failed to send data to the printer |
| 4 | Read | 4 | Failed to read data from the printer |
| 5 | Permissions | 5 | Required permission not granted (Bluetooth or USB) |
| 6 | DeviceNotFound | 6 | Device not found or no longer available |
USB devices require explicit permission from the user. The plugin provides a complete permission flow:
`typescript
const { devices } = await EscPosPrinter.getUsbPrinterDevices();
const device = devices.find(d => d.vendorId === 0x0483); // Find by vendor ID
if (device && !device.hasPermission) {
console.log('Permission required for:', device.name);
}
`
`typescript
// Request permission - triggers system dialog
const { value: granted } = await EscPosPrinter.requestUsbPermission({
address: device.id
});
if (granted) {
console.log('Permission granted!');
// Refresh device list to update permission status
const { devices: updated } = await EscPosPrinter.getUsbPrinterDevices();
} else {
console.log('Permission denied by user');
}
`
``
┌─────────────────────┐
│ getUsbPrinterDevices│
└──────────┬──────────┘
│
▼
┌──────────────┐
│hasPermission?│
└──────┬───────┘
│
┌─────┴─────┐
│ │
Yes No
│ │
▼ ▼
┌─────────┐ ┌────────────────────┐
│ Connect │ │requestUsbPermission│
└─────────┘ └─────────┬──────────┘
│
▼
┌──────────────────┐
│System Permission │
│ Dialog │
└────────┬─────────┘
│
┌─────┴─────┐
│ │
Granted Denied
│ │
▼ ▼
┌─────────┐ ┌───────┐
│ Connect │ │ Error │
└─────────┘ └───────┘
- Permission is granted per-device and persists until the app is uninstalled
- If the device is unplugged and replugged, permission may need to be re-requested
- The permission dialog is a system UI and cannot be customized
- Permission requests are idempotent - multiple calls for already-permitted devices return immediately
Some printers support bi-directional communication. The read() method is best-effort:
`typescript
// Send status request command
await printer.send([0x10, 0x04, 0x01]); // DLE EOT 1 (transmit status)
// Read response
const response = await printer.read();
if (response.length > 0) {
console.log('Printer status:', response);
} else {
console.log('No response (printer may not support reading)');
}
`
Note: Many USB ESC/POS printers do not implement a read endpoint. The read() method will return an empty array in such cases without throwing an error.
Network/TCP printing is planned for a future release. The API design is already prepared:
`typescript`
// Future API (not yet implemented)
const printer = new NetworkPrinter('192.168.1.100:9100');
await printer.link();
await printer.connect();
// ... same send/read API
The PrinterConnectionType.Network` enum value is already defined for forward compatibility.
See CONTRIBUTING.md for development setup and contribution guidelines.
MIT