Skip to main content

General

LCK is an in-game camera SDK for Unity and Unreal Engine that lets developers add user-spawnable cameras, video recording, screenshot capture, and live streaming to their games. It is the official capture solution for Meta Quest, integrated in 300+ Quest apps.
Unreal Engine 5.4+ and Meta Fork.
Meta Quest 2, Quest 3, Quest 3s, and Windows PCVR (DirectX 11 or Vulkan). On Android (Quest), Vulkan is required — OpenGL ES is not supported for video encoding.
Register on the LIV Developer Dashboard, create your game entry, and download the SDK. See the Installation guide.
LCK is free for developers. See the SDK License Agreement for terms.
The SDK is modular. Required: LCK (core recording & encoding), LCKAudio (audio interface). Recommended: LCKUI (3D button components), LCKTablet (virtual tablet interface), LCKUnrealAudio (Unreal Engine audio capture). Optional: LCKOboe (Android low-latency mic), LCKFMOD, LCKWwise, LCKVivox (audio middleware integrations — disabled by default, require third-party plugins).
Join the LIV Discord community for direct support.

Recording

Four quality profiles are pre-configured:
ProfileResolutionFramerateVideo BitrateAudio Bitrate
SD1280 x 72030 fps4 Mbps128 Kbps
HD1920 x 108060 fps12 Mbps256 Kbps
2K2560 x 144060 fps20 Mbps320 Kbps
4K3840 x 216060 fps35 Mbps320 Kbps
All profiles use 48 kHz audio sample rate. Framerate and bitrate are adjustable per profile in Project Settings > Plugins > LCK SDK.
Recordings are saved as MP4 files (H.264 video, AAC audio). Photos are saved as PNG files.
Android (Quest): Videos are saved to Movies/{GameName} and photos to Pictures/{GameName}.Windows: Videos are saved to {User}/Videos/{GameName} and photos to {User}/Pictures/{GameName}.The {GameName} subfolder name is set in Project Settings > Plugins > LCK SDK > Game Name.
Yes. Call Service->TakePhoto() or use the tablet UI photo button. Photos are captured as a single frame from the active scene capture component and saved as PNG to the platform’s gallery.
Yes. The ULCKRecorderSubsystem (a UTickableWorldSubsystem) provides full recording control:
ULCKRecorderSubsystem* Recorder = GetWorld()->GetSubsystem<ULCKRecorderSubsystem>();
Recorder->StartRecording();   // Start
Recorder->StopRecording();    // Stop
Recorder->TakePhoto();        // Capture a photo
Recorder->IsRecording();      // Query state
Recorder->GetTime();          // Current duration in seconds
Async variants (StartRecordingAsync, StopRecordingAsync) are also available with completion and progress callbacks.
Yes. If using the LCKTablet plugin, ULCKService provides PauseRecording() and ResumeRecording(). The recording state transitions to ELCKRecordingState::Paused and back to Recording when resumed. Paused segments are excluded from the final output.
Yes. Use Recorder->StartPreview() to start capturing frames without encoding to disk. This is useful for live camera preview and composition. Call Recorder->StopPreview() to stop.
Recording will not work without a valid Tracking ID. Get one from https://dashboard.liv.tv/dev/login.

Camera & Tablet

Three modes ship with the tablet:
  • Selfie — Front/back facing camera attached to the tablet. Default: 80° FOV, 50% smoothness, 2.0m follow distance, follow mode off.
  • First-Person — Captures from the player’s HMD perspective. Default: 90° FOV, 75% smoothness.
  • Third-Person — Follows the player at a distance via SpringArm. Default: 90° FOV, 100% smoothness, 2.0m distance, -30° pitch.
All modes support adjustable FOV (20°-120°, step 5°), smoothness (0%-100%, step 5%), and distance (1.0-20.0, step 0.5).
Place ALCKTablet (or BP_LCKTablet) in your level, or spawn it programmatically:
ALCKTablet* Tablet = GetWorld()->SpawnActor<ALCKTablet>();
The tablet auto-initializes on BeginPlay, loading saved user preferences (camera mode, FOV, quality, etc.) from disk.
Yes. The tablet uses a JSON-based save system (FLCKJsonSaveHelper) that persists all user preferences: camera mode, FOV per mode, smoothness, follow distance, screen orientation, video quality, and camera facing. Settings are saved automatically on change and loaded on BeginPlay.
Tablet buttons use collision-based interaction. Each button has a UBoxComponent for collision detection. When a VR controller (or any collider) overlaps a button, ButtonPressed fires; when overlap ends, ButtonReleased fires. Buttons include an automatic cooldown to prevent double-triggers.
Yes. Create a class extending ULCKBaseButton (or ULCKToggle / ULCKStepper for toggles or step controls), override ButtonPressed(), and add it to the tablet component hierarchy. Register it with the ULCKUISystem to enable UI feedback. See the existing button implementations in the LCKUI plugin for examples.

Audio

Five audio source plugins are available:
PluginChannelsPlatformsNotes
LCKUnrealAudioGame + MicrophoneAllBuilt-in, enabled by default
LCKFMODGame onlyWin64, AndroidRequires FMODStudio plugin
LCKWwiseGame onlyWin64, AndroidRequires Wwise plugin
LCKOboeMicrophone onlyAndroid onlyLow-latency via Google Oboe
LCKVivoxMicrophone + Voice ChatWin64, AndroidRequires VivoxCore plugin
Game audio middleware priority: FMOD > Wwise > UnrealAudio. Only one game audio middleware should be active at a time.
These plugins are disabled by default because they require third-party plugins to compile. To enable:
  1. Install the third-party plugin (FMODStudio, Wwise, or VivoxCore)
  2. Set "Enabled": true for both the third-party plugin and the LCK audio plugin in your .uproject
  3. Rebuild the project
If using FMOD or Wwise for game audio, disable “Game Audio” in the UnrealAudio settings to avoid conflicts.
Yes. LCKVivox captures voice chat audio (incoming voice + outgoing microphone), not game audio. It can safely coexist with FMOD/Wwise/UnrealAudio without conflicts.
All audio sources deliver 32-bit float PCM, interleaved stereo (L,R,L,R…) at 48 kHz by default. The sample rate is queried from the active audio device at capture start.
Audio data callbacks can fire on the audio render thread, audio capture thread, or middleware threads depending on the source. If you need to process audio on the game thread, queue it:
AsyncTask(ENamedThreads::GameThread, [Data = TArray<float>(PCM)]() {
    ProcessAudioOnGameThread(Data);
});
LCKVivox has the most robust thread safety (uses TAtomic for all state). FMOD/Wwise copy buffers to TArrays before dispatching. The built-in FLCKAudioMix class handles thread-safe mixing internally.

Platform-Specific

Yes. The LCK encoder on Android uses Vulkan + EGL texture interop for hardware-accelerated H.264 encoding. OpenGL ES is not supported for video encoding. Ensure Vulkan is enabled in your Android project settings and OpenGL ES is removed.
  • RECORD_AUDIO — Required for microphone capture (must be requested at runtime on Android 6.0+)
  • WRITE_EXTERNAL_STORAGE / READ_EXTERNAL_STORAGE — Only needed on Android 9 and below; Android 10+ uses scoped storage via MediaStore automatically
DeviceStatusRecommended Quality
Meta Quest 2Full SupportSD (720p) or HD (1080p) @ 30fps
Meta Quest 3Full SupportHD (1080p) @ 60fps
Meta Quest 3sFull SupportHD (1080p) @ 60fps
Meta Quest ProFull SupportHD (1080p) @ 60fps
  1. Use SD (720p) or HD (1080p) at 30 fps
  2. Lower the video bitrate (4 Mbps is good for SD)
  3. Use Preview mode for camera composition before recording
  4. The hardware encoder runs on a dedicated chip and has minimal impact on game framerate — the main cost is the scene capture component rendering an extra view
  1. Verify Windows Media Foundation is available (built into Windows 10+)
  2. Ensure your GPU drivers are up to date (NVIDIA, AMD, or Intel)
  3. Check that the AVCodecsCore plugin is enabled in your project
  4. Look for errors in the LogLCKEncoding log category

Integration & Setup

ULCKRecorderSubsystem (in LCKCore) is the low-level recording API — a UTickableWorldSubsystem that handles encoding, frame capture, and file output. Access it via GetWorld()->GetSubsystem<ULCKRecorderSubsystem>().ULCKService (in LCKTablet) is a high-level wrapper that adds pause/resume, error delegates (OnRecordingError, OnRecordingSaveFinished), quality profile management, and integration with the tablet UI. Access it through the tablet or create one programmatically.Use ULCKService if you want the full feature set. Use ULCKRecorderSubsystem directly if you need minimal integration without the LCKTablet plugin.
Minimal (recording only):
PublicDependencyModuleNames.AddRange(new string[] {
    "LCKCore",
    "LCKAudio"
});
Full (with tablet UI):
PublicDependencyModuleNames.AddRange(new string[] {
    "LCKCore",
    "LCKAudio",
    "LCKUI",
    "LCKTablet"
});
The SDK loads modules in this order:
  1. LCKVulkan (EarliestPossible) — Vulkan support layer
  2. Platform encoders: LCKWindowsEncoder or LCKAndroidEncoder (Default phase)
  3. LCKAudio (PostDefault) — Audio interface
  4. LCKCore (PostDefault) — Core recording subsystem
  5. Audio middleware plugins (LCKFMOD, LCKWwise, LCKVivox, LCKOboe) and UI plugins (LCKUI, LCKTablet) load at Default phase
LCKVulkan must load first as it provides the Vulkan context required by platform encoders. LCKAudio and LCKCore load at PostDefault to ensure platform encoders are already registered.
If you use the LCKTablet, it creates and manages a USceneCaptureComponent2D automatically. If you use the recording API directly without the tablet, you need to either pass a capture component to SetupRecorder() or set one later via SetSceneCaptureComponent().
The SDK sends anonymized usage events (recording start/stop, errors, performance metrics) to errors.liv.tv. Device telemetry is enabled by default and can be disabled in Project Settings. Location telemetry is disabled by default. A valid Tracking ID is required.

Troubleshooting

  1. Verify the Tracking ID is set and valid (UUID v4) in Project Settings
  2. Ensure a valid USceneCaptureComponent2D is registered
  3. On Android, confirm Vulkan is enabled (not OpenGL ES)
  4. Check LogLCK and LogLCKEncoding log categories for errors
  5. If using the LCKTablet plugin, subscribe to ULCKService::OnRecordingError for runtime error messages. If using ULCKRecorderSubsystem directly, check log categories for errors
The scene capture component is likely not rendering:
  1. Verify the capture component is enabled and visible
  2. Check that a valid render target is assigned
  3. Ensure the capture component resolution matches the recording profile
  4. Try CaptureComponent->CaptureScene() to force a manual capture
  1. Verify at least one audio plugin is enabled (LCKUnrealAudio is the default)
  2. On Android, ensure the RECORD_AUDIO permission is granted at runtime
  3. Check that audio sources are registered: look for "Found LCK Audio Source" in logs
  4. If using FMOD or Wwise, disable “Game Audio” in UnrealAudio settings to avoid conflicts
Add to DefaultEngine.ini:
[Core.Log]
LogLCK=VeryVerbose
LogLCKEncoding=VeryVerbose
LogLCKAudio=VeryVerbose
LogLCKUI=Verbose
LogLCKTablet=Verbose