npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-bluetooth-escpos-printer-dj

v0.2.4

Published

React-Native plugin for the bluetooth ESC/POS printers.

Downloads

522

Readme

React Native Bluetooth ESC/POS Printer

React Native Bluetooth printing for ESC/POS receipt printers and TSC label printers.

This fork is based on the original React Native Bluetooth ESC/POS printer module.

license

What You Can Print

| Printer mode | Use for | Module | | --- | --- | --- | | ESC/POS | Receipts, invoices, kitchens, cash drawers, QR codes, barcodes | BluetoothEscposPrinter | | TSC | Shipping labels, product labels, stickers, QR labels, barcode labels | BluetoothTscPrinter | | Bluetooth | Discovery, pairing, connecting, connection status | BluetoothManager |

Install

npm install <package-name> --save

For React Native 0.60 and newer, autolinking should handle native setup.

For React Native 0.59 and older:

react-native link <package-name>

Manual Android linking path:

include ':react-native-bluetooth-escpos-printer'
project(':react-native-bluetooth-escpos-printer').projectDir =
    new File(rootProject.projectDir, '../node_modules/<package-name>/android')
dependencies {
  implementation project(':react-native-bluetooth-escpos-printer')
}

Import

import {
  BluetoothManager,
  BluetoothEscposPrinter,
  BluetoothTscPrinter,
} from '<package-name>';

The Happy Path

The safest flow is always:

  1. Check or enable Bluetooth.
  2. Scan for devices.
  3. Parse the returned device JSON.
  4. Connect by device address.
  5. Print with ESC/POS or TSC.
async function connectFirstPrinter() {
  const enabled = await BluetoothManager.isBluetoothEnabled();

  if (!enabled || enabled === 'false') {
    await BluetoothManager.enableBluetooth();
  }

  const scanResult = await BluetoothManager.scanDevices();
  const { paired = [], found = [] } = JSON.parse(scanResult);
  const printer = paired[0] || found[0];

  if (!printer) {
    throw new Error('No Bluetooth printer found');
  }

  await BluetoothManager.connect(printer.address);
  return printer;
}

On Android, enableBluetooth() resolves with paired devices. On iOS, it resolves null because iOS does not let apps toggle Bluetooth directly.

Bluetooth Manager

| Method | Params | Resolves | Notes | | --- | --- | --- | --- | | isBluetoothEnabled() | none | boolean on Android, 'true' or 'false' on iOS | Use loose checks if supporting both platforms. | | enableBluetooth() | none | paired device array on Android, null on iOS | Android may show the system Bluetooth dialog. | | disableBluetooth() | none | boolean or null | Android only behavior; iOS resolves null. | | scanDevices() | none | JSON string { paired, found } | Also emits discovery events. | | stopScan() | none | null | iOS supported. | | connect(address) | address: string | null or address | Address is MAC on Android, UUID on iOS. | | disconnect(address) | address: string | address | Android method. | | unpaire(address) | address: string | address | Android method. Name is intentionally legacy-spelled in native code. | | isDeviceConnected() | none | boolean | Android method. | | getConnectedDeviceAddress() | none | string | Android method. |

Discovery Events

Use DeviceEventEmitter on Android and NativeEventEmitter patterns as needed for your React Native version.

import { DeviceEventEmitter } from 'react-native';

const subscriptions = [
  DeviceEventEmitter.addListener(
    BluetoothManager.EVENT_DEVICE_ALREADY_PAIRED,
    ({ devices }) => console.log('paired', JSON.parse(devices)),
  ),
  DeviceEventEmitter.addListener(
    BluetoothManager.EVENT_DEVICE_FOUND,
    (event) => console.log('found', event),
  ),
  DeviceEventEmitter.addListener(
    BluetoothManager.EVENT_CONNECTED,
    () => console.log('connected'),
  ),
  DeviceEventEmitter.addListener(
    BluetoothManager.EVENT_CONNECTION_LOST,
    () => console.log('connection lost'),
  ),
];

// Later:
subscriptions.forEach((subscription) => subscription.remove());

Events exposed by the module:

| Event | Meaning | | --- | --- | | EVENT_DEVICE_ALREADY_PAIRED | Previously paired devices were read. | | EVENT_DEVICE_FOUND | A device was discovered during scan. | | EVENT_DEVICE_DISCOVER_DONE | Scan finished. | | EVENT_CONNECTED | Device connected. | | EVENT_UNABLE_CONNECT | Connection attempt failed. | | EVENT_CONNECTION_LOST | Active connection was lost. | | EVENT_BLUETOOTH_NOT_SUPPORT | Android device has no Bluetooth adapter. |

ESC/POS Receipts

Use this for thermal receipt printers.

