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) as a standalone process on Linux (e.g. Ubuntu), without the Electron desktop app. This is useful for headless servers or remote machines where you want to control recordings via the HTTP API.

Prerequisites

  • A Linux x86_64 system (e.g. Ubuntu 20.04+)
  • At least 1 GB of free disk space for binaries
  • Sufficient storage for recorded videos

Step 1: Download the Required Binaries

You need the following files: recorderd, transcoder, ffmpeg, ffprobe, curl, and cacert.pem. If you have the CaptureGem Linux AppImage, you can extract them from it. Otherwise, download them individually.

Option A: Extract from AppImage

If you have the CaptureGem .AppImage file:

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

Option B: Download Individually

FFmpeg (static build):

mkdir -p bin
wget https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n7.1-latest-linux64-gpl-7.1.tar.xz
tar xf ffmpeg-n7.1-latest-linux64-gpl-7.1.tar.xz
cp ffmpeg-n7.1-latest-linux64-gpl-7.1/bin/ffmpeg ./bin/
cp ffmpeg-n7.1-latest-linux64-gpl-7.1/bin/ffprobe ./bin/
rm -rf ffmpeg-n7.1-latest-linux64-gpl-7.1*

Static curl (for HTTPS requests):

wget -O ./bin/curl https://github.com/moparisthebest/static-curl/releases/latest/download/curl-amd64
chmod +x ./bin/curl

CA Certificates:

wget -O ./bin/cacert.pem https://curl.se/ca/cacert.pem

The recorderd and transcoder binaries must come from a CaptureGem release (AppImage extraction) or be compiled from source.

Set Permissions

Make sure all binaries are executable:

chmod +x ./bin/recorderd ./bin/transcoder ./bin/ffmpeg ./bin/ffprobe ./bin/curl

Step 2: Directory Structure

Your bin directory setup should look like this:

capturegem/
└── bin/
    ├── recorderd
    ├── transcoder
    ├── ffmpeg
    ├── ffprobe
    ├── curl
    └── cacert.pem

By default, recorderd stores configuration and recorded videos in ~/CaptureGem_Data/. You can change the video save directory by using the ChangeGlobalSettings API call after starting the daemon.

Step 3: Start recorderd

Run the daemon with the required flags:

./bin/recorderd -http 28471 -ws 28472 -binDir ./bin

Startup Flags

FlagRequiredDescription
-httpYesPort for the HTTP API server
-wsYesPort for the WebSocket server (used for real-time state updates)
-proxyNoPort for the proxy recording server
-binDirNoPath to the directory containing ffmpeg, transcoder, and curl
-defaultPortsNoUse default ports instead of specifying them manually
-startupDiagNoEnable/disable startup diagnostics (default: true)

Running in the Background

To keep recorderd running after you close your terminal:

nohup ./bin/recorderd -http 28471 -ws 28472 -binDir ./bin > recorderd.log 2>&1 &

Or create a systemd service (see "Running as a systemd Service" below).

Step 4: Verify It's Running

Once started, check that recorderd is responding:

curl http://localhost:28471/getVersion

You should see a JSON response with the version number.

Running as a systemd Service

Create a service file at /etc/systemd/system/recorderd.service:

[Unit]
Description=CaptureGem Recording Daemon
After=network.target

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/capturegem
ExecStart=/home/your-username/capturegem/bin/recorderd -http 28471 -ws 28472 -binDir /home/your-username/capturegem/bin
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Then enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable recorderd
sudo systemctl start recorderd
sudo systemctl status recorderd

HTTP API Reference

Once recorderd is running, you can control it entirely via HTTP. All GET endpoints use query parameters. All POST endpoints (except /forceUnlockConfigFile) accept a JSON body with a single top-level field that determines the action.

GET Endpoints

State & Configuration

EndpointDescription
/getVersionReturns the application version
/getInitialStateReturns full global state (config + all model states)
/getDefaultConfigReturns the default configuration
/getQueueState?filter=...Returns transcoding queue, ffmpeg queue, and API request queue state. Supports ETag caching
/getSystemMonitorHistoryReturns system monitoring event history
/getRecordingLifecycleHistoryReturns the recording lifecycle audit history

Video Metadata

EndpointDescription
/getAllMetadata?page=1&entries=20Returns paginated video metadata. Supports filters: tags, negativeTags, modelName, site, search, sort, startDate, endDate. Supports ETag caching
/getAuditFiles?videoId=...Returns audit files (playlist history, recording stats, transcoder audit) for a video
/fetchImageGrid?videoId=...&size=smallServes an image grid thumbnail for a video (small or large)

Preview & Monitoring

EndpointDescription
/getPreviewFilesReturns all live preview image files. Supports If-None-Match / 304 caching
/fetchPreviewImage?previewFile=...&isCacheFile=falseServes a preview image file
/getFakeOfflineModelsReturns sorted list of models configured to appear as fake-offline

Proxy

EndpointDescription
/getProxyStreamsReturns currently active proxy video streams
/getProxyStreamFiles?streamId=...Returns file info for a proxy stream's saved directory
/getProxyStatsReturns proxy server statistics

Utilities

EndpointDescription
/getRequestConfig?site=...Returns decoded cURL request config for a cam site
/testUrlFetchChainTests the URL fetch communication chain

POST Endpoints

All POST requests use a JSON body. The action is determined by which field is present in the JSON object.

Model Management

# Add a model
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"AddModel": {"username": "example_user", "site": "Chaturbate"}}'

# Remove a model
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"RemoveModel": {"username": "example_user", "site": "Chaturbate"}}'

# Change model settings (e.g. enable auto-record)
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ChangeModelSettings": {"username": "example_user", "site": "Chaturbate", "autoRecord": true}}'

# Add/remove fake offline
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"AddFakeOfflineModel": {"username": "example_user", "site": "Chaturbate"}}'

Recording Control

# Start recording
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"StartRecording": {"username": "example_user", "site": "Chaturbate"}}'

# Stop recording
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"StopRecording": {"username": "example_user", "site": "Chaturbate"}}'

# Pause recording
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"PauseRecording": {"username": "example_user", "site": "Chaturbate"}}'

# Start monitoring (check online status without recording)
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"StartMonitoring": {"username": "example_user", "site": "Chaturbate"}}'

Recording Groups

# Create a recording group
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"CreateRecordingGroup": {"models": [{"username": "user1", "site": "Chaturbate"}]}}'

# Update a recording group
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"UpdateRecordingGroup": {"groupId": "group-id-here"}}'

# Disassociate models from a group
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"DisassociateRecordingGroup": {"models": [{"username": "user1", "site": "Chaturbate"}]}}'

Video Management

# Delete videos
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"DeleteVideo": {"filenames": ["video1.mp4", "video2.mp4"]}}'

# Cut/trim a video
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"CutVideo": {"videoId": "my-video-id", "cutTimes": [10, 60]}}'

# Concatenate videos
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ConcatVideo": {"filenames": ["video1.mp4", "video2.mp4"]}}'

# Export/copy videos to a directory
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ExportVideos": {"filenames": ["video1.mp4"], "destination": "/path/to/backup"}}'

# Update video metadata
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"UpdateVideoMetadata": {"filename": "video.mp4", "modelName": "example_user", "siteName": "Chaturbate", "recordTime": "2026-03-09T12:00:00Z"}}'

# Add boolean metadata tags
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"AddVideoBoolMetadata": {"videoId": "my-video-id", "tags": ["favorite"]}}'

Import & Export Models

# Export models to CSV
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ExportModels": {}}'

# Import models from CSV
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ImportModels": {"filePath": "/path/to/models.csv"}}'

Proxy Recording

# Start proxy recording
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"StartProxyRecording": {"streamId": "stream-123"}}'

# Stop proxy recording (auto-imports)
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"StopProxyRecording": {"streamId": "stream-123"}}'

# Manually import proxy recording
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ImportProxyRecording": {"streamId": "stream-123", "site": "Chaturbate", "username": "example_user"}}'

Configuration

# Change global settings
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ChangeGlobalSettings": {"videoSaveDirectory": "/path/to/videos"}}'

# Reset to default configuration
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ResetToDefaultConfig": {}}'

# Set active tab
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"SetActiveTab": {"tab": "dashboard"}}'

Authentication & Licensing

# Activate via Patreon email
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"EnterPatreon": {"email": "[email protected]"}}'

# Request email verification code (v2 licensing)
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"RequestEmailCode": {"email": "[email protected]"}}'

# Submit email verification code
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"SubmitEmailCode": {"email": "[email protected]", "code": "123456"}}'

# Chaturbate login
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"ChaturbateLogin": {"username": "...", "password": "..."}}'

# Filebaron authentication
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"EnterFilebaronAuth": {"email": "...", "password": "..."}}'

Config Lock

# Force unlock config file (URL-path based, not JSON field)
curl -X POST http://localhost:28471/forceUnlockConfigFile

Utilities

# Test a cURL request for a site
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"TestCurlRequest": {"site": "Chaturbate", "request": "base64-encoded-curl-request", "testType": "example"}}'

# Forward a URL fetch request
curl -X POST http://localhost:28471/ \
  -H "Content-Type: application/json" \
  -d '{"UrlFetchRequest": {"method": "GET", "url": "https://example.com", "headers": {}, "body": ""}}'

WebSocket

Connect to the WebSocket server on the -ws port for real-time state updates:

# Using websocat (install with: cargo install websocat)
websocat ws://127.0.0.1:28472/ws

The WebSocket pushes state changes as they happen (model status changes, recording progress, etc.), which is the same mechanism the desktop UI uses to stay in sync.

Troubleshooting

  • "bin directory not set": Make sure you're passing -binDir pointing to the directory with ffmpeg/transcoder
  • Transcoder version check failed: Ensure the transcoder binary is in the bin directory and is executable
  • Permission denied: Run chmod +x on all binaries in the bin directory
  • Port already in use: Choose different port numbers for -http and -ws
  • Config file locked: Use the /forceUnlockConfigFile POST endpoint to release the lock
Return to Guides