Soenneker.Playwrights.Extensions.Stealth
4.0.66
Prefix Reserved
dotnet add package Soenneker.Playwrights.Extensions.Stealth --version 4.0.66
NuGet\Install-Package Soenneker.Playwrights.Extensions.Stealth -Version 4.0.66
<PackageReference Include="Soenneker.Playwrights.Extensions.Stealth" Version="4.0.66" />
<PackageVersion Include="Soenneker.Playwrights.Extensions.Stealth" Version="4.0.66" />
<PackageReference Include="Soenneker.Playwrights.Extensions.Stealth" />
paket add Soenneker.Playwrights.Extensions.Stealth --version 4.0.66
#r "nuget: Soenneker.Playwrights.Extensions.Stealth, 4.0.66"
#:package Soenneker.Playwrights.Extensions.Stealth@4.0.66
#addin nuget:?package=Soenneker.Playwrights.Extensions.Stealth&version=4.0.66
#tool nuget:?package=Soenneker.Playwrights.Extensions.Stealth&version=4.0.66
Soenneker.Playwrights.Extensions.Stealth
A .NET extension library for Microsoft Playwright that makes browser automation harder to detect. It applies launch-argument hardening, context shaping, and init-script evasions so Chromium sessions look more like normal user sessions.
Installation
dotnet add package Soenneker.Playwrights.Extensions.Stealth
Quick start
- Launch Chromium with stealth defaults:
Playwright.LaunchStealthChromium(). - Create a stealth browser context:
browser.CreateStealthContext(). - Use the context as usual to create pages and run automation.
using Microsoft.Playwright;
using Soenneker.Playwrights.Extensions.Stealth;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.LaunchStealthChromium(new BrowserTypeLaunchOptions
{
Headless = true,
Channel = "chromium"
});
var browserContext = await browser.CreateStealthContext();
var page = await browserContext.NewPageAsync();
With proxy
Pass an optional proxy into CreateStealthContext:
var context = await browser.CreateStealthContext(new Proxy
{
Server = "http://proxy.example.com:8080",
Username = "user",
Password = "secret"
});
Customizing launch and context
Tune stealth behavior without forking Playwright:
using Microsoft.Playwright;
using Soenneker.Playwrights.Extensions.Stealth;
using Soenneker.Playwrights.Extensions.Stealth.Options;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.LaunchStealthChromium(
new BrowserTypeLaunchOptions { Headless = true },
new StealthLaunchOptions
{
Channel = "chrome",
IncludeNoSandboxArgument = false,
IgnoreDetectableDefaultArguments = true,
AdditionalIgnoredDefaultArguments = ["--disable-features=DialMediaRouteProvider"],
AdditionalArguments = ["--disable-features=Translate"]
});
var context = await browser.CreateStealthContext(
new BrowserNewContextOptions
{
// Optionally specify a UserAgent
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36"
},
new StealthContextOptions
{
NormalizeDocumentHeaders = true,
InjectClientHintHeaders = true,
WarmupSpeechVoices = true,
EnableCdpDomainHardening = true,
DisableConsoleDomain = true,
DisableRuntimeDomain = false,
Surfaces = new StealthSurfaceOptions
{
UserAgentData = StealthSurfaceMode.Native,
PermissionsQuery = StealthSurfaceMode.Native,
DocumentFonts = StealthSurfaceMode.Native,
Canvas = StealthSurfaceMode.Native,
MediaDevices = StealthSurfaceMode.Native
},
AdditionalHttpHeaders = new Dictionary<string, string>
{
["DNT"] = "1"
}
});
Applying stealth to an existing context
You can apply the same stealth behavior to a context you already created:
var context = await browser.NewContextAsync();
await context.ApplyStealthAsync();
Features
| Area | Description |
|---|---|
| Launch options | Normalizes Chromium args with stealth-oriented defaults: ensures --disable-blink-features=AutomationControlled, forces --headless=new when headless, and can strip detectable Playwright default args via IgnoreDefaultArgs. |
| Channel selection | If BrowserTypeLaunchOptions.Channel is unset, StealthLaunchOptions.Channel is used (default chromium). Set Channel = "chrome" (or pass BrowserTypeLaunchOptions.Channel) when you want the installed Google Chrome channel. |
| Hardware profile | Each context gets a random but internally consistent Windows/Chrome profile: CPU cores, memory, viewport, DPR, Chrome version, timezone, locale/languages, and WebGL identity. Randomized geolocation is available as an explicit opt-in. |
| Context shaping | Sets coherent User-Agent, language headers, timezone, viewport, DPR, and color scheme from the same generated profile. Generated Chromium User-Agents follow UA reduction (Chrome/<major>.0.0.0>), and a caller-supplied BrowserNewContextOptions.UserAgent is propagated into the derived Client Hints fields when header injection is enabled. Fingerprint surfaces such as navigator.userAgentData, navigator.permissions.query(), document.fonts, canvas, and media devices can each be left native, spoofed, or disabled. |
| Speech voices | The injected init script can warm up native speechSynthesis voices before page scripts run, reducing the chance that a site observes an empty or not-yet-populated voice list. |
| Request shaping | Registers early context routing so top-level document navigations get normalized navigation headers before the first page load. |
| CDP hardening (optional) | Can disable selected Chromium CDP domains (e.g. Console, optionally Runtime) per page to reduce protocol surface. |
| Init script | Injected before page load to reduce automation signals: hides navigator.webdriver; aligns navigator/screen/window (e.g. hardwareConcurrency, deviceMemory, platform, vendor, languages, plugins, dimensions, DPR); Client Hints and navigator.userAgentData; window.chrome; permissions/connection/battery/media/geolocation shims; timezone via Intl; canvas noise; WebGL vendor/renderer spoofing; WebRTC host-candidate stripping. |
Options reference
- StealthLaunchOptions — Controls how launch arguments are normalized (
Channel,RemoveDetectableArguments,IncludeNoSandboxArgument,IgnoreDetectableDefaultArguments,AdditionalArguments,AdditionalIgnoredDefaultArguments). - StealthContextOptions — Controls context and request behavior (
Proxy,AdditionalHttpHeaders,InjectClientHintHeaders,NormalizeDocumentHeaders,AlignColorScheme,RandomizeGeolocation,WarmupSpeechVoices,Surfaces,EnableCdpDomainHardening,DisableConsoleDomain,DisableRuntimeDomain). - StealthSurfaceOptions — Controls per-surface behavior with
StealthSurfaceMode(Native,Spoofed,Disabled) forUserAgentData,PermissionsQuery,DocumentFonts,Canvas, andMediaDevices.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Playwright (>= 1.59.0)
- Soenneker.Extensions.String (>= 4.0.666)
- Soenneker.Extensions.Task (>= 4.0.120)
- Soenneker.Extensions.ValueTask (>= 4.0.113)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Soenneker.Playwrights.Extensions.Stealth:
| Package | Downloads |
|---|---|
|
Soenneker.Cloudflare.Downloader
Allows for navigating and downloading from Cloudflare sites in under-attack mode |
|
|
Soenneker.Playwrights.Crawler
A configurable Playwright crawler with rich stealth and control options. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.66 | 0 | 4/17/2026 |
| 4.0.65 | 32 | 4/16/2026 |
| 4.0.63 | 289 | 4/14/2026 |
| 4.0.62 | 472 | 4/9/2026 |
| 4.0.61 | 1,609 | 3/15/2026 |
| 4.0.60 | 110 | 3/15/2026 |
| 4.0.59 | 88 | 3/15/2026 |
| 4.0.58 | 421 | 3/13/2026 |
| 4.0.57 | 99 | 3/12/2026 |
| 4.0.56 | 100 | 3/12/2026 |
| 4.0.55 | 99 | 3/12/2026 |
| 4.0.53 | 204 | 3/12/2026 |
| 4.0.52 | 105 | 3/12/2026 |
| 4.0.51 | 466 | 3/11/2026 |
| 4.0.50 | 103 | 3/11/2026 |
| 4.0.49 | 174 | 3/10/2026 |
| 4.0.48 | 212 | 3/10/2026 |
| 4.0.47 | 96 | 3/10/2026 |
| 4.0.46 | 175 | 3/9/2026 |
| 4.0.45 | 95 | 3/9/2026 |
Additional configuration
Header alignment