Receipt Example

async function printReceipt() {
  await BluetoothEscposPrinter.printerInit();
  await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.CENTER);

  await BluetoothEscposPrinter.printText('MY STORE\n\r', {
    size: 2,
    bold: true,
  });

  await BluetoothEscposPrinter.printText('Tax Invoice\n\r', {
    size: 1,
  });

  await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.LEFT);
  await BluetoothEscposPrinter.printText('Order: #10023\n\r', {});
  await BluetoothEscposPrinter.printText('Date: 2026-07-02\n\r', {});
  await BluetoothEscposPrinter.printText('--------------------------------\n\r', {});

  await BluetoothEscposPrinter.printColumn(
    [18, 6, 8],
    [
      BluetoothEscposPrinter.ALIGN.LEFT,
      BluetoothEscposPrinter.ALIGN.CENTER,
      BluetoothEscposPrinter.ALIGN.RIGHT,
    ],
    ['Item', 'Qty', 'Total'],
    { bold: true },
  );

  await BluetoothEscposPrinter.printColumn(
    [18, 6, 8],
    [
      BluetoothEscposPrinter.ALIGN.LEFT,
      BluetoothEscposPrinter.ALIGN.CENTER,
      BluetoothEscposPrinter.ALIGN.RIGHT,
    ],
    ['Coffee', '2', '160.00'],
    {},
  );

  await BluetoothEscposPrinter.printText('--------------------------------\n\r', {});
  await BluetoothEscposPrinter.printColumn(
    [18, 6, 8],
    [
      BluetoothEscposPrinter.ALIGN.LEFT,
      BluetoothEscposPrinter.ALIGN.CENTER,
      BluetoothEscposPrinter.ALIGN.RIGHT,
    ],
    ['Grand Total', '', '160.00'],
    { bold: true },
  );

  await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.CENTER);
  await BluetoothEscposPrinter.printQRCode(
    'https://example.com/order/10023',
    220,
    BluetoothEscposPrinter.ERROR_CORRECTION.M,
  );

  if (BluetoothEscposPrinter.printAndFeed) {
    await BluetoothEscposPrinter.printAndFeed(3);
  } else {
    await BluetoothEscposPrinter.printText('\n\r\n\r\n\r', {});
  }
}

ESC/POS Methods

| Method | Platform | Params | Notes | | --- | --- | --- | --- | | printerInit() | Android, iOS | none | Reset/init printer state. Call before a new receipt. | | printAndFeed(feed) | Android | feed: number | Print buffer and feed paper by lines/dots, depending on printer firmware. | | printerLeftSpace(sp) | Android, iOS | sp: number | Set left spacing. | | printerLineSpace(sp) | Android | sp: number | Set line spacing. 0 resets default on Android. | | printerUnderLine(line) | Android, iOS | 0, 1, 2 | Off, on, thicker underline. | | printerAlign(align) | Android, iOS | BluetoothEscposPrinter.ALIGN.* | LEFT, CENTER, RIGHT. Does not affect image positioning on some printers. | | printText(text, options) | Android, iOS | string, EscposTextOptions | Print text. Add \n\r when you want a new line. | | printColumn(widths, aligns, texts, options) | Android, iOS | arrays plus EscposTextOptions | Arrays must have the same length. | | setWidth(width) | Android, iOS | 384 or 576 usually | Set printer dot width. 58 mm often uses 384; 80 mm often uses 576. | | printPic(base64, options) | Android, iOS | base64 without data URI prefix | Print image. | | setBlob(weight) | Android, iOS | 0 or 1 | Legacy name for bold mode. | | rotate(value) | Android, iOS | BluetoothEscposPrinter.ROTATION.* | OFF or ON. | | printQRCode(content, size, correctionLevel) | Android, iOS | string, number, correction level | Prints QR as bitmap. | | printBarCode(str, type, width, height, hriFontType, hriPosition) | Android, iOS | see constants | Prints 1D barcode. | | openDrawer(mode, time1, time2) | Android | numbers | Opens cash drawer. | | cutOnePoint() | Android | none | Sends cut command. | | selfTest(callback) | Android | callback | Prints self-test. |

ESC/POS Text Options

| Option | Type | Default | Notes | | --- | --- | --- | --- | | encoding | string | GBK | Use UTF-8 when your printer firmware supports it. | | codepage | number | 0 | Printer code page. | | widthtimes | 0..3 | 0 | Width multiplier. | | heigthtimes | 0..3 | 0 | Height multiplier. Legacy spelling is required. | | fonttype | number | 0 | Printer font type. iOS also accepts fontType. | | size | 0..3 | none | Convenience option. Sets widthtimes and heigthtimes unless they are already provided. | | bold | boolean | none | Convenience option. Enables bold for this call and resets it afterward. |

