Compare / browsers
WebKit vs Chromium
Playwright's WebKit 26.4 claims a Mac in its user agent but reports Linux, sets navigator.webdriver and speaks HTTP/1.1 through a proxy. Where it beats Chromium (CSS, testing), and why it is not an iPhone's browser.
WebKit on the fleet is the WebKit build that ships with Playwright — the engine behind Apple's browser, compiled for Linux — at version 26.4. Chromium is Playwright's Chromium build, 148.0.7778.96. Both are measured headful, the same night, through the same proxy. Two questions: what is different for a page that renders in each, and what does a site see — in particular when you put WebKit behind an iPhone device descriptor to stand in for an iPhone?
As a developer: driving them
| WebKit | Chromium | |
|---|---|---|
| Version on the fleet | WebKit 26.4 (Playwright's build), one version. | Chromium 148.0.7778.96 (Playwright's build), one version. |
| Launch options | screen_size, keep_alive, start_url (headful), profile, record. No cdp and no live_view: headful sessions get a VNC live link, but WebKit ignores the viewer's clicks. | The same plus cdp (connectOverCDP, Puppeteer) and live_view (headless live view). |
| Playwright features | Main-world evaluate, console events, init scripts, routing, screenshots, device emulation and tracing work. page.pdf() fails: "PDF generation is only supported for Headless Chromium" (measured). | All of them, page.pdf() included — headful too (measured). |
| Web platform (newer CSS and APIs) | Has CSS margin-trim, CSS random(), FontFace width and WebTransport reliability — none of which Chromium 148 has (measured). | Has WebGPU, WebHID, the Topics API, Fenced Frames, Shared Storage, Protected Audience, Compression Dictionary transport and requestStorageAccessFor — none of which WebKit has (measured). |
| Cookies | Refuses every cookie on a domain listed in the Public Suffix List (httpbin.org is one) — case 57. | Keeps host-only cookies there. |
| Fulfilled responses | HTML served from page.route with only charset=utf-8 in its Content-Type is decoded as Latin-1 — case 48. | Decoded as UTF-8. |
As a scraper: what the site sees
| WebKit | Chromium | |
|---|---|---|
| User agent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Safari/605.1.15 — a Mac, while navigator.platform says Linux x86_64. | Mozilla/5.0 (X11; Linux x86_64) … Chrome/148.0.0.0 Safari/537.36 and navigator.platform Linux x86_64 — they agree. |
| Client hints | None: no navigator.userAgentData. | Brands Chromium 148, Not/A)Brand 99; platform Linux, desktop. |
navigator.webdriver | true. | false. |
| TLS | JA4 t13d2914h1_723694b0fccc_067a5f92fbdb: 29 ciphers, 14 extensions, and ALPN offers HTTP/1.1 only. | JA4 t13d1516h2_8daaf6152771_d8a2da3f94cd: 16 ciphers, 18 extensions, HTTP/2. |
| HTTP | HTTP/1.1 through the proxy, so no HTTP/2 fingerprint at all (case 01). | HTTP/2 with Chromium's SETTINGS (1:65536;2:0;4:6291456;6:262144|15663105) and header order. |
| Vendor and WebGL | navigator.vendor "Apple Computer, Inc."; WebGL vendor "Apple Inc.", renderer "Apple GPU". | "Google Inc."; WebGL on SwiftShader (ANGLE, Vulkan). |
| Device signals | No navigator.connection, no deviceMemory. | navigator.connection and deviceMemory present. |
| Bot checks | bot.sannysoft.com runs 37 of its checks: 2 flags, "WebDriver (New)" and "Chrome (New)". | 57 checks: 1 flag, "WebGL Renderer" (SwiftShader on a GPU-less server). |
WebKit with an iPhone descriptor is not an iPhone's browser
- With Playwright's
devices['iPhone 15']the page gets the iPhone user agent (iPhone OS 17_5 … Version/26.4 Mobile/15E148 Safari/604.1), a 393×659 viewport on a 393×852 screen, pixel ratio 3,ontouchstartand a coarse pointer (measured). - But
navigator.platformstaysLinux x86_64,navigator.maxTouchPointsis 0,navigator.webdriveristrue, andnavigator.standalonedoesn't exist (measured). A script that checks any of these can tell it isn't a phone. - The same descriptor on Chromium also keeps
Linux x86_64and addsnavigator.vendor"Google Inc." under that iPhone user agent, with one touch point — not a real phone either. - So use WebKit + a device descriptor for layout and rendering checks: how a page lays out, what CSS it gets, how the engine behind Apple's browser handles it. For a real iOS WebView, see iPhone.
Which to pick
- Chromium for scraping: consistent identity, no webdriver flag, HTTP/2, CDP, and PDF.
- WebKit for cross-browser testing — the engine and CSS behaviour behind Apple's browser, at a layout level, including mobile viewports with a device descriptor. Don't use it where a site checks for automation: its user agent and platform disagree and it reports
navigator.webdriver. - Both cost the same: two threads headful, one headless.
Measured on the fleet (2026-10-18)
One headful launch of each through the same proxy, probed from inside a page and via tls.peet.ws.
Launch and cost
Single run; timings depend on the proxy and on fleet load.
| WebKit | Chromium | |
|---|---|---|
| Launch body | {"headless":false} | {"headless":false} |
| Threads used | 2 (linux_headful) | 2 (linux_headful) |
| Browser version | 26.4 | 148.0.7778.96 |
| Launch request → browser ready | 0.8 s | 0.7 s |
| Playwright connect | 0.1 s | 0.1 s |
| Load example.com | 6.2 s | 1.0 s |
| Load tls.peet.ws/api/all | 2.2 s | 0.9 s |
What the network sees
From tls.peet.ws/api/all, requested by the browser itself. JA3 hashes change between runs of the same build (GREASE), so compare JA4 and the HTTP/2 fingerprint.
| WebKit | Chromium | |
|---|---|---|
| HTTP version | HTTP/1.1 | h2 |
| JA4 | t13d2914h1_723694b0fccc_067a5f92fbdb | t13d1516h2_8daaf6152771_d8a2da3f94cd |
| Peetprint hash | bb44ee2f537184f8584269789ab7ffee | 1d4ffe9b0e34acac0bd883fa7f79d7b5 |
| Akamai HTTP/2 fingerprint | — | 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p |
| Cipher suites / extensions | 29 / 14 | 16 / 18 |
| Header order (first 12) | — | method, authority, scheme, path, sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform, upgrade-insecure-requests, user-agent, accept, sec-fetch-site, sec-fetch-mode |
What page scripts see
Read with page.evaluate on example.com. Cores and memory are the server's and vary between fleet nodes.
| WebKit | Chromium | |
|---|---|---|
| navigator.userAgent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Safari/605.1.15 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 |
| UA-CH brands | — | Not/A)Brand 99 · Chromium 148 |
| UA-CH full version list | — | Not/A)Brand 99.0.0.0 · Chromium 148.0.7778.96 |
| navigator.platform / vendor | Linux x86_64 / Apple Computer, Inc. | Linux x86_64 / Google Inc. |
| Languages | en-US | en-US |
| Timezone / locale | UTC / en-US | UTC / en-US |
| Screen (w×h×availW×availH×depth) | 1280x720x1280x720x24 | 1280x720x1280x720x24 |
| Window outer / inner / DPR | 1280x758 / 1280x720 / 1 | 1288x805 / 1280x720 / 1 |
| hardwareConcurrency / deviceMemory | 8 / — | 64 / 32 |
| WebGL vendor | Apple Inc. | Google Inc. (Google) |
| WebGL renderer | Apple GPU | ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver) |
| WebGL version | WebGL 2.0 | WebGL 2.0 (OpenGL ES 3.0 Chromium) |
| WebGPU (navigator.gpu) | no | yes |
| Canvas hash | 25c86b3f | f5a94624 |
| navigator.webdriver | yes | no |
| window.chrome / navigator.connection | no / no | yes / yes |
| Plugins / PDF viewer | 5 / yes | 5 / yes |
| Notification.permission / permissions.query | default / prompt | default / prompt |
Web platform features
Presence probes; a user agent that claims one version while exposing another's features is a detectable inconsistency.
| WebKit | Chromium | |
|---|---|---|
Iterator.prototype.includes (new in Chrome 154) | no | no |
FontFace.width (new in Chrome 154) | yes | no |
CSS text-decoration-inset (new in Chrome 154) | no | no |
Iterator.prototype.join (Chrome 153) | no | no |
Iterator.zip (Chrome 153) | no | no |
CSS scroll-axis-lock (Chrome 153) | no | no |
<camera> element (Chrome 153) | no | no |
document.requestStorageAccessFor (deprecated in 153) | no | yes |
Topics API (document.browsingTopics) | no | yes |
Protected Audience (navigator.joinAdInterestGroup) | no | yes |
Shared Storage (window.sharedStorage) | no | yes |
Attribution Reporting (window.attributionReporting) | no | no |
| Private Aggregation | no | no |
WebHID (navigator.hid) | no | yes |
CSS margin-trim (Chrome 155) | yes | no |
CSS text-decoration-skip-spaces (Chrome 155) | no | no |
CSS corner shorthand (Chrome 155) | no | no |
CSS symbols() (Chrome 155) | no | no |
Element.streamAppendHTML (Chrome 155) | no | no |
WebTransport.reliability (Chrome 155) | yes | no |
window.maximize() — Additional Windowing Controls (Chrome 155) | no | no |
Canvas srgb-linear colour space (Chrome 155) | no | no |
Permission policy media-playback-while-not-visible (Chrome 155) | no | no |
CSS random() (Chrome 156) | yes | no |
CSS scroll-snap-type: pair (Chrome 156) | no | no |
Fenced frames (window.fence) — removal starts in 157 | no | yes |
rel=compression-dictionary (Chrome 156 updates) | no | yes |
bot.sannysoft.com
The classic headless-detection test page; what it marks red.
| WebKit | Chromium | |
|---|---|---|
| Checks / failed | 37 / 2 | 57 / 1 |
| Failed checks | WebDriver (New), Chrome (New) | WebGL Renderer |
A plain-HTTP URL (http://ip-api.com/json)
Chrome 154 warns before loading insecure HTTP by default — does that reach an automated session?
| WebKit | Chromium | |
|---|---|---|
| Final URL | http://ip-api.com/json/?fields=status | http://ip-api.com/json/?fields=status |
| HTTP status | 200 | 200 |
| Content loaded / warning page first | yes / no | yes / no |
Playwright over the remote connection
Which client features work on this side.
| WebKit | Chromium | |
|---|---|---|
| page.evaluate runs in the page's own world | yes | yes |
| addInitScript visible to page scripts | yes | yes |
| Console events | yes | yes |
| Request interception (page.route) | yes | yes |
| Screenshot | yes | yes |
| no — Error: page.pdf: PDF generation is only supported for Headless Chromium | yes | |
| Mobile device emulation | yes | yes |
| Tracing | yes | yes |
Rows where the two sides differ are highlighted. IP addresses are replaced with placeholders (203.0.113.x). The probe is compare/probe.mjs in our repository; the raw result is below.
Raw output
{
"ran_at": "2026-10-18T01:03:40.639Z",
"sides": [
{
"label": "WebKit",
"engine": "webkit",
"body": {
"headless": false
},
"launch": {
"browser": "webkit",
"resource_class": "linux_headful",
"weight": 2,
"launch_ms": 752,
"connect_ms": 63,
"example_ms": 6229,
"peet_ms": 2246
},
"network": {
"http_version": "HTTP/1.1",
"ja4": "t13d2914h1_723694b0fccc_067a5f92fbdb",
"ja3_hash": "4ded71be9138938d71dbef4272be7708",
"peetprint_hash": "bb44ee2f537184f8584269789ab7ffee",
"ciphers": 29,
"extensions": 14,
"header_order": null
},
"page": {
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Safari/605.1.15",
"platform": "Linux x86_64",
"vendor": "Apple Computer, Inc.",
"languages": [
"en-US"
],
"hardware_concurrency": 8,
"device_memory": null,
"max_touch_points": 0,
"webdriver": true,
"plugins": 5,
"pdf_viewer": true,
"ua_data": null,
"screen": "1280x720x1280x720x24",
"window": {
"outer": "1280x758",
"inner": "1280x720",
"dpr": 1
},
"timezone": "UTC",
"locale": "en-US",
"webgl": {
"vendor": "Apple Inc.",
"renderer": "Apple GPU",
"version": "WebGL 2.0"
},
"canvas_hash": "25c86b3f",
"webgpu": false,
"chrome_object": false,
"chrome_runtime": false,
"notification_permission": "default",
"notification_query": "prompt",
"has_focus": true,
"connection_api": false,
"stack_read_by_debugger": false,
"features": {
"iterator_includes": false,
"iterator_join": false,
"iterator_zip": false,
"fontface_width": true,
"css_text_decoration_inset": false,
"css_scroll_axis_lock": false,
"websocket_options_bag": null,
"camera_element": false,
"topics_api": false,
"protected_audience": false,
"shared_storage": false,
"attribution_reporting": false,
"request_storage_access_for": false,
"webhid": false,
"private_aggregation": false,
"css_margin_trim": true,
"css_text_decoration_skip_spaces": false,
"css_corner_shorthand": false,
"css_symbols": false,
"stream_append_html": false,
"webtransport_reliability": true,
"window_maximize": false,
"canvas_srgb_linear": false,
"policy_media_playback_while_not_visible": false,
"css_random": true,
"css_scroll_snap_pair": false,
"fenced_frames": false,
"compression_dictionary": false
}
},
"page_main_world": null,
"sannysoft": {
"checks": 37,
"failed": 2,
"failed_names": [
"WebDriver (New)",
"Chrome (New)"
],
"passed": 9
},
"plain_http": {
"final_url": "http://ip-api.com/json/?fields=status",
"status": 200,
"title": "",
"loaded": true,
"warning_page": false,
"page_text": "{\"status\":\"success\"}"
},
"playwright": {
"evaluate_in_main_world": true,
"console_events": true,
"init_script": true,
"route": true,
"screenshot": true,
"pdf": false,
"pdf_error": "Error: page.pdf: PDF generation is only supported for Headless Chromium",
"mobile_emulation": true,
"tracing": true
},
"browser_version": "26.4"
},
{
"label": "Chromium",
"engine": "chromium",
"body": {
"headless": false
},
"launch": {
"browser": "chromium",
"resource_class": "linux_headful",
"weight": 2,
"launch_ms": 740,
"connect_ms": 53,
"example_ms": 1000,
"peet_ms": 868
},
"network": {
"http_version": "h2",
"ja4": "t13d1516h2_8daaf6152771_d8a2da3f94cd",
"ja3_hash": "22d4b0372811536f39e50c3823b66c25",
"peetprint_hash": "1d4ffe9b0e34acac0bd883fa7f79d7b5",
"ciphers": 16,
"extensions": 18,
"akamai_h2": "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p",
"akamai_h2_hash": "52d84b11737d980aef856699f885ca86",
"header_order": [
"method",
"authority",
"scheme",
"path",
"sec-ch-ua",
"sec-ch-ua-mobile",
"sec-ch-ua-platform",
"upgrade-insecure-requests",
"user-agent",
"accept",
"sec-fetch-site",
"sec-fetch-mode"
]
},
"page": {
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",
"platform": "Linux x86_64",
"vendor": "Google Inc.",
"languages": [
"en-US"
],
"hardware_concurrency": 64,
"device_memory": 32,
"max_touch_points": 0,
"webdriver": false,
"plugins": 5,
"pdf_viewer": true,
"ua_data": {
"brands": [
{
"brand": "Not/A)Brand",
"version": "99"
},
{
"brand": "Chromium",
"version": "148"
}
],
"mobile": false,
"platform": "Linux",
"architecture": "x86",
"bitness": "64",
"formFactors": [
"Desktop"
],
"fullVersionList": [
{
"brand": "Not/A)Brand",
"version": "99.0.0.0"
},
{
"brand": "Chromium",
"version": "148.0.7778.96"
}
],
"model": "",
"platformVersion": "",
"uaFullVersion": "148.0.7778.96",
"wow64": false
},
"screen": "1280x720x1280x720x24",
"window": {
"outer": "1288x805",
"inner": "1280x720",
"dpr": 1
},
"timezone": "UTC",
"locale": "en-US",
"webgl": {
"vendor": "Google Inc. (Google)",
"renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)",
"version": "WebGL 2.0 (OpenGL ES 3.0 Chromium)"
},
"canvas_hash": "f5a94624",
"webgpu": true,
"chrome_object": true,
"chrome_runtime": false,
"notification_permission": "default",
"notification_query": "prompt",
"has_focus": true,
"connection_api": true,
"stack_read_by_debugger": false,
"features": {
"iterator_includes": false,
"iterator_join": false,
"iterator_zip": false,
"fontface_width": false,
"css_text_decoration_inset": false,
"css_scroll_axis_lock": false,
"websocket_options_bag": null,
"camera_element": false,
"topics_api": true,
"protected_audience": true,
"shared_storage": true,
"attribution_reporting": false,
"request_storage_access_for": true,
"webhid": true,
"private_aggregation": false,
"css_margin_trim": false,
"css_text_decoration_skip_spaces": false,
"css_corner_shorthand": false,
"css_symbols": false,
"stream_append_html": false,
"webtransport_reliability": false,
"window_maximize": false,
"canvas_srgb_linear": false,
"policy_media_playback_while_not_visible": false,
"css_random": false,
"css_scroll_snap_pair": false,
"fenced_frames": true,
"compression_dictionary": true
}
},
"page_main_world": null,
"sannysoft": {
"checks": 57,
"failed": 1,
"failed_names": [
"WebGL Renderer"
],
"passed": 30
},
"plain_http": {
"final_url": "http://ip-api.com/json/?fields=status",
"status": 200,
"title": "",
"loaded": true,
"warning_page": false,
"page_text": "{\"status\":\"success\"}"
},
"playwright": {
"evaluate_in_main_world": true,
"console_events": true,
"init_script": true,
"route": true,
"screenshot": true,
"pdf": true,
"mobile_emulation": true,
"tracing": true
},
"browser_version": "148.0.7778.96"
}
]
}Bottom line
WebKit and Chromium differ in everything a site can measure: TLS and HTTP version, client hints, vendor, WebGL, the webdriver flag, and a different set of newer CSS and web APIs.
WebKit is the one to check layouts against the engine behind Apple's browser; it is not a stealth browser and not an iPhone.