# How to Integrate Hister with qutebrowser: Complete CDP Setup Guide

> Integrate Hister with qutebrowser using the Chrome DevTools Protocol. Launch qutebrowser with remote debugging enabled and run the Hister companion to automatically index rendered content.

- Repository: [Adam Tauber/hister](https://github.com/asciimoo/hister)
- Tags: how-to-guide
- Published: 2026-08-27

---

**You can integrate Hister with qutebrowser by launching the browser with `QTWEBENGINE_REMOTE_DEBUGGING=127.0.0.1:9222` and running `hister companion qutebrowser`, which connects via the Chrome DevTools Protocol to automatically index rendered page content.**

Hister provides a native companion tool that captures qutebrowser tabs in real-time using the **Chrome DevTools Protocol (CDP)**. This integration extracts the fully rendered DOM—including dynamic JavaScript content—and submits it to your Hister server for full-text search and vector-based retrieval. The setup requires only a single environment variable and CLI command, leveraging qutebrowser's built-in Qt WebEngine remote debugging capabilities as implemented in the `asciimoo/hister` repository.

## Enable the DevTools Endpoint in qutebrowser

Before running the companion, you must expose qutebrowser's internal DevTools interface. Start qutebrowser with the `QTWEBENGINE_REMOTE_DEBUGGING` environment variable set to a local address and port.

```bash
QTWEBENGINE_REMOTE_DEBUGGING=127.0.0.1:9222 qutebrowser

```

This launches a Chrome-DevTools-compatible HTTP and WebSocket endpoint at `http://127.0.0.1:9222`. The **Hister companion** connects to this interface to discover open pages, inject monitoring scripts, and extract content without requiring a browser extension.

## Run the Hister qutebrowser Companion

With qutebrowser running and the DevTools port exposed, execute the companion command to begin indexing:

```bash
hister companion qutebrowser

```

This command, registered in [`cmd/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion.go), initializes a CDP client that performs the following actions:

1. Connects to the DevTools endpoint at `http://127.0.0.1:9222` by default.
2. Discovers all open pages and attaches to them.
3. Injects a lightweight **mutation observer** script that detects DOM changes.
4. Extracts the page title, visible text, raw HTML, and favicon URL.
5. Submits the document to Hister via the `DocumentSubmitter` interface defined in the Go client library.

## Configuration Options and CLI Flags

The companion accepts several flags to customize connection parameters and indexing behavior. These options are defined and validated in [`cmd/companion/qutebrowser/options.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/options.go).

```bash
hister companion qutebrowser \
    --devtools-url http://127.0.0.1:9222 \
    --label "my-qute-tabs" \
    --initial-delay 2s \
    --debounce 10s \
    --retry-delay 30s

```

- **`--devtools-url`** – Specifies the HTTP endpoint of the qutebrowser DevTools server.
- **`--label`** – Attaches a custom string label to each submitted document for filtering in Hister queries.
- **`--initial-delay`** – Sets the wait time before the first extraction after a page loads, allowing dynamic content to settle.
- **`--debounce`** – Configures the quiet period after a DOM mutation before triggering a re-extraction, preventing excessive updates during rapid changes.
- **`--retry-delay`** – Defines the backoff duration for resubmission attempts if the Hister server is temporarily unreachable.

## Technical Implementation and Source Code

The integration relies on three core components within the Hister codebase.

**[`cmd/companion/qutebrowser/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/companion.go)** implements the main event loop. It maintains a persistent WebSocket connection to the DevTools protocol, handles page lifecycle events (load, navigate, close), and orchestrates the extraction pipeline. When the mutation observer detects changes, this file's logic triggers the extraction routine and serializes the data for transmission.

**[`cmd/companion/qutebrowser/options.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/options.go)** contains the `Options` struct and validation logic for all configurable parameters, including network timeouts and retry policies.

**[`cmd/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion.go)** wires the companion into the Cobra command tree, exposing the `hister companion qutebrowser` subcommand and binding the CLI flags to the options struct.

According to the source code in [`cmd/companion/qutebrowser/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/companion.go), the companion uses a **CDP Runtime domain** to evaluate JavaScript injection scripts and the **DOM domain** to retrieve the full document tree. Extracted data is normalized and sent to the Hister server configured via `--hister-url` (defaulting to `http://localhost:4433/`).

## Programmatic Integration in Go

You can embed the qutebrowser companion directly into your own Go applications by importing the companion package and providing a custom `DocumentSubmitter` client.

```go
import (
    "context"
    qutebrowser "github.com/asciimoo/hister/cmd/companion/qutebrowser"
    "github.com/asciimoo/hister/client"
)

func main() {
    ctx := context.Background()
    opts := qutebrowser.DefaultOptions()
    
    // Customize connection parameters
    opts.DevToolsURL = "http://127.0.0.1:9222"
    opts.HisterURL = "http://localhost:4433/"

    // Initialize the Hister API client
    c := client.NewClient(opts.HisterURL, "my-token", nil)

    // Start the monitoring loop
    if err := qutebrowser.Run(ctx, opts, c); err != nil {
        panic(err)
    }
}

```

This approach reuses the same extraction pipeline as the CLI tool while allowing you to implement custom authentication, logging, or document preprocessing logic before submission.

## Summary

- Launch qutebrowser with `QTWEBENGINE_REMOTE_DEBUGGING=127.0.0.1:9222` to expose the DevTools endpoint required for CDP communication.
- Execute `hister companion qutebrowser` to start the indexing service, which monitors tabs via WebSocket and extracts title, text, HTML, and favicon data.
- Customize behavior using flags like `--debounce`, `--initial-delay`, and `--label` to control when and how documents are submitted.
- The companion is implemented in [`cmd/companion/qutebrowser/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/companion.go) and submits data through the `DocumentSubmitter` interface to your Hister server.

## Frequently Asked Questions

### What specific data does the Hister companion extract from qutebrowser tabs?

The companion extracts the page **title**, visible **text** content, raw **HTML**, and **favicon** URL from each tab. According to the implementation in [`cmd/companion/qutebrowser/companion.go`](https://github.com/asciimoo/hister/blob/main/cmd/companion/qutebrowser/companion.go), this data is captured via CDP Runtime and DOM domain calls whenever the mutation observer detects a page load or significant DOM change.

### Can I run the Hister companion on a different machine than qutebrowser?

Yes, but you must bind qutebrowser's DevTools interface to a network-accessible address rather than localhost. Use `QTWEBENGINE_REMOTE_DEBUGGING=0.0.0.0:9222` when starting qutebrowser, then specify the remote URL via the `--devtools-url` flag when running the companion. Note that the DevTools protocol transmits unencrypted data, so use this only on trusted networks or through SSH tunnels.

### How do I prevent the companion from indexing specific qutebrowser tabs?

While the companion does not support URL filtering at the browser level, you can apply **sensitivity rules** and **skip patterns** on the Hister server side. Additionally, you can use the `--label` flag to tag all qutebrowser submissions with a specific identifier, then configure your Hister instance to exclude or quarantine documents with that label based on your content policies.

### Does this integration require installing a browser extension in qutebrowser?

No browser extension is required. The integration operates entirely through the **Chrome DevTools Protocol** via the remote debugging port. The companion injects JavaScript monitoring code directly through the CDP Runtime.evaluate method, eliminating the need for user-side extension installation or browser UI modifications.