ESC/POS Constants

BluetoothEscposPrinter.ALIGN.LEFT;   // 0
BluetoothEscposPrinter.ALIGN.CENTER; // 1
BluetoothEscposPrinter.ALIGN.RIGHT;  // 2

BluetoothEscposPrinter.ERROR_CORRECTION.L; // 1
BluetoothEscposPrinter.ERROR_CORRECTION.M; // 0
BluetoothEscposPrinter.ERROR_CORRECTION.Q; // 3
BluetoothEscposPrinter.ERROR_CORRECTION.H; // 2

BluetoothEscposPrinter.BARCODETYPE.CODE128;
BluetoothEscposPrinter.ROTATION.OFF;
BluetoothEscposPrinter.ROTATION.ON;

TSC Labels

Use this for label printers that understand TSC commands.

Label Example

async function printShippingLabel(base64Logo) {
  await BluetoothTscPrinter.printLabel({
    width: 60,
    height: 40,
    gap: 2,
    speed: BluetoothTscPrinter.PRINT_SPEED.SPEED3,
    density: BluetoothTscPrinter.DENSITY.DNESITY8,
    direction: BluetoothTscPrinter.DIRECTION.FORWARD,
    reference: [0, 0],
    tear: BluetoothTscPrinter.TEAR.ON,
    sound: 1,
    home: 1,
    text: [
      {
        text: 'SHIP TO',
        x: 24,
        y: 20,
        fonttype: BluetoothTscPrinter.FONTTYPE.FONT_2,
        rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
        xscal: BluetoothTscPrinter.FONTMUL.MUL_1,
        yscal: BluetoothTscPrinter.FONTMUL.MUL_1,
        bold: true,
      },
      {
        text: 'Customer Name',
        x: 24,
        y: 55,
        fonttype: BluetoothTscPrinter.FONTTYPE.FONT_2,
        rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
        xscal: BluetoothTscPrinter.FONTMUL.MUL_1,
        yscal: BluetoothTscPrinter.FONTMUL.MUL_1,
      },
    ],
    barcode: [
      {
        x: 24,
        y: 105,
        type: BluetoothTscPrinter.BARCODETYPE.CODE128,
        height: 60,
        readable: BluetoothTscPrinter.READABLE.EANBLE,
        rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
        code: 'PKG10023',
        wide: 2,
        narrow: 1,
      },
    ],
    qrcode: [
      {
        x: 360,
        y: 40,
        level: BluetoothTscPrinter.EEC.LEVEL_M,
        width: 5,
        rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
        code: 'PKG10023',
      },
    ],
    image: base64Logo
      ? [
          {
            x: 24,
            y: 170,
            mode: BluetoothTscPrinter.BITMAP_MODE.OVERWRITE,
            width: 120,
            image: base64Logo,
          },
        ]
      : [],
  });
}

printLabel(options)

Top-level options:

| Option | Type | Required | Notes | | --- | --- | --- | --- | | width | number | yes | Label width in mm. | | height | number | yes | Label height in mm. | | gap | number | no | Gap between labels in mm. Use 0 for gapless media. | | speed | number | no | Use BluetoothTscPrinter.PRINT_SPEED.*. | | density | number | no | Use BluetoothTscPrinter.DENSITY.*. | | direction | number | no | FORWARD or BACKWARD. Defaults to forward. | | reference | [x, y] | no | Label origin. Defaults to [0, 0]. | | tear | string | no | BluetoothTscPrinter.TEAR.ON or OFF. | | sound | 0 or 1 | no | Beep after print. | | home | 0 or 1 | no | Back-feed and return home before printing. | | text | array | no | Text blocks. | | barcode | array | no | 1D barcode blocks. | | qrcode | array | no | QR blocks. | | image | array | no | Bitmap blocks. | | reverse | array | no | Reverse/black-fill areas on Android. iOS currently reads the legacy key revers. |

Text block:

| Option | Type | Notes | | --- | --- | --- | | text | string | Text to print. | | x, y | number | Position in dots. | | fonttype | string | Use BluetoothTscPrinter.FONTTYPE.*. | | rotation | number | Use BluetoothTscPrinter.ROTATION.*. | | xscal, yscal | number | Use BluetoothTscPrinter.FONTMUL.*. | | bold | boolean | Simulates bold by drawing text with small offsets. |

Barcode block:

| Option | Type | Notes | | --- | --- | --- | | x, y | number | Position in dots. | | type | string | Use BluetoothTscPrinter.BARCODETYPE.*. | | height | number | Barcode height in dots. | | readable | 0 or 1 | Human readable text off/on. | | rotation | number | Use BluetoothTscPrinter.ROTATION.*. | | code | string | Barcode content. | | wide | number | Wide bar width. | | narrow | number | Narrow bar width. |

