# How Read Frog's Site Control Mechanages Extension Behavior with Whitelisting and Blacklisting

> Learn how Read Frog's site control, using whitelisting and blacklisting, manages extension behavior on websites. Understand its flexible configuration for targeted content script execution.

- Repository: [MengXi/read-frog](https://github.com/mengxi-ream/read-frog)
- Tags: internals
- Published: 2026-03-07

---

**Read Frog's site control mechanism uses a configuration object with `mode` and `patterns` fields to determine whether content scripts run on specific websites, supporting both universal activation ("all" mode) and domain-specific whitelisting.**

Read Frog implements a granular site control system that governs where its browser extension activates. The mechanism, defined in the repository's configuration schema and utility modules, allows users to either enable the extension globally or restrict it to specific domains through pattern matching.

## Core Components of the Site Control System

### Configuration Schema and Data Structure

The site control configuration is defined in [`src/types/config/config.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/types/config/config.ts) (lines 76-80). The `siteControl` object contains two critical fields:

- **`mode`**: Accepts either `"all"` or `"whitelist"`. When set to `"all"`, the extension activates on every website. When set to `"whitelist"`, activation depends on pattern matching.
- **`patterns`**: An array of domain strings (e.g., `example.com`, `sub.example.com`) that define permitted domains when operating in whitelist mode.

### The Site Enablement Logic

The core decision logic resides in [`src/utils/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/site-control.ts) (lines 4-15). The `isSiteEnabled` function evaluates whether a given URL should trigger extension behavior:

```typescript
export function isSiteEnabled(url: string, config: Config | null): boolean {
  if (!config) return true;
  const { mode, patterns } = config.siteControl;
  if (mode === "all") return true;
  // whitelist mode – enable only if a pattern matches
  return patterns.some(pattern => matchDomainPattern(url, pattern));
}

```

Content scripts throughout the extension import this utility and abort initialization if the site fails the check:

```typescript
import { isSiteEnabled } from "@/utils/site-control";
import { getLocalConfig } from "@/utils/config/storage";
import { DEFAULT_CONFIG } from "@/utils/constants/config";

const config = await getLocalConfig() ?? DEFAULT_CONFIG;

if (!isSiteEnabled(window.location.href, config)) {
  // Extension will stay dormant on this page
  return;
}

// …continue initializing UI…

```

## Domain Pattern Matching Implementation

The pattern matching algorithm is implemented in [`src/utils/url.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/url.ts) (lines 3-20). The `matchDomainPattern` function normalizes both the URL and pattern, then checks for either an exact hostname match or a subdomain relationship:

```typescript
// matchDomainPattern handles cases like:
// pattern: "example.com" matches "example.com" and "sub.example.com"
// but does not match "badexample.com"

```

This implementation allows users to specify broad domain coverage (e.g., `github.com` covers both `github.com` and `gist.github.com`) without requiring explicit subdomains in the pattern list.

## User Interface and State Management

### Popup Atoms for Whitelist Control

The popup interface manages whitelist state using Jotai atoms defined in [`src/entrypoints/popup/atoms/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/entrypoints/popup/atoms/site-control.ts). Two primary atoms track the current configuration:

- **`isWhitelistModeAtom`**: Boolean indicating whether `mode === "whitelist"`
- **`isCurrentSiteInWhitelistAtom`**: Boolean indicating whether the active tab's URL matches any pattern in the current whitelist

The `initSiteControlAtomsAtom` initializes these values by reading the stored configuration when the popup loads (lines 25-32).

### Toggling Site Inclusion

The `toggleCurrentSiteInWhitelistAtom` handles adding or removing the current site's hostname from the `siteControl.patterns` array (lines 35-75). When a user enables the extension for the current site:

```typescript
import { toggleCurrentSiteInWhitelistAtom } from "@/entrypoints/popup/atoms/site-control";
import { useSetAtom } from "jotai/react";

const toggle = useSetAtom(toggleCurrentSiteInWhitelistAtom);

// When a user checks the "Enable on this site" switch:
await toggle(true); // adds hostname to config.siteControl.patterns

```

After updating the configuration, the atom triggers a page reload of the active tab. This ensures content scripts re-evaluate `isSiteEnabled` with the updated pattern list, immediately activating the extension on the newly whitelisted domain.

## Persistence and Storage

The site control configuration persists across browser sessions using extension storage helpers in [`src/utils/config/storage.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/config/storage.ts). The `getLocalConfig` function retrieves the stored configuration on startup, while updates write back to Chrome or Firefox extension storage.

When users modify the whitelist through the popup, the Jotai atoms update both the in-memory state and the persistent storage, ensuring that content scripts loading on subsequent page visits respect the latest site control settings.

## Implementation in Content Scripts

Every content script entry point (such as the side panel in [`src/entrypoints/side.content/index.tsx`](https://github.com/mengxi-ream/read-frog/blob/main/src/entrypoints/side.content/index.tsx)) implements the site control check before rendering any UI components. This pattern prevents the extension from injecting elements into pages where the user has not authorized activity, or conversely, ensures activation on permitted domains when whitelist mode is active.

The check occurs early in the script lifecycle to minimize performance impact on non-target pages.

## Summary

- Read Frog's site control mechanism relies on a `siteControl` configuration object with `mode` and `patterns` fields defined in [`src/types/config/config.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/types/config/config.ts).
- The `isSiteEnabled` function in [`src/utils/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/site-control.ts) implements the core logic, returning `true` for all sites when `mode` is `"all"`, or checking domain patterns when `mode` is `"whitelist"`.
- Domain matching uses the `matchDomainPattern` helper in [`src/utils/url.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/url.ts), supporting exact matches and subdomain wildcards.
- The popup UI manages whitelist state through Jotai atoms in [`src/entrypoints/popup/atoms/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/entrypoints/popup/atoms/site-control.ts), allowing users to toggle the current site and trigger page reloads.
- Configuration persists via extension storage helpers in [`src/utils/config/storage.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/config/storage.ts), ensuring site control settings survive browser restarts.
- Content scripts check `isSiteEnabled` before initialization to respect user preferences.

## Frequently Asked Questions

### How does Read Frog determine if a website is whitelisted?

Read Frog uses the `isSiteEnabled` function in [`src/utils/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/site-control.ts) to evaluate the current URL against the stored configuration. When `siteControl.mode` is set to `"whitelist"`, the function iterates through the `patterns` array and uses `matchDomainPattern` from [`src/utils/url.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/url.ts) to check if the hostname matches any pattern exactly or as a subdomain.

### Can Read Frog block specific sites while allowing all others?

The current implementation does not include a dedicated blacklist mode. To achieve blacklist-like behavior, users must set `siteControl.mode` to `"whitelist"` and include all desired domains in the `patterns` array while omitting the sites they wish to block. The extension will then remain inactive on any domain not explicitly listed.

### Where is the site control configuration stored?

The configuration persists in the browser's extension storage using helpers defined in [`src/utils/config/storage.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/utils/config/storage.ts). The `getLocalConfig` function retrieves settings on startup, and the Jotai atoms in [`src/entrypoints/popup/atoms/site-control.ts`](https://github.com/mengxi-ream/read-frog/blob/main/src/entrypoints/popup/atoms/site-control.ts) write updates back to storage whenever users modify the whitelist through the popup interface.

### How does the extension update when I change the whitelist?

When you toggle a site's inclusion via the popup, the `toggleCurrentSiteInWhitelistAtom` updates the configuration and triggers a reload of the active tab. This reload causes content scripts to re-execute, calling `isSiteEnabled` with the updated `siteControl.patterns` array, which immediately activates or deactivates the extension for that site.