Launch-readiness release. Phase 2: integration tokens and the AI key move out of the websites you test and into the extension's own storage (2a), and every send to GitHub, Linear, Slack or an AI provider now happens inside the extension, behind a confirmation you see first (2b).
- ⚠️ Rotate your tokens.If you configured GitHub, Linear, Slack or an AI key before 1.11, revoke and re-create it, then enter the new one in TraceBug settings. Earlier versions stored these in each website's own
localStorage, where any script on that site could read them. - Tokens and API keys are no longer stored on the pages you test(
src/ext-transport.ts,src/integrations/tracker-client.ts,src/ai/llm-client.ts) — in extension mode they live inchrome.storage.local. The extension's SDK runs in the host page's main world, so pagelocalStoragewas readable by the site under test. The page-world code now never receives a secret: the getters return nothing in extension mode, and "is GitHub configured?" is answered from a non-secret boolean snapshot the content script pushes in, so nothing had to become async. - Secrets are no longer typed into the page either(
tracebug-extension/options.html,options.js) — there is a new TraceBug settings page (options_ui, opens in a tab, Chrome + Firefox). The old in-page forms both collected tokens inside the host page's DOM *and* pre-filled them as attribute values, so a page script could read a stored token the moment the modal opened. The in-page modal now links to settings instead. Saved values are never echoed back into a field — the page shows a "Configured" pill. - Old page-stored keys are migrated automatically(
tracebug-extension/secret-migration.js) — when TraceBug next runs on a site that still holdstracebug_integrations/tracebug_ai_config(or the legacytracebug_ai_key), they are moved into extension storage and deleted from the site. If extension storage already holds a config, the existing one is kept and settings shows a one-time notice naming the site whose older token was dropped, so nothing disappears silently. - Provider calls no longer run in the page(
src/providers/api.ts,tracebug-extension/background.js,provider-bridge.js) — GitHub, Linear, Slack and the AI providers are called by the extension's background worker, which reads the token from its own storage. Previously every call was afetch()from the page's main world, so a site that had replacedwindow.fetchcould read theAuthorizationheader even when it could not read the stored token. The page now hands over the report content only — no repository, team, channel, webhook, base URL or key — and an unexpected field is rejected rather than ignored, at both the content script and the worker. - Every send to GitHub, Linear or Slack is confirmed first(
tracebug-extension/confirm-send.html) — a window the extension owns shows which site asked, where it is going, the title and the full report body, and warns when the body contains a remote image (a read receipt for whoever hosts it) or an @mention (those notify real people). Nothing is sent until you click Send; Cancel, closing the window and a two-minute timeout all send nothing. A send cancelled this way no longer falls back to the copy/prefill path — it just stops. Approving is accepted only from that window, never from a page. - AI analysis is approved per site, then rate limitedthe first analysis on a site asks once and is remembered (revocable under "Sites allowed to run AI analysis" in TraceBug settings); after that each site is capped at 10 analyses a minute, so a page cannot quietly spend your API credits.
- Slack delivery is now confirmed for real(
src/providers/api.ts) — with access tohooks.slack.comthe worker is not bound by page CORS, so it reads Slack's actual reply instead of assuming success. A rejected webhook now says why (invalid_payload,no_service) instead of showing a bare "✓ Sent to Slack". - Provider failures read as sentences401, 403, 404, 422, rate limits and network failures become plain messages ("GitHub rejected the token. Re-create it and enter the new one in TraceBug settings."), keeping the provider's own wording where it helps.
- Addedfor
optional_host_permissionsapi.github.com,api.linear.app,hooks.slack.com,api.openai.com,api.anthropic.com,localhostand127.0.0.1— requested from TraceBug settings when you save that integration, and only the one host it talks to. Optional host permissions add no install warning and do not disable the extension for existing users. - Added thethe send confirmation times out after two minutes, and that timer has to survive the service worker being shut down mid-decision.
alarmspermissionalarmstriggers no install warning. - Site access is now optional: the install warning is gone(
tracebug-extension/build/manifest.base.json) —<all_urls>moved fromhost_permissionstooptional_host_permissions, so a fresh install asks for no permissions at all instead of "Read and change all your data on all websites". Capture on the page you are looking at ridesactiveTab, granted by your own click. TraceBug asks for site access only for the thing that genuinely needs it — continuing to capture after you navigate to another site — from the popup, with the reason stated first. Declining is fine: capture keeps working on the current page and says so. Existing users keep the access they already granted (docs/testing/upgrade-host-permission.mdis the test that proves it). - A custom Ollama base URL now works(
tracebug-extension/options.js,background.js) — saving an Ollama provider pointed at any host requests access to that one address, instead of refusing anything that was notlocalhostor127.0.0.1. Only a URL that is not parseable HTTP is still rejected, and it says so in the settings page rather than at send time. - The keyboard shortcut (
Ctrl/Cmd+Shift+B) keeps capturing the page you are on without any site access — it is a page-level shortcut inside TraceBug, so it cannot ask for a permission itself. When access has been withheld it now says that the capture covers this page only, and where to allow more.
- A new install's capture no longer asks to share your screen(
src/index.ts,tracebug-extension/popup.js) — Capture Bug now records the console, the network, your clicks and an interactive DOM replay, with no screen-share picker and no operating-system permission. Previously the first thing a brand-new user met was Chrome's "Choose what to share" dialog, before they had seen TraceBug do anything. Screen recording is paused in this release while we finish it — it is back in 1.11.1. If you had it on, your setting is remembered and comes back with it; you will not have to choose again. The npm SDK records video as before. - The DOM replay is what lands in the exported.htmlin place of the video: tens or hundreds of KB of inspectable DOM events instead of tens of MB of opaque WebM. A report from an events-only capture carries everything a video report does except the pixels. - The capture now survives navigation by default, which the video path could not always do, and the on-page HUD comes back on the new page with its timer still running. One limitation worth knowing: the DOM replay covers the page the capture ends on, while the console, network and action timeline span every page you crossed. - The HUD drops Pause and the microphone (there is nothing to pause or mute) and keeps Stop, Screenshot, Draw and Blur. Blur is not a video-only tool: it masks the element's text in the DOM replay too. - One line before your browser asks what to share(
src/ui/pre-record.ts) — the share dialog is the browser's own, it offers three surfaces, and it says nothing about which one a bug report wants. Picking "Entire screen" records your whole desktop and picking the wrong tab records the wrong page, neither of which can be undone afterwards. TraceBug now explains it first, and the wording matches the dialog you are about to see: "already set to this tab — choose Share" when Capture is Current tab, "pick this tab" when it's Desktop / window. - "Having trouble?" in the popup, with nothing phoning home(
tracebug-extension/diagnostics.js) - Copy diagnostics puts TraceBug's version, your browser and OS, the permissions you've granted and TraceBug's own recent internal errors on your clipboard. Report a TraceBug bug opens a prefilled GitHub issue you read and submit yourself. Neither sends anything: there is no upload path in that file at all. No URLs, no page content, no stored values and no captured data go in - error messages and stack traces are scrubbed of hostnames, file paths, emails, tokens and long number runs, stack frames are reduced to TraceBug's own code, and a provider origin you added yourself is counted rather than named. - A big export warns you before you wait for it(
src/ui/quick-bug.ts) - if the estimate is over 20 MB the modal says so and names GitHub's 25 MB attachment limit, with one click to Export without video (keeping the report, console, network and screenshots) or to download the recording separately. - A canvas page says what the replay can't show(
src/replay-fidelity.ts) - on pages that draw their content in a<canvas>(charts, maps, WebGL), the interactive replay renders an empty space, because recording canvas pixel-by-pixel would make captures enormous. TraceBug now says so when the capture starts, while turning on video is still an option, instead of leaving you to discover it in the report. Console, network and your clicks are unaffected. - "Jira" is now "Copy for Jira"it copies the report as Jira markup for you to paste. It never filed anything, and the old label implied it did.
- Issues you file carry one credit line, and you can turn it off(
src/integrations/issue-signature.ts) - GitHub, Linear and Slack bodies end with "Reported with TraceBug". It is one line, it links to the listing, and Issue credit: on/off in the export menu removes it - an issue body gets written into someone else's tracker and stays there, so that has to be your call. Slack posts previously ended with an unlinked "Reported via TraceBug"; that is now the same single line, linked. - The TraceBug line in an exported report can be turned off(
src/exporters/html-template.ts) - the footer of an exported.htmlnow links straight to the extension listing rather than the marketing site, so someone who receives your report can install it in one step. And because exports get attached to public issues and sent to clients, Export footer: on/off in the export menu removes it entirely. - An optional, once-or-twice review ask(
src/ui/review-ask.ts) - after your third exported report, in a later session than your first, a small card asks whether TraceBug saved you time. Dismiss it and it asks once more, much later; dismiss that and it never asks again. No ratings on display, no counts, no incentives, and nothing is gated on answering. - A blocked page now tells you which page(
tracebug-extension/popup.js,page-support.js) - the "can't run here" panel shows the host and path above the explanation, with an icon that matches the reason. When TraceBug has no site access it cannot see the URL, so the card is left out rather than showing an empty row. - Uninstalling asks one optional question(
website/app/bye) - removing TraceBug opens a short page with seven reasons, an optional note, and a Skip that is as easy to click as Send. The link carries the version number and nothing else, which the page says in plain text. - Updating tells you what changed, without taking over a tab(
tracebug-extension/popup.js) - after an update the popup shows a short "What's new" card the next time you open it, with a "Got it" that dismisses it for good. No new tab, no page stealing focus while you were doing something else. A fresh install never sees it: it gets the welcome page instead. - A bundled welcome page, so first run works offline(
tracebug-extension/welcome.html) — installing used to opentracebug.dev/try.htmlin a new tab, which meant the first thing you ever saw of TraceBug depended on your connection. The welcome page now ships inside the extension: pin it to the toolbar, try it on the bug playground, and your capture shortcut — showing the key your browser actually bound, or an easy way to set one if it bound nothing. It also says plainly what a capture can see, and what never leaves your machine. The playground is still one click away, as step 2. - The exported replay says which page it covers(
src/exporters/html-template.ts) — the heading on a DOM-replay export now reads "Replay of the last page (/checkout/payment)" instead of just "Replay". The console, network and action lists beside it span every page the capture crossed, so a recipient — usually not the person who captured it — could reasonably read a bare "Replay" as covering all of them and conclude the earlier pages had nothing on them. A screen recording does keep rolling across navigations, so the video export is unchanged, and so is the timeline scrubber's own label. - Your video setting is remembered for 1.11.1(
tracebug-extension/popup.js,background.js) — screen recording is paused in the extension this release, but the preference it would use is kept, not cleared. If you had video on, it comes back on. That required moving the setting into the extension's own storage: it lived in each popup's page storage, which the part of TraceBug that handles installs and updates cannot read, so "chose not to record video" and "has never been asked" were the same missing value. - "Capture: Current tab" steers the npm SDK only, and the extension now says so(
tracebug-extension/offscreen.js,docs/chrome-extension.md) — in the extension the share dialog always shows the full tab/window/screen choice. It cannot do otherwise: the recorder runs in an offscreen document, and the browser hint for "record the current tab" means *the tab of the page that asked*, which an offscreen document does not have. An earlier 1.11 build tried to pass that hint anyway and broke recording outright. The docs no longer describe the SDK's behaviour as if it were the extension's.
- A browser blocked by macOS no longer looks like you changed your mind(
src/capture-errors.ts,tracebug-extension/offscreen.js) — if your browser is not enabled under System Settings → Privacy & Security → Screen Recording,getDisplayMediafails with the same error name as closing the share dialog, and TraceBug reported both as "cancelled". There was no way to find out that the fix was in System Settings. It now reads the error text to tell them apart, says where the setting is, mentions the part everyone misses (the browser has to be quit and reopened), and offers a Capture without video button that gets you the capture you came for. On the popup's capture path this failure used to be entirely silent — no dialog, no capture, no message at all. - A blocked page now says which kind of blocked, and offers a way out(
tracebug-extension/page-support.js,popup.js) — the popup's "Can't run on this page" panel used to be a dead end that also missed three real cases: the Chrome Web Store and the other add-on galleries (the page a brand-new user most likely has open),file://pages when "Allow access to file URLs" is off, and the built-in PDF viewer. Each one now gets its own sentence plus a single button — Try it on a demo page, Open extension settings or Reload tab. - The capture shortcut now works on any tab, from a cold start(
tracebug-extension/manifest.json,background.js) — it used to be a keydown handler inside the injected TraceBug, so it did nothing until you had already started TraceBug on that tab, which is not what the quickstart said. It is now a real browser shortcut,Alt+Bby default, and it captures the current tab whether or not TraceBug is running there.Ctrl+Shift+Bis not the default because Chrome will not give it up — it toggles the bookmarks bar, andAlt+Shift+Bfocuses it, so Chrome silently leaves both unbound.Ctrl+Shift+Bstill opens Quick Bug once TraceBug is on the page. - Nothing hardcodes the shortcut any more(
tracebug-extension/popup.js,src/ext-transport.ts) — the popup tip and the in-page tip show whatever key your browser has bound, and offer Set a shortcut when there is none. Rebind or clear it atchrome://extensions/shortcuts(Firefox: Add-ons → Manage Extension Shortcuts). If you rebind it ontoCtrl+Shift+B, one press still opens Quick Bug once, not twice. - An extension update no longer destroys a recording in progress(
tracebug-extension/background.js) —runtime.onUpdateAvailablewas not handled at all, so an auto-update landing mid-recording tore down the worker and the recorder together, and the video only exists in the recorder's memory until the stop finalizes it. TraceBug now holds the update until the recording has ended and been saved, then applies it. With nothing recording it applies right away. - A tab left open across an extension update works again(
tracebug-extension/background.js,content-script.js) — the worker now pings the page before dispatching anything, and repairs a tab that does not answer. Previously the dead copy of TraceBug on such a tab could not be reached, the orphan errors were suppressed on purpose to keep the page's console clean, and the dispatch failure was swallowed, so every popup action on that tab did nothing at all and said nothing. The repair replaces the bridge only when the page still has a running TraceBug, so no second toolbar appears; if the tab still cannot be reached, the popup says "Reload this tab to capture" and offers the button. - An action that fails explains itself in English(
tracebug-extension/page-support.js) — raw browser strings like "Cannot access contents of the page…" or "Receiving end does not exist" are mapped to a sentence with a next step attached, and the ones carrying an instruction take over the popup instead of flashing past in a 2.5-second toast. An unrecognised error is shown verbatim rather than replaced with a vague catch-all. - Error and warning rows in the Actions tab say what happened(
src/action-chips.ts) — an error row showed the literal text[object Object], and aconsole.warnrow showed only the word "Warning" with no content. Collectors emit the text nested asdata.error.message; the Actions builder was readingdata.messageand stringifying the error object when that came up empty. It now shows the message, falls back to the error name (aTypeErrorwith no message is still worth reading), and never stringifies an object.