QR block:

| Option | Type | Notes | | --- | --- | --- | | x, y | number | Position in dots. | | level | string | LEVEL_L, LEVEL_M, LEVEL_Q, or LEVEL_H. | | width | number | QR module size. | | rotation | number | Use BluetoothTscPrinter.ROTATION.*. | | code | string | QR content. |

Image block:

| Option | Type | Notes | | --- | --- | --- | | x, y | number | Position in dots. | | mode | number | OVERWRITE, OR, or XOR. | | width | number | Target image width in dots. | | image | string | Base64 image data without data:image/...;base64,. |

Reverse block:

| Option | Type | Notes | | --- | --- | --- | | x, y | number | Position in dots. | | width, height | number | Reverse area size in dots. |

TSC Constants

BluetoothTscPrinter.DIRECTION.FORWARD;
BluetoothTscPrinter.DIRECTION.BACKWARD;

BluetoothTscPrinter.TEAR.ON;
BluetoothTscPrinter.TEAR.OFF;

BluetoothTscPrinter.PRINT_SPEED.SPEED1DIV5;
BluetoothTscPrinter.PRINT_SPEED.SPEED2;
BluetoothTscPrinter.PRINT_SPEED.SPEED3;
BluetoothTscPrinter.PRINT_SPEED.SPEED4;

BluetoothTscPrinter.DENSITY.DNESITY0;
BluetoothTscPrinter.DENSITY.DNESITY8;
BluetoothTscPrinter.DENSITY.DNESITY15;

BluetoothTscPrinter.FONTTYPE.FONT_1;
BluetoothTscPrinter.FONTTYPE.FONT_2;
BluetoothTscPrinter.FONTTYPE.SIMPLIFIED_CHINESE;

BluetoothTscPrinter.ROTATION.ROTATION_0;
BluetoothTscPrinter.ROTATION.ROTATION_90;
BluetoothTscPrinter.ROTATION.ROTATION_180;
BluetoothTscPrinter.ROTATION.ROTATION_270;

BluetoothTscPrinter.FONTMUL.MUL_1;
BluetoothTscPrinter.FONTMUL.MUL_2;

BluetoothTscPrinter.BARCODETYPE.CODE128;
BluetoothTscPrinter.EEC.LEVEL_M;
BluetoothTscPrinter.BITMAP_MODE.OVERWRITE;
BluetoothTscPrinter.READABLE.EANBLE;
BluetoothTscPrinter.READABLE.DISABLE;

Note: DNESITY and EANBLE keep the native module's legacy spellings for backward compatibility.

Base64 Images

Pass raw base64 only:

const rawBase64 = dataUri.replace(/^data:image\/\w+;base64,/, '');
await BluetoothEscposPrinter.printPic(rawBase64, { width: 384, left: 0 });

Common receipt widths:

| Paper | Width | | --- | --- | | 58 mm | 384 dots | | 80 mm | 576 dots |

Android Permissions

Add Bluetooth permissions required by your target SDK. Modern Android versions may require both classic Bluetooth and runtime permissions.

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Request runtime permissions in your app before scanning on Android 6+ and especially Android 12+.

iOS Notes

Add the Bluetooth usage description to your app plist:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app connects to Bluetooth printers.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app connects to Bluetooth printers.</string>

iOS uses BLE peripheral UUIDs as addresses, not Android MAC addresses.

Troubleshooting

| Problem | What to check | | --- | --- | | COMMAND_NOT_SEND | Printer is not connected, disconnected during write, or does not support the command. | | Scan returns no devices on Android | Runtime location/Bluetooth permissions, Bluetooth enabled, printer discoverable. | | Text prints as boxes | Try encoding: 'GBK', correct codepage, or confirm printer font/codepage support. | | Image is too wide | Use setWidth(384) for 58 mm or setWidth(576) for 80 mm, then pass matching image width. | | Columns wrap badly | Keep total column width under printable character width: about 32 for 58 mm, 48 for 80 mm. | | iOS cannot connect by MAC address | Use the UUID returned by scanDevices() on iOS. | | Drawer does not open | openDrawer() requires ESC/POS printer hardware wired to a cash drawer port. |

Development

npm install
cd examples && npm install
cd examples && npm start
cd examples && npm test
cd examples/android && ./gradlew assembleDebug

The root npm test script is a placeholder. Use the example app for JavaScript tests.

Publish

npm publish --access public

If npm reports cache ownership errors:

sudo chown -R "$(id -u):$(id -g)" "$HOME/.npm"

License

MIT