# Streambert Ad Tracker Blocking Network Requests: A Deep Dive into the Architecture

> Discover how Streambert blocks ad tracker network requests using Electron's webRequest API. Learn about its static host filter list and real-time statistics for effective ad blocking.

- Repository: [true_lock/streambert](https://github.com/truelockmc/streambert)
- Tags: architecture
- Published: 2026-05-21

---

**Streambert blocks ads and trackers using Electron's `webRequest` API in the main process, employing a static host filter list combined with session-level interception and real-time statistics reporting to prevent advertising and analytics traffic from reaching the renderer.**

Streambert is an Electron-based media streaming client designed to strip advertising and tracking traffic before it ever reaches the webview. According to the [truelockmc/streambert](https://github.com/truelockmc/streambert) source code, the blocking logic operates entirely within the privileged main process across three tightly coupled layers: network filtering, session management, and statistics reporting.

## Static Block List Definition

The foundation of Streambert's ad blocking capability is the `BLOCKED_HOSTS` array defined in **[[`index.js`](https://github.com/truelockmc/streambert/blob/main/index.js)](https://github.com/truelockmc/streambert/blob/main/index.js#L46-L99)**. This static list contains approximately 50+ URL patterns targeting common analytics and advertising domains.

```javascript
const BLOCKED_HOSTS = [
  "*://www.google-analytics.com/*",
  "*://analytics.google.com/*",
  "*://googletagmanager.com/*",
  // … additional patterns
];

```

This array is initialized once at application startup and serves as the primary filter for the Electron `webRequest` API. Because `BLOCKED_HOSTS` is exported as a plain JavaScript array, it can be extended at runtime without requiring a rebuild of the application.

## Session-Level Request Interception

The **`setupSession`** function in **[[`index.js`](https://github.com/truelockmc/streambert/blob/main/index.js)](https://github.com/truelockmc/streambert/blob/main/index.js#L8-L85)** creates two persistent Electron sessions: `persist:player` and `persist:trailer`. Each session receives different filtering rules based on its purpose.

### Trailer Session Blocking

For trailer content, only the ad blocking rules apply:

```javascript
trailerSession.webRequest.onBeforeRequest(
  { urls: BLOCKED_HOSTS },
  (_, cb) => cb({ cancel: true })
);

```

### Player Session Blocking

The player session combines ad blocking with media URL interception for formats like `*.m3u8` and `*.vtt`. When a request matches a blocked host, it is cancelled immediately; otherwise, media URLs are forwarded to the renderer via IPC:

```javascript
playerSession.webRequest.onBeforeRequest(
  { urls: [...BLOCKED_HOSTS, ...MEDIA_URLS] },
  (details, callback) => {
    // Cancel if blocked, forward if media
  }
);

```

This architecture ensures that advertising and tracking scripts never execute in the renderer, while legitimate media streams flow through to the player components.

## Recording and Persisting Blocked Requests

When the `onBeforeRequest` handler cancels a request, it triggers **`recordBlockedRequest(url)`** in **[[`src/ipc/blockStats.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/blockStats.js)](https://github.com/truelockmc/streambert/blob/main/src/ipc/blockStats.js)** (lines 48-82). This function:

1. Parses the hostname from the blocked URL
2. Updates in-memory counters (total and per-domain)
3. Debounces IPC updates to the UI (every 250ms)
4. Debounces disk persistence (every 3 seconds to minimize I/O overhead)

The statistics are stored in **[`blockStats.json`](https://github.com/truelockmc/streambert/blob/main/blockStats.json)** within the user's data directory, ensuring counts survive application restarts.

## UI Integration and Real-Time Reporting

The renderer process receives updates through the **`useBlockedStats`** hook in **[[`src/utils/useBlockedStats.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/useBlockedStats.js)](https://github.com/truelockmc/streambert/blob/main/src/utils/useBlockedStats.js)**. This React hook listens to the `blocked-stats-update` IPC channel and merges incremental batches into component state.

The **[[`BlockedStatsModal.jsx`](https://github.com/truelockmc/streambert/blob/main/BlockedStatsModal.jsx)](https://github.com/truelockmc/streambert/blob/main/src/components/BlockedStatsModal.jsx)** component displays both the aggregate blocked count and a per-domain breakdown, providing users with transparent visibility into exactly how many ad and tracker requests have been prevented.

## Practical Implementation Examples

### Adding Custom Hosts to the Block List

Extend the blocking capabilities at runtime by pushing new patterns to the exported array:

```javascript
// After app is ready
const { session } = require('electron');
const { BLOCKED_HOSTS } = require('../index');

BLOCKED_HOSTS.push('*://ads.example.com/*');

const playerSession = session.fromPartition('persist:player');
playerSession.webRequest.onBeforeRequest(
  { urls: BLOCKED_HOSTS },
  (_, cb) => cb({ cancel: true })
);

```

### Accessing Statistics in the Renderer

Use the provided hook to display real-time blocking data:

```jsx
import { useBlockedStats } from '../utils/useBlockedStats';

export default function StatsPanel() {
  const { total, domains } = useBlockedStats();
  
  return (
    <div>
      <strong>Blocked:</strong> {total}
      <ul>
        {Object.entries(domains).map(([domain, count]) => (
          <li key={domain}>{domain}: {count}</li>
        ))}
      </ul>
    </div>
  );
}

```

### Resetting Block Statistics

Clear accumulated data from the main process:

```javascript
const blockStats = require('./src/ipc/blockStats');
const fs = require('fs');
const path = require('path');
const { app } = require('electron');

// Option 1: Reload from disk (clears memory)
blockStats.loadBlockStats();

// Option 2: Delete persistence file
fs.unlinkSync(path.join(app.getPath('userData'), 'blockStats.json'));

```

## Summary

- **Static filtering**: The `BLOCKED_HOSTS` array in [`index.js`](https://github.com/truelockmc/streambert/blob/main/index.js) defines URL patterns for known ad and analytics domains.
- **Session isolation**: Separate Electron sessions (`persist:player`, `persist:trailer`) receive appropriate filtering rules via `setupSession`.
- **Request cancellation**: The `webRequest.onBeforeRequest` API cancels matching requests before they reach the renderer.
- **Statistics tracking**: The `recordBlockedRequest` function in [`blockStats.js`](https://github.com/truelockmc/streambert/blob/main/blockStats.js) maintains counters with debounced IPC updates (250ms) and disk writes (3s).
- **UI transparency**: The `useBlockedStats` hook streams data to React components, displaying total and per-domain blocked counts.

## Frequently Asked Questions

### How does Streambert prevent ads from loading without breaking video content?

Streambert distinguishes between ad/tracker requests and legitimate media streams by using separate URL pattern arrays. The `BLOCKED_HOSTS` filter blocks analytics and advertising domains, while `MEDIA_URLS` (containing patterns like `*.m3u8` and `*.vtt`) allows video manifests and subtitles to pass through. This selective filtering happens in the main process before any content reaches the renderer.

### Can users customize which domains are blocked in Streambert?

Yes. Because `BLOCKED_HOSTS` is exported as a mutable array from [`index.js`](https://github.com/truelockmc/streambert/blob/main/index.js), users or extensions can push additional patterns at runtime. After modifying the array, the new patterns can be applied to existing sessions by re-registering the `onBeforeRequest` handler with the updated URL list.

### Where does Streambert store the ad blocking statistics?

Block statistics are persisted to a JSON file named [`blockStats.json`](https://github.com/truelockmc/streambert/blob/main/blockStats.json) located in the Electron user data directory (retrieved via `app.getPath('userData')`). The data includes total blocked requests and a breakdown by domain, allowing the counter to survive application restarts.

### What is the performance impact of Streambert's request interception?

The implementation minimizes overhead through strategic debouncing. While request interception itself happens synchronously for every network call, statistics reporting uses a 250ms debounce for IPC updates to the renderer and a 3-second debounce for disk writes. This ensures that heavy media playback does not trigger excessive I/O operations or UI re-renders.