nativeMessaging Permission
5 min readnativeMessaging Permission
Overview
- Permission string:
"nativeMessaging" - Enables communication between extension and native applications
- Two modes: connection-based (persistent) and message-based (one-shot)
Manifest Declaration
{ "permissions": ["nativeMessaging"] }
User warning: “Communicate with cooperating native applications”
API Methods
Persistent Connection
chrome.runtime.connectNative(hostName) returns Port for persistent connection.
Port Methods: Port.postMessage(msg), Port.onMessage, Port.onDisconnect
const port = chrome.runtime.connectNative('com.example.myhost');
port.onMessage.addListener((msg) => console.log('From native:', msg));
port.onDisconnect.addListener(() => {
if (chrome.runtime.lastError) console.error('Disconnect:', chrome.runtime.lastError.message);
});
port.postMessage({ action: 'startMonitoring' });
One-Shot Messages
chrome.runtime.sendNativeMessage(hostName, message) — single request/response.
const response = await chrome.runtime.sendNativeMessage('com.example.myhost', {
action: 'getVersion'
});
console.log(response.version);
Native Messaging Host Setup
Host Manifest (JSON)
{
"name": "com.example.myhost",
"description": "My native messaging host",
"path": "/path/to/native/app",
"type": "stdio",
"allowed_origins": ["chrome-extension://abcdef.../"]
}
Registration by OS
| OS | Path |
|—|—|
| macOS | ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.example.myhost.json |
| Linux | ~/.config/google-chrome/NativeMessagingHosts/com.example.myhost.json |
| Windows | Registry: HKCU\Software\Google\Chrome\NativeMessagingHosts\com.example.myhost |
Message Format
- 32-bit message length prefix (native byte order) + UTF-8 JSON payload
- Maximum: 1 MB incoming, 4 GB outgoing from host
- Host reads from stdin, writes to stdout
Native Host Example (Python)
import struct, sys, json
def read_message():
raw_length = sys.stdin.buffer.read(4)
if not raw_length: return None
length = struct.unpack('=I', raw_length)[0]
return json.loads(sys.stdin.buffer.read(length))
def send_message(msg):
encoded = json.dumps(msg).encode('utf-8')
sys.stdout.buffer.write(struct.pack('=I', len(encoded)))
sys.stdout.buffer.write(encoded)
sys.stdout.buffer.flush()
while (msg := read_message()):
if msg.get('action') == 'getVersion':
send_message({'version': '1.0.0'})
Use Cases
- File system access beyond browser sandbox
- Native app integration (password managers, VPNs)
- Hardware access (USB, Bluetooth via native helper)
- System services and legacy app bridges
Security Considerations
allowed_originsmust list specific extension IDs only- Host app path must be absolute
- Validate all messages in both directions
- Host process runs with user privileges
Code Examples
One-Shot Message Pattern
async function sendNativeMessage(hostName: string, message: object) {
try {
return await chrome.runtime.sendNativeMessage(hostName, message);
} catch (error) {
console.error('Native message failed:', error);
throw error;
}
}
const version = await sendNativeMessage('com.example.myhost', { action: 'getVersion' });
Persistent Connection with Reconnect
class NativeHostConnection {
private port: chrome.runtime.Port | null = null;
private attempts = 0;
constructor(private hostName: string) {}
connect(): void {
this.port = chrome.runtime.connectNative(this.hostName);
this.port.onMessage.addListener((msg) => console.log('Received:', msg));
this.port.onDisconnect.addListener(() => {
this.port = null;
if (this.attempts++ < 3) setTimeout(() => this.connect(), 1000 * this.attempts);
});
}
send(message: object): void { this.port?.postMessage(message); }
}
Error Handling
chrome.runtime.connectNative('com.example.myhost', (port) => {
if (chrome.runtime.lastError) {
const err = chrome.runtime.lastError.message;
if (err.includes('not found')) console.error('Host not installed');
else if (err.includes('exited')) console.error('Host crashed');
else if (err.includes('forbidden')) console.error('Check allowed_origins');
return;
}
port.onMessage.addListener(handleMessage);
});
Common Errors
- “Native host has exited” — host crashed or wrong path
- “Specified native messaging host not found” — manifest location incorrect
- “Access to the specified native messaging host is forbidden” — extension ID not in
allowed_origins
Cross-References
- Related:
docs/reference/message-passing-patterns.md
Frequently Asked Questions
How do I communicate with a native app?
Use chrome.runtime.sendNativeMessage() to send messages to a native application configured in your manifest. The app must register a messaging host.
Is nativeMessaging secure?
NativeMessaging is secure but requires user consent and careful validation of messages to prevent injection attacks. —
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.