Skip to content

Limitations ​

Jint.Browser is not a rendering engine.

  • No pixels, screenshots, PDF output, browser window, canvas rendering, WebGL, or media playback.
  • SVG is a DOM and geometry surface, not a renderer. getBBox() uses basic-shape attributes without stroke, clipping, markers or transforms; other elements use a synthetic layout box if available, otherwise zeros. getCTM() and getScreenCTM() compose SVG ancestor transform attributes, not CSS transforms or viewport/viewBox fitting.
  • SVG outline lengths are exact for straight rectangles, circles, lines and polygonal chains. Rectangles ignore rounded corners, ellipses use a 256-segment approximation, and paths return zero length and the origin for getPointAtLength(). Fill/stroke hit tests always return false. SVG text character counts use Unicode code points; text lengths return zero (no shaping). These are not rendered measurements.
  • SVG length conversion uses CSS absolute units, a fixed 16px em / 8px ex fallback, and percentages relative to the nearest SVG viewport's viewBox or width/height attributes; a missing viewport resolves percentages to zero. Assigning a pixel value or converting into a percentage with no viewport throws NotSupportedError. Value readers support scalar units, not CSS math, escapes or comments.
  • No SVG SMIL animation: animVal mirrors the base value through read-only views. Animation pause/time methods only retain explicit state; redraw methods are no-ops. SVG path parsing, fe* filter-primitive interfaces, text character-layout methods, and legacy SVG root intersection/selection APIs are deferred. SVG lists support indexed reads; mutation uses their named methods, not indexed assignment.
  • Canvas getContext('2d') returns a stateful no-op context, including on OffscreenCanvas. Drawing and paths produce no pixels; hit tests return false and getImageData always returns transparent black, even after putImageData or when alpha is false. toDataURL, toBlob and convertToBlob serialize a blank transparent PNG, irrespective of requested format. Empty canvases return "data:," / a null callback blob; offscreen encoding rejects with IndexSizeError. Encoding and ImageData allocation are limited to 16,777,216 pixels: larger encodings return "data:," / null / EncodingError, and larger ImageData allocations throw RangeError. PNG encoding streams zero bytes through zlib rather than allocating a raster.
  • Canvas text metrics are estimates: advance width is 0.5 em per Unicode code point, plus letter spacing per code point and word spacing per ASCII whitespace, clamped at zero; ascent/descent are 0.8/0.2 em, adjusted for alignment/baseline. They do not use loaded fonts. Colors accept CSS names, hex, RGB, HSL and HWB; advanced color spaces/functions are unsupported, and currentColor is black. Filters accept basic numeric functions and blur, not URL or drop-shadow filters. Contexts negotiate sRGB/unorm8 with desynchronized: false; float16 ImageData is explicitly unsupported. Paths are validation-only shells, with no SVG path geometry retained. WebGL, WebGPU and bitmap-rendering contexts remain null. Canvas worker exposure, structured cloning/transfers, transferControlToOffscreen, ImageBitmap and capture streams are not implemented.
  • No visual layout. Synthetic boxes are deterministic tree rows; text does not wrap and elements are never truly side by side.
  • Geometry, hit testing, scrolling, intersection, and resize observations use that synthetic model.
  • Web Animations effects never change computed style or layout, and style sheets create no CSSAnimation or CSSTransition objects. commitStyles() explicitly writes discrete keyframe values (the last specified value at or before iteration progress), without interpolation, additive composition, or an effect-stack cascade. Connected HTML/SVG elements are treated as rendered; pseudo-element effects cannot commit styles. Frames use a fixed 16 ms cadence, shared with requestAnimationFrame; paused, idle, zero-rate and finished animations do not keep a frame timer alive. Only document timelines are supported. Keyframe property names use the native CSS catalog; property values retain the parser's text-only CSS boundary rather than per-property grammar validation.
  • Images are fetched and their container headers read, never their pixels. complete, currentSrc, naturalWidth/naturalHeight, width/height and the load/error events answer per HTML §4.8.4; PNG, JPEG, GIF, WebP, BMP, ICO and SVG state a size, and any other container is the broken state with an error event. srcset, sizes and a <picture>'s <source media>/type select a candidate per HTML §4.8.4.3.6, against the configured viewport and device scale factor, and img.decode() resolves once the current request is completely available and rejects with an EncodingError when it is broken. There is no bitmap, no colour, no EXIF orientation and no animation, so an animated GIF is its logical screen and has no frames. loading="lazy" loads eagerly: whether an image intersects the viewport is a question about a layout this package does not have. Set BrowserOptions.MaxImageRequests to 0 to fetch none, which records every reference in the request log as before.
  • Fonts are fetched and their file signature checked, never decoded, so nothing about a face's glyphs or metrics is known. A local() source is never available, @font-face rules do not add faces to document.fonts, and a set matches faces by family name and unicode-range only. document.fonts.ready waits for the faces in the set, not for the document to finish loading, and workers have no fonts.
  • Child-frame documents have window realms and can run same-origin classic scripts, but independent child navigation/history services are not implemented. Their navigation object and interface constructors are installed; entries are empty, current entry/activation are null, and navigation operations reject with InvalidStateError rather than navigating the parent.
  • Each popup has its own engine and loop. Even same-origin cross-page windows expose only HTML's cross-origin WindowProxy surface: no document, DOM access, arbitrary properties or same-origin scripting. location.href is write-only and location.replace() can navigate; remote length is 0 and parent/top name the popup itself. Identity is stable within the caller's engine across target-page navigations.
  • Popup creation is asynchronous behind the synchronous window.open result. Cross-page operations queue until the page is registered; closed is false while it is opening. Remote navigations are serialized in request order; messages and close requests do not wait for network loads. No transient-user-activation popup blocking is applied (the LightPanda-style headless policy), and window UI/size features, focus() and blur() have no effect. Named-page familiarity is scoped to a BrowserContext, not HTML's full familiarity rules.
  • Cross-page postMessage clones in the sender and checks targetOrigin against the current destination document at delivery, including "*" and "/". Any nonempty transfer list throws DataCloneError; MessagePort, ArrayBuffer and stream transfers are not supported across pages.
  • Only pages opened by window.open or a link/form target are script-closable. A host-created page ignores window.close() even with a single history entry, where HTML would let script close it, so a page cannot end the host's session. window.name persists across a page's navigations and is not cleared on cross-site top-level navigations.
  • A target matching a child iframe/frame name keeps the same-page navigation fallback and records a diagnostic; other unknown names create popups. _self, _parent and _top select the current top-level page. Child-frame window opening/navigation remains outside the independent popup services.
  • Navigation API intercept({precommitHandler}) explicitly throws NotSupportedError; deferred commit and its controller interfaces are not implemented. There are no UA visual transitions (hasUAVisualTransition is false). Focus reset uses the existing focus controller and autofocus target; scrolling uses synthetic boxes, with no persisted traversal/reload scroll restoration or sequential-focus starting-point model. focusReset: "manual" and scroll: "manual" suppress automatic behavior.
  • Navigation API sourceElement covers anchors/areas and form submitters (or the form for direct submission); same-page POST submissions supply formData, and input-driven activation sets userInitiated. Cross-page navigations carry encoded POST bodies, not source-engine DOM nodes or FormData objects. An anchor's download value is exposed as downloadRequest, but an unintercepted download still follows the existing document-navigation path: there is no file-download manager. window.stop() remains a no-op. Cross-document traversals refetch rather than restore a back/forward cache; outgoing navigation result promises remain pending when their document is replaced. Entries follow the navigator's existing fixed request referrer policy, not response/meta policy changes.
  • No WebAssembly, CSP enforcement, or ServiceWorker.
  • Shared workers are available in top-level page realms with the default Browser worker provider and the Workers feature enabled, not in child-frame or worker globals or with a custom provider. Scripts use the existing HTTP(S) loader: data: and blob: worker scripts are unsupported, with load failures reported asynchronously. The last owning document closing or navigating away terminates its shared worker immediately, even with extendedLifetime: true; closing a port alone does not release document ownership. close() stops the worker independently of its owners. Neither dedicated nor shared workers have CDP targets.
  • Options.WebApi.Workers.MaxWorkers also bounds live shared-worker instances per BrowserContext (separately from the per-parent dedicated-worker limit); reconnecting to a live shared worker uses no new slot. MaxQueuedMessages bounds each connection's message queue in each direction. Page.Workers counts dedicated workers only. Shared workers retain their first creator's configured worker capabilities, budgets and host diagnostic sink; closing that page does not cancel another page's connection.
  • IndexedDB is context-owned and in memory only. Durability hints have no disk-flush effect, and there is no eviction, public provider, IndexedDB CDP domain, or Storage.clearDataForOrigin integration. The per-origin quota counts committed serialized data and metadata, not peak transaction-copy allocations. IDB 3.1 additions (getAllRecords and the newer getAll options overload) are omitted; full upstream IndexedDB WPT conformance has not been established.
  • Cache Storage is in memory by default, not an HTTP cache, and not cleared through CDP: neither a CacheStorage domain nor Storage.clearDataForOrigin is implemented. Cache quotas count body bytes, UTF-16 metadata and fixed bookkeeping overhead across all named caches; deleted caches with live handles remain charged (unreferenced handles release their charge after collection). Custom partitions own their quotas and must return thread-safe providers with stable store instances. Existing partition subclasses default to no caches grant. Insecure HTTP and initial opaque about:blank/data: documents have no caches; creator-inherited about:blank uses its creator's origin. A secure opaque file: content document exposes a getter throwing SecurityError; file navigation itself is not supported.
  • Resource Timing has no separate DNS/connect/TLS/redirect instrumentation: unavailable phases are zero or collapsed to fetchStart. serverTiming is an empty frozen array, deliveryType is empty, and transfer overhead is the specified 300-byte estimate. Automatic decompression can hide encoded size, in which case actual body bytes are used. Cross-origin responses without Timing-Allow-Origin conservatively hide detailed timings, protocol, sizes, content type and status. A fetch response is streamed on demand, so its entry completes only when the body is consumed or cancelled. No entry is invented for a resource the browser does not fetch (including speculative preloads). Child frames have their own resource timelines but no independent navigation-timing entry; unavailable navigation unload, Client Hints restart and back/forward-cache diagnostics are zero/null. Navigation confidence and experimental worker-routing fields are not implemented.
  • Cookie Store has no service-worker CookieStoreManager or subscriptions. Following the current Cookie Store IDL, results contain only name and value, not Chrome's additional attributes; deleted event items omit value. sameSite is validated and partitioned converted, but the default CookieContainer jar retains neither and does not enforce them. Its existing capacity, grammar and domain restrictions still apply (including refusal of empty names), and there is no public suffix list. Custom non-CookieContainer jars expose neither HttpOnly nor cookie identity/attributes: as with document.cookie, those jars must themselves hide/protect HttpOnly cookies; attributes must be representable by a Set-Cookie string.
  • Cookie Store change detection snapshots script-visible cookies only while a change listener or onchange handler is registered. Processing occurs after page turns, in nested rendering pumps and on idle wakes for external writes/expiry; each interval's net changes produce one later task. Intermediate writes/deletions, unchanged-value rewrites and attribute-only changes the jar cannot retain are not reported. No jar scans, timers or CookieStore allocation occur for an unused API. Jar operations run synchronously on the page loop, with results and parallel-algorithm validation failures settled in queued tasks; WebIDL conversion and early origin/URL checks reject immediately.
  • Cookie Store is exposed without secure-context gating. Opaque origins and non-HTTP(S) creation URLs (including inherited about:blank) reject with SecurityError. Writes always use Secure cookies. On non-loopback HTTP pages, set() and delete() reject with SecurityError before touching either the default or a custom jar; they previously resolved without changing the jar. HTTPS and HTTP loopback pages can write and delete; HTTP loopback is trusted for Secure cookie retrieval by the default shared jar. This operation refusal preserves the documented broader exposure and is not a full secure-context implementation (for example, ancestor contexts are not checked).
  • No drag and drop, clipboard API, touch event dispatch, or native input.
  • Nothing is ever granted: every navigator.permissions.query answers prompt and Notification.permission is default, so a Notification fires error rather than showing. registerProtocolHandler validates its arguments and registers nothing, screen.orientation.lock rejects with NotSupportedError, and navigator.storage reports a 1 GiB quota with no usage and never persists. navigator.userAgentData names Jint.Browser only while the user agent is its own; any other user agent without metadata has no brands, and no Sec-CH-UA request headers are sent.
  • No file picker: clicking an <input type=file> records that a page asked for one. Page.SetInputFilesAsync and DOM.setFileInputFiles make the selection instead.
  • Hover dispatches movement but not mouse boundary events such as mouseenter.
  • contenteditable support is intentionally limited; structural editing such as Enter-created blocks is absent.
  • Isolated CDP worlds are aliases, not isolated realms.
  • Playwright and Puppeteer compatibility covers supported public/client paths, not every browser or protocol feature.
  • The package is not currently trim- or AOT-compatible.

CSS values come from the native renderless declaration and cascade model rather than computed rendering. Stylesheet @media rules use the emulated viewport, media type and supported preferences. Supported syntax and remaining differences are recorded in the DOM divergence register.

Prefer feature detection and handle NotSupportedException or protocol errors. Never use synthetic geometry as evidence of real visual placement.