# How Sherlock's QueryNotify Notification System Enables Real-Time Updates

> Learn how Sherlock's QueryNotify system delivers real-time updates and live results to your terminal as HTTP requests complete. Enhance your Sherlock scan efficiency today.

- Repository: [Sherlock/sherlock](https://github.com/sherlock-project/sherlock)
- Tags: internals
- Published: 2026-03-02

---

**Sherlock's notification system uses an abstract `QueryNotify` base class and a concrete `QueryNotifyPrint` implementation to stream live results to the terminal as each asynchronous HTTP request completes, rather than waiting for the entire scan to finish.**

The **Sherlock QueryNotify notification system** powers the tool's live feedback during username investigations across hundreds of social platforms. In [`sherlock_project/sherlock.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/sherlock.py), the system instantiates a `QueryNotifyPrint` object that receives callbacks immediately after each site query resolves, delivering real-time status updates directly to the console.

## Architecture of the QueryNotify System

The notification architecture follows an **observer pattern** with three lifecycle hooks. According to the source code in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py), the base class defines the interface while the concrete implementation handles the actual rendering.

### The QueryNotify Base Class

Located in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py) (lines 14-30), the **`QueryNotify`** abstract class establishes the contract for all notifiers. It defines three methods that subclasses must override:

- `start(message)` – Called once when scanning begins
- `update(result)` – Invoked after every individual site check completes  
- `finish(message)` – Executed once when the batch finishes

The base implementation is intentionally minimal, allowing different output formats (JSON, CSV, silent mode) to extend the same interface.

### QueryNotifyPrint: The Real-Time Console Implementation

The **`QueryNotifyPrint`** class (lines 11-87 in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py)) provides the colorful terminal output users see during scans. Its constructor accepts three boolean flags that control verbosity:

- `verbose` – Appends response times in milliseconds
- `print_all` – Displays "not found" and error states, not just successful matches
- `browse` – Automatically opens discovered profiles in the default web browser

The `update()` method receives a **`QueryResult`** object containing the site name, URL, status code (`CLAIMED`, `AVAILABLE`, `WAF`, etc.), and timing data. It immediately prints a formatted line with color-coded symbols: green `+` for claimed usernames, red `-` for available ones, and yellow `!` for errors or WAF blocks.

## Integration with Asynchronous Scanning

The real-time behavior emerges from Sherlock's use of **`SherlockFuturesSession`** for concurrent HTTP requests. In [`sherlock_project/sherlock.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/sherlock.py) (lines 81-91), the core `sherlock()` function wraps each site query in a future. As soon as any future resolves, the code constructs a `QueryResult` and calls `query_notify.update(result)`.

Because threads complete independently based on network latency, **updates appear in the order responses arrive**, not the order sites were defined in the manifest. This creates the characteristic "live" scrolling effect where results from fast-responding sites appear before slower ones.

The lifecycle follows this sequence:

1. `main()` instantiates `QueryNotifyPrint` (lines 111-113 in [`sherlock_project/sherlock.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/sherlock.py))
2. `query_notify.start(username)` prints the header banner
3. Each completed future triggers `query_notify.update(result)` with real-time coloring
4. `query_notify.finish()` emits the final count (line 38 in `main()`)

## Configuration and Browser Integration

Users control the notification behavior through command-line arguments passed to the constructor:

```python
query_notify = QueryNotifyPrint(
    result=None,
    verbose=args.verbose,
    print_all=args.print_all,
    browse=args.browse,
)

```

When `--browse` (`-b`) is enabled, the `update()` method executes `webbrowser.open()` immediately upon finding a claimed username (lines 12-14 in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py)). This launches the profile URL in the default browser **before the scan completes**, providing instant access to discovered accounts.

The `countResults()` helper (using a global `globvar`) tracks how many claimed accounts have been printed. This tally drives the final summary line displayed by `finish()`, such as "Search completed with 12 results."

## Practical Implementation Example

To use the notification system programmatically outside the CLI:

```python
from sherlock_project.notify import QueryNotifyPrint
from sherlock_project.result import QueryResult, QueryStatus

# Initialize with full verbosity and browser auto-open

notifier = QueryNotifyPrint(verbose=True, print_all=True, browse=True)

# Signal scan start

notifier.start("target_user")

# Simulate a discovered account

github_result = QueryResult(
    username="target_user",
    site_name="GitHub",
    site_url_user="https://github.com/target_user",
    status=QueryStatus.CLAIMED,
    query_time=0.245,
)
notifier.update(github_result)  # Prints green + line, opens browser

# Simulate an available username

twitter_result = QueryResult(
    username="target_user",
    site_name="Twitter",
    site_url_user="https://twitter.com/target_user",
    status=QueryStatus.AVAILABLE,
    query_time=0.189,
)
notifier.update(twitter_result)  # Prints red - line (visible because print_all=True)

# Complete the scan

notifier.finish()  # Shows total count

```

This produces immediate terminal output identical to the standard Sherlock CLI experience, demonstrating how the **QueryNotify** abstraction decouples result generation from presentation.

## Summary

- **Sherlock's notification system** centers on the `QueryNotify` abstract base class in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py), which defines `start()`, `update()`, and `finish()` lifecycle methods.
- **`QueryNotifyPrint`** provides the concrete implementation that renders color-coded, real-time terminal output as each asynchronous HTTP request completes.
- The system integrates with **`SherlockFuturesSession`** to stream results immediately upon response arrival, rather than batching output at scan completion.
- Configuration flags (`verbose`, `print_all`, `browse`) control output detail and enable automatic browser opening for discovered profiles.
- The architecture separates concerns between result generation ([`sherlock.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock.py)) and presentation ([`notify.py`](https://github.com/sherlock-project/sherlock/blob/main/notify.py)), allowing future extensions for JSON, CSV, or webhook notifications.

## Frequently Asked Questions

### How does Sherlock print results immediately instead of waiting for the full scan?

Sherlock uses Python's `concurrent.futures` via `SherlockFuturesSession` to execute HTTP requests in parallel background threads. In [`sherlock_project/sherlock.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/sherlock.py), each completed future immediately calls `query_notify.update(result)`, which triggers `QueryNotifyPrint` to render the line to the terminal. This callback-based approach ensures output appears in real-time as network responses arrive, rather than collecting all results first.

### What do the different colors and symbols mean in Sherlock's output?

According to [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py), the `update()` method assigns visual indicators based on `QueryStatus`: a green `+` indicates a **claimed** username (profile found), a red `-` marks an **available** username (profile not found), and a yellow `!` signals errors, WAF blocks, or illegal characters. When `verbose=True`, response times in milliseconds appear after the site name.

### Can I use Sherlock's notification system for custom reporting or webhooks?

Yes. The `QueryNotify` base class in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py) provides a clean extension point. By subclassing `QueryNotify` and overriding `start()`, `update()`, and `finish()`, developers can redirect output to JSON logs, HTTP webhooks, or databases instead of the console. The `QueryNotifyPrint` implementation demonstrates the pattern for terminal output, but the abstraction supports any consumer that implements the three-method interface.

### Does the browser auto-open feature work during the scan or only at the end?

The browser opens **immediately upon discovery** when using the `--browse` flag. Inside `QueryNotifyPrint.update()`, the code checks `if self.browse and result.status == QueryStatus.CLAIMED` and executes `webbrowser.open()` synchronously (lines 12-14 in [`sherlock_project/notify.py`](https://github.com/sherlock-project/sherlock/blob/main/sherlock_project/notify.py)). This happens while other threads continue scanning remaining sites, providing instant access to profiles without waiting for the batch to complete.