Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/botnadzor/extension/llms.txt

Use this file to discover all available pages before exploring further.

The Botnadzor extension is built with WXT and follows the standard browser extension architecture with three distinct entrypoints that work together to provide bot detection functionality on VK.com.

Architecture Overview

The extension consists of three main entrypoints:
  • Background Service Worker — Manages services, state, and communication
  • Content Script — Injects UI elements and modifies the DOM on VK.com pages
  • Popup — Provides the extension’s user interface when clicking the extension icon

Background Service Worker

The background entrypoint (src/entrypoints/background.ts) runs as a persistent service worker and serves as the central hub for:
  • Service Registration — Initializes and registers all proxy services
  • State Management — Manages authentication, configuration, and static lists
  • Cross-Context Communication — Facilitates communication between content scripts and popup

Service Initialization

The background script registers 13 services using @webext-core/proxy-service:
src/entrypoints/background.ts
import { registerService } from "@webext-core/proxy-service";

// Initialize service instances
const authService = new AuthService({
  aliasManagerForDynamicApi,
});

const staticListsService = new StaticListsService({
  aliasManagerForStaticApi,
  rootConfigService,
});

// Register services for cross-context access
registerService(authServiceKey, authService);
registerService(staticListsServiceKey, staticListsService);
// ... 11 more services

Registered Services

All services are registered at startup:
ServicePurpose
AffiliationServiceChecks account affiliations (bot/spam lists)
AuthServiceManages access code authentication
CollectingServiceCollects comment data for analysis
DxConfigServiceDeveloper experience configuration
ExtensionVersionServiceTracks extension version and updates
FrontendServiceManages frontend base URL
InspectorServiceProvides comment inspection tools
NotificationServiceBrowser notifications
PopupServicePopup state management
RegDateServiceFetches VK registration dates
RootConfigServiceRemote configuration management
StaticListsServiceBot/spam list management
UserConfigServiceUser preferences
See Proxy Services for detailed information about service communication.

Background Orchestration

The background script orchestrates long-running tasks:
src/entrypoints/background.ts
// Monitor and update alias managers when config changes
void orchestrateAliasManagers({
  aliasManagerForDynamicApi,
  aliasManagerForFrontend,
  aliasManagerForStaticApi,
  rootConfigService,
});

// Populate static lists when configuration is ready
void populateInitialStaticListsIfNeeded({
  rootConfigService,
  staticListsService,
});

// Persist collected comments before service worker suspension
browser.runtime.onSuspend.addListener(() => {
  void collectingService.persistRegisteredCommentsIfNeeded();
});

Content Script

The content script (src/entrypoints/content.ts) runs on VK.com pages and is responsible for:
  • DOM Modification — Injects UI elements into the page
  • Page Analysis — Detects page type and extracts relevant information
  • Insertion Management — Manages the lifecycle of UI insertions

Content Script Initialization

src/entrypoints/content.ts
export default defineContentScript({
  matches: contentScriptMatches,
  cssInjectionMode: "manual",

  async main(ctx) {
    configureLogging();

    const contentId = setupContentId();
    const derivedPageInfo = derivePageInfo(window.location);

    if (!derivedPageInfo) {
      logger.info("Content script does not apply to this page, exiting");
      return;
    }

    // Start managing DOM insertions
    void startManagingInsertions({ contentId, ...derivedPageInfo });

    // Developer overlays (DX features)
    if (getAppConfig().dxFeaturesEnabled) {
      void startManagingDxOverlays();
    }

    // Start in-page app for isolated UI
    await startInPageApp(contentId, ctx);
  },
});

Persistent Content ID

The content script uses a persistent ID system to maintain state across page reloads:
src/entrypoints/content.ts
function setupContentId(): ContentId {
  if (!getAppConfig().persistentContentIdEnabled) {
    return contentIdSchema.parse(undefined);
  }

  const contentId = contentIdSchema.parse(window.name);

  if (!window.name) {
    // Set window.name to preserve state on reload
    window.name = contentId;
    logger.debug("Setting empty window.name to content id {contentId}", {
      contentId,
    });
  }

  return contentId;
}
This allows features like the inspector to maintain their triggered state when the user refreshes the page.

DOM Insertion System

The content script uses a config-driven insertion system to modify the VK.com DOM. See Insertion System for details. The popup entrypoint (src/entrypoints/popup/app.tsx) provides the extension’s main UI:
  • React Application — Built with React and TypeScript
  • Tab-Based Interface — Multiple tabs (Stats, Config, Announcements, Access)
  • Service Integration — Communicates with background services via proxy-service
src/entrypoints/popup/app.tsx
import * as React from "react";
import * as ReactDOM from "react-dom/client";

function startPopupApp() {
  configureLogging();

  const rootElement = document.querySelector("#root");
  if (!rootElement) {
    logger.error("Root element not found");
    return;
  }

  // Dark theme support
  const darkThemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
  document.documentElement.classList.toggle(
    "dark-theme",
    darkThemeQuery.matches,
  );

  darkThemeQuery.addEventListener("change", (event) => {
    document.documentElement.classList.toggle("dark-theme", event.matches);
  });

  ReactDOM.createRoot(rootElement).render(
    <React.StrictMode>
      <TooltipProvider>
        <div className="absolute inset-0 flex flex-col">
          <Header />
          <div className="flex flex-1 overflow-hidden">
            <Sidebar />
            <ActiveTab />
          </div>
        </div>
      </TooltipProvider>
    </React.StrictMode>,
  );
}

startPopupApp();
  • Stats Tab — Extension usage statistics and insights
  • Config Tab — User preferences and configuration options
  • Announcements Tab — Important updates and announcements
  • Access Tab — Authentication and access code management

Styling Conventions

The popup uses standard Tailwind CSS classes without prefixes:
<div className="flex flex-col gap-4 p-6">
  {/* Popup UI components */}
</div>
Unlike content script insertions which require the bn: prefix, the popup uses unprefixed Tailwind classes because it runs in an isolated context.

Communication Flow

All three entrypoints communicate using the @webext-core/proxy-service library:
// Content script accessing a background service
import { staticListsService } from "@/shared/proxy-services";

const insertions = await staticListsService.getItems("insertions");
See Proxy Services for detailed information about cross-context communication.

Next Steps

Insertion System

Learn how the content script modifies the VK.com DOM

Proxy Services

Understand cross-context communication

Build docs developers (and LLMs) love