Summary
pixelshot's default cdp backend never actually measures the true page height when run against Brave Browser as CHROME_PATH — it silently falls back to whatever --tile-height was passed, so any page taller than one tile is truncated to a single viewport-height capture. Content below that point (e.g. a table further down a long Wikipedia article) is never rendered at all, with no error or warning.
Reproduction
uv tool install pixelrag
CHROME_PATH="/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" \
pixelshot "https://en.wikipedia.org/wiki/2010_UEFA_Champions_League_Final" \
--output ./tiles --tile-height 1568 --wait-network-idle
cat ./tiles/en.wikipedia.org_wiki_2010_UEFA_Champions_League_Final.png.tiles/tiles.json
# {"page_height": 1568, "tiles": ["tile_0000.jpg"], "complete": true}
Re-running with --tile-height 500 instead of 1568 reproduces page_height: 500 — i.e. page_height always exactly equals whatever --tile-height is passed, for a page that is obviously several thousand pixels tall (it has an infobox, "Road to the final" table, full match report, and a "Statistics" section well past any of these values). This isn't a short-page edge case; the height detection itself is failing every time and falling back silently.
Root cause (best guess)
In pixelrag_render/backends/cdp.py, _readiness_expr():
await new Promise(res => { ... load event, with LOAD_TIMEOUT_MS guard ... });
await document.fonts.ready; # <-- no timeout guard
await Promise.race([
new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))),
new Promise(r => setTimeout(r, 1000)),
]);
Every other async step in this expression has an explicit timeout/race guard against headless quirks (the load event, and explicitly the rAF call per the comment about requestAnimationFrame never ticking in some headless modes). document.fonts.ready has none. Under Brave's headless implementation this promise appears to never resolve, so the whole Runtime.evaluate call presumably times out or errors at the CDP layer, which is silently swallowed in capture_url:
try:
page_height = result["result"]["value"]
except (KeyError, TypeError):
page_height = tile_h
...falling back to tile_h with no logging, so the failure is invisible to the caller.
Suggested fix
- Wrap
document.fonts.ready in the same kind of Promise.race(..., setTimeout(...)) guard already used for the rAF step.
- Log (at least at debug/warning level) when the
page_height fallback path is hit, so this failure mode isn't silent.
Environment
pixelrag==0.4.0 (via uv tool install pixelrag)
- macOS (Darwin 25.6.0, arm64)
CHROME_PATH pointed at Brave Browser (no Google Chrome/Chromium installed on this machine)
- Backend:
cdp (default). Note --backend playwright is documented in --help and the module docstring but isn't actually wired up in render_urls() in this version — it raises Unknown backend: 'playwright'. Choose 'cdp'. — so it isn't currently a usable workaround.
Happy to provide more logs/repro if useful.
Summary
pixelshot's defaultcdpbackend never actually measures the true page height when run against Brave Browser asCHROME_PATH— it silently falls back to whatever--tile-heightwas passed, so any page taller than one tile is truncated to a single viewport-height capture. Content below that point (e.g. a table further down a long Wikipedia article) is never rendered at all, with no error or warning.Reproduction
Re-running with
--tile-height 500instead of1568reproducespage_height: 500— i.e.page_heightalways exactly equals whatever--tile-heightis passed, for a page that is obviously several thousand pixels tall (it has an infobox, "Road to the final" table, full match report, and a "Statistics" section well past any of these values). This isn't a short-page edge case; the height detection itself is failing every time and falling back silently.Root cause (best guess)
In
pixelrag_render/backends/cdp.py,_readiness_expr():Every other async step in this expression has an explicit timeout/race guard against headless quirks (the load event, and explicitly the rAF call per the comment about
requestAnimationFramenever ticking in some headless modes).document.fonts.readyhas none. Under Brave's headless implementation this promise appears to never resolve, so the wholeRuntime.evaluatecall presumably times out or errors at the CDP layer, which is silently swallowed incapture_url:...falling back to
tile_hwith no logging, so the failure is invisible to the caller.Suggested fix
document.fonts.readyin the same kind ofPromise.race(..., setTimeout(...))guard already used for the rAF step.page_heightfallback path is hit, so this failure mode isn't silent.Environment
pixelrag==0.4.0(viauv tool install pixelrag)CHROME_PATHpointed at Brave Browser (no Google Chrome/Chromium installed on this machine)cdp(default). Note--backend playwrightis documented in--helpand the module docstring but isn't actually wired up inrender_urls()in this version — it raisesUnknown backend: 'playwright'. Choose 'cdp'.— so it isn't currently a usable workaround.Happy to provide more logs/repro if useful.