Output Console: watch the page's console.log inside a tab panel — no DevTools
DevTools console works great — when it's open. Most of the time it isn't. And worse: the DevTools console shows logs from every page you currently use. Hard to fish out "my logs from this specific flow" in the noise avalanche. Output Console (since v2.13.66) is a read-only log viewer in the tab itself — you see logs of this tab, scoped to this domain, always available like other JustZix panels.
Four window types — where Output Console fits
| Type | What it does | Read/write |
|---|---|---|
| CSS pane | Live CSS editor, applied via <style> | WRITE (CSS → page) |
| JS pane | Run-on-demand JS script (▶ button) | WRITE (JS → page) |
| JS Console | REPL with Ctrl+Enter eval + ↑↓ history | WRITE (JS → page) + READ (eval result) |
| Output Console | Read-only log viewer | READ ONLY |
The first three types do something to the page. Output Console listens. Every console.log/warn/error/info/debug call from the page (and from other JustZix scripts) lands as a coloured line. Plus — a dedicated window.JUSTZIX.log() channel (since v2.13.73; primary alias since v2.13.76, brand-named with vanishingly small collision risk) that does NOT pipe to native console, only to Output Console — your scripts can log without polluting DevTools.
Architecture — page hook + sink broadcast
Output Console works in two steps:
- Page hook (MAIN world) — Injected via
chrome.scripting.executeScript({world: 'MAIN', func: hookFn})(CSP-immune since v2.13.74). Wrapsconsole.log/warn/error/info/debugpreserving passthrough to the original (DevTools loses nothing), but every call also postswindow.postMessage({source:'jz-output-console', kind:'console', level, text, t}). - Sink broadcast (ISOLATED world) — JustZix content script listens for
window.messageand broadcasts entries to all currently rendered Output Console panels via the_outputConsoleSinksMap. Each panel appends its line to its own log (per-instance state).
Plus stringifyArg — type-aware argument transformer:
- string/number/bool → literal
Error→.stack(full stack trace, not just message)- object →
JSON.stringifywith a circular guard (WeakSet, soJSON.stringify(window)won't hang) - function →
[Function: name]sentinel - undefined →
undefinedliteral (doesn't disappear inside JSON.stringify)
viewMode: [C+J] / [C] / [J] — two channels, one panel
Since v2.13.73 Output Console has a cyclic viewMode button in the header. Three states:
| Mode | What you see | Use case |
|---|---|---|
[C+J] (Both) | Everything — page console + JustZix scripts | Default — most complete view |
[C] (Console only) | Only page console.* | Debug the page, without your own logs |
[J] (JustZix only) | Only window.JUSTZIX.log/.warn/.error/.info/.debug (or JZ.log if not taken) | Your actions, clean, no noise |
Implementation: zero JS overhead per line. Each entry gets a jz-output-line-{kind} class, and the mode adds a jz-output-mode-{mode} class on the pane. CSS hide-rules do the rest:
.jz-output-mode-standard .jz-output-line-jz { display: none; }
.jz-output-mode-jz .jz-output-line-console { display: none; }
/* .jz-output-mode-both shows everything */
Per-level filters + search — power-user features
Under the ⚙ button opens a popover with 5 checkboxes: log / info / warn / error / debug. All checked by default except debug (default off — pages overuse console.debug for spam). Same mechanism as viewMode — class jz-output-hide-{level} + CSS rule, zero JS overhead.
Plus a 🔍 search toggle above the log. Live-filter substring match, case-insensitive. Esc clears. Persisted in sessionStorage per-tab — filters/search survive reload.
// In JS Console type:
for (let i = 0; i < 5; i++) console.log(`User ${i} action`);
for (let i = 0; i < 5; i++) console.warn(`User ${i} warning`);
JUSTZIX.log('My script log');
// Output Console will show 11 lines.
// Toggle [J] → only 1 (JUSTZIX.log).
// Toggle [C] + filter "warn" only → 5 (console.warn).
// Search "User 3" → catches "User 3 action" + "User 3 warning".
Use case 1 — Monitor dataLayer.push (GTM debug)
Classic GTM problem: you want to know what each tag sends to dataLayer. DevTools console = wade through dozens of other logs. Output Console:
// JS rule (auto-runs on site):
const origPush = window.dataLayer.push;
window.dataLayer.push = function(event) {
JUSTZIX.log('[dataLayer]', JSON.stringify(event));
return origPush.call(this, event);
};
JUSTZIX.log('dataLayer hook installed.');
Output Console in [J] mode shows only your JUSTZIX.log lines — each GTM tag = one coloured line. Filter "purchase" → only ecommerce. Filter "ga4" → only GA events. No F12, no Tag Assistant, no Network panel.
Use case 2 — Long-running QA flow monitoring
A QA tester logs a 30-minute flow. The DevTools console fills up after 5 minutes (default max ~1000 lines). Output Console:
- maxLines 2000 (since v2.13.73, was 500) — enough for a long session.
- Per-tab sessionStorage — reload doesn't clear the log (only closing the tab does).
- Auto-scroll toggle in the header — turn off to stop scrolling at a specific line; scroll-back won't jump to the bottom on each new log.
- Clear button with customisable
runColor(since v2.13.71) — wipe the log before the next QA step.
Use case 3 — Async error tracking
JS pane error overlay (red bar) does NOT catch async errors — setTimeout(() => { throw err }, 100) won't show in the pane. Output Console DOES catch them — because console.error is also invoked by the global error handler:
// JS rule:
window.addEventListener('error', (e) => {
JUSTZIX.error('[unhandled]', e.message, '@', e.filename + ':' + e.lineno);
});
window.addEventListener('unhandledrejection', (e) => {
JUSTZIX.error('[promise reject]', e.reason);
});
Output Console in [J] mode + "error only" filter — every global error in a readable list. Handy when an SPA logs 50 errors per minute and you only want yours.
Use case 4 — API response monitor
A page has fetches that don't show up in the view (background sync). Check what the server replies:
// JS rule — proxy fetch:
const origFetch = window.fetch;
window.fetch = async function(...args) {
const res = await origFetch.apply(this, args);
const clone = res.clone();
clone.json().then(data => {
JUSTZIX.log('[fetch]', args[0], '→', JSON.stringify(data).slice(0, 200));
}).catch(() => {});
return res;
};
Output Console shows URL + first 200 chars of JSON response. Search by URL → see only one endpoint. Great for debugging flaky fetches without the F12 Network panel.
CSP-strict pages — why inline script failed (v2.13.74 fix)
Up to v2.13.73 the page hook was injected as a <script> element with textContent. Worked on ~99% of pages — but strict CSP (script-src 'self' without 'unsafe-inline', e.g. GitHub, Stripe checkout, banks) silently blocked execution. appendChild succeeded (DOM mutation OK), but the script didn't execute, no error thrown.
Symptom: window.JUSTZIX.log is not a function + console.log doesn't show up in Output Console. Fix (v2.13.74): the hook moved to chrome.scripting.executeScript({world: 'MAIN', func: hookFn}) — extension privileges trump page CSP. After first install Output Console gets a welcome message (since v2.13.76 it lists active aliases): [JustZix] Output Console hook ready. API: window.JUSTZIX (or JZ / __JUSTZIX__).log/.warn/.error/.info/.debug.
Pitfalls
- Read-only. You can't type
2+2here and get4. This is a stream view, not a REPL. For a REPL use the JS Console. - console.debug is OFF by default in filters. First time you won't see debug logs — that's intentional (debug spam is a productivity drain). Toggle it on in the ⚙ popover if you need it.
- Page hook needs to be early. The hook injects on first render of an Output Console panel. Logs before that moment are lost. Best practice: panel attached to a parent rule with a URL match — then the hook installs from page load.
- The logger always works, even when the page takes window.JZ. Since v2.13.76 the primary alias is
window.JUSTZIX(brand name, vanishingly small collision risk) pluswindow.__JUSTZIX__always set. The shorterwindow.JZis an alias ONLY when free — on a conflict with the page (e.g. Google Ads) it stays with the page. UseJUSTZIX.log()when you're not sure about the domain. - 2000 lines cap. Longer flow → older lines are evicted (FIFO). Save the log to a file via Clear button (export to JSON planned for v2.13.75; for now copy-paste from the DOM).
What's next
Output Console closes out the in-tab mini-IDE — a read-only channel alongside the three write-channels (CSS pane / JS pane / JS Console). Together this is "Chrome DevTools alternative for 80% of cases" — no F12, scoped per domain, with customisable UI. Check also window.JZ helpers for the dedicated logging channel and debug GTM dataLayer.push as a concrete application.
Install JustZix — completely free, no account, no server.
Rate this post
No ratings yet — be the first.