
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
@finan-me/react-native-thermal-printer
Advanced tools
React Native Thermal Printer Library with ESC/POS, CPCL, TSPL support
React Native library for ESC/POS thermal printers with Bluetooth, BLE, and LAN support.
yarn add @finan-me/react-native-thermal-printer
cd ios && pod install
Add to Info.plist:
<!-- Required: Bluetooth access for connecting to printers -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth access to connect to thermal printers for receipt printing</string>
<!-- iOS 13+: Required for discovering BLE printers -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth to discover and connect to thermal printers</string>
Notes:
Add to AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- ========== NETWORK PERMISSIONS ========== -->
<!-- Required: For LAN/WiFi printing -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- ========== ANDROID 12+ (API 31+) ========== -->
<!-- Required: Scan for Bluetooth devices -->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="31" />
<!-- Required: Connect to Bluetooth devices -->
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT"
tools:targetApi="31" />
<!-- ========== ANDROID 11 AND BELOW (API ≤30) ========== -->
<!-- Required: Legacy Bluetooth permissions -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- Required: BLE scan requires location on API ≤30 -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
</manifest>
Permission Explanations:
| Permission | API Level | Purpose | Required? |
|---|---|---|---|
BLUETOOTH_SCAN | 31+ | Scan for Bluetooth devices | ✅ Yes |
BLUETOOTH_CONNECT | 31+ | Connect to Bluetooth devices | ✅ Yes |
BLUETOOTH | ≤30 | Legacy Bluetooth access | ✅ Yes (old Android) |
BLUETOOTH_ADMIN | ≤30 | Legacy Bluetooth discovery | ✅ Yes (old Android) |
ACCESS_FINE_LOCATION | ≤30 | BLE scan on old Android | ✅ Yes (old Android) |
INTERNET | All | LAN/WiFi printing | ✅ Yes |
ACCESS_NETWORK_STATE | All | Check network connectivity | ✅ Yes |
neverForLocation Flag:
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="31" />
Without neverForLocation: ❌ "App wants to access Bluetooth and Location"
With neverForLocation: ✅ "App wants to access Nearby devices"
Runtime Permissions:
import {PermissionsAndroid, Platform} from 'react-native'
async function requestBluetoothPermissions() {
if (Platform.OS === 'android') {
if (Platform.Version >= 31) {
// Android 12+
const granted = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
])
return (
granted['android.permission.BLUETOOTH_SCAN'] === 'granted' &&
granted['android.permission.BLUETOOTH_CONNECT'] === 'granted'
)
} else {
// Android 11 and below
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION)
return granted === 'granted'
}
}
return true // iOS handles automatically
}
// Use before scanning
const hasPermission = await requestBluetoothPermissions()
if (hasPermission) {
await ThermalPrinter.scanDevices()
}
import {ThermalPrinter} from '@finan-me/react-native-thermal-printer'
// 1. Scan devices
const {paired, found} = await ThermalPrinter.scanDevices()
// 2. Print receipt
const job = {
printers: [
{
address: 'bt:AA:BB:CC:DD:EE:FF',
options: {
paperWidthMm: 58,
encoding: 'CP1258', // Vietnamese
marginMm: 1, // 1mm margin each side (default)
},
},
],
documents: [
[
// Header
{type: 'text', content: 'COFFEE SHOP', style: {align: 'center', bold: true, size: 'double'}},
{type: 'text', content: '123 Main St', style: {align: 'center'}},
{type: 'line'},
// Table
{
type: 'table',
headers: ['Item', 'Qty', 'Price'],
rows: [
['Cappuccino', '2', '90.000đ'],
['Sandwich', '1', '35.000đ'],
],
columnWidths: [50, 20, 30],
alignments: ['left', 'center', 'right'],
},
// Total
{type: 'line'},
{type: 'text', content: 'TOTAL: 125.000đ', style: {bold: true, size: 'double_width'}},
// QR payment
{type: 'qr', content: 'https://payment.link/123', size: 6, align: 'center'},
// Footer
{type: 'text', content: 'Cảm ơn quý khách!', style: {align: 'center'}},
{type: 'feed', lines: 3},
{type: 'cut'},
],
],
}
await ThermalPrinter.printReceipt(job)
| Type | Format | Example |
|---|---|---|
| Bluetooth Classic | bt:MAC | bt:AA:BB:CC:DD:EE:FF |
| BLE | ble:MAC | ble:AA:BB:CC:DD:EE:FF |
| LAN/WiFi | lan:IP:PORT | lan:192.168.1.100:9100 |
Text: {type: 'text', content: 'Hello', style: {align: 'center', bold: true, size: 'double'}}
Line: {type: 'line'}
Table: {type: 'table', headers: ['A', 'B'], rows: [['1', '2']], columnWidths: [50, 50]}
Columns: {type: 'columns', columns: [{content: 'Left', width: 50}, {content: 'Right', width: 50, align: 'right'}]}
QR Code: {type: 'qr', content: 'https://...', size: 6, align: 'center'}
Barcode: {type: 'barcode', content: '123456', format: 'CODE128', align: 'center'}
Image: {type: 'image', imagePath: '/path/to/image.png', options: {align: 'center', marginMm: 2}}
Feed: {type: 'feed', lines: 3}
Spacer: {type: 'spacer', height: 2, fill: '-'}
Cut: {type: 'cut', partial: true}
{
paperWidthMm?: 32 | 58 | 80, // default: 58
encoding?: 'CP1258' | 'UTF8' | 'ASCII', // default: CP1258
marginMm?: number, // default: 1mm each side
keepAlive?: boolean
}
{
concurrent?: boolean, // print to multiple printers in parallel
continueOnError?: boolean, // continue if one printer fails
onProgress?: (completed: number, total: number) => void,
onJobComplete?: (address: string, success: boolean) => void
}
{
address: string,
copies?: number, // number of copies (default: 1)
delayBetweenCopies?: number, // delay in ms (default: 200)
options?: PrinterOptions
}
const job = {
printers: [
{address: 'bt:11:11:11:11:11:11', copies: 2}, // Kitchen: 2 copies
{address: 'lan:192.168.1.100:9100'}, // Counter: 1 copy
],
documents: [[{type: 'text', content: 'Order #123'}, {type: 'cut'}]],
options: {
concurrent: true, // Print in parallel
continueOnError: true,
onProgress: (completed, total) => console.log(`${completed}/${total}`),
},
}
const result = await ThermalPrinter.printReceipt(job)
// result.success, result.results (per-printer status)
{
options: {
encoding: 'CP1258'
}
}
try {
await ThermalPrinter.printReceipt(job)
} catch (error) {
console.log(error.code) // E1001, E2001, E4003...
console.log(error.message) // Human readable
console.log(error.suggestion) // How to fix
console.log(error.retryable) // Can retry?
}
Vietnamese not printing?
encoding: 'CP1258'testCodepages() utilityConnection timeout?
testConnection() before printingImage not printing?
MIT
FAQs
React Native Thermal Printer Library with ESC/POS, CPCL, TSPL support
We found that @finan-me/react-native-thermal-printer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.