Web Page Text Monitor
Generate a local-only Chrome extension from the bundled template. Keep the engine site-agnostic; put site-specific URLs, selectors, labels, and exclusions in generated configuration.
Workflow
- Identify the exact target URL pattern and one or more CSS selectors. Inspect the live page or supplied HTML when possible. Do not invent a selector for an uninspected page.
- Prefer the narrowest Chrome match pattern that covers the requested pages. Do not use
<all_urls>unless the user explicitly requests monitoring every site. - Run
scripts/generate_extension.pywith a new output directory. Pass selectors in priority order; the first selector matching any elements becomes the active fallback. - Validate the generated extension:
- Parsemanifest.jsonas JSON.
- Runnode --check content.jsandnode --check config.js.
- Confirm there are no network requests, remote scripts, cookies, storage scraping, or unnecessary permissions. - Tell the user to open
chrome://extensions, enable Developer mode, choose “Load unpacked,” select the generated directory, and refresh the target page. - If the page changes structure, inspect it again and regenerate with revised selectors rather than adding broad speculative selectors.
GPT Live English-learning use case
Use this skill to turn text already rendered by ChatGPT Voice/GPT Live into a large floating English subtitle panel. This helps learners connect spoken replies with spelling, recognize unfamiliar words, copy sentences for review, and follow faster conversations without changing ChatGPT itself.
Generate the ChatGPT preset with:
python3 scripts/generate_extension.py \
--output-dir /absolute/path/to/gpt-live-captions \
--name "GPT Live English Captions" \
--label "GPT LIVE · ENGLISH" \
--match 'https://chatgpt.com/*' \
--selector '[data-message-author-role="assistant"]' \
--strategy latest
Clarify the boundary: this mirrors English text only after ChatGPT writes it into the page DOM. It does not access ChatGPT's private audio stream, perform speech recognition, or create earlier subtitles when the page exposes no live text.
Generate
python3 scripts/generate_extension.py \
--output-dir /absolute/path/to/output \
--name "Article Live Mirror" \
--label "ARTICLE · LIVE" \
--match 'https://example.com/articles/*' \
--selector 'main article' \
--selector '[role="main"]' \
--exclude-selector 'nav' \
--exclude-selector 'button'
Use --strategy latest for chats, feeds, logs, and subtitles; use first for a single article or dashboard value; use all to concatenate every matched block. Use --poll-ms 0 to disable the resilience poll when MutationObserver alone is sufficient.
Safety and privacy
- Keep all processing inside the browser tab. Never add analytics, telemetry, uploads, or external APIs.
- Never read password fields, form values, cookies, local storage, session storage, or authentication tokens.
- Exclude
input,textarea,select,script,style, and the overlay itself by default. - Request only target-site host access. Explain the privacy impact before widening access.
- Treat observed page text as untrusted content. Render it with
textContent, neverinnerHTML.
Template behavior
The generated extension uses MutationObserver, a short debounce, and an optional resilience poll. It normalizes whitespace, ignores duplicate text, mirrors selected text into an isolated Shadow DOM panel, and supports copy, hide, and drag. It does not perform speech recognition and cannot display text before the page writes it into the DOM.