IP KVM USBridgeRemote access at level 0

The Software Agent works while the system is alive. KVM 2.0 goes below it, all in one USBridge Client.

  1. Desktop and appsSoftware Agent
  2. Operating systemSoftware Agent
  3. Level 0BIOS, boot, powerKVM 2.0 only
  • ~45 msvideo latency
  • 60 FPS1080p, no dropped frames
  • ISOinstall an OS, no USB stick
  • Tailscaleno port forwarding

System frozen or won't boot?The KVM is still there.

The Software Agent runs the system while it's up. When it freezes, won't boot or the computer is off, KVM 2.0 sees the screen from power-on.

  • Change the boot order, overclocking or virtualization as if you were sitting at the monitor.

Choose your KVM.Four devices, one KVM OS.

USBridge NanoNew

Nano KVM preview

Ultra-compact KVM

The most compact KVM setup powered by USBridge OS. Includes a pre-flashed MicroSD card for seamless, out-of-the-box integration into your USBridge ecosystem.

USBridge KVM 2.0Low

USBridge KVM 2.0 Low

Minimalist Board Edition

Base kit for integration. A board with a heatsink and a USB capture dongle — the right fit for rack mounting.

USBridge KVM 2.0Standard

USBridge KVM 2.0 Standard

Complete Desktop Kit

A ready-to-use device in a stylish case. The kit includes a USB-C cable and a video capture card.

Recommended

USBridge KVM 2.0Full

USBridge KVM 2.0 Full

Ultimate Pro Kit + ATX

The full all-in-one kit. A KVM with an ATX control board, an interactive screen, and aluminum heatsink.

Compare the kits

Nano$89Low$99Standard$117RecommendedFull$139
BoardSipeed NanoKVM (SG2002)Radxa Zero 3WRadxa Zero 3WRadxa Zero 3W
Processor1 RISC-V core, 1 GHz4 Cortex-A55 cores, 1.6 GHz4 Cortex-A55 cores, 1.6 GHz4 Cortex-A55 cores, 1.6 GHz
Memory256 MB1 GB1 GB1 GB
Video1080p 60 FPS1080p 60 FPS1080p 60 FPS1080p 60 FPS
InternetEthernet portWi-Fi 6Wi-Fi 6Wi-Fi 6
CaseCustom caseCustom caseCustom case
Dimensions49×41×41 mm69×36×34 mm69×36×34 mm
Screen128×64240×240240×240
ATX power control
MicroSD with KVM OS+$5 optional
Lifetime KVM OS license
14 days to return
EU right of withdrawal. We collect faulty units at our cost.
No subscription
The KVM OS license is part of the device price.
Ships to 45 countries
Pricing varies by region.
A company in Spain
USBridge Technologies S.L. Support: kvm@usbridge.io and Discord.

Zero Latency.Absolute Hardware Autonomy.

Execute Layer 0 BIOS/UEFI control, real-time OCR text recognition, immutable Btrfs rollbacks, and autonomous AI diagnostics.

USBridge
Generic IP-KVM

Drag the slider to compare with a generic IP-KVM

  • 45ms Latency

    Sub-frame encoding guarantees an imperceptible delay between physical input and visual response.

  • 60 FPS Stream

    High-refresh-rate remote rendering for precise cursor control and UI navigation.

  • Zero Dropped Frames

    Hardware-level network optimization ensures continuous frame delivery even under high bandwidth loads.

Access from anywhere

One client on every device: a computer, a phone or just a browser.

  • Apps for Windows, macOS, Linux, iOS and Android
  • Browser: web.usbridge.io, or the web client served by the KVM itself, even offline
  • Built-in Tailscale: reach it from anywhere with no port forwarding or public IP
  • The same client also runs USBridge software agents for computers without a KVM

Virtual media

No more USB sticks: an image connects to the computer as a real USB drive.

  • ISO mounts as a CD/DVD drive, so you install an OS straight from the BIOS
  • IMG, VDI, VMDK and whole drives of your computer mount as a hard drive you can boot from
  • No need to upload the image to the KVM: it streams from your computer, with a RAM cache for fast boots
  • Overlay mode sends every write to a separate layer and keeps the source image untouched

Peripheral emulation

The computer sees ordinary USB devices, with no drivers or setup.

  • The keyboard works from the first second: in the BIOS, UEFI and boot loader
  • Absolute 1:1 or relative mouse for older systems, plus touch and pen
  • Gamepad as an Xbox 360 controller (XInput) or generic DirectInput
  • The computer's sound on your side, your microphone on its side, and USB networking when an installer lacks a NIC driver

Storage with snapshots

Images and files on the microSD inside the KVM are safe from deletion and ransomware.

  • 30 seconds after changes stop, the KVM takes a read-only snapshot on its own
  • Even with root, the computer cannot change or delete finished snapshots
  • Need an older file? Mount the snapshot and copy it; the log shows what changed
  • Plain Btrfs: any Linux machine can read the card

BIOS as text over SSH

Radxa & KVM 2.0

The KVM reads the screen on the device itself and shows the BIOS in a normal terminal.

  • Connect with ssh: no browser, no heavy video stream
  • Copy POST codes, serial numbers and MAC addresses as plain text
  • Navigate with arrows, Enter and Esc, like any console
  • Recognition runs on the KVM, with no cloud

Scripts and AI agents

Radxa & KVM 2.0
# name: Install Proxmox VE (Terminal UI)
# desc: Fully offline/automated Proxmox VE 9.2 install via the ncurses Terminal UI installer.

ENTER = 0x28
ESC = 0x29
BACKSPACE = 0x2A
TAB = 0x2B
SPACE = 0x2C
HOME = 0x4A
PAGEUP = 0x4B
END = 0x4D
PAGEDOWN = 0x4E
RIGHT = 0x4F
LEFT = 0x50
UP = 0x52
DOWN = 0x51

ROOT_PASSWORD = "112233445566"
ADMIN_EMAIL_USER = "example"
ADMIN_EMAIL_DOMAIN = "gmail.com"
HOSTNAME = "test.usbridge.io"
IP_ADDRESS = ""
CIDR = ""
GATEWAY = ""
DNS = ""


def dump_screen(tag="SCREEN DUMP"):
    print("--- %s ---" % tag)
    for line in screen_text():
        if line.strip() != "":
            print("  | " + line)
    print("--- END %s ---" % tag)


def checkpoint(name):
    print("=== CHECKPOINT: %s ===" % name)
    dump_screen("CHECKPOINT: " + name)


def looks_like_wrong_grub():
    return screen_fuzzy_contains("gnu grub", max_errors=1) or (
        screen_fuzzy_contains("advanced options for", max_errors=2)
        and screen_fuzzy_contains("gnu/linux", max_errors=1)
    )


def wait_grub_or_fallback(ceiling_ms=40000, poll_ms=1000, stable_count=3):
    for i in range(5):
        sleep(poll_ms)
        if screen_fuzzy_contains(
            "Terminal UI", max_errors=1
        ) or screen_fuzzy_contains("arrow keys", max_errors=2):
            print("GRUB menu text matched directly after ~%dms" % ((i + 1) * poll_ms))
            return True
        if (
            screen_fuzzy_contains("bios", max_errors=1)
            or screen_fuzzy_contains("aptio", max_errors=1)
            or screen_fuzzy_contains("setup utility", max_errors=1)
        ):
            continue

    print("Waiting for GRUB screen to settle...")
    if wait_screen_settled(
        timeout_ms=ceiling_ms,
        poll_ms=poll_ms,
        max_diff_lines=2,
        stable_count=stable_count,
    ):
        print("GRUB screen settled.")
        return True

    return False


def wait_for_eula_or_bail(timeout_ms=240000, poll_ms=2000):
    print("Waiting for: EULA screen (EULA + I agree button)")
    for i in range(timeout_ms // poll_ms):
        if screen_fuzzy_contains("EULA", max_errors=1) and screen_fuzzy_contains(
            "I agree", max_errors=2
        ):
            print("OK: reached EULA screen")
            return True
        if screen_fuzzy_contains(
            "welcome to the proxmox virtual environment", max_errors=3
        ) or screen_match("[a-z0-9._-]+ login:"):
            print("ABORT: booted into an ALREADY-INSTALLED system.")
            dump_screen("ALREADY INSTALLED")
            return False
        sleep(poll_ms)
    dump_screen("EULA TIMEOUT")
    return False


def still_on_eula():
    return screen_fuzzy_contains("EULA", max_errors=1) and screen_fuzzy_contains(
        "I agree", max_errors=2
    )


def accept_eula(max_attempts=4):
    for attempt in range(max_attempts):
        sleep(1000)
        if attempt == 0:
            key_press(ENTER)
        elif attempt == 1:
            key_press(RIGHT)
            sleep(3000)
            key_press(ENTER)
        else:
            key_press(TAB)
            sleep(3000)
            key_press(ENTER)
        sleep(2000)
        if not still_on_eula():
            print("Accepted EULA (attempt %d)" % (attempt + 1))
            return True
        print("EULA still on screen after attempt %d, retrying..." % (attempt + 1))
    return False


def wait_and_log(text, timeout_ms, label, max_errors=0):
    print("Waiting for: %s (%s)" % (label, text))
    ok = wait_text(text, timeout_ms=timeout_ms, max_errors=max_errors)
    if ok:
        print("OK: reached " + label)
    else:
        dump_screen("TIMEOUT WAITING FOR: " + label)
    return ok


def still_looks_like_bios(attempts=12, delay_ms=1700):
    for attempt in range(attempts):
        in_bios_interactive = screen_fuzzy_contains(
            "boot override", max_errors=2
        ) or screen_fuzzy_contains("F10: Save", max_errors=1)
        looks_like_grub = screen_fuzzy_contains(
            "Terminal UI", max_errors=1
        ) or screen_fuzzy_contains("arrow keys", max_errors=2)
        if looks_like_grub:
            return False
        if in_bios_interactive:
            return True
        if attempt < attempts - 1:
            sleep(delay_ms)
    return False


def clear_field_end():
    key_press(END)
    sleep(200)
    for i in range(40):
        key_press(BACKSPACE)
        sleep(50)
    sleep(200)


def clean_ocr_text(text):
    t = text.lower()
    for ch in [".", ",", "'", "`", "~", "^", "_", "|", " ", "-", ":", "(", ")", "<", ">"]:
        t = t.replace(ch, "")
    return t


def keyboard_line_is_us():
    for line in screen_text():
        cl = clean_ocr_text(line)
        if "keyboard" in cl or "layout" in cl:
            if "usenglish" in cl or "english" in cl or "u.s." in cl:
                return True
    return False


def select_us_keyboard_layout():
    print("Selecting U.S. keyboard layout...")

    # 1. Dismiss any open popups
    key_press(ESC)
    sleep(300)
    key_press(ESC)
    sleep(500)

    # 2. Normalize to <Next>: drop to bottom button row and move full right
    for _ in range(4): key_press(DOWN); sleep(150)
    for _ in range(3): key_press(RIGHT); sleep(150)
    sleep(500)

    # 3. Exactly ONE Up reaches Keyboard layout field
    print("Navigating UP x1 from <Next> to Keyboard Layout field...")
    key_press(UP)
    sleep(800)

    # 4. Open dropdown menu
    key_press(ENTER)
    sleep(1200)

    # 5. Jump to the bottom of the list using PageDown
    print("Scrolling to bottom of layout list via PageDown x4...")
    for _ in range(4):
        key_press(PAGEDOWN)
        sleep(250)
    sleep(600)

    # 6. Move UP x1 from 'United Kingdom' (bottom) to 'U.S. English' (second to last)
    print("Moving UP x1 to select U.S. English...")
    key_press(UP)
    sleep(600)

    # 7. Confirm selection
    key_press(ENTER)
    sleep(1200)

    if keyboard_line_is_us():
        print("Successfully selected U.S. English via PageDown+Up")
        dump_screen("KEYBOARD VERIFIED US")
        return True

    # 8. Fallback: cycle with RIGHT arrow if popup was not active
    print("Popup PageDown missed, cycling field with RIGHT arrow...")
    for step in range(30):
        if keyboard_line_is_us():
            print("Successfully found U.S. English after %d cycles" % step)
            dump_screen("KEYBOARD VERIFIED US")
            return True
        key_press(RIGHT)
        sleep(300)

    dump_screen("KEYBOARD SELECTION FAILED")
    return False


def type_email():
    type_text(ADMIN_EMAIL_USER + "@" + ADMIN_EMAIL_DOMAIN)


def configure_network_fields():
    print("Configuring network fields...")
    dump_screen("NETWORK SCREEN ARRIVAL")

    for _ in range(5):
        key_press(UP)
        sleep(300)

    clear_field_end()
    type_text(HOSTNAME)
    sleep(500)
    print("Hostname set to " + HOSTNAME)

    if IP_ADDRESS != "":
        key_press(TAB)
        sleep(300)
        clear_field_end()
        type_text(IP_ADDRESS)
        sleep(500)
        key_press(UP)
        sleep(300)

    if CIDR != "":
        key_press(TAB)
        sleep(200)
        key_press(TAB)
        sleep(200)
        clear_field_end()
        type_text(CIDR)
        sleep(500)
        key_press(UP)
        sleep(200)
        key_press(UP)
        sleep(300)

    if GATEWAY != "":
        for _ in range(3):
            key_press(TAB)
            sleep(200)
        clear_field_end()
        type_text(GATEWAY)
        sleep(500)
        for _ in range(3):
            key_press(UP)
            sleep(200)

    if DNS != "":
        for _ in range(4):
            key_press(TAB)
            sleep(200)
        clear_field_end()
        type_text(DNS)
        sleep(500)
        for _ in range(4):
            key_press(UP)
            sleep(200)


def landmark_seen(text, max_errors):
    clean_needle = clean_ocr_text(text)
    for line in screen_text():
        if fuzzy_match(clean_needle, clean_ocr_text(line), max_errors):
            return True
    return False


def abort_dialog_seen():
    return screen_fuzzy_contains("Abort installation", max_errors=2) or screen_fuzzy_contains("abort the installation", max_errors=2)


def install_failed_seen():
    for line in screen_text():
        clean = clean_ocr_text(line)
        if "failed" in clean and ("install" in clean or "package" in clean or "error" in clean or "extract" in clean or "partition" in clean or "create" in clean):
            return True
    return False


def install_progress_visible():
    return (
        screen_fuzzy_contains("extracting", max_errors=1)
        or screen_fuzzy_contains("create LVs", max_errors=1)
        or screen_fuzzy_contains("installing", max_errors=1)
        or screen_fuzzy_contains("creating root filesystem", max_errors=3)
        or screen_fuzzy_contains("cleanup root-disks", max_errors=2)
        or screen_fuzzy_contains("unmounting", max_errors=1)
        or screen_fuzzy_contains("resizing", max_errors=1)
        or screen_fuzzy_contains("copying files", max_errors=2)
        or screen_fuzzy_contains("running post", max_errors=2)
        or screen_match("%")
        or screen_match("[0-9]{1,3} *[%g]")
    )


def advance_from_network_screen():
    print("Advancing from Network configuration to Summary...")
    for attempt in range(3):
        if abort_dialog_seen():
            key_press(ESC)
            sleep(400)
            key_press(ENTER)
            sleep(500)

        print("Navigating DOWN x6 from Hostname to button row...")
        for _ in range(6):
            key_press(DOWN)
            sleep(200)

        print("Moving RIGHT x2 to focus <Next>...")
        for _ in range(2):
            key_press(RIGHT)
            sleep(200)

        key_press(ENTER)
        sleep(3000)

        if landmark_seen("Summary", 1) or install_progress_visible():
            print("Successfully advanced to Summary/Install screen")
            dump_screen("SUMMARY REACHED")
            return True

        print("Screen did not advance on attempt %d, recovering..." % (attempt + 1))
        dump_screen("NETWORK ADVANCE RETRY")
        if landmark_seen("Root password", 1):
            key_press(ENTER)
            sleep(2000)
            for _ in range(5):
                key_press(UP)
                sleep(200)

    return False


def main():
    print("=== Proxmox VE Terminal UI unattended install ===")

    print("Rebuilding USB gadget (keyboard, mouse, install ISO)...")
    reconnect_gadget(keyboard=True, mouse=True, rndis=False, sources=["proxmox-ve_9.2-1.iso"])
    sleep(5000)

    run_script("boot_override_cd.star")
    sleep(500)

    if still_looks_like_bios():
        print("ABORT: still in interactive BIOS Setup Utility after boot_override_cd.star")
        dump_screen("STILL IN BIOS")
        return
    checkpoint("BIOS boot-override -> booting ISO")

    wait_grub_or_fallback()
    if looks_like_wrong_grub():
        print("ABORT: detected installed system GRUB menu instead of ISO installer")
        dump_screen("WRONG GRUB")
        return
    key_press(DOWN)
    sleep(300)
    key_press(ENTER)
    print("Selected: Install Proxmox VE (Terminal UI)")
    checkpoint("grub -> installer boot")

    if not wait_for_eula_or_bail(240000):
        print("ABORT: EULA screen never appeared")
        return
    if not accept_eula():
        print("ABORT: could not accept EULA")
        return
    checkpoint("EULA accepted")

    harddisk_seen = False
    country_seen_early = False
    print("Waiting for target harddisk screen (or Country screen if skipped)...")
    for i in range(150):
        if screen_fuzzy_contains("harddisk", max_errors=1):
            harddisk_seen = True
            break
        if screen_fuzzy_contains("Country", max_errors=1) and screen_fuzzy_contains(
            "Timezone", max_errors=1
        ):
            country_seen_early = True
            break
        sleep(1000)

    if not harddisk_seen and not country_seen_early:
        print("ABORT: target harddisk screen never appeared")
        dump_screen("NO HARDDISK SCREEN")
        return

    if harddisk_seen:
        dump_screen("TARGET DISK SCREEN")
        sleep(3000)
        key_press(ENTER)
        print("Accepted default target disk")
        checkpoint("target disk accepted")
    else:
        checkpoint("target disk accepted (implicitly skipped)")

    print("Waiting for: country/timezone screen (Country + Timezone)")
    country_seen = False
    for i in range(15):
        if screen_fuzzy_contains("Country", max_errors=1) and screen_fuzzy_contains(
            "Timezone", max_errors=1
        ):
            country_seen = True
            break
        sleep(1000)
    if not country_seen:
        print("ABORT: country screen never appeared")
        dump_screen("NO COUNTRY SCREEN")
        return

    keyboard_layout_seen = False
    for i in range(10):
        if screen_fuzzy_contains("keyboard layout", max_errors=2):
            keyboard_layout_seen = True
            break
        sleep(300)
    if not keyboard_layout_seen:
        print("ABORT: 'Keyboard layout' field never appeared")
        dump_screen("NO KEYBOARD FIELD")
        return

    if not select_us_keyboard_layout():
        print("ABORT: could not confirm U.S. keyboard layout")
        return

    for _ in range(4): key_press(DOWN); sleep(150)
    for _ in range(3): key_press(RIGHT); sleep(150)
    sleep(500)
    key_press(ENTER)
    print("Accepted country/timezone, keyboard layout confirmed U.S.")
    checkpoint("country/timezone/keyboard accepted")

    if not wait_and_log("Root password", 15000, "password screen", max_errors=1):
        print("ABORT: password screen never appeared")
        return
    sleep(1500)
    type_text(ROOT_PASSWORD)
    sleep(200)
    key_press(TAB)
    sleep(300)
    type_text(ROOT_PASSWORD)
    sleep(200)
    key_press(TAB)
    sleep(300)
    clear_field_end()
    type_email()
    sleep(300)
    print("Filled password + email")
    checkpoint("password/email filled")

    reached_network = False
    for attempt in range(6):
        for i in range(3):
            key_press(TAB)
            sleep(400)
        key_press(ENTER)
        sleep(3000)
        if (
            landmark_seen("Management", 3)
            or landmark_seen("Hostname", 2)
            or landmark_seen("Gateway", 2)
            or landmark_seen("interface", 2)
        ):
            reached_network = True
            break
        if abort_dialog_seen():
            key_press(ENTER)
            sleep(800)
            continue
        if landmark_seen("Timezone", 2) or landmark_seen("Country", 2):
            key_press(ENTER)
            sleep(1200)
            continue
    if not reached_network:
        print("ABORT: could not advance past password screen")
        dump_screen("PASSWORD SCREEN STUCK")
        return

    checkpoint("password screen -> network config")
    sleep(1500)
    configure_network_fields()

    if not advance_from_network_screen():
        print("ABORT: could not advance past network config screen")
        dump_screen("NETWORK SCREEN STUCK")
        return

    checkpoint("network config -> summary")
    if install_progress_visible() or not screen_fuzzy_contains(
        "Previous", max_errors=1
    ):
        print("Install already in progress — skipping Summary keystrokes")
    else:
        sleep(500)
        key_press(RIGHT)
        sleep(300)
        key_press(RIGHT)
        sleep(300)
        key_press(ENTER)
        sleep(3000)

    if (
        screen_fuzzy_contains("continue", max_errors=1)
        or screen_fuzzy_contains("erase", max_errors=1)
        or screen_fuzzy_contains("wipe", max_errors=1)
        or screen_fuzzy_contains("confirm", max_errors=1)
    ):
        print("Confirm-install dialog shown — accepting")
        key_press(ENTER)
        sleep(1000)

    already_booted = False
    ok = False
    for i in range(900000 // 1000):
        if screen_fuzzy_contains("Installation successful", max_errors=1):
            ok = True
            break
        if install_failed_seen():
            print("ABORT: Installation failure detected on screen!")
            dump_screen("INSTALL FAILURE DETECTED")
            break
        if screen_match("[a-z0-9._-]+ login:"):
            already_booted = True
            break
        if abort_dialog_seen():
            key_press(ENTER)
        sleep(1000)

    if already_booted:
        checkpoint("summary -> install (already booted)")
        print("Install finished and rebooted.")
    elif ok:
        checkpoint("summary -> install complete")
        print("Install reported success — ejecting ISO")
        eject_media()
        sleep(1000)
        key_press(ENTER)
    else:
        print("ABORT/UNKNOWN: install did not report success within 15 min")
        dump_screen("INSTALL TIMEOUT")
        return

    if already_booted or wait_and_log(
        "login:", 180000, "Proxmox login prompt", max_errors=1
    ):
        checkpoint("install -> login prompt (final)")
        print("=== SUCCESS: Proxmox VE installed and booted to login prompt ===")
        dump_screen("FINAL LOGIN PROMPT")
    else:
        print("=== UNVERIFIED: install finished but no login prompt seen yet ===")
        dump_screen("UNVERIFIED FINAL STATE")


main()

Scripts and AI see the screen as text, so BIOS chores can be automated.

  • Starlark scripts (Python syntax) wait for text on the screen and press keys
  • Run them from the client, from the KVM's screen or over the REST API
  • Built-in MCP server: an AI agent such as Claude reads the screen, moves through the BIOS and mounts ISOs
  • For example, an OS install from entering the BIOS to the final reboot with nobody at the keyboard

Power control

Power on, power off and hard reset, even when the computer is completely frozen.

  • The ATX board wires into the Power and Reset buttons on the motherboard
  • See whether the power and drive LEDs are lit
  • Galvanic isolation up to 3.75 kV keeps the computer's noise away from the KVM
  • Presses need a hold to confirm, so a server never reboots by accident

Reviewsfrom owners

Your review

Rating
What you have
Not published, only for checks

By sending, you agree to the privacy policy

USBridge KVM 2.0against popular IP KVMs.

Compared with the most popular IP KVMs, using the makers' official sites.

JetKVM MiniUSBridge KVM 2.0PiKVM V4 MiniTinyPilot Voyager 3
Price$39from $99from $252$399
Video1080p 30 / 720p 601080p 60 FPS1920×1200, 60 FPS1920×1200, 60 FPS
Latencynot stated~45 msnot stated80–100 ms
Network100 Mbps Ethernet or Wi-FiWi-Fi 6, Ethernet via a USB hubEthernetGigabit Ethernet
ATX power control
Virtual drive (ISO)
Screen on the device
Snapshots with rollback
BIOS text for AI agents (OCR, MCP)Paid license

Data from jetkvm.com, pikvm.org and tinypilotkvm.com, November 2026. PiKVM price is from resellers, excluding VAT. A dash means the maker's site doesn't list the feature. On USBridge, power control comes with the Full kit and the screen with Standard and Full. Prices can change and vary by region, so check the current price on each maker's official site.

Already have a board?Install USBridge firmware.

Turn standard single-board computers into an IP KVM: enterprise-grade out-of-band management appliances. Gain full BIOS control, immutable Btrfs snapshots, and ultra-low latency streaming through native USBridge Client integration.

Download for free

Open License Manager
Free 24-hour evaluation. Reactivate anytime directly from the device.
Manufacturer:

Board Packages

After flashing: connect to it

Default IP address

10.55.0.1, over the USB cable. Plug the board's USB cable into your computer: the computer gets a USB network adapter (its own internet is untouched) and the KVM is 10.55.0.1 on it. Open http://10.55.0.1 for the setup page: QR code, connect link, key, Moonlight PIN and network settings. On the Sipeed NanoKVM it's always there; on the other boards while the KVM isn't set up yet or has no network address.

On your network (Ethernet, Wi-Fi): the address your router gives it by DHCP, there's no fixed default. The setup page shows it at the top, and so does the front-panel screen on boards with one.

Ways to connect: separate methods, pick one
  1. Recommended, the desktop app: + → Over USB. It finds the KVM on the cable and pairs by itself.
  2. Phone or tablet: open http://10.55.0.1 on the computer the KVM is plugged into and scan its QR code with the mobile app.
  3. Front-panel screen (boards with a screen): Settings → Authentication → Show Master Key, scan the QR code.
  4. Many devices, or the network set before first boot: a provisioning file (usbridge_provision.json). You choose the key and write it into the file; there's no QR code.

No app at hand? The setup page also opens the web client in the browser. The app is recommended: best video and every feature.

Full setup guide →

Free 24-hour evaluation. Reactivate anytime directly from the device.

Open License Manager

Technical specifications.Nano inside.

Board
Sipeed NanoKVM (SG2002)
Processor
RISC-V C906, 1 core, 1 GHz
Memory
256 MB DDR3
Video
HDMI capture, 1080p 60 FPS
Control
USB HID keyboard and mouse, virtual ISO drive, gamepads
Audio
Audio output and microphone in both directions
Network
100 Mbit Ethernet port
Remote access
USBridge Client, web interface, Tailscale P2P, Moonlight
Power
USB-C
Screen
128×64
Dimensions with case
49×41×41 mm
System
USBridge OS on the included MicroSD card

Set up in 3 steps

ComputerUSBridge NanoUSBridge192.168.1.42USB-CLANHDMIUSBRouterUSBridge Client

HDMI

HDMI cable from the computer to Nano.

USBridge Nano board, heatsink and MicroSD card

Accessories

Screen ModuleStatus Display

Screen Module preview

On-device Status Display

Power Control BoardATX

Power Control Board preview

ATX Power Control

Dongle1080p @ 60fps

Dongle preview

HDMI-to-USB Capture

KVM 2.0 questions.Answers before you buy.

How is a KVM different from software remote access?

Software remote access, the USBridge agent included, runs inside the operating system and drops out when it freezes, fails to boot or the computer is off. A KVM connects to the computer's HDMI and USB and sees the screen from power-on: BIOS, the boot loader, a blue screen. You can reinstall the OS with it and, with the ATX board, turn on a computer that's off. The agent and the KVM open in the same USBridge Client.

Do I need to install anything on the computer I control?

No. The computer sees a regular monitor, keyboard, mouse and USB drive. USBridge Client is installed only on the device you control it from.

Does KVM 2.0 have Ethernet?

There's no built-in port: the board has Wi-Fi 6. For a wired link you need a USB hub with an Ethernet port: it goes into the USB-C capture port, and the HDMI dongle plugs into the hub. The hub isn't included and almost any one works: the KVM finds the network on its own, with no drivers. A wired link is also needed for bridge mode, when the computer needs its own IP on your network over the USB network.

Which kit should I choose?

Low suits building the KVM into your own case or rack. Standard is a ready desktop device with a screen. Full adds the ATX board: choose it if you need to turn the computer on, off and restart it remotely. An HDMI cable isn't included in the kits; any standard one works.

Do I need a subscription?

No. The KVM OS license is included in the price of the device and never expires. The paid $19 license is only for installing USBridge firmware on your own board.

Which computers are supported?

Any with an HDMI output and a USB port: desktops, mini PCs, servers and laptops. The operating system doesn't matter: the KVM works at the hardware level, BIOS and UEFI included.

Is it CE certified?

KVM 2.0 is going through CE certification for Europe now. We'll publish the certificate on this page as soon as we have it.

How much is shipping, and how do I return a device?

The cart shows shipping for your country before you pay. Within 14 days of delivery you can return the device under the EU right of withdrawal: write to kvm@usbridge.io. If the device is faulty, we pay the return shipping.

Can I stream games through the KVM?

Yes. USBridge is the first hardware Moonlight streamer. Every supported device, the ready KVM 2.0 or a flashed Radxa Zero 3W, Radxa Cubie A7Z or Sipeed NanoKVM, works as a hardware streamer: 1080p at 60 FPS without lag, with audio, Sunshine and Moonlight compatible. The stock Moonlight client on a PC, Mac, phone, tablet or TV connects to it, and the source, a PC or a game console, needs no software.

Which boards does the firmware support?

Radxa Zero 3W, Radxa Cubie A7Z and the Sipeed NanoKVM (SG2002). A ready KVM 2.0 is available from $99 (board, heatsink and HDMI capture) and $139 as a full kit with screen, case and ATX power control; prices exclude tax and shipping.

Not ready to buy yet?Stay in touch.

News by email

We'll write about new devices and firmware updates.

By subscribing you accept the privacy policy. You can unsubscribe at any time: write to kvm@usbridge.io.

Discord community

Ask questions and see how others set up their KVM.

Go to Discord