CloakHQ/CloakBrowser · error · StealthEvaluationError
<viewport>
Error message
<viewport>
What it means
StealthEvaluationError thrown by GetLiveWindowSizeAsync when evaluating the stealth viewport JS in the isolated world fails to return an object with width/height properties — i.e. the probe result is null, not JSON, or malformed.
Source
Thrown at dotnet/src/CloakBrowser/Human/PlaywrightAdapters.cs:102
}
public (int Width, int Height)? ViewportSize
{
get
{
var vs = _page.ViewportSize;
return vs == null ? null : (vs.Width, vs.Height);
}
}
public async Task<(int Width, int Height)?> GetLiveWindowSizeAsync()
{
var world = await _getStealthAsync().ConfigureAwait(false);
var value = await world.EvaluateAsync(StealthDom.ViewportJs).ConfigureAwait(false);
if (value == null || value.Value.ValueKind != System.Text.Json.JsonValueKind.Object
|| !value.Value.TryGetProperty("width", out var width)
|| !value.Value.TryGetProperty("height", out var height))
throw new StealthEvaluationError("<viewport>");
int resolvedWidth = (int)width.GetDouble();
int resolvedHeight = (int)height.GetDouble();
if (resolvedWidth <= 0 || resolvedHeight <= 0)
throw new StealthEvaluationError("<viewport>");
return (resolvedWidth, resolvedHeight);
}
public async Task<(double Y, double MaxY)?> GetScrollStateAsync()
{
var world = await _getStealthAsync().ConfigureAwait(false);
var value = await world.EvaluateAsync(
"(() => { const e = document.scrollingElement || document.documentElement;" +
" return { y: window.scrollY, maxY: Math.max(0, e.scrollHeight - e.clientHeight) }; })()")
.ConfigureAwait(false);
if (value == null || value.Value.ValueKind != System.Text.Json.JsonValueKind.Object
|| !value.Value.TryGetProperty("y", out var y)
|| !value.Value.TryGetProperty("maxY", out var maxY))View on GitHub (pinned to d6bad5de26)
Solutions
- Await page.WaitForLoadStateAsync (DOMContentLoaded/NetworkIdle) before humanize calls
- Check page.IsClosed and that the stealth world is available before calling
- Let CloakBrowser create the context so stealth scripts are guaranteed installed
- Retry once after a short delay if a navigation race is suspected
Example fix
// before await page.GoToAsync(url); await page.HumanScrollIntoViewAsync(sel); // after await page.GoToAsync(url); await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); await page.HumanScrollIntoViewAsync(sel);
Defensive patterns
Strategy: retry
Validate before calling
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); if (page.IsClosed) return;
Try / catch
catch (StealthEvaluationError e) when (e.Message == "<viewport>") { await Task.Delay(250); retry once; } Prevention
- Set explicit viewport to avoid the live-dimension fallback path
- Never call humanize APIs mid-navigation
- Create contexts via CloakBrowser so the stealth world exists
When it happens
Trigger: Calling APIs that need live window size (scroll-into-view fallback in headed no_viewport mode) when the stealth world's EvaluateAsync returns null or a non-object — page mid-navigation, page crashed, or stealth scripts not injected.
Common situations: Calling humanize APIs right after GoToAsync before load completes, on a crashed page, or when the isolated world/stealth scripts were not installed (custom context setup bypassing CloakBrowser defaults).
Related errors
- CloakBrowser — Pre-built binaries are currently only availab
- <scroll-state>
- StealthEvaluationError: {selector}
- Unsupported platform: ${platform} ${arch}. Supported: ${supp
- Download completed but binary not found at expected path: ${
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/1165ef7bf1c19842.
Report an issue: GitHub.