Skip to content

Web platform support ​

What a page running in Lightningpanda can use: JavaScript language features, DOM and HTML, CSS and layout, networking, storage, workers, media and the other Web APIs, with the known gaps. Lightningpanda follows headless Chrome where Chrome and the specification differ.

This page summarizes the repository's own records (docs/PARITY.md, docs/COMPATIBILITY.md, docs/webapi/*, docs/browser/*). Where those records are older than the code, the presence of an interface was checked against the published 0.0.33 browser, and the newer result is given. For the CDP protocol surface see CDP coverage; for the Playwright API surface see API coverage.

Status values ​

StatusMeaning
YesImplemented and tested; gaps are edge cases.
PartialA useful subset; the notes name what is missing.
NoNot available (the global is undefined or the feature does nothing).

Web platform tests ​

A pinned subset of web-platform-tests runs on every pull request in CI (.github/workflows/wpt.yml, scripts in bench/wpt). The gate fails a pull request that loses a passing subtest or breaks a page that completed. The numbers below come from the committed baseline (bench/wpt/baseline.json, WPT revision a421f2fe, last updated 2026-11-10). They count the pages the baseline records (pages that pass at least one subtest or complete), tested on the fork build (patched JavaScriptCore).

WPT directoryPagesSubtests passing
dom62559,689 / 60,737 (98.3%)
html/dom24664,067 / 65,412 (97.9%)
css/selectors2285,158 / 5,803 (88.9%)
shadow-dom1858,700 / 8,877 (98.0%)
encoding1,2581,139,158 / 1,139,218 (100.0%)
url489,990 / 9,999 (99.9%)
xhr146429 / 469 (91.5%)
fetch/api/basic990 / 96 (93.8%)
uievents17115 / 116 (99.1%)
webstorage511,271 / 1,288 (98.7%)

The subset does not cover every area on this page; areas outside it are tested by the repository's own suites.

JavaScript engine ​

Pages run on JavaScriptCore (the WebKit/Safari engine), so the language is Safari's: ES2025+, Intl, Temporal, WebAssembly, WeakRef/FinalizationRegistry.

Two engine builds exist (see Platforms): the patched JavaScriptCore (macOS arm64 and both Linux builds) and the system framework (macOS Intel). Features marked "patched" below need the first.

FeatureStatusNotes
ES modulesYesStatic and dynamic import, top-level await, import.meta.url, modulepreload, SRI integrity on module scripts. Module responses must have a JavaScript, JSON or CSS MIME type.
Import mapsPartial (patched)imports, scopes, trailing-slash packages, merging later maps, bare specifiers, import.meta.resolve. Only parser-inserted inline maps; maps added by script or document.write and external maps are ignored; integrity in a map is not enforced; a rejected map fires no error event. The system framework ignores import maps with a console warning.
JSON and CSS module scriptsYes (patched)with { type: "json" } and with { type: "css" } (a constructed CSSStyleSheet); a typed import fails with a TypeError on the system framework. CSS module url()s resolve against the document, not the module.
TimersYessetTimeout/setInterval with the HTML 4 ms nesting clamp (windows only, not workers), queueMicrotask, requestAnimationFrame, requestIdleCallback.
unhandledrejectionYesThe event fires (checked on 0.0.33; older records say it did not).
ConsolePartialLevels, count, time*; format specifiers such as %s are not applied.
Function.prototype.toString on interface objectsDiffersReports function () { [native code] }.
Debugger/Profiler (inspector)No

Runtime deviations ​

Deliberate, tested deviations (from docs/COMPATIBILITY.md):

DeviationEffect
Window global shapewindow is JSC's default global: Window members are own properties and Object.getPrototypeOf(window) is Object.prototype. window instanceof Window still holds and the tag is [object Window]. Patching EventTarget.prototype.addEventListener does not change window.addEventListener.
Interface objects are ProxiesNode, HTMLElement and the other interface objects are Proxies whose members are installed on first use. Descriptors and inheritance match; property operations on interface objects (including instanceof) pay a proxy-trap cost.
TerminationCode that catches a termination (Runtime.terminateExecution, a timeout) inside native frames is terminated again within about 50 ms.
Inline module URLsInline module scripts get import.meta.url = <document URL>#inline-module-N.
Deferred modules and DOMContentLoadedDOMContentLoaded waits for each deferred module to finish evaluating, including top-level await. Browsers wait only for the fetch.
Root-relative module URLs (system framework)import "/x.js" loads from the page origin but reports import.meta.url as file:///x.js.
Named window propertieswindow.foo finds elements by id/name (patched only), but the names are not listed by Object.getOwnPropertyNames.

DOM and HTML ​

AreaStatusNotes
DOM tree, Node, Element, Document, AttrYesMutation records, templates, Attr as a Node. Character data is UTF-8: lone UTF-16 surrogates are not preserved.
HTML parserYeshtml5ever, incremental around scripts; document.write from parser-reached scripts parses at the insertion point (writes from async, deferred or module scripts are ignored).
SelectorsYesStylo's matcher, :has() with state invalidation, :state(), :focus-visible, :user-valid/:user-invalid.
Custom elementsPartialdefine, upgrades, all lifecycle callbacks, form-associated elements with ElementInternals, CustomStateSet. No customized built-ins (is=), no formStateRestoreCallback.
Shadow DOMYesDeclarative roots, getHTML, setHTMLUnsafe, Document.parseHTMLUnsafe, named and manual slot assignment, delegatesFocus.
Range, StaticRange, SelectionPartialRange per the DOM spec; StaticRange exists; AbstractRange does not; Selection is not backed by a live Range.
NodeIterator, TreeWalkerYes
CollectionsPartialHTMLCollection, NodeList, NamedNodeMap, DOMTokenList follow the legacy platform object rules where the JSC C API allows; index descriptors report enumerable: false and defineProperty on an index does not throw.
HTML attribute reflectionYesAll reflection kinds of WPT html/dom/reflection-*, obsolete elements included. Accessors only: <track> and <frame> load nothing.
Node.moveBeforeYesPreserves focus, iframes, modal dialogs and popovers.
TablesPartialinsertRow/deleteRow/insertCell/deleteCell and section helpers; the caption/tHead/tFoot setters are missing.
XPathYesXPath 1.0, all axes and the 27 core functions, document.evaluate, XPathEvaluator/XPathExpression/XPathResult; 32-level nesting cap.
DOMParser, XMLSerializerPartialHTML and bounded XML 1.0 with namespaces; DTDs and XML 1.1 return a parsererror document.
XML documents, XSLTPartial / NoXML documents load and stop at each script (0.0.31); XSLTProcessor is undefined.

Events and input ​

AreaStatusNotes
Event dispatchYesActivation behaviour, retargeting across shadow trees, window.event.
Event handler attributesYeson* IDL attributes and setAttribute('on…'); markup handlers such as <button onclick="…"> set through innerHTML run (checked on 0.0.33; older records say parser-created handlers were not compiled).
Mouse, keyboard, wheel, touchYesMouseEvent, PointerEvent, KeyboardEvent, TouchEvent, DragEvent, pointer capture, Chrome's touch compatibility events. Input usually comes from CDP or the SDK.
FocusYesTab order over shadow trees and slots, positive tabindex, delegatesFocus, focus scrolling, :focus-visible.
Clipboard and editingPartialTyping, deletion, caret and word movement with platform modifiers, Selection.modify(), multi-click selection, copy/cut/paste with trusted ClipboardEvent, execCommand and queryCommand*, undo/redo, caretRangeFromPoint/caretPositionFromPoint, navigator.clipboard (in memory per context). Lines are logical (no soft wraps); execCommand('paste') is unavailable to script, as in Chromium.

Forms ​

AreaStatusNotes
Value sanitization, valueAsNumber/valueAsDate, stepUp/stepDownYesAll input types, including date/time kinds.
Constraint validationYesEvery ValidityState flag, Chrome's messages for common cases, interactive validation, :user-valid/:user-invalid, :in-range/:out-of-range.
SubmissionYesFormData (with submitter), the formdata event, method=dialog, implicit submission on Enter, legacy encodings and accept-charset. POST to a new window fails explicitly.
Keyboard defaultsPartialNumber, range, radio groups, single <select> (one-character typeahead). No UI pickers, no multi-character typeahead.
File inputsYesSet through CDP/SDK uploads; FileList, File, FileReader.

CSS, layout and rendering ​

Styles are computed by Stylo (Firefox's style engine) and laid out by Blitz and Taffy (block, inline, flex, grid, tables). Screenshots and PDFs are painted on the CPU. See Rendering.

AreaStatusNotes
Cascade, computed styleYesgetComputedStyle including pseudo-elements, custom properties, matchMedia, CSS.supports.
Layout geometryYesgetBoundingClientRect, offset*, client*, scrolling, scrollIntoView through nested scrollers, hit testing for input.
innerTextYesFollows computed display (blockification, tables, display: contents).
CSSOMPartialcssRules parses on first access; CSSStyleRule exists. The media and disabled CSSOM APIs are missing and cssRules is a live array, not a real CSSRuleList (per docs/browser/STYLESHEETS.md). Constructed stylesheets and adoptedStyleSheets work.
Linked stylesheetsYesLoad with load/error events, block parser scripts and load, SRI enforced. Per document: 128 stylesheets, 4 MiB per response, 16 MiB total source.
Web fontsPartial@font-face with unicode-range selection (0.0.31). FontFace and document.fonts' FontFaceSet constructor are undefined; document.fonts exists.
Web AnimationsPartialElement.animate, Animation and KeyframeEffect exist; completeness is not recorded.
Top layerYesModal dialogs and popovers paint above the document with ::backdrop.
visualViewportYesPresent on 0.0.33. Explicit screen orientation and MediaQueryList change events are missing.

Networking ​

AreaStatusNotes
HTTP/1.1 and HTTP/2Yesrustls with Mozilla's roots; HTTP/2 by ALPN (one connection per origin and context, 100 concurrent streams). No HTTP/3, no cleartext h2c, no server push.
fetch, Request, Response, HeadersYesStreaming bodies, abort, keepalive, referrer/referrerPolicy, SRI. Over HTTP/2 statusText is empty. The Request constructor works on 0.0.33 (older records list it as missing).
XMLHttpRequestYesSync and async, upload and download progress, responseXML, timeouts. Synchronous requests skip Fetch interception (Playwright routes do not see them).
WebSocketYesWindows and dedicated workers, permessage-deflate, WebSockets over HTTP/2 (RFC 8441). Visible to Playwright's page.on('websocket').
EventSource, navigator.sendBeaconYes
CookiesYesRFC 6265bis parsing, public suffix list, per-context jar. CookieStore is undefined.
CORS, Referrer Policy, Fetch MetadataYesCORS with preflight, all eight referrer policies (default strict-origin-when-cross-origin), Sec-Fetch-* headers. Full Fetch response filtering is not claimed.
HTTP cacheYesPrivate in-memory cache per context (RFC 9111 subset, Fetch cache modes). Controlled by CDP Network.setCacheDisabled and Network.clearBrowserCache.
AuthenticationPartialOpt-in Basic challenges for servers and proxies; no credential cache or auth UI.
ProxiesPartialHTTP forward proxy per context or serve --proxy (CONNECT for https). SOCKS and https:// proxies are refused.
file: URLsYesNavigations and the subresources of file: documents; not reachable from http(s) pages or through fetch/XHR. LIGHTNINGPANDA_FILE_URLS=0 turns them off.
blob: and data: URLsYesblob: loads through fetch/XHR and as script, stylesheet, image and iframe source.
URL, URLSearchParamsYesCurrent WHATWG URL Standard; every case of WPT urltestdata.json, setters_tests.json and toascii.json passes. URLPattern is undefined.
EncodingYesTextEncoder/TextDecoder (streaming), legacy encodings for forms.
DownloadsPartialWith CDP Browser.setDownloadBehavior (or the SDK download step): <a download> links to blob:, data: or same-origin URLs, and navigations answered with Content-Disposition: attachment, are saved with Chrome's download events. Browser.cancelDownload is missing. See CDP coverage.
CSP, cross-origin isolationPartialContent-Security-Policy is only honoured for hiding the nonce attribute of script-inserted elements (no other CSP enforcement is recorded). crossOriginIsolated is always false (no COOP/COEP).

Storage ​

All storage is in memory: nothing is written to disk, and a new browser context starts empty unless seeded (see serve --local-storage and Profiles).

AreaStatusNotes
localStorage, sessionStorageYesPer context and origin (local) and per top-level page (session); per-origin quota. No cross-document storage events. Opaque origins get per-document ephemeral storage instead of Chrome's SecurityError.
IndexedDBYesIndexedDB 3.0 with getAll(options)/getAllRecords, per context and origin, shared with dedicated workers. Blob/File values throw DataCloneError; opaque origins throw SecurityError. Works with Dexie, idb, localForage, Firebase.
Cache StorageYescaches per context and origin, shared by documents and workers; requires a non-opaque origin.
navigator.storagePartialestimate() (fixed 10 GiB quota), persisted()/persist() resolve false; no getDirectory().
Web Locks, File System AccessNonavigator.locks and showOpenFilePicker are undefined.

Workers and messaging ​

AreaStatusNotes
Dedicated workersYesOwn thread and VM; importScripts, fetch, WebSocket, IndexedDB, streams, crypto, OffscreenCanvas, transfers both ways; visible as CDP worker targets. Module workers need the patched JavaScriptCore. Worker timers are not clamped.
Service workersPartialRegistration per context in memory, install/activate, skipWaiting, clients.claim, fetch events for page fetches, XHR, subresources and navigations, Cache Storage, MSW 2.x browser mode. Missing: requests of workers a controlled page starts, redirects answered by the worker for navigations, streamed worker responses, navigation preload, Push/Sync, persistence. navigator.serviceWorker exists only in secure contexts.
Shared workersNoSharedWorker is undefined.
MessageChannel, postMessageYesAcross frames, popups and workers, with transfer of ports, streams, ImageBitmap, OffscreenCanvas. No port close event.
BroadcastChannelYesAcross the pages of a browser context.
structuredCloneYesOrdinary graphs, Error/DOMException, Blob/File, CryptoKey, ImageBitmap, transferables.
StreamsYesReadable (default and byte), Writable, Transform, text and compression streams (gzip, deflate, deflate-raw), transferable.

Crypto ​

AreaStatusNotes
crypto.getRandomValues, randomUUIDYes
crypto.subtleYesDigest, HMAC, AES-GCM/CBC/CTR/KW, PBKDF2, HKDF, ECDSA/ECDH (P-256/384/521), Ed25519/X25519, RSASSA-PKCS1-v1_5/RSA-PSS/RSA-OAEP; raw/spki/pkcs8/jwk; wrap/unwrap. No Ed448/X448. Exposed regardless of secure context.

Canvas, images and media ​

AreaStatusNotes
Canvas 2DYesRasterized on the CPU: paths, gradients, patterns, composite operators, shadows, text, drawImage, image data, toDataURL/toBlob (PNG/JPEG/WebP), Path2D, DOMMatrix, ImageData. Canvas filter and SVG image sources are missing. Canvases appear in screenshots.
OffscreenCanvas, ImageBitmapYesAlso in workers; transferControlToOffscreen.
WebGLNoWebGLRenderingContext is undefined.
ImagesYes<img> loading, decode(), new Image().
<audio>, <video>PartialContainer metadata (MP4, WebM, Ogg, WAV, MP3, FLAC, ADTS), ready-state events, playback on the page clock, Chrome's autoplay policy. Video frames decode on demand for screenshots and drawImage (AV1, H.264; no VP8/VP9/HEVC). No audio output. MediaSource exists but isTypeSupported('video/mp4') returns false.
Web AudioPartialAudioContext (a clock, no output), OfflineAudioContext with buffer source, oscillator, constant source and gain nodes, decodeAudioData (MP3, AAC, Vorbis, Opus, FLAC, WAV). No other nodes.
MediaRecorder, WebRTC, speechNoMediaRecorder, RTCPeerConnection and speechSynthesis are undefined.

Observers and timing ​

AreaStatusNotes
MutationObserverYesAll options, microtask delivery.
IntersectionObserverPartialThresholds, root, rootMargin, clipping and scrolling; some options throw NotSupportedError. Records describe this as computed over an approximate layout.
ResizeObserverPartialOne size for all boxes (the box option is ignored, as in upstream Lightpanda).
PerformanceObserver, timelineYesUser Timing, Paint Timing (first-paint/first-contentful-paint at the first rendering opportunity), Resource Timing, Navigation Timing, performance.timing.
AreaStatusNotes
Location and HistoryYesEvery Location setter, pushState/replaceState, popstate and hashchange in Chrome's order, <meta http-equiv=refresh> and the Refresh header.
Navigation APIYeswindow.navigation, navigate events with intercept(), entries, traversal promises.
Page lifecycleYespagehide, visibilitychange, unload when a document is left; beforeunload on Page.close.
iframesPartialSame-process child frames for src, srcdoc and about:blank, sandbox flags, per-frame realms, cross-origin WindowProxy restrictions, postMessage between frames. At most 128 child frames per page and 32 levels deep. No out-of-process frames, no joint session history, no loading=lazy.
window.open, popupsYesOpens a page in the opener's context with window.opener, named reuse and window.close(); Playwright's popup event fires.
Dialogs (alert, confirm, prompt)YesBlock for Page.handleJavaScriptDialog while a CDP session has Page enabled; otherwise dismissed and reported.
<dialog>, popovers, invokers, <details>YesModal dialogs and inertness, popover stacks with light dismiss, command/commandfor, exclusive accordions.

Identity and environment ​

AreaDefaultNotes
User agentMozilla/5.0 (compatible; lightningpanda/<version>)Override per page through CDP Emulation.setUserAgentOverride (Playwright userAgent); serve has no user-agent flag. navigator.userAgentData and low-entropy Sec-CH-UA headers follow the override's metadata. Some sites serve different assets to this UA than to Chrome's.
Viewport1280x720 at DPR 1 over CDP (observed with the SDK on 0.0.33)Set per page through CDP Emulation.setDeviceMetricsOverride or the SDK/Playwright viewport. A size change fires resize.
LocaleProcess localenavigator.language and Accept-Language follow the per-page locale; Intl and Date keep the process locale.
TimezoneProcess timezoneOne timezone per connection: a different zone in a second context of the same connection fails.
PermissionsPromptPer context through Browser.grantPermissions; Notification shows nothing (fires show when granted). navigator.geolocation exists; geolocation emulation is not recorded.
Secure contextComputedhttps:, localhost, loopback, file:, about:blank, data: are potentially trustworthy.

Not available ​

Checked as undefined on 0.0.33: SharedWorker, WebGLRenderingContext/WebGL2RenderingContext, RTCPeerConnection, MediaRecorder, speechSynthesis, XSLTProcessor, URLPattern, CookieStore, WebTransport, FontFace, FontFaceSet, AbstractRange, TrustedHTML, Sanitizer, TextTrack, Gamepad, EyeDropper, navigator.locks. Also absent: WebDriver BiDi, Push and Background Sync, disk persistence of any storage.

If a page needs one of these, check Troubleshooting and Platforms and limits.

AGPL-3.0-only. A derivative of Lightpanda. Built by Povio.