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

capacitor-zebra-bluetooth

v1.0.0

Published

Capacitor plugin for Zebra thermal printer communication via Classic Bluetooth. Supports iOS (ExternalAccessory) and Android (Bluetooth SPP) with ZPL command support.

Readme

capacitor-zebra-bluetooth

A Capacitor plugin for communicating with Zebra thermal printers via Classic Bluetooth. Supports both iOS and Android platforms with full ZPL (Zebra Programming Language) command support.

Features

  • Discover paired Zebra Bluetooth printers
  • Connect/disconnect to printers
  • Send ZPL commands for label printing
  • Get printer status (paper out, head open, etc.)
  • Support for both iOS (ExternalAccessory framework) and Android (Bluetooth SPP)
  • TypeScript support with full type definitions

Supported Printers

This plugin works with Zebra mobile and desktop printers that support Bluetooth Classic (SPP profile), including:

  • Mobile Printers: ZQ310, ZQ320, ZQ510, ZQ520, ZQ610, ZQ620, ZQ630
  • Desktop Printers: ZD410, ZD420, ZD620, ZT230, ZT410, ZT420

Installation

npm install capacitor-zebra-bluetooth
npx cap sync

Platform Configuration

iOS Configuration

1. Add Bluetooth Protocol to Info.plist

Add the Zebra Bluetooth protocol string to your ios/App/App/Info.plist:

<key>UISupportedExternalAccessoryProtocols</key>
<array>
    <string>com.zebra.rawport</string>
</array>

2. Add Bluetooth Usage Description

Also add the Bluetooth usage description:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to connect to Zebra printers for label printing.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to connect to Zebra printers for label printing.</string>

3. Enable External Accessory Background Mode (Optional)

If you need to maintain printer connections in the background:

<key>UIBackgroundModes</key>
<array>
    <string>external-accessory</string>
</array>

Important Notes for iOS

  • Printers must be paired via iOS Settings before they can be discovered by the app
  • The plugin uses Apple's ExternalAccessory framework, which requires MFi certification
  • Zebra printers are MFi certified and use the com.zebra.rawport protocol

Android Configuration

The plugin automatically adds required permissions to your AndroidManifest.xml:

<!-- Bluetooth permissions (Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!-- Bluetooth permissions (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Location permission (required for Bluetooth scanning on older versions) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Important Notes for Android

  • Printers must be paired via Android Settings before they can be discovered
  • On Android 12+, the plugin requests BLUETOOTH_SCAN and BLUETOOTH_CONNECT permissions
  • On older versions, ACCESS_FINE_LOCATION is required for Bluetooth scanning

Usage

Import the Plugin

import { CapacitorZebraBluetooth } from 'capacitor-zebra-bluetooth';

Discover Printers

Discover all paired Zebra printers:

const result = await CapacitorZebraBluetooth.discoverPrinters();
console.log('Found printers:', result.printers);

// Result structure:
// {
//   printers: [
//     {
//       friendlyName: "ZQ320-ABC123",
//       manufacturer: "Zebra Technologies",
//       modelName: "ZQ320",
//       connected: false
//     }
//   ]
// }

Connect to a Printer

const result = await CapacitorZebraBluetooth.connectToPrinter({
  friendlyName: 'ZQ320-ABC123'
});

if (result.success) {
  console.log('Connected successfully');
} else {
  console.error('Connection failed:', result.message);
}

Check Connection Status

const { connected } = await CapacitorZebraBluetooth.isConnected();
console.log('Is connected:', connected);

Get Connected Printer

const { printer } = await CapacitorZebraBluetooth.getConnectedPrinter();
if (printer) {
  console.log('Connected to:', printer.friendlyName);
}

Send ZPL Commands

// Simple label example
const zpl = `
^XA
^FO50,50^A0N,50,50^FDHello World^FS
^FO50,120^BY3^BCN,100,Y,N,N^FD12345678^FS
^XZ
`;

const result = await CapacitorZebraBluetooth.sendZPL({ zpl });

if (result.success) {
  console.log('Label printed successfully');
} else {
  console.error('Print failed:', result.message);
}

Get Printer Status

const { status } = await CapacitorZebraBluetooth.getPrinterStatus();

console.log('Printer status:', {
  connected: status.connected,
  ready: status.ready,
  printing: status.printing,
  paperOut: status.paperOut,
  headOpen: status.headOpen,
  message: status.message
});

Disconnect

await CapacitorZebraBluetooth.disconnect();

Complete Example

Here's a complete example of a print service:

import { CapacitorZebraBluetooth, type ZebraPrinter } from 'capacitor-zebra-bluetooth';

class PrintService {
  private selectedPrinter: ZebraPrinter | null = null;

  async discoverAndConnect(): Promise<boolean> {
    try {
      // Discover printers
      const { printers } = await CapacitorZebraBluetooth.discoverPrinters();

      if (printers.length === 0) {
        console.log('No printers found. Please pair a printer in device settings.');
        return false;
      }

      // Connect to first available printer
      this.selectedPrinter = printers[0];
      const result = await CapacitorZebraBluetooth.connectToPrinter({
        friendlyName: this.selectedPrinter.friendlyName
      });

      return result.success;
    } catch (error) {
      console.error('Error:', error);
      return false;
    }
  }

  async printLabel(text: string, barcode: string): Promise<boolean> {
    // Check connection
    const { connected } = await CapacitorZebraBluetooth.isConnected();
    if (!connected) {
      const success = await this.discoverAndConnect();
      if (!success) return false;
    }

    // Generate ZPL
    const zpl = `
^XA
^CI28
^FO50,50^A0N,40,40^FD${text}^FS
^FO50,100^BY2^BCN,80,Y,N,N^FD${barcode}^FS
^XZ
    `;

    // Send to printer
    const result = await CapacitorZebraBluetooth.sendZPL({ zpl });
    return result.success;
  }

  async checkPrinterReady(): Promise<boolean> {
    const { status } = await CapacitorZebraBluetooth.getPrinterStatus();

    if (status.paperOut) {
      console.warn('Printer is out of paper');
      return false;
    }

    if (status.headOpen) {
      console.warn('Printer head is open');
      return false;
    }

    return status.ready;
  }
}

ZPL Quick Reference

Here are some common ZPL commands:

| Command | Description | Example | |---------|-------------|---------| | ^XA | Start label format | ^XA | | ^XZ | End label format | ^XZ | | ^FO | Field origin (x,y position) | ^FO50,100 | | ^FD | Field data | ^FDHello^FS | | ^FS | Field separator (end field) | ^FS | | ^A0N | Scalable font | ^A0N,50,50 | | ^BC | Code 128 barcode | ^BCN,100,Y,N,N | | ^BQ | QR Code | ^BQN,2,5 | | ^BY | Bar code field default | ^BY3 | | ^GB | Graphic box (line/rectangle) | ^GB200,3,3^FS | | ^CI28 | UTF-8 character set | ^CI28 | | ^LL | Label length | ^LL400 | | ^PW | Print width | ^PW400 |

Sample Labels

Simple Text Label

^XA
^CI28
^FO50,50^A0N,30,30^FDProduct: Widget^FS
^FO50,90^A0N,30,30^FDPrice: $9.99^FS
^XZ

Barcode Label

^XA
^FO50,50^A0N,25,25^FDSKU: ABC123^FS
^FO50,80^BY2^BCN,80,Y,N,N^FDABC123^FS
^XZ

QR Code Label

^XA
^FO50,50^BQN,2,5^FDQA,https://example.com^FS
^XZ

Receipt-style Label

^XA
^CI28
^PW400
^LL800

^FO50,30^A0N,30,30^FDCompany Name^FS
^FO50,70^GB300,2,2^FS

^FO50,90^A0N,20,20^FDItem 1^FS
^FO300,90^A0N,20,20^FD$10.00^FS

^FO50,120^A0N,20,20^FDItem 2^FS
^FO300,120^A0N,20,20^FD$15.00^FS

^FO50,160^GB300,2,2^FS
^FO50,180^A0N,25,25^FDTotal: $25.00^FS

^XZ

API Reference

discoverPrinters()

discoverPrinters(): Promise<{ printers: ZebraPrinter[] }>

Discover available Zebra printers via Classic Bluetooth. On iOS, only previously paired printers will be returned.

connectToPrinter(options)

connectToPrinter(options: { friendlyName: string }): Promise<{ success: boolean; message?: string }>

Connect to a Zebra printer by its friendly name.

disconnect()

disconnect(): Promise<{ success: boolean }>

Disconnect from the currently connected printer.

isConnected()

isConnected(): Promise<{ connected: boolean }>

Check if a printer is currently connected.

getConnectedPrinter()

getConnectedPrinter(): Promise<{ printer: ZebraPrinter | null }>

Get the currently connected printer information.

sendZPL(options)

sendZPL(options: { zpl: string }): Promise<{ success: boolean; message?: string }>

Send ZPL commands to the connected printer.

getPrinterStatus()

getPrinterStatus(): Promise<{ status: PrinterStatus }>

Get the current printer status including paper and head status.

Type Definitions

ZebraPrinter

interface ZebraPrinter {
  friendlyName: string;
  manufacturer?: string;
  modelName?: string;
  serialNumber?: string;
  connected: boolean;
}

PrinterStatus

interface PrinterStatus {
  connected: boolean;
  ready: boolean;
  printing: boolean;
  paperOut: boolean;
  headOpen: boolean;
  message?: string;
}

Troubleshooting

Printer not discovered

  1. Ensure the printer is paired in your device's Bluetooth settings
  2. Restart the printer and your device
  3. Check battery level on mobile printers
  4. On Android, ensure location services are enabled (required for Bluetooth scanning)

Connection fails

  1. Unpair and re-pair the printer in device settings
  2. Restart the printer - hold power button until it beeps twice
  3. Check that no other app is connected to the printer
  4. Verify printer is in Bluetooth Classic mode, not BLE-only

Printing issues

  1. Check paper/labels are loaded correctly
  2. Calibrate the printer using the feed button (hold for 2 seconds)
  3. Verify ZPL syntax - use Zebra's labelary.com for testing
  4. Ensure ^XA and ^XZ tags are present

iOS-specific issues

  • Printer must appear in Settings > Bluetooth > My Devices
  • Check UISupportedExternalAccessoryProtocols includes com.zebra.rawport
  • Some older Zebra printers may not be MFi certified

Android-specific issues

  • On Android 12+, grant both Nearby devices and Location permissions
  • Ensure the app has permission to scan and connect via Bluetooth

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development

# Install dependencies
npm install

# Build the plugin
npm run build

# Watch for changes
npm run watch

# Run linter
npm run lint

# Format code
npm run fmt

License

MIT License - see the LICENSE file for details.

Acknowledgments

  • Zebra Technologies for their printer SDKs and documentation
  • Capacitor team for the excellent plugin architecture
  • Contributors and users who provide feedback and improvements

Support