A native macOS client for GeForce NOW - built for Mac, built for controllers.
โฌ Download the latest release ยท What's new ยท Build from source
Independent community project. Not affiliated with, endorsed by, or sponsored by NVIDIA. NVIDIA and GeForce NOW are trademarks of NVIDIA Corporation; other product and storefront names are trademarks of their respective owners. Bundled components, their licenses, and trademark details are listed in the Third-Party Notices, which also ships inside the app bundle.
Huge thanks to @Jayian1890 - the main contributor of all base and core functionality of openNOW-Mac. This project stands on that foundation.
OpenNOW is written in SwiftUI from the ground up and driven by the same WebRTC and NVST streaming protocols the official desktop app uses - not a web view in a wrapper. The pitch is simple: treat a Mac like a Mac, and treat a controller like a controller. Browse your library and launch in seconds, stream at up to 5K, record the runs you want to keep, and play with a Steam Controller 2026 without ever installing Steam.
GeForce NOW works on a Mac, but the official client leaves a lot on the table - a mouse-and-keyboard web view, pillarbox bars baked into every ultrawide stream, and no love for the controllers people actually game with. OpenNOW fills those gaps with a real Mac app, and then keeps going.
| ๐ฎ Steam Controller 2026 support | Wired, Bluetooth LE, and both 2.4 GHz dongles. Full HID parsing, haptics, back grips, trackpads, custom mappings - no Steam required. |
| ๐ฅ๏ธ Built for ultrawide | 21:9 up to 5120ร2160 and 32:9 up to 5120ร1440, HEVC and AV1, and six ways to kill the black bars. More โ |
| ๐ผ Upscaling, on both transports | Off, Spatial, or MetalFX, targeting 2K/4K/5K, with live Clarity and Noise Reduction sliders - gamepad-navigable, same on WebRTC and native NVST. More โ |
| โก Native NVST transport | Stream over NVIDIA's NVST protocol on OpenNOW's own native stack - RTSPS control, raw-SRTP video, VideoToolbox decode - with no vendor runtime in the bundle. More โ |
| โบ๏ธ Record your sessions | One keystroke (โR) captures gameplay locally, with a browsable library and opt-in trim/crop/export editor. More โ |
| ๐ Your whole catalog | Hero rotation, game rails, search and filters, store ownership picker, persistent Library and Favorites - plus a live banner that drops you straight back into an active session. |
| ๐ Remote Co-Op | Invite a friend from a browser link and hand them a player slot in your session - hosted by OpenNOW itself, no server to deploy, host-approved, native input path. |
| โจ๏ธ On-screen keyboard in-stream | Steam + X summons a Steam Deck-style keyboard right over the game - dual trackpads aim, L2/R2 or a pad click types. Tap the โฌ key to flip it to the top of the screen when it overlaps something important. Works on any controller. |
| ๐ 5.1 / 7.1 surround | Multi-channel Opus on both transports, negotiated from your output device and membership, with a stereo fold for recordings and Remote Co-Op. |
| ๐ Session ready | Queue in the background: pick a system notification or have OpenNOW come to the front the moment your seat is ready. |
| ๐ Settings you can find | Nine destinations named for what they hold, and a search that answers the word you know: type 5.1, black bars or vsync and it lands on the setting. More โ |
| ๐ฌ Discord Rich Presence | Your friends see what you're playing, automatically. |
| ๐น๏ธ Full controller navigation | Drive the entire app - catalog, details, settings - from the pad. Never reach for the mouse. |
| ๐ Real diagnostics | Live stream HUD, session timers, network stats, and exportable logs when something goes wrong. |
- Download
OpenNOW.dmgfrom the Releases page. - Open it and drag OpenNOW to Applications.
- Launch from Spotlight. If macOS blocks it, right-click the app โ Open.
Requires macOS 15.6 or later and your own GeForce NOW account.
Pick your shape, then your resolution - 16:9, 16:10, 21:9, or 32:9. The wide end tops out at 5120ร2160 on 21:9 and 5120ร1440 on 32:9, all at 30/60/120/240 fps. HEVC carries true 5K streams where H.264 hardware decode runs out of headroom, and AV1 leans in whenever bandwidth is the bottleneck, decoded in hardware on M3-and-later Apple silicon. 10-bit 4:2:0/4:4:4 colour is there when the codec supports it, HDR10 rides a 10-bit HEVC stream straight to an EDR drawable on both transports, and any codec your Mac can't decode greys itself out instead of failing mid-session.
GeForce NOW bakes pillarbox columns into 16:9-only titles - real black pixels, not window padding, so a wide monitor is stuck with them. OpenNOW detects those bars in the incoming frames and lets you decide what fills them:
| Mode | What you get |
|---|---|
| Black | Leave the encoded bars alone. Zero cost, default. |
| Colour | Flat fill in any colour you pick. |
| Blur Mirror | Mirrors the picture edge outward, blurred. Seamless, no distortion. |
| Blur Zoom | Blown-up blurred copy of the frame behind the sharp image. |
| Stretch | Fills the full width, pushing distortion to the edges so the centre stays true. |
| Crop | Scales to fill and trims top and bottom. No bars, no warping - costs vertical view. |
Blur modes take an adjustable dim. Everything but Black runs through the custom Metal render path.
Three tiers, three targets, and it's the same feature whether you're on WebRTC or native NVST - pick a resolution the game doesn't actually render at and let the client fill in the rest.
| Tier | What it does |
|---|---|
| Off | Present the decoded frame as-is. Zero cost, default. |
| Spatial | A custom Metal shader: edge-aware sharpen and denoise, tuned per source resolution. |
| MetalFX | Apple's spatial scaler, perceptual color processing, best detail reconstruction at a real GPU cost. |
Pick a target of 2K, 4K, or 5K and the output caps there - never past your actual window or display size, so it never spends GPU time supersampling beyond what you'd see anyway. Clarity and Noise Reduction sliders tune the Spatial/MetalFX pass live, mid-stream. Every control - tier, target, both sliders - is gamepad-navigable from the in-stream HUD (โG), no mouse required.
WebRTC is the default, but it isn't the only way in. OpenNOW also speaks NVST - NVIDIA's native streaming protocol - on its own native stack, reproducing the exact pipeline the official client establishes, with no NVIDIA libraries in the bundle.
- OpenNOW's own implementation, no vendor runtime - an RTSPS-over-WSS control channel (OPTIONS โ DESCRIBE โ SETUP โ ANNOUNCE โ PLAY), a client-generated SRTP master key, and a video handoff derived from the seat's answers the same way the native client derives it.
- Native video and input - Mjolnir video access units (H.264, HEVC, and AV1) decode through VideoToolbox, while keyboard, mouse, text, and gamepad input plus audio ride the SCTP data channels of the seat's ICE/DTLS bundle.
- Live native telemetry - latency, jitter, bitrate, packet and frame loss in the in-stream stats HUD, plus a network governor that adapts bitrate to path conditions.
- Microphone on NVST - when the seat offers bundle mic in DESCRIBE (every current seat does), the bundle carries a send-only Opus mic section exactly like the official client, driven by push-to-talk / voice-activity / mute / the volume slider. Verified live on 2026-09-03: game audio and voice chat together on a fresh session. Seats on NVST's legacy RTSP mic transport are not supported yet and report that when the mic is enabled. Settings โ Audio has a local microphone test either way.
- Session recording - โR captures decode frames and game audio straight off the native pipeline.
Enable it in Settings โ Network โ Transport โ Native/NVST Transport. Off keeps the default WebRTC session path.
The two-transport architecture is documented in docs/StreamTransportArchitecture.md, and the provenance of the vendor-protocol code in docs/PROTOCOL_PROVENANCE.md.
OpenNOW talks to Valve's controllers directly over HID, so you get the pad in your GeForce NOW stream without Steam running in the background.
- Every 2026 variant - wired, BLE, and both dongles - plus the original 2015 controller.
- Haptics, grips, trackpads - rumble feedback, four back grips, and both pads parsed and bindable client-side.
- Visual mapping editor - click any control on the controller diagram and bind it to a gamepad button, a key, a mouse action, or nothing at all.
- Combos on any control - bind a back grip to
B + R2; the modifier lands first, the press follows a beat later, so games read it as a real combo. - Profiles - save as many as you like and switch between them.
- Built-in tester - Settings โ Input โ Steam Controller shows every button, axis, and pad live.
- Lizard mode off - the firmware's keyboard/mouse emulation is suppressed so nothing leaks to the desktop.
A Steam Deck-style overlay for logins, chat, and search fields in any GeForce NOW title. The keyboard works on both the WebRTC and native NVST streaming paths and sends keys exactly the way a physical keyboard does - UTF-8 text for characters, macOS keycodes for Return/Backspace.
- Dual trackpads each own one half of the grid. Touch a pad to aim, click it (or pull L2/R2) to type the aimed key.
- No trackpads? D-pad or left stick moves the grid cursor; A types, B is Backspace, X is Space, Y toggles Shift, Start presses Enter.
- Overlapping game UI? Tap the โฌ position key in the bottom bar to flip the keyboard to the top of the screen.
- Steam alone still works as the local-cursor modifier - hold Steam to drive the Mac cursor with the right pad, same as before.
Steam grabs the controller exclusively while it's running. Quit Steam first.
Supported hardware and report formats
| Product ID | Device |
|---|---|
0x1102 |
Steam Controller (2015), wired |
0x1142 |
Steam Controller (2015) wireless dongle |
0x1302 |
Steam Controller (2026, "Triton"), wired |
0x1303 |
Steam Controller (2026), Bluetooth LE |
0x1304 |
Steam Controller (2026) 2.4 GHz dongle ("Proteus") |
0x1305 |
Steam Controller (2026) dongle variant ("Nereid") |
Pipeline
OPN/Stream/SteamControllerHIDMonitor.swiftmatches devices by vendor ID0x28deand the product IDs above, opens them via IOKit HID, disables lizard mode with periodic heartbeats, and streams raw input reports.OPN/Stream/SteamControllerReport.swiftparses each report into aSteamControllerInputSnapshot(buttons, triggers, sticks, trackpads).- Snapshots feed the in-app test screen and, during streaming,
NativeWebRTCGamepadMonitor, which forwards a standard gamepad subset to the GeForce NOW session. Steam/QAM, back grips, and trackpads are parsed and bindable client-side but not forwarded as raw stream input.
Report layouts - bit/byte mappings verified against Valve's contributions to SDL's HIDAPI drivers:
- Legacy (2015) -
ValveInReport_t-framed packets; buttons across three bytes, trackpads double as stick/D-pad emulation. Reference:SDL_hidapi_steam.c. - Triton (2026) - report IDs
0x42(wired/dongle state),0x45(BLE state), and0x47(timestamped state; inserts a 16-bit trackpad timestamp before the pad fields, shifting them by 2 bytes). A 32-bit button mask includes the Steam button (0x0001_0000), Quick Access (0x0000_0010), four back grips, trackpad touch/click bits, and per-pad X/Y plus pressure. Reference:SDL_hidapi_steam_triton.c. - Deck state - report ID
0x09, the Steam Deck-style 64-bit button mask with pads at fixed offsets; used when a device speaks the deck packet format. Reference:SDL_hidapi_steamdeck.c.
Struct layouts for all three formats are documented in SDL's controller_structs.h. Axis values normalize to -1...1 (Int16 full scale), triggers and pad pressure to 0...1. Parsing is covered by Tests/Stream/SteamControllerReportTests.swift.
โR starts and stops a local capture on either transport - frames come straight off the decode path and game audio off the stream, so nothing is re-encoded from the screen and no Screen Recording permission is involved. Recordings land in a browsable library with search, sort, and resolution filters.
Quick Edit is opt-in and non-destructive - trim the ends, split and cut a middle section, join what is left, then save as a new video. The advanced pass adds crop, rotate, flip, speed, and audio. The original file is never rewritten.
Nine destinations named for what they hold - Account, Video, Audio, Input, Recording, Network, Remote Co-Op, General, and Labs - down a sidebar that shows all of them at once. Settings that arrived recently wear a NEW tag until you have seen them, so a new option in a tab you never open still announces itself.
Search answers the word you already know rather than the one the setting is filed under: type 5.1, black bars, or vsync and it lands on the row, in whichever tab it lives.
xcodebuild build -project OpenNOW.xcodeproj -scheme OpenNOW -configuration Debug -destination platform=macOS CODE_SIGNING_ALLOWED=NORun the package tests from the repository root so SwiftPM uses one shared .build graph:
swift test --scratch-path .build/sharedProject layout, packages, and tooling
Layout
Model- persisted SwiftData models, DTOs, stream value types, Twitch realtime models, and catalog value objectsOpenNOWApp.swift- macOS app entry pointApp- application delegate and app-lifecycle wiringResources- bundled images, fonts, and store icon assetsView- SwiftUI/AppKit views, stream host views, design primitives, and asset catalogsViewModel- observable UI state for login, catalog, controller catalog, and recordingsOPN- authentication, catalog/session services, native WebRTC, telemetry, Twitch, preferences, logging, and app infrastructureGFN- protocol-specific GeForce NOW clients and wire types (CloudMatch, GDN, Jarvis, LCARS, NesAuth, NetworkTest, NVST, Starfleet, UDS)RemoteCoOp- Remote Co-Op operator notes; the guest page itself ships inResources/RemoteCoOp/browserTests- root SwiftPM test target covering the package-exposed production logic
Packages
The root Package.swift exposes a testable OpenNOW library target over non-app-entry production logic from Model, OPN, and GFN. The Xcode app target compiles all six production directories - those three plus App, View, and ViewModel.
Focused test runs
swift test --scratch-path .build/shared --filter WebRTCStreamRecording
swift test --scratch-path .build/shared --filter OpenNOWGameServicesTestsAvoid package-local build directories during normal development. Use the root package and shared scratch path so generated SwiftPM state stays in one place and large binary artifacts such as sentry-cocoa are not duplicated.
scripts/report-spm-build-size.sh # audit generated SwiftPM disk usage
scripts/clean-spm-builds.sh # reclaim disk spacePull requests welcome. Use conventional commit prefixes (fix:, feat:, docs:, test:, refactor:, style:, chore:), keep changes focused, and verify the relevant package tests or app build before submitting.





