CaptureGem Hero Banner

Record Cam Sites With CaptureGem

The high performance desktop app for cam recording

Running CaptureGem Recorderd Standalone on Linux

This guide explains how to run CaptureGem's recording daemon, recorderd, on a Linux x86_64 machine without the desktop interface. It is intended for a private, headless machine that you control. The daemon's HTTP API has no authentication, so do not expose its HTTP, WebSocket, or proxy ports directly to the internet.

What You Need

  • A Linux x86_64 system, such as Ubuntu 20.04 or newer.
  • Storage for recordings, plus at least 1 GB for the application binaries and working files.
  • CaptureGem binaries from the same release: recorderd, transcoder, ffmpeg, ffprobe, curl, streamlink, and cacert.pem.

The daemon checks that transcoder has the same version as recorderd, so always keep those two binaries from the same CaptureGem release.

Prepare the Binaries

The easiest source is the CaptureGem Linux AppImage. Extract it and copy the bundled files into one directory:

mkdir -p ~/capturegem/bin
chmod +x CaptureGem-*.AppImage
./CaptureGem-*.AppImage --appimage-extract
cp squashfs-root/resources/resources/recorderd ~/capturegem/bin/
cp squashfs-root/resources/resources/transcoder ~/capturegem/bin/
cp squashfs-root/resources/resources/ffmpeg ~/capturegem/bin/
cp squashfs-root/resources/resources/ffprobe ~/capturegem/bin/
cp squashfs-root/resources/resources/curl ~/capturegem/bin/
cp squashfs-root/resources/resources/streamlink ~/capturegem/bin/
cp squashfs-root/resources/resources/cacert.pem ~/capturegem/bin/
rm -rf -- ./squashfs-root
chmod +x ~/capturegem/bin/recorderd ~/capturegem/bin/transcoder ~/capturegem/bin/ffmpeg ~/capturegem/bin/ffprobe ~/capturegem/bin/curl ~/capturegem/bin/streamlink

Your installation should contain:

~/capturegem/
  bin/
    recorderd
    transcoder
    ffmpeg
    ffprobe
    curl
    streamlink
    cacert.pem

Use an absolute -binDir path in a service. The daemon uses this directory to find the transcoder, FFmpeg tools, cURL, Streamlink, and CA certificate bundle. Streamlink is required when recording generic stream URLs and other Streamlink-backed sites.

Start recorderd

Run the daemon with its default port assignments:

~/capturegem/bin/recorderd -defaultPorts -binDir ~/capturegem/bin

Default ports are HTTP 28471, WebSocket 28472, and proxy 28474. To choose ports yourself, provide HTTP and WebSocket ports; the proxy port is optional and otherwise remains 28474:

~/capturegem/bin/recorderd -http 28471 -ws 28472 -proxy 28474 -binDir ~/capturegem/bin

The -startupDiag=false flag turns off the startup-diagnosis log. Do not use -isChild or -parentPort for a standalone installation; those flags are for the Electron desktop app.

On first start, CaptureGem creates its data directory at ~/CaptureGem_Data. By default, recordings are stored in ~/CaptureGem_Data/videos/out, temporary HLS data is in ~/CaptureGem_Data/videos/tmp-hls, metadata is in ~/CaptureGem_Data/metadata, and proxy downloads are in ~/CaptureGem_Data/proxy/downloads.

Verify the Daemon

In another terminal, request the version and initial state:

curl http://127.0.0.1:28471/getVersion
curl http://127.0.0.1:28471/getInitialState

Use 127.0.0.1 for local control. The HTTP server is not an authenticated remote-management interface.

Enable Live Monitor Thumbnails in Headless Mode

Important: headless clients must activate the Monitor tab.

The desktop app sends this signal when you open its Monitor tab, but a standalone recorderd has no UI to do that automatically. Without the signal, recorderd may create the first preview image for a recording, but it will not keep refreshing that thumbnail.

After every recorderd restart, send SetActiveTab with the exact lowercase value monitor before relying on /getPreviewFiles:

curl -X POST http://127.0.0.1:28471/ \
  -H "Content-Type: application/json" \
  -d '{
    "SetActiveTab": {
      "tabName": "monitor"
    }
  }'

The active-tab signal is kept in memory and is not persisted across daemon restarts. The Monitor feature must also be enabled in CaptureGem settings (disableMonitor must be false, which is the default).

When you no longer need continuously refreshed previews, signal another tab such as dashboard to avoid the extra thumbnail-processing work:

curl -X POST http://127.0.0.1:28471/ \
  -H "Content-Type: application/json" \
  -d '{
    "SetActiveTab": {
      "tabName": "dashboard"
    }
  }'

Run It as a User Service

For a long-running headless setup, use a per-user systemd service. Create ~/.config/systemd/user/capturegem-recorderd.service:

[Unit]
Description=CaptureGem recording daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=%h/capturegem
ExecStart=%h/capturegem/bin/recorderd -defaultPorts -binDir %h/capturegem/bin
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target

Security: lock down the HTTP and proxy ports before starting the service.

Recorderd listens for HTTP on all network interfaces (TCP 28471 by default), and its proxy does the same on TCP 28474. These interfaces do not authenticate requests. The WebSocket listener (TCP 28472) is loopback-only. On a VPS or any machine connected to an untrusted network, block direct access to 28471 and 28474 in both the provider firewall/security group and the host firewall.

For example, if UFW is already enabled, run these commands with administrator privileges before enabling the service:

ufw deny in to any port 28471 proto tcp
ufw deny in to any port 28474 proto tcp
ufw status numbered

Adjust the rules if you selected different ports. Do not add public inbound allow rules for these ports. For remote administration, prefer a VPN or an SSH local-forward; this example makes the HTTP API available only at 127.0.0.1:28471 on your workstation:

ssh -N -L 28471:127.0.0.1:28471 your-user@your-server

If you use an authenticated TLS reverse proxy instead, keep recorderd's raw HTTP and proxy ports blocked from external access so clients cannot bypass the proxy.

Then reload, enable, and inspect the service:

systemctl --user daemon-reload
systemctl --user enable --now capturegem-recorderd
systemctl --user status capturegem-recorderd
journalctl --user -u capturegem-recorderd -f

If the daemon must keep running after you log out, enable lingering for that Linux user using your system administrator's normal account-management procedure.

HTTP API

All GET routes and JSON POST messages use the HTTP port. Every POST except /forceUnlockConfigFile accepts a JSON object with one top-level action field. JSON field names below match recorderd's API.

GET Routes

RoutePurpose
/getInitialStateFull configuration and model state
/getVersionRecorderd version
/getDefaultConfigDefault configuration
/getPreviewFilesCurrent live preview files; supports ETag caching
/getAllMetadataPaginated video metadata; accepts page, entries, tags, negativeTags, modelName, site, search, sort, startDate, and endDate
/getQueueStateTranscoding, ffmpeg, metadata, and API queue state; accepts optional filter
/getSystemMonitorHistorySystem-monitor history
/getAuditFiles?videoId=...Playlist, recording-stat, and transcoder audit files
/getVideoDetails?videoId=...Video dimensions, codec, and recorded end reason
/getRecordingLifecycleHistoryRecording lifecycle history
/getFakeOfflineModelsConfigured fake-offline models
/getRequestConfig?site=...Saved cURL request configuration for a site
/fetchPreviewImage?previewFile=...&isCacheFile=falseA live preview image
/fetchImageGrid?videoId=...&size=smallA small or large review image grid
/getProxyStreamsProxy streams active in the last 15 seconds
/getProxyStreamFiles?streamId=...Files captured for a proxy stream
/getProxyStatsProxy request statistics
/testUrlFetchChainDiagnostic route for the renderer URL-fetch chain

Common POST Examples

POST to the HTTP root. For example, add a model, then start recording it:

curl -X POST http://127.0.0.1:28471/ -H "Content-Type: application/json" -d '{"AddModel":{"username":"example_user","site":"Chaturbate"}}'
curl -X POST http://127.0.0.1:28471/ -H "Content-Type: application/json" -d '{"StartRecording":{"username":"example_user","site":"Chaturbate"}}'
Action fieldBodyPurpose
AddModel{ username, site, monitor? }Add a model, optionally in monitor mode
RemoveModel{ username, site }Remove a model
ChangeModelSettings{ username, site, modelConfig, startRecording }Change auto-record settings, notes, or rating
StartRecording / StopRecording / PauseRecording / StartMonitoring{ username, site }Control recording or monitoring
AddFakeOfflineModel / RemoveFakeOfflineModel{ username, site }Manage the fake-offline list
CreateRecordingGroup{ modelIds, color? }Create a recording group
UpdateRecordingGroup{ groupId, modelIds, color? }Update a recording group
DisassociateRecordingGroup{ modelIds }Remove models from a group
ChangeGlobalSettings{ settings... }Update directories and global recorder settings
ResetToDefaultConfig{}Restore default configuration
SetActiveTab{ tabName }Set dashboard, review, monitor, or settings; use lowercase monitor for continuously refreshed headless previews
ExportModels{}Export models to CSV
ImportModels{ csvPath }Import models from a CSV path on the server
DeleteVideo{ videoNames }Delete videos by name
CutVideo{ videoFile, cutTimes, keepOriginal, enableBoomerang }Trim a video; cutTimes contains startSecs/endSecs pairs
ConcatVideo{ videoFiles, keepOriginal }Combine videos by absolute path
ExportVideos{ videoFiles, destinationDir }Copy videos to a directory
AddVideoBoolMetadata{ fileMetadata }Set boolean metadata entries by filename and key
UpdateVideoMetadata{ filename, modelName, siteName, recordTime }Update video metadata
StartProxyRecording / StopProxyRecording{ streamId }Control a captured proxy stream
ImportProxyRecording{ streamId, site, username }Import a proxy recording manually
EnterLicense{ license }Activate a license key
EnterPatreon{ patreonEmail }Activate with a Patreon email
RequestEmailCode{ email }Request an email verification code
SubmitEmailCode{ email, code }Submit an email verification code
ChaturbateLogin{ username, password }Log in to Chaturbate
EnterFilebaronAuth{ email, password }Authenticate with Filebaron
TestCurlRequest{ username, curlRequest, testType }Test a base64-encoded cURL request
UrlFetchRequest{ method, url, headers, body, timeout? }Send a URL request through the renderer chain

For example, update the output directory with the correct ChangeGlobalSettings payload:

curl -X POST http://127.0.0.1:28471/ -H "Content-Type: application/json" -d '{"ChangeGlobalSettings":{"videoSaveDirectory":"/home/your-user/videos"}}'

To clear a stale configuration lock, use the one path-based POST route:

curl -X POST http://127.0.0.1:28471/forceUnlockConfigFile

WebSocket

The real-time WebSocket route is ws://127.0.0.1:28472/ws. It is bound to loopback and broadcasts state changes such as model status and recording progress.

Troubleshooting

  • Transcoder version mismatch or not found: put the release-matched transcoder next to recorderd and pass the correct -binDir.
  • cURL or certificate errors: confirm that the bundled curl and cacert.pem are in -binDir and that cURL is executable.
  • Port already in use: use different -http, -ws, and, if needed, -proxy values.
  • Configuration locked: stop duplicate daemon instances, then use /forceUnlockConfigFile only when you are certain no other instance is writing that data directory.
  • Corrupted or missing recordings: never run two recorderd instances against the same CaptureGem_Data directory. One process can clean up temporary files the other still needs.
Return to Guides