Soenneker.Playwrights.Extensions.Stealth
4.0.106
Prefix Reserved
dotnet add package Soenneker.Playwrights.Extensions.Stealth --version 4.0.106
NuGet\Install-Package Soenneker.Playwrights.Extensions.Stealth -Version 4.0.106
<PackageReference Include="Soenneker.Playwrights.Extensions.Stealth" Version="4.0.106" />
<PackageVersion Include="Soenneker.Playwrights.Extensions.Stealth" Version="4.0.106" />
<PackageReference Include="Soenneker.Playwrights.Extensions.Stealth" />
paket add Soenneker.Playwrights.Extensions.Stealth --version 4.0.106
#r "nuget: Soenneker.Playwrights.Extensions.Stealth, 4.0.106"
#:package Soenneker.Playwrights.Extensions.Stealth@4.0.106
#addin nuget:?package=Soenneker.Playwrights.Extensions.Stealth&version=4.0.106
#tool nuget:?package=Soenneker.Playwrights.Extensions.Stealth&version=4.0.106
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.
Related Repos
You might also be interested in:
- soenneker.playwrights.crawler for crawling and mirroring sites to disk with Playwright.
- soenneker.playwrights.installation for ensuring Playwright browsers are installed before first use.
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();
Connecting to a remote Playwright sidecar
If Chromium is already running remotely, for example in a Docker sidecar, connect with the endpoint overload:
using Microsoft.Playwright;
using Soenneker.Playwrights.Extensions.Stealth;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.LaunchStealthChromium(
"ws://playwright:3000/",
new BrowserTypeConnectOptions());
var context = await browser.CreateStealthContext();
var page = await context.NewPageAsync();
In endpoint mode, stealth launch arguments are not applied because the remote browser is already running. Stealth still applies at the browser-context level via CreateStealthContext().
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
The defaults are recommended, but if you want to tune options further:
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,
PatchFunctionToString = false,
EnableCdpDomainHardening = true,
DisableConsoleDomain = true,
DisableRuntimeDomain = false,
Surfaces = new StealthSurfaceOptions
{
NavigatorProfile = StealthSurfaceMode.Native,
NavigatorPlugins = StealthSurfaceMode.Native,
Screen = StealthSurfaceMode.Native,
Battery = StealthSurfaceMode.Native,
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 profile getters, plugins/mimeTypes, screen values, battery, 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,PatchFunctionToString,Surfaces,EnableCdpDomainHardening,DisableConsoleDomain,DisableRuntimeDomain). - StealthSurfaceOptions — Controls per-surface behavior with
StealthSurfaceMode(Native,Spoofed,Disabled) forNavigatorProfile,NavigatorPlugins,Screen,Battery,UserAgentData,PermissionsQuery,DocumentFonts,Canvas,MediaDevices, andWebGl.
| 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.61.0)
- Soenneker.Extensions.String (>= 4.0.705)
- Soenneker.Extensions.Task (>= 4.0.124)
- Soenneker.Extensions.ValueTask (>= 4.0.117)
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.106 | 922 | 7/19/2026 |
| 4.0.105 | 823 | 7/17/2026 |
| 4.0.104 | 390 | 7/16/2026 |
| 4.0.102 | 118 | 7/16/2026 |
| 4.0.101 | 675 | 7/15/2026 |
| 4.0.100 | 1,522 | 7/3/2026 |
| 4.0.99 | 2,147 | 6/24/2026 |
| 4.0.98 | 570 | 6/20/2026 |
| 4.0.97 | 491 | 6/20/2026 |
| 4.0.96 | 635 | 6/19/2026 |
| 4.0.95 | 115 | 6/19/2026 |
| 4.0.94 | 232 | 6/18/2026 |
| 4.0.93 | 755 | 6/17/2026 |
| 4.0.92 | 191 | 6/17/2026 |
| 4.0.91 | 387 | 6/16/2026 |
| 4.0.90 | 116 | 6/16/2026 |
| 4.0.89 | 764 | 6/13/2026 |
| 4.0.88 | 102 | 6/13/2026 |
| 4.0.87 | 734 | 6/10/2026 |
| 4.0.86 | 1,065 | 6/10/2026 |
Update dependency Soenneker.Extensions.Task to 4.0.124 (#387)
Automatically merged