# How Browser Extensions Use Native Messaging to Send Downloads to Motrix

> Learn how browser extensions use native messaging to send downloads to Motrix. Discover the process of invoking chrome.runtime.sendNativeMessage and forwarding requests via local IPC.

- Repository: [Dr_rOot/Motrix](https://github.com/agalwood/Motrix)
- Tags: how-to-guide
- Published: 2026-08-19

---

**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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/src/main/bridge/native-messaging-installer.ts) |

## Message Flow

When a user initiates a download through the extension, the following sequence occurs:

1. **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.

2. **Browser Spawns Host**: The browser locates [`app.motrix.bridge.json`](https://github.com/agalwood/Motrix/blob/main/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**.

3. **Host Validates Input**: The `motrix-native-host` binary reads the single-line JSON message from stdin, deserializes it, and validates required fields (`url`, `filename`).

4. **IPC Forwarding**: The host opens a connection to Motrix's local IPC endpoint—a Unix domain socket at `$XDG_RUNTIME_DIR/motrix.sock` on Linux/macOS or a Windows named pipe (`\\.\pipe\motrix-ipc`).

5. **Download Creation**: Motrix's main process receives the message, parses the command, and invokes `addDownload()` in [`src/main/engine/aria2-service.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/engine/aria2-service.ts) to create an Aria2 task.

6. **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.

```javascript
// 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`](https://github.com/agalwood/Motrix/blob/main/src/main/bridge/native-messaging-installer.ts) to generate [`app.motrix.bridge.json`](https://github.com/agalwood/Motrix/blob/main/app.motrix.bridge.json) and copy the native binary into the application resources. The manifest specifies the host binary path and allowed extension IDs.

```json
{
  "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`](https://github.com/agalwood/Motrix/blob/main/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.

```rust
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`](https://github.com/agalwood/Motrix/blob/main/src/main/engine/aria2-service.ts) parses the incoming JSON and interfaces with the Aria2 RPC client.

```javascript
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`](https://github.com/agalwood/Motrix/blob/main/src/main/bridge/native-messaging-installer.ts)**: Generates the [`app.motrix.bridge.json`](https://github.com/agalwood/Motrix/blob/main/app.motrix.bridge.json) manifest 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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/packages/native-host/src/main.rs)**: The Rust source for the `motrix-native-host` binary, implementing the stdio-based native messaging protocol and local IPC client.

- **[`src/main/engine/aria2-service.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/engine/aria2-service.ts)**: Core service that receives IPC messages from the native host and translates them into Aria2 RPC calls using `aria2.addUri`.

- **[`tests/scripts/snap-project.test.ts`](https://github.com/agalwood/Motrix/blob/main/tests/scripts/snap-project.test.ts)**: Validates that the Snap package includes the native-host binary and declares the `browser-native-messaging` plug for sandboxed Linux environments.

- **[`tests/scripts/snap-artifact.test.ts`](https://github.com/agalwood/Motrix/blob/main/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.sendNativeMessage` with the host name `app.motrix.bridge`.
- The **`motrix-native-host`** Rust 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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/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`](https://github.com/agalwood/Motrix/blob/main/native-messaging-installer.ts), Motrix installs [`app.motrix.bridge.json`](https://github.com/agalwood/Motrix/blob/main/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.