Content scripts
Content scripts are the most hostile place an extension runs. Your code shares a JavaScript context with a page you don’t control, that changes without warning, and that has its own bugs.
Other sites’ bugs stay out
Section titled “Other sites’ bugs stay out”A content script shares the host page’s window. So window.onerror fires for
the site’s own errors too — a broken analytics script on some news site
would land in your inbox as though it were yours.
CrxTrace only reports events with at least one stack frame inside your extension bundle. Everything else is dropped in the browser, before any send.
Two things follow from that, and the second matters more:
- You don’t drown in other people’s noise.
- Their stack traces never reach your server. A host page’s error can contain their internal file paths, function names, and sometimes user data. Collecting that because your content script happened to be loaded is a liability you don’t want.
Errors group by host
Section titled “Errors group by host”Every content script event carries the page’s host. A selector that breaks when one site redesigns becomes one issue on one host, rather than a flood of identical-looking errors from thousands of installs across hundreds of sites.
// This breaks the day the site ships a redesignconst title = document.querySelector(".video-title").textContent;Grouped by host, that reads as “example.com broke at 14:20 UTC, 400 users
affected” — which tells you what to fix and roughly when it started.
Only the host is used for grouping. Full URLs are truncated to origin + path, and query strings are dropped entirely unless you opt in. See Privacy.
Relaying through the worker
Section titled “Relaying through the worker”Content scripts never talk to your ingest endpoint directly. They forward events to the service worker, which owns the durable queue and does all sending.
content script ──relay──▶ service worker ──▶ durable queue ──▶ your endpointThis is deliberate:
- CSP. Many sites set a Content Security Policy that would block your request outright. The worker isn’t subject to the page’s CSP.
- Privacy. A cross-origin request from someone else’s page, carrying your API key, is visible to that page.
- Durability. One queue in one place. A content script is destroyed on every navigation; the worker’s queue survives.
You don’t configure any of this. init() detects the surface and wires it up.
Scoping which sites you collect from
Section titled “Scoping which sites you collect from”If your extension runs on a broad match pattern but you only care about a few sites — or must not collect from some — filter by host:
CrxTrace.init({ dsn: "...", allowHosts: ["app.example.com", /\.mycompany\.com$/], denyHosts: [/bank/, "internal.corp"],});denyHosts wins over allowHosts. Both accept strings and regular
expressions. See Filtering events.
Extension id normalization
Section titled “Extension id normalization”Stack frames pointing at chrome-extension://<id>/content.js are rewritten to
app:///content.js.
Every user’s install has a different id in unpacked development, and frames would otherwise never group — you’d get one issue per developer per bug. After normalization, one bug is one issue everywhere.
Related
Section titled “Related”- Privacy and redaction — what leaves the browser
- Filtering events —
allowHosts,denyHosts,beforeSend