Skip to content

Your desktop applications are URLs. Run VS Code, browsers, LibreOffice, any GUI program—accessible from your phone, tablet, laptop, or TV. Just open the URL.

Every Hoody container includes hoody-display, transforming your entire Linux desktop into a web-native interface with zero client installation.


hoody-display provides complete desktop access through HTTP:

  • 🖥️ Full Desktop Environments - Run any GUI application via HTML5 client
  • 📱 Universal Access - Phone, tablet, laptop, TV—anything with a browser
  • 👥 Multiplayer Sessions - Multiple users viewing/controlling same desktop simultaneously
  • 🎨 50+ Customization Options - Configure via URL parameters (themes, performance, input)
  • 📸 Screenshot API - Capture desktop state as PNG/JPEG programmatically
  • 🖱️ Computer Use API - Full mouse, keyboard, and window control over HTTP (dozens of endpoints)
  • 🔧 Zero Installation - No VNC client, no RDP, just browser
  • ⚡ Hardware Acceleration - H264 video encoding for smooth graphics
  • 📋 Clipboard Sync - Copy/paste between local and remote automatically

Official Technical Reference:

For complete endpoint documentation with all parameters, responses, and examples:

Web Client Interface:

Screenshot & Thumbnail API:

System Information:

Mouse Control:

  • POST /api/v1/display/mouse/click - Click a mouse button
  • POST /api/v1/display/mouse/double-click - Double-click
  • POST /api/v1/display/mouse/move - Move cursor to absolute position
  • POST /api/v1/display/mouse/move-relative - Move cursor by offset
  • POST /api/v1/display/mouse/down - Press and hold mouse button
  • POST /api/v1/display/mouse/up - Release mouse button
  • POST /api/v1/display/mouse/scroll - Scroll
  • GET /api/v1/display/mouse/location - Get current cursor position

Keyboard Control:

  • POST /api/v1/display/keyboard/type - Type a string of text
  • POST /api/v1/display/keyboard/key - Press key combinations (X11 keysym notation)
  • POST /api/v1/display/keyboard/key-down - Hold a key down
  • POST /api/v1/display/keyboard/key-up - Release a held key

Window Management:

  • GET /api/v1/display/windows - List all windows
  • POST /api/v1/display/window/focus - Focus/activate a window
  • POST /api/v1/display/window/move - Move a window
  • POST /api/v1/display/window/resize - Resize a window
  • POST /api/v1/display/window/minimize - Minimize a window
  • POST /api/v1/display/window/close - Close a window
  • POST /api/v1/display/window/raise - Raise window to top
  • GET /api/v1/display/window/active - Get active window ID
  • POST /api/v1/display/window/search - Search windows by title pattern
  • GET /api/v1/display/window/{windowId}/geometry - Get window position and size
  • GET /api/v1/display/window/{windowId}/name - Get window title
  • GET /api/v1/display/window/{windowId}/properties - Get extended window properties

Compound Actions (Computer Use):

  • POST /api/v1/display/input/click-at - Move cursor and click
  • POST /api/v1/display/input/type-at - Move, click, and type in one operation
  • POST /api/v1/display/input/drag - Drag from one position to another
  • POST /api/v1/display/input/select - Select a range via click + shift-click
  • POST /api/v1/display/input/act - Execute one action with optional screenshot
  • POST /api/v1/display/input/wait - Wait with optional screenshot
  • POST /api/v1/display/input/batch - Execute a sequence of actions atomically
  • POST /api/v1/display/input/reset - Emergency release all held inputs
  • GET /api/v1/display/input/display-geometry - Get display dimensions

Every container can run multiple display instances—one per application:

https://{project}-{container}-display-1.{server}.containers.hoody.icu
https://{project}-{container}-display-2.{server}.containers.hoody.icu
https://{project}-{container}-display-3.{server}.containers.hoody.icu

Recommended pattern: One display per application

  • display-1 - Your main IDE (VS Code)
  • display-2 - Web browser (Firefox/Chrome)
  • display-3 - Office applications (LibreOffice)
  • display-4 - Graphics editor (GIMP)
  • display-5 - Database tools

Why separate displays matter:

Each display runs independently with its own:

  • Screen resolution
  • Window manager state
  • Application set
  • Performance profile

Access any display from any browser—phone, tablet, laptop, TV. No installation. No configuration. Just open the URL.

Terminal integration: When you use terminal-5, it automatically connects to display-5 (:5 in X11 terms). This makes GUI programs work seamlessly—run firefox in terminal-5, and it appears in display-5.

Manual display selection: Set the DISPLAY environment variable to target a specific display:

Terminal window
# In any terminal
export DISPLAY=:5
# Now GUI programs open in display-5
firefox & # Opens in display-5
code . # Opens in display-5

This flexibility lets you organize applications across displays while controlling them from any terminal.

Your phone is now a full computer:

Same URL on different devices:

  • Laptop browser → Full desktop experience
  • Phone browser → Same desktop, touch-optimized
  • Tablet → Perfect for presentations
  • TV → Display on big screen
  • Smart watch → View monitoring dashboards
  • Smart glasses (future) → AR overlays of your infrastructure

Because everything is HTTP, device capabilities don’t limit you. Your phone didn’t get more powerful—it became a window into infinite compute.

Share the URL and everyone sees/controls the same desktop:

https://{project}-{container}-display-1.{server}.containers.hoody.icu/?sharing=true

Multiple users connecting:

  • ✅ See the same screen in real-time
  • ✅ Can all type and click simultaneously
  • ✅ Cursors show who’s doing what
  • ✅ Changes reflect instantly for everyone

Perfect for:

  • Team debugging (everyone sees the error)
  • Teaching (instructor and students share desktop)
  • Pair programming (both using same IDE)
  • Customer support (solve issues together)

See: Multiplayer by Default → for collaboration philosophy.

Configure the entire experience via URL parameters:

# Read-only dashboard
?readonly=true&decorations=false&toolbar=false&reconnect=true
# Low-bandwidth mode
?encoding=jpeg&bandwidth_limit=1000000&video=false&sound=false
# Collaborative session
?sharing=true&steal=false
# macOS user setup
?swap_keys=true&keyboard_layout=us
# Dark mode with floating menu
?floating_menu=true&dark_mode=true

Over 50 parameters control UI, performance, input, features, and behavior.

See: Web Client Interface → for complete customization reference.

Programmatically capture desktop state:

Terminal window
# Capture current screenshot
GET /screenshot?displayId=1
# Get as base64 for AI vision
GET /screenshot?base64=true
# Lightweight thumbnail
GET /thumbnail/last

Use cases:

  • AI vision analysis of UI states
  • Automated testing verification
  • Documentation generation
  • Monitoring dashboards
  • Time-lapse recordings

See: Screenshot API →

Because displays are URLs, they’re <iframe>able:

<!-- Embed desktop in webpage -->
<iframe src="https://{project}-{container}-display-1.{server}.containers.hoody.icu"
width="1280" height="720" />
<!-- Multiple displays in one page -->
<iframe src="https://prod-container-display-1.hoody.icu" />
<iframe src="https://staging-container-display-1.hoody.icu" />
<iframe src="https://dev-container-display-1.hoody.icu" />

Build custom dashboards by composing iframes. Your infrastructure IS the UI.

See: Embeddability Revolution →


RDP Client (installed) → RDP Server (configured) → Desktop (complex)

Problems:

  • Client installation required (difficult on mobile devices)
  • Port configuration and firewalls
  • Not embeddable (can’t iframe RDP)
  • Single-user (one connection kicks others)
  • AI can’t see (binary protocol)
  • Complex setup
Any Browser → Display URL → Desktop (immediately)

Advantages:

  • ✅ Zero installation (every device has browser)
  • ✅ Zero port configuration (HTTPS port 443 through Hoody Proxy)
  • ✅ Naturally embeddable (<iframe src="display-url" />)
  • ✅ Multiplayer by default (share URL = instant collaboration)
  • ✅ AI-accessible (HTTP + screenshot API)
  • ✅ Observable (all HTTP, fully logged)
  • ✅ Mobile-native (works on phones out-of-box)

Your phone can now run:

// Phone browser opens display URL
https://{project}-{container}-display-1.{server}.containers.hoody.icu
// Inside that desktop:
- Full VS Code IDE
- Chrome browser with DevTools
- Terminal sessions
- Database tools
- Any Linux GUI application

The device doesn’t matter. The URL is the computer.


This is where Hoody gets dangerous. Full programmatic control of any desktop over HTTP — mouse, keyboard, windows, compound actions. Dozens of endpoints. Every one of them a REST call.

AI agents, automation scripts, remote operators — anything that can make an HTTP request can now drive a GUI application with the precision of a human, at the speed of software.

Pixel-precise cursor control at any speed:

Terminal window
# Move cursor to position
hoody display move --x 640 --y 480 --display-id 10 -c <container-id>
# Click at current position
hoody display click --button 1 --display-id 10 -c <container-id>
# Double-click
hoody display double-click --button 1 --display-id 10 -c <container-id>
# Scroll down
hoody display scroll --direction down --clicks 5 --display-id 10 -c <container-id>

Available mouse buttons: 1 (left), 2 (middle), 3 (right)

Type text and send any key combination the OS understands:

Terminal window
# Type text
hoody display type --text "Hello, World!" --delay 50 --display-id 10 -c <container-id>
# Press key combination
hoody display key --keys "ctrl+s" --display-id 10 -c <container-id>
# Hold key
hoody display key-down --key "Shift_L" --hold-ms 2000 --display-id 10 -c <container-id>

Enumerate, target, and fully control any window on the desktop:

Terminal window
# List visible windows
hoody display list --only-visible --display-id 10 -c <container-id>
# Focus a window
hoody display focus --window-id 83886081 --display-id 10 -c <container-id>
# Move a window
hoody display move --window-id 83886081 --x 100 --y 100 --display-id 10 -c <container-id>
# Resize a window
hoody display resize --window-id 83886081 --width 1024 --height 768 --display-id 10 -c <container-id>
# Search for windows by name
hoody display search --pattern "Firefox" --name --only-visible --display-id 10 -c <container-id>

The high-level interface for computer use workflows. These endpoints combine multiple primitives into single atomic operations — exactly what AI agents need:

Terminal window
# Click at specific position
hoody display click-at --x 640 --y 480 --button 1 --display-id 10 -c <container-id>
# Type at position
hoody display type-at --x 300 --y 400 --text "Hello" --delay 50 --display-id 10 -c <container-id>
# Drag between positions
hoody display drag --start-x 100 --start-y 100 --end-x 300 --end-y 300 --button 1 --steps 50 --display-id 10 -c <container-id>
# Execute action with screenshot
hoody display act --action "mouse/click" --params '{"button":1}' --screenshot --screenshot-delay 200 --display-id 10 -c <container-id>

AI agent opens a browser, navigates, fills a form, submits:

const base = 'https://{project}-{container}-display-1.{server}.containers.hoody.icu';
// 1. Find the browser window
const windows = await fetch(`${base}/api/v1/display/windows`).then(r => r.json());
const browser = windows.find(w => w.name.includes('Firefox'));
// 2. Focus it
await fetch(`${base}/api/v1/display/window/focus`, {
method: 'POST',
body: JSON.stringify({ windowId: browser.id })
});
// 3. Navigate to URL via address bar
await fetch(`${base}/api/v1/display/input/batch`, {
method: 'POST',
body: JSON.stringify({
actions: [
{ action: 'keyboard/key', params: { keys: ['ctrl+l'] } }, // Focus address bar
{ action: 'wait', params: { ms: 200 } },
{ action: 'keyboard/type', params: { text: 'https://app.example.com/login' } },
{ action: 'keyboard/key', params: { keys: ['Return'] } },
{ action: 'wait', params: { ms: 2000 } }, // Wait for page load
{ action: 'screenshot' } // Verify it loaded
]
})
});
// 4. Fill in login form
await fetch(`${base}/api/v1/display/input/type-at`, {
method: 'POST',
body: JSON.stringify({ x: 640, y: 380, text: 'user@example.com' })
});
await fetch(`${base}/api/v1/display/input/type-at`, {
method: 'POST',
body: JSON.stringify({ x: 640, y: 450, text: 'supersecretpassword' })
});
// 5. Submit and capture result
const result = await fetch(`${base}/api/v1/display/input/act`, {
method: 'POST',
body: JSON.stringify({
action: 'keyboard/key',
params: { keys: ['Return'] },
screenshot: true
})
}).then(r => r.json());
// result.screenshot contains base64 PNG — send to vision model to verify login success

This is full computer use. Not CLI wrappers. Not browser automation. Actual pixel-level GUI control over HTTP, on any Linux application, in any window, driven by anything that can make a curl request.


Access your full dev environment from any device:

Terminal window
# Laptop: Configure display
https://dev-container-display-1.hoody.icu/?fontSize=14&swap_keys=true
# Phone (later): Same URL, same environment
https://dev-container-display-1.hoody.icu/?fontSize=14&swap_keys=true
# Tablet (during presentation): Same environment
https://dev-container-display-1.hoody.icu/?fontSize=16

One computer. Accessible from phone, laptop, tablet, TV. Not synced—actually the same running instance.

Multiple users working in same desktop:

// Setup: Create collaborative session
const displayUrl = 'https://{project}-{container}-display-1.{server}.containers.hoody.icu';
const collaborativeUrl = `${displayUrl}/?sharing=true&steal=false`;
// Share URL with team
// Everyone sees same desktop
// Everyone can:
// - Open files in shared VS Code
// - Type in shared terminal
// - Click in shared browser
// - Edit in shared applications
// Real-time collaboration like Google Docs, but for your entire desktop

Support agent helps customer by joining their desktop:

Terminal window
# Customer shares display URL
https://customer-issue-container-display-1.hoody.icu/?sharing=true
# Support agent opens URL on phone during commute
# Sees customer's desktop
# Types fix directly
# Issue resolved in 2 minutes
# No screen share setup
# No "can you see my screen?"
# Just shared desktop state

Present live desktop to team:

# Presenter URL (full control)
?sharing=true&steal=false&readonly=false
# Viewers URL (watch only)
?sharing=true&steal=false&readonly=true

Presenter controls desktop. Viewers watch in real-time. Perfect for:

  • Product demos
  • Architecture reviews
  • Training sessions
  • Live coding demonstrations

Let AI see and analyze your desktop:

// 1. Capture screenshot via HTTP
const response = await fetch(
'https://{project}-{container}-display-1.{server}.containers.hoody.icu/screenshot?base64=true'
);
const { image, info } = await response.json();
// 2. Send to a vision model via Hoody AI (any provider you've configured)
const analysis = await ai.chat.completions.create({
model: 'your-vision-model',
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'What errors do you see in this IDE?' },
{ type: 'image_url', image_url: { url: `data:image/png;base64,${image.data}` }}
]
}]
});
// 3. AI describes what it sees
console.log(analysis.choices[0].message.content);
// "I see a syntax error on line 23: unclosed bracket..."

AI can now see your desktop and provide visual debugging, UI analysis, and accessibility testing.

Embed multiple displays in monitoring dashboard:

<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
<!-- Production -->
<iframe src="https://prod-container-display-1.hoody.icu/?readonly=true&toolbar=false" />
<!-- Staging -->
<iframe src="https://staging-container-display-1.hoody.icu/?readonly=true&toolbar=false" />
<!-- Development -->
<iframe src="https://dev-container-display-1.hoody.icu/?readonly=true&toolbar=false" />
</div>

Live view of all environments. No switching tabs. All visible at once.


Work from café, beach, airport, hotel—anywhere with internet. Your desktop isn’t on your laptop—it’s in the URL. Laptop breaks? Use any device. Travel light, work heavy.

20 brand accounts, one desktop, five team members:

One container runs multiple browsers, each logged into different social accounts. All team members open the display URL. Everyone sees all 20 browsers. Coordinate without “whose turn to post?” or credential sharing.

One computer is shared control center. No individual logins. No syncing. Just shared desktop state.

Start coding on laptop. Continue on tablet during commute. Finish on phone at café. Same VS Code. Same terminal. Same files. Not synced—same actual desktop.

AI agent joins your display URL:

  1. Takes screenshots to see what you’re working on
  2. Types in your IDE via input API
  3. Runs tests in your terminal
  4. Debugs by seeing actual UI state

AI and human as peers on same desktop. Not AI suggesting—AI executing.

Instructor’s desktop URL shared with 30 students. Everyone sees the same screen. Instructor demonstrates. Students can take control when invited. Interactive learning at scale.

Customer has issue. Shares display URL. Support agent opens URL on ANY device. Sees customer’s desktop. Types fix. Issue resolved. No Zoom. No “can you click here?”. Just shared desktop via URL.


On fast connection:

?encoding=h264&quality=90&video=true

On slow/metered connection:

?encoding=jpeg&quality=60&video=false&bandwidth_limit=500000

Prevent accidental input during demos:

?readonly=true&steal=false&sharing=true

Viewers can’t type or click. Perfect for presentations or monitoring dashboards.

macOS users need key swap:

?swap_keys=true&keyboard_layout=us

Maps Cmd to Ctrl automatically, preserving muscle memory for copy/paste.

Auto-reconnect on network interruption:

?reconnect=true

Essential for mobile use (switching WiFi/cellular) or unreliable networks.

Build monitoring views with lightweight previews:

// Get thumbnail (small, fast)
const thumb = await fetch('.../thumbnail/last');
// Full screenshot only when needed
const full = await fetch('.../screenshot/last');

Thumbnails are 320px wide vs full 1920px—dramatically less bandwidth.

Turn off unused features:

?sound=false&printing=false&clipboard=false&file_transfer=false

Reduces bandwidth and CPU usage. Enable only what you need.


Can I really run desktop applications on my phone?

Section titled “Can I really run desktop applications on my phone?”

Yes! Your phone’s browser becomes a window into a full Linux desktop. Run VS Code, LibreOffice, GIMP, browsers—any GUI application. The phone isn’t running the apps—it’s displaying a desktop that runs in the container. The heavy lifting happens on your server.

What’s the difference between display-1, display-2, etc.?

Section titled “What’s the difference between display-1, display-2, etc.?”

Each number is a separate desktop environment. display-1 might show VS Code, display-2 shows monitoring tools, display-3 shows browsers. Each isolated, each accessible via its own URL. One container can have multiple desktops.

How does multiplayer actually work without conflicts?

Section titled “How does multiplayer actually work without conflicts?”

The display protocol synchronizes state automatically. When User A types, it updates the display server, which broadcasts to all connected clients including User B. Input is serialized (one keystroke at a time), but visual updates are instant for everyone. Like Google Docs for desktops.

Yes — fully. The Computer Use API provides complete programmatic mouse and keyboard control over HTTP. AI agents can: 1) Capture screenshots via GET /screenshot to see desktop state, 2) Move and click the mouse at exact coordinates, 3) Type text and press key combinations, 4) Manage windows (focus, resize, move, close), 5) Chain compound actions via POST /api/v1/display/input/batch for complex multi-step workflows. This is one of Hoody’s most powerful capabilities — see Computer Use API below.

What happens if my internet drops while using a display?

Section titled “What happens if my internet drops while using a display?”

With ?reconnect=true (default), the client automatically reconnects when your connection returns. The desktop keeps running on the server—you just lost the view temporarily. When reconnected, you see current state (not what it was when you disconnected).

Do displays work on touch devices like tablets?

Section titled “Do displays work on touch devices like tablets?”

Yes! The HTML5 client adapts to touch input automatically. Tap = click, pinch = zoom, two-finger scroll = scroll. Virtual keyboard available via ?keyboard=true. Full desktop control from touch-only devices.

Extensively. Control: floating menu style, window decorations, toolbar visibility, dark mode. All via URL parameters. Build your perfect visual environment.

See: UI Theming →

How much bandwidth does a display session use?

Section titled “How much bandwidth does a display session use?”

Depends on encoding and activity. H264 video: 2-5 Mbps for smooth graphics. JPEG static updates: 100-500 Kbps. Configure via: ?encoding=jpeg&quality=60&bandwidth_limit=1000000 to cap at 1 Mbps.

Absolutely! Use iframes to embed container displays directly. Common patterns: dashboards showing live server states, documentation with interactive examples, customer portals with diagnostic desktops.

Keep in mind that this isn’t our priority for now, but we promise total smoothness with Displays, soon. As of now, typically 50-200ms depending on distance to server and network quality. H264 encoding optimized for smooth interaction. Good enough for coding, document editing, web browsing—not recommended for gaming or high-frequency trading.


Display Won’t Load or Shows Black Screen

Section titled “Display Won’t Load or Shows Black Screen”

Check container is running:

Terminal window
curl "https://api.hoody.icu/api/v1/containers/{container_id}?runtime=true" \
-H "Authorization: Bearer $HOODY_TOKEN"

Verify runtime_info.displays shows active display with PID.

Common causes:

  1. Container stopped - Start it:

    Terminal window
    curl -X POST "https://api.hoody.icu/api/v1/containers/{container_id}/start" \
    -H "Authorization: Bearer $HOODY_TOKEN"
  2. Display service not started - Wait 30-60 seconds after container start for services to initialize

  3. Wrong display number - Check container’s runtime_info.displays for available display IDs

Enable reconnect:

?reconnect=true

Reduce quality for stability:

?quality=50&encoding=jpeg&video=false

Check network:

  • Test on different WiFi/cellular
  • Verify server connectivity
  • Check firewall isn’t blocking WebSocket

For macOS users:

?swap_keys=true&keyboard_layout=us

For other layouts:

?keyboard_layout=gb # UK
?keyboard_layout=de # German
?keyboard_layout=fr # French

Enable virtual keyboard on touch devices:

?keyboard=true

Enable clipboard if disabled:

?clipboard=true

Check browser permissions:

  • Browser may block clipboard access
  • Try different browser
  • Grant clipboard permissions when prompted

Some browsers restrict clipboard for security. Copy/paste within the remote desktop always works.

Optimize encoding:

# Fast connection
?encoding=h264&quality=90
# Slow connection
?encoding=jpeg&quality=40&video=false

Reduce bandwidth:

?bandwidth_limit=500000 # 500 Kbps max

Disable high-bandwidth features:

?sound=false&video=false

Check server load:

Terminal window
# Query system resources
GET /api/v1/system/resources

Check URL parameter:

?readonly=false # Enable control

Verify permissions:

  • Display might have proxy permissions restricting control
  • Check container’s proxy-permissions configuration
  • Try removing permissions temporarily for testing

Use session sharing:

?sharing=true&steal=false

Without this:

  • sharing=false allows only one user
  • steal=true (default) lets new users kick old ones out

For collaboration, enable sharing.


Explore other visual services:

Browser

Chrome automation as REST API—control browsers programmatically, scrape data, run tests.

Explore Browser →

Terminals

Execute shell commands via HTTP—your terminal as an API, accessible everywhere.

Explore Terminals →

Code

VS Code instances via HTTP—spawn IDEs on-demand, share coding sessions.

Explore Code →

Master display configuration:


Your desktop is a URL.
Access from any device.
Share instantly.
Embed everywhere.

This is how desktops work in the HTTP era.