How Browser Extensions Use Native Messaging to Send Downloads to Motrix
Browser extensions send downloads to Motrix by invoking chrome.runtime.sendNativeMessage('app.motrix.bridge', payload), which spawns the motrix-native-host binary to forward the request via local IPC to Motrix's internal Aria2 download engine.
Motrix is an open-source, Electron-based download manager that exposes a native-messaging host, enabling Chrome, Edge, and Firefox extensions to delegate file downloads directly to the application. This architecture eliminates the need for background HTTP servers or manual link copying, allowing the browser to hand off download metadata via stdin to a trusted native process. According to the agalwood/Motrix source code, the bridge consists of a Rust-based native host, a dynamically generated manifest file, and a local Unix socket or Windows named pipe for inter-process communication.
Architecture Overview
The native-messaging integration involves five primary components that handle the journey from browser click to active download:
| Component | Role | Key Source File |
|---|---|---|
| Browser Extension | Captures download URLs and forwards JSON messages via the browser's Native Messaging API. | src/renderer/extension/* |
| Native-Messaging Manifest | Registers the host binary with the browser, defining the app.motrix.bridge identifier and allowed extensions. |
src/main/bridge/native-messaging-installer.ts |
| Native Host Binary | A Rust executable (motrix-native-host) that validates browser messages and relays them to Motrix over local IPC. |
packages/native-host/src/main.rs |
| Motrix Core | Listens on a local socket, receives the download command, and creates an Aria2 task via aria2.addUri. |
src/main/engine/aria2-service.ts |
| Installation Helper | Writes the manifest to browser-specific directories (Chrome, Edge, Firefox) during Motrix's first run. | src/main/bridge/native-messaging-installer.ts |
Message Flow
When a user initiates a download through the extension, the following sequence occurs:
-
Extension Invokes Native Messaging: The extension calls
chrome.runtime.sendNativeMessage('app.motrix.bridge', payload)with a JSON object containing the URL, filename, and optional parameters. -
Browser Spawns Host: The browser locates
app.motrix.bridge.json(installed in the browser's NativeMessagingHosts directory), launches the executable specified in the"path"field, and pipes the JSON payload to its stdin. -
Host Validates Input: The
motrix-native-hostbinary reads the single-line JSON message from stdin, deserializes it, and validates required fields (url,filename). -
IPC Forwarding: The host opens a connection to Motrix's local IPC endpoint—a Unix domain socket at
$XDG_RUNTIME_DIR/motrix.sockon Linux/macOS or a Windows named pipe (\\.\pipe\motrix-ipc). -
Download Creation: Motrix's main process receives the message, parses the command, and invokes
addDownload()insrc/main/engine/aria2-service.tsto create an Aria2 task. -
Response Return: The native host writes a JSON response (success or error) to stdout, which the browser relays back to the extension's callback function.
All communication remains local to the machine; no external network requests are required for the handshake.
Implementation Details
Browser Extension Integration
Browser extensions interact with Motrix using the standard chrome.runtime.sendNativeMessage API. The extension must declare the nativeMessaging permission in its manifest and use the exact host name app.motrix.bridge as registered by Motrix.
// background.js - Extension side implementation
function sendToMotrix(url, filename, options = {}) {
const payload = {
url: url,
filename: filename,
options: options // e.g., { referer: "https://example.com/" }
};
chrome.runtime.sendNativeMessage(
'app.motrix.bridge', // Must match the manifest name
payload,
(response) => {
if (chrome.runtime.lastError) {
console.error('Native messaging error:', chrome.runtime.lastError);
} else {
console.log('Motrix queued download:', response);
}
}
);
}
Native-Messaging Manifest
During installation, Motrix executes the logic in src/main/bridge/native-messaging-installer.ts to generate app.motrix.bridge.json and copy the native binary into the application resources. The manifest specifies the host binary path and allowed extension IDs.
{
"name": "app.motrix.bridge",
"description": "Motrix download bridge",
"path": "/Applications/Motrix.app/Contents/Resources/bin/motrix-native-host",
"type": "stdio",
"allowed_origins": [
"chrome-extension://your-extension-id/",
"chrome-extension://edge-extension-id/"
]
}
On macOS, the installer writes this file to ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/. On Linux, it targets ~/.config/google-chrome/NativeMessagingHosts/ and ~/.mozilla/native-messaging-hosts/. Windows installations use registry keys under HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\.
Native Host Binary
The native host is a Rust executable compiled from packages/native-host/src/main.rs. It handles the stdio-based protocol required by browser native messaging: reading length-prefixed JSON messages from stdin and writing responses to stdout.
use std::io::{self, BufRead, Write};
use serde::Deserialize;
#[derive(Deserialize)]
struct DownloadRequest {
url: String,
filename: String,
#[serde(default)]
options: serde_json::Value,
}
fn main() -> io::Result<()> {
// Native messaging protocol: read JSON line from stdin
let stdin = io::stdin();
let request: DownloadRequest = serde_json::from_reader(stdin.lock())?;
// Connect to Motrix via local Unix socket
let mut stream = std::os::unix::net::UnixStream::connect("/tmp/motrix.sock")?;
let cmd = serde_json::json!({
"cmd": "add",
"url": request.url,
"filename": request.filename,
"options": request.options
});
stream.write_all(cmd.to_string().as_bytes())?;
stream.flush()?;
// Return success response to browser
let response = serde_json::json!({ "status": "ok", "task": "queued" });
println!("{}", response);
Ok(())
}
The actual production binary includes additional error handling, logging, and cross-platform IPC abstraction for Windows named pipes.
Motrix IPC Listener
Motrix's main Electron process creates a local server to receive commands from the native host. The implementation in src/main/engine/aria2-service.ts parses the incoming JSON and interfaces with the Aria2 RPC client.
import net from 'net';
import { addDownload } from './aria2-service';
const IPC_SOCKET_PATH = process.platform === 'win32'
? '\\\\.\\pipe\\motrix-ipc'
: `${process.env.XDG_RUNTIME_DIR || '/tmp'}/motrix.sock`;
const server = net.createServer((socket) => {
let data = '';
socket.on('data', chunk => data += chunk);
socket.on('end', () => {
try {
const msg = JSON.parse(data);
if (msg.cmd === 'add') {
// Forward to Aria2 engine
addDownload(msg.url, { out: msg.filename, ...msg.options });
socket.write(JSON.stringify({ status: 'queued' }));
}
} catch (e) {
socket.write(JSON.stringify({ status: 'error', message: e.message }));
}
socket.end();
});
});
server.listen(IPC_SOCKET_PATH, () => {
console.log(`Native messaging IPC listening on ${IPC_SOCKET_PATH}`);
});
Key Source Files
The native-messaging bridge is implemented across several critical files in the agalwood/Motrix repository:
-
src/main/bridge/native-messaging-installer.ts: Generates theapp.motrix.bridge.jsonmanifest and installs it to browser-specific directories for Chrome, Edge, and Firefox. Handles cross-platform path resolution for macOS, Linux, and Windows. -
src/main/bridge/native-messaging-installer.test.ts: Unit tests verifying correct manifest paths and permissions across supported platforms and browsers. -
packages/native-host/src/main.rs: The Rust source for themotrix-native-hostbinary, implementing the stdio-based native messaging protocol and local IPC client. -
src/main/engine/aria2-service.ts: Core service that receives IPC messages from the native host and translates them into Aria2 RPC calls usingaria2.addUri. -
tests/scripts/snap-project.test.ts: Validates that the Snap package includes the native-host binary and declares thebrowser-native-messagingplug for sandboxed Linux environments. -
tests/scripts/snap-artifact.test.ts: Inspects the built Snap artifact to ensure the native-messaging manifest entries are correctly bundled for Chrome and Firefox.
Summary
- Browser extensions communicate with Motrix using the standard Native Messaging API, calling
chrome.runtime.sendNativeMessagewith the host nameapp.motrix.bridge. - The
motrix-native-hostRust binary acts as the intermediary, reading JSON from browser stdin and forwarding commands to Motrix via local IPC. - Manifest installation is handled automatically by
src/main/bridge/native-messaging-installer.ts, which registers the host with Chrome, Edge, and Firefox during Motrix's initial launch. - Motrix receives download requests through a local Unix socket or Windows named pipe, eliminating network overhead and keeping communication confined to the local machine.
- The download is ultimately created by
aria2-service.ts, which wraps the Aria2 RPC interface to start the actual file transfer.
Frequently Asked Questions
What is the native messaging host name used by Motrix?
Motrix registers its native host under the identifier app.motrix.bridge. Browser extensions must use this exact string when calling chrome.runtime.sendNativeMessage or browser.runtime.sendNativeMessage to establish communication with the download manager.
Which browsers support sending downloads to Motrix via native messaging?
The implementation in src/main/bridge/native-messaging-installer.ts supports Google Chrome, Microsoft Edge, and Mozilla Firefox across macOS, Linux, and Windows. The installer writes the appropriate manifest files to each browser's NativeMessagingHosts directory (or registry on Windows) during the first run of Motrix.
How does Motrix handle the download request after receiving it from the browser?
Once the native host forwards the message via local IPC, Motrix's main process parses the JSON command in the IPC listener and invokes the addDownload() function defined in src/main/engine/aria2-service.ts. This function constructs an Aria2 RPC payload and calls aria2.addUri with the URL, output filename, and any additional options (such as referer headers) provided by the extension.
Where is the native messaging manifest installed on different operating systems?
According to the source code in native-messaging-installer.ts, Motrix installs app.motrix.bridge.json to the following locations:
- macOS:
~/Library/Application Support/Google/Chrome/NativeMessagingHosts/(Chrome/Edge) and~/Library/Application Support/Mozilla/NativeMessagingHosts/(Firefox) - Linux:
~/.config/google-chrome/NativeMessagingHosts/and~/.mozilla/native-messaging-hosts/ - Windows: Registry keys under
HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\and corresponding Firefox registry paths.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →