Skip to content

Web APIs

Web APIs are globals, so there is nothing to import. Write the code you would write in a browser:

TypeScript
const response = await fetch('https://api.example.com/data');
const data = await response.json();
const socket = new WebSocket('wss://echo.example.com');
socket.addEventListener('message', (event) => console.log(event.data));
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode('hi'));

An --app gjs build scans the bundled output, works out which globals your code actually reaches, and registers only those: fetch becomes a Soup.Session call, WebSocket a Soup.WebsocketConnection, crypto.subtle a GLib-backed implementation. An --app browser build uses the browser’s own versions of the same source, and an --app node build leaves the ones Node, Bun and Deno already define to the runtime.

Sometimes you want the constructor as a value: to subclass it, to pass it around, or to keep a module free of globals. Every package exports its classes, and importing a package root has no side effects.

TypeScript
import fetch, { Headers, Request, Response, FormData } from '@gjsify/fetch';
import { WebSocket } from '@gjsify/websocket';
import { localStorage } from '@gjsify/webstorage';

These specifiers only resolve in a GJSify build, so prefer the globals in code that also has to run on Node.js or in a browser.

If a bundle dies with ReferenceError: X is not defined, the detector could not see X, usually because a library reads it through a stored globalThis reference. Keep auto detection on and name the identifier:

Terminal
gjsify build src/index.ts -o dist/index.js --globals auto,matchMedia

Groups work too (--globals auto,dom). The full identifier and group list is in the CLI Reference.

Web Platform Coverage

34 of 59 web standards

Coverage of relevant W3C and WHATWG standards, including 10 APIs that are explicitly out of scope for desktop GTK apps (Service Worker, FS Access, Web Bluetooth, …).

58% 32 full 2 partial 15 planned 10 out of scope
5 / 5 Full Full Full Full Full 1 / 5 localStorage + sessionStorage Full libgda could back Planned Planned Service Worker companion Out of scope Browser sandbox; GTK uses Gio.File directly Out of scope 5 / 5 Full Full Full Full Full 1 / 1 Full 4 / 5 Full Full Full Full scheduler.postTask — GLib idle could back Planned 2 / 4 file-based; no DOM-Worker shim Partial Full Browser multi-tab concept Out of scope HTTP cache proxy — irrelevant for GTK apps Out of scope 4 / 7 Phase 1: AudioContext + Source + Gain Partial Full Full Full GStreamer encodebin could back Planned no GNOME backend yet — multi-year effort Planned Native apps use ALSA/JACK directly Out of scope 4 / 8 Full Full Full Full Needed for Adwaita component composition Planned Planned Browser render-pipeline specific Out of scope Planned 2 / 5 Full Full Gdk.Seat.grab could back Planned GTK apps use BlueZ directly Out of scope Native apps use libusb/udev directly Out of scope 3 / 5 Full Full Full Trivial via Blob+streams Planned GTK uses Gio.File directly Out of scope 3 / 3 Full Full Full 0 / 3 Gio.Notification candidate Planned GeoClue2 + consent dialog Planned Planned 0 / 3 GLib.Mutex async wrapper Planned Planned Service Worker tier Out of scope
PackageBacked byWhat you get
@gjsify/abort-controllerpure TSAbortController, AbortSignal incl. .abort, .timeout, .any
@gjsify/compression-streamsGioCompressionStream, DecompressionStream (gzip, deflate, deflate-raw). Routed through node:zlib, which is Gio.ZlibCompressor on GJS
@gjsify/dom-eventspure TSEvent, CustomEvent, EventTarget, UIEvent, MouseEvent, PointerEvent, KeyboardEvent, WheelEvent, FocusEvent
@gjsify/dom-exceptionpure TSDOMException per WebIDL
@gjsify/domparserpure TSDOMParser.parseFromString over a minimal DOM. text/html runs an HTML5 tokenizer and tree builder, the XML types run the XML scanner, and an unsupported type throws rather than guessing. Subpaths /html, /selectors (CSS Selectors 4: querySelector, matches, closest) and /entities
@gjsify/eventsourceSoup 3.0EventSource (Server-Sent Events), TextLineStream
@gjsify/fetchSoup 3.0, Gio, GLibfetch(), Request, Response, Headers, redirects, file:// and data: URIs
@gjsify/formdatapure TSFormData, File, multipart encoding
@gjsify/gamepadManette 0.2 (Linux), SDL3 via @gjsify/gamepad-native (macOS, Windows)Gamepad, GamepadButton, GamepadEvent, GamepadHapticActuator (dual rumble)
@gjsify/message-channelpure TSMessageChannel, MessagePort. Also the transport behind iframe messaging and worker IPC
@gjsify/web-streamspure TSReadableStream (incl. byte streams), WritableStream, TransformStream, TextEncoderStream, TextDecoderStream
@gjsify/web-globalspure TSNamed re-exports of the common Web classes in one place. Its /register subpath sets them all on globalThis
@gjsify/webassemblypure TSWebAssembly.compile, instantiate, validate and the streaming variants, wrapping SpiderMonkey’s synchronous constructors
@gjsify/webaudioGst 1.0, GstApp 1.0AudioContext over a GStreamer decodebin and playback chain, AudioBufferSourceNode, GainNode, AudioParam
@gjsify/webcryptoGLib, GioSubtleCrypto (AES, AES-KW, RSA-OAEP, RSA-PSS, ECDSA, HMAC, PBKDF2, HKDF, ECDH), CryptoKey, getRandomValues, randomUUID. The algorithms come from node:crypto, entropy from /dev/urandom
@gjsify/webrtcGst 1.0, GstWebRTC 1.0, GstSDP 1.0RTCPeerConnection, RTCDataChannel, RTCRtpSender / Receiver / Transceiver, MediaStream, getUserMedia, RTCDTMFSender, RTCCertificate. WebRTC & Media Capture walks through a data channel, how a capture device gets picked, and the limits worth knowing
@gjsify/webrtc-nativeGst 1.0, GstWebRTC 1.0Prebuilt signal bridge that @gjsify/webrtc uses. You never import it directly
@gjsify/websocketSoup 3.0WebSocket, MessageEvent, CloseEvent, with NUL-safe text frames
@gjsify/webstoragepure TSStorage, localStorage, sessionStorage. Import only, they are not injected as globals, and both are in memory, so nothing survives a restart yet
@gjsify/xmlhttprequestSoup 3.0, GLibXMLHttpRequest with responseType arraybuffer, blob, json, text and document

Fifteen further standards are tracked as planned but not built yet, and ten are marked out of scope because they make no sense in a desktop GTK app. The dashboard above names each one.

The Adwaita widgets for --app browser builds are custom elements rather than a standard, and they are documented in the Adwaita gallery.

Every package declares the runtimes it supports, in a gjsify.runtimes field, and the answer differs per standard. fetch, WebSocket, crypto.subtle, FormData, WebAssembly and the compression streams are native on Node, Bun and Deno, so a build for those runtimes polyfills nothing. EventSource, DOMParser, localStorage and the DOM event classes carry a polyfill for them as well, and most of the pure TypeScript packages run in the browser and under NativeScript too. The GStreamer-backed AudioContext and RTCPeerConnection, and XMLHttpRequest, are declared for GJS and the browser only.

More than 50 packages across the Node, Web and DOM pillars ship a browser test suite that CI runs against real Firefox with Playwright. Runtimes has the full picture.