Skip to main content

Documentation Index

Fetch the complete documentation index at: https://crsdk.app/llms.txt

Use this file to discover all available pages before exploring further.

CameraManager is the entry point for the Client SDK. It replaces the manual ServerManager + CameraClient + EventStream workflow — one class handles binary management, camera discovery, connection lifecycle, SSE events, and reconnection.

Server (Node.js)

Import from camera-remote-web-api/server. This variant spawns and manages the native binary.
import { CameraManager } from 'camera-remote-web-api/server';

const manager = new CameraManager({ port: 8080 });

manager.on('camera-ready', async ({ cameraId, camera }) => {
  console.log(`${camera.model} connected`);
  const cam = manager.camera(cameraId);
  await cam.setPriorityKey({ setting: 'pc-remote' });
  await cam.triggerShutter();
});

await manager.start();

Browser

Import from camera-remote-web-api (the default export). Connects to an already-running server — no binary management.
import { CameraManager } from 'camera-remote-web-api';

const manager = new CameraManager({
  baseUrl: 'http://localhost:8080',
});

manager.on('camera-ready', ({ cameraId, camera }) => {
  console.log(`${camera.model} ready`);
});

manager.start();  // Synchronous — just starts polling + SSE
Use manager.camera(cameraId) to get a bound camera object with all methods pre-bound — no need to pass the camera ID to every call. For direct access, manager.client is also available as a full CameraClient instance. See Properties & Actions.

Options

const manager = new CameraManager({
  // Server options (server variant only)
  port: 8080,              // Default: 8080
  autoPort: true,          // Find next available port if busy
  binaryPath: '/path/to', // Explicit path to CameraWebApp binary

  // Connection options (all variants)
  baseUrl: 'http://localhost:8080', // Server URL (browser variant only)
  autoConnect: true,       // Auto-connect discovered cameras (default: true)
  connectionMode: 'remote-transfer', // Default: 'remote'
  autoReconnect: true,     // Reconnect on unexpected disconnect (default: true)
  maxReconnectAttempts: 5, // Give up after N attempts (default: 5)
  pollInterval: 5000,      // Camera discovery interval in ms (default: 5000)
});
OptionDefaultDescription
port8080Server port (server only)
autoPortfalseFind next available port if busy (server only)
binaryPathauto-detectedExplicit binary path (server only, required in Next.js)
baseUrlhttp://localhost:8080Server URL (browser only)
autoConnecttrueConnect cameras automatically on discovery
connectionMode'remote'Default connection mode for auto-connect
autoReconnecttrueReconnect on unexpected disconnect
maxReconnectAttempts5Max reconnect attempts before giving up
pollInterval5000Camera discovery polling interval (ms)

Connection Modes

The connection mode determines what operations are available on a connected camera.
ModeDescription
remoteFull camera control. Photos auto-transfer to host PC.
remote-transferFull camera control + explicit SD card file download.
contentsSD card browsing and file download only — no shooting or settings.
Not all cameras support all modes or APIs. See Compatibility for per-camera details.

Choosing a mode

I want to shoot and auto-save photos to my computer

Use remote. Set still-image-store-destination to 0x1 (Host PC) or 0x3 (Both) for auto-transfer. Listen for downloadComplete events to know when files are saved.
Use remote-transfer. You get full shooting control plus explicit file listing and download from the SD card. This is the most flexible mode.
Use contents. No shooting or settings control — just file browsing and download.
// Set mode globally
const manager = new CameraManager({ connectionMode: 'remote-transfer' });

// Or per-camera when using manual connection
await manager.connect(camera.id, { mode: 'remote-transfer' });

Lifecycle

// Start — boots binary (server), begins polling, subscribes to SSE
await manager.start();

// Get a bound camera — all methods pre-bound with the camera ID
const cam = manager.camera(cameraId);
await cam.setProperty('iso', { value: '400' });

// Or use the underlying client directly
await manager.client.setProperty(cameraId, 'iso', { value: '400' });

// Stop — closes SSE, stops polling, kills binary (server)
await manager.close();

Discovery & batch connection

// Trigger immediate discovery (useful when autoConnect is off)
const cameras = await manager.discover();

// Connect all detected cameras in parallel
await manager.connectAll({ mode: 'remote-transfer' });

Server-only methods

These are only available on the server variant (camera-remote-web-api/server):
manager.getPort();           // Current port (may differ if autoPort)
await manager.isRunning();   // Binary health check
manager.getPid();            // Binary process ID
manager.getStdout();         // Binary stdout lines
manager.getStderr();         // Binary stderr lines

Camera Access

// All cameras with state
const cameras = manager.getCameras();
// → [{ info: { id, model, connectionType, connected }, state: 'connected', reconnectAttempts: 0 }]

// Single camera by ID
const cam = manager.getCamera('D10F60149B0C');
// → { info: {...}, state: 'connected', reconnectAttempts: 0 }

Bound Camera Accessor

manager.camera(id) returns a BoundCamera object with all CameraClient methods pre-bound with the camera ID. This is the recommended way to interact with cameras — it eliminates the need to thread the camera ID through every call.
const cam = manager.camera('D10F60149B0C');

// No cameraId parameter needed
await cam.setPriorityKey({ setting: 'pc-remote' });
await cam.triggerShutter();
const iso = await cam.getProperty('iso');
console.log(iso.data.formatted);  // "ISO 400"

// Per-camera SSE events via .events
cam.events.on('downloadComplete', (data) => {
  console.log('Saved:', data.filename);
});

// One-shot listener — auto-removed after first fire
cam.events.once('transferProgress', (data) => {
  console.log('First transfer:', data.filename);
});
Bound cameras are lazily created and cached — calling manager.camera(id) multiple times returns the same object.

Available methods

All CameraClient methods are available without the camera ID parameter:
CategoryMethods
Connectionconnect(), disconnect(), getConnectionStatus()
PropertiesgetProperty(), setProperty(), getAllProperties(), getPriorityKey(), setPriorityKey()
ActionstriggerShutter(), halfPress(), afShutter(), controlZoom(), stopZoom(), focusNearFar()
Live ViewenableLiveView(), disableLiveView(), getLiveViewStatus(), startLiveViewStream(), stopLiveViewStream(), getLiveViewFrame()
OSDenableOSD(), disableOSD(), getOSDStatus(), getOSDFrame()
SD CardlistSDCardFiles(), downloadSDCardFile()
SettingsgetSaveInfo(), setSaveInfo(), downloadCameraSettings(), uploadCameraSettings(), listSettingsFiles()

Per-camera events

The events property returns a CameraEventStream — a typed SSE client scoped to that camera.
const cam = manager.camera(cameraId);

cam.events.on('propertyChanged', (data) => {
  console.log('Changed:', data.codes);
});

cam.events.on('warning', (data) => {
  if (data.code === '0x20011') console.log('Photo captured!');
});

// Cleanup
cam.events.close();
MethodDescription
on(event, callback)Subscribe to events
off(event, callback?)Unsubscribe
once(event, callback)One-shot listener — auto-removed after first fire
close()Close SSE connection
connectedWhether SSE is connected (read-only)

Manual Connection Control

For full manual control over connection lifecycle — connecting specific cameras, managing state transitions, and handling reconnection yourself — use the stateful API classes directly instead of CameraManager.

Stateful API Access

Direct access to CameraClient, EventStream, and ServerManager without CameraManager automation