This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: capacitor-7-native-webview-batching-backpressure

Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail

High-frequency native notifications in Capacitor 7 overwhelm the single-threaded WebView event loop, causing runaway V8/JavaScriptCore heap allocation, dropped frames, and mobile OS memory terminations (Jetsam/LMK). This guardrail mandates bounded sliding-window batching, cooperative pull-based backpressure, and queue-overflow shedding strategies across the native-to-JS bridge interface.

Prohibited Anti-Pattern: Unbounded fire-and-forget native telemetry flooding the Capacitor JS bridge without backpressure

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail - High-frequency native notifications in Capacitor 7 overwhelm the single-threaded WebView event loop, causing runaway V8/JavaScriptCore heap allocation, dropped frames, and mobile OS memory terminations (Jetsam/LMK). This guardrail mandates bounded sliding-window batching, cooperative pull-based backpressure, and queue-overflow shedding strategies across the native-to-JS bridge interface.
globs: src/**/*.{ts,tsx}, ios/App/App/**/*.swift, android/app/src/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/capacitor-7-native-webview-batching-backpressure"
---

# Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unbounded fire-and-forget native telemetry flooding the Capacitor JS bridge without backpressure

## System Constraints
You are a Principal Mobile Architect enforcing strict throughput boundaries and cooperative backpressure on Capacitor 7 native-to-WebView communication channels. High-frequency sensors (BLE, IMU, GPS, audio PCM, network telemetry) must never emit individual unthrottled notifyListeners() calls into the WebView. You must enforce discrete batch windows, maximum ring-buffer queue depths, drop-oldest eviction semantics, and pull-based consumer acknowledgments before scheduling additional native bridge transfers.

## Strict Guidelines
- Engineers MUST ALWAYS aggregate high-frequency native telemetry into micro-batches using fixed time windows (e.g., 16ms-50ms) or maximum batch sizes before crossing the Capacitor bridge.
- Engineers MUST NOT allow native plugins to invoke notifyListeners() on raw hardware sensor callbacks without bounded queue validation and rate limiting.
- Code SHOULD implement an explicit backpressure acknowledgment token where the WebView signals ready-state before native queues dispatch subsequent payload batches.
- Services MUST enforce a DROP_OLDEST or DROP_LATEST eviction policy when bridge queue capacity exceeds safe operational thresholds (default max depth: 1000 items).
- Components NEVER attach direct React/Vue state updates directly to raw Capacitor plugin listeners without debouncing, batching, or running through requestAnimationFrame.

## Bad vs Good Implementations
### Native Plugin Streaming vs. Bounded Batch Flow Control

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Raw continuous sampling fires hundreds of times per second. Capacitor must serialize each event to JSON and dispatch evaluateJavascript or postMessage across the IPC bridge. This rapidly exhausts the single-threaded JS run loop, balloons memory allocation, causes severe GC pauses, and triggers iOS Jetsam or Android LowMemoryKiller terminations.
```typescript
import { PluginListenerHandle } from '@capacitor/core';
import { SensorPlugin, TelemetryReading } from './definitions';

export class TelemetryConsumer {
  private listener: PluginListenerHandle | null = null;

  // BAD: Every single high-frequency hardware event fires across the bridge,
  // immediately allocating in V8 heap and blocking the WebView main thread.
  async startStreaming(onData: (reading: TelemetryReading) => void): Promise<void> {
    this.listener = await SensorPlugin.addListener('rawTelemetry', (reading) => {
      onData(reading);
    });
    await SensorPlugin.startContinuousSampling();
  }

  async stopStreaming(): Promise<void> {
    await this.listener?.remove();
    await SensorPlugin.stopContinuousSampling();
  }
}
```

#### Production Standard (Correct)
> **Standard**: The native layer compresses events into timestamped batches, respecting configured window intervals and max element counts. The WebView acknowledges processed sequence IDs, creating backpressure that forces the native layer to retain or shed data according to an explicit eviction policy rather than thrashing the JavaScript thread.
```typescript
import { PluginListenerHandle } from '@capacitor/core';
import { SensorPlugin, TelemetryBatch } from './definitions';

interface StreamOptions {
  readonly maxBufferSize?: number;
  readonly flushIntervalMs?: number;
}

export class TelemetryConsumer {
  private listener: PluginListenerHandle | null = null;
  private isProcessing = false;
  private pendingQueue: TelemetryBatch[] = [];
  private readonly MAX_QUEUE_DEPTH = 50;

  // GOOD: Coordinates pull/ack backpressure with native batching
  async startStreaming(
    onBatch: (readings: TelemetryBatch) => Promise<void>,
    options: StreamOptions = {}
  ): Promise<void> {
    const flushInterval = options.flushIntervalMs ?? 33; // Align to ~30 FPS

    this.listener = await SensorPlugin.addListener('telemetryBatch', async (batch: TelemetryBatch) => {
      if (this.pendingQueue.length >= this.MAX_QUEUE_DEPTH) {
        // Drop oldest to preserve WebView responsiveness under severe load
        this.pendingQueue.shift();
      }
      this.pendingQueue.push(batch);
      this.drainQueue(onBatch);
    });

    await SensorPlugin.configureStream({
      batchWindowMs: flushInterval,
      maxBatchSize: 100,
      dropPolicy: 'dropOldest'
    });
    await SensorPlugin.startContinuousSampling();
  }

  private async drainQueue(processBatch: (readings: TelemetryBatch) => Promise<void>): Promise<void> {
    if (this.isProcessing) return;
    this.isProcessing = true;

    try {
      while (this.pendingQueue.length > 0) {
        const currentBatch = this.pendingQueue.shift();
        if (currentBatch) {
          await processBatch(currentBatch);
          // Cooperative acknowledgment releases native queue lock
          await SensorPlugin.acknowledgeBatch({ sequenceId: currentBatch.sequenceId });
        }
      }
    } finally {
      this.isProcessing = false;
    }
  }

  async stopStreaming(): Promise<void> {
    await this.listener?.remove();
    this.pendingQueue = [];
    await SensorPlugin.stopContinuousSampling();
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail

Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail defines an industrial-grade behavioral standard for mobile engineering. High-frequency native notifications in Capacitor 7 overwhelm the single-threaded WebView event loop, causing runaway V8/JavaScriptCore heap allocation, dropped frames, and mobile OS memory terminations (Jetsam/LMK). This guardrail mandates bounded sliding-window batching, cooperative pull-based backpressure, and queue-overflow shedding strategies across the native-to-JS bridge interface. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Unbounded fire-and-forget native telemetry flooding the Capacitor JS bridge without backpressure Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftUnbounded fire-and-forget native telemetry flooding the Capacitor JS bridge without backpressureCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS aggregate high-frequency native telemetry into micro-batches using fixed time windows (e.g., 16ms-50ms) or maximum batch sizes before crossing the Capacitor bridge.

Engineers MUST ALWAYS aggregate high-frequency native telemetry into micro-batches using fixed time windows (e.g., 16ms-50ms) or maximum batch sizes before crossing the Capacitor bridge.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT allow native plugins to invoke notifyListeners() on raw hardware sensor callbacks without bounded queue validation and rate limiting.

Engineers MUST NOT allow native plugins to invoke notifyListeners() on raw hardware sensor callbacks without bounded queue validation and rate limiting.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code SHOULD implement an explicit backpressure acknowledgment token where the WebView signals ready-state before native queues dispatch subsequent payload batches.

Code SHOULD implement an explicit backpressure acknowledgment token where the WebView signals ready-state before native queues dispatch subsequent payload batches.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST enforce a DROP_OLDEST or DROP_LATEST eviction policy when bridge queue capacity exceeds safe operational thresholds (default max depth

Services MUST enforce a DROP_OLDEST or DROP_LATEST eviction policy when bridge queue capacity exceeds safe operational thresholds (default max depth: 1000 items).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER attach direct React/Vue state updates directly to raw Capacitor plugin listeners without debouncing, batching, or running through requestAnimationFrame.

Components NEVER attach direct React/Vue state updates directly to raw Capacitor plugin listeners without debouncing, batching, or running through requestAnimationFrame.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Capacitor 7 Native-to-WebView Message Batching & Reactive Backpressure Guardrail critical for AI coding assistants?

High-frequency native notifications in Capacitor 7 overwhelm the single-threaded WebView event loop, causing runaway V8/JavaScriptCore heap allocation, dropped frames, and mobile OS memory terminations (Jetsam/LMK). This guardrail mandates bounded sliding-window batching, cooperative pull-based backpressure, and queue-overflow shedding strategies across the native-to-JS bridge interface. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Unbounded fire-and-forget native telemetry flooding the Capacitor JS bridge without backpressure) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

Capacitor