Repository navigation
Recording SDK can start capture after its React component unmounts #2794
Description
Description
Closing a React recorder component while camera or microphone permission is pending does not cancel startup. If the permission request later succeeds, @cap/sdk-recorder starts MediaRecorder after the hook has unmounted. The capture track stays live without recorder controls on the page.
There is a second consequence of the same ownership gap. If screen sharing has already been granted and the microphone prompt is still pending, destroy() leaves the acquired screen track live. The recorder only stores those streams after all permission requests finish.
Expected: destroying a recorder releases acquired tracks immediately, releases any tracks returned later, and prevents that start from creating a recorder or changing a replacement recording.
Actual: a late grant resumes startup and changes the destroyed recorder back to recording. A late denial can also clean up a new recording started on the same instance.
Reproduction
- Mount a component that uses the following hook and calls
start()from a button:
const recorder = useCapRecorder({
publicKey: "YOUR_SDK_PUBLIC_KEY",
apiBase: "https://cap.so",
mode: "camera",
microphone: { enabled: false },
});- Leave the camera permission request pending. Unmount the component, for example by closing its recorder modal.
- Allow the pending camera request.
- Observe that the camera track stays live and MediaRecorder starts after unmount. The hook cleanup already called
destroy(), so the component has no controls for this recording.
The class API shows the same sequence with const starting = recorder.start(); recorder.destroy();, followed by the browser granting the pending request.
Additional Context
- Baseline main:
d27360a8ac928ba15bfbaec75236762f922d2e52, package version0.1.0. - Verified with React 19.2.8 and Chrome 154 on Linux x86_64. Real React DOM, MediaRecorder and MediaStreamTrack lifecycle APIs were used. Device acquisition was a deferred fixture returning a canvas stream. The screen and microphone case used a canvas stream and an AudioContext destination stream. Physical devices and native permission prompts were not exercised.
- Before: a late camera grant leaves one real MediaRecorder in
recordingwith a live track. After cancellation is carried through startup: no MediaRecorder is constructed and the track isended. - The screen track is
liveimmediately afterdestroy()on main while microphone permission is pending. With cancellation it is immediatelyended, and the late microphone track also ends. - No cloud requests are needed to reproduce startup. The successful recording control used HTTP response fixtures.
Relevant source: start and destroy, stream acquisition, and React cleanup.
Activity
linear commentedon Oct 21, 2026
CAP-860