diff --git a/src/frontend/src/features/rooms/components/Join.tsx b/src/frontend/src/features/rooms/components/Join.tsx
index 5bc75070..3d83c767 100644
--- a/src/frontend/src/features/rooms/components/Join.tsx
+++ b/src/frontend/src/features/rooms/components/Join.tsx
@@ -55,6 +55,7 @@ import {
import { saveUsername, userStore } from '@/stores/user'
import { useCannotUseDevice } from '../livekit/hooks/useCannotUseDevice'
+import { useSyncTrackDeviceId } from '../livekit/hooks/useSyncTrackDeviceId'
import { useSnapshot } from 'valtio'
import { useUser } from '@/features/auth/api/useUser'
import { useConfig } from '@/api/useConfig'
@@ -274,6 +275,8 @@ export const Join = ({
const videoTrack = dynamicVideoTrack || previewVideoTrack
const audioTrack = dynamicAudioTrack || previewAudioTrack
+ useSyncTrackDeviceId(audioTrack, saveAudioInputDeviceId)
+ useSyncTrackDeviceId(videoTrack, saveVideoInputDeviceId)
const videoEl = useRef(null)
const isVideoInitiated = useRef(false)
diff --git a/src/frontend/src/features/rooms/livekit/components/SyncDevicePreferences.tsx b/src/frontend/src/features/rooms/livekit/components/SyncDevicePreferences.tsx
new file mode 100644
index 00000000..ba02c17d
--- /dev/null
+++ b/src/frontend/src/features/rooms/livekit/components/SyncDevicePreferences.tsx
@@ -0,0 +1,20 @@
+import { useLocalParticipant } from '@livekit/components-react'
+import type { LocalTrack } from 'livekit-client'
+import { useSyncTrackDeviceId } from '../hooks/useSyncTrackDeviceId'
+import {
+ saveAudioInputDeviceId,
+ saveVideoInputDeviceId,
+} from '@/stores/userChoices'
+
+export const SyncDevicePreferences = () => {
+ const { cameraTrack, microphoneTrack } = useLocalParticipant()
+ useSyncTrackDeviceId(
+ cameraTrack?.track as LocalTrack | undefined,
+ saveVideoInputDeviceId
+ )
+ useSyncTrackDeviceId(
+ microphoneTrack?.track as LocalTrack | undefined,
+ saveAudioInputDeviceId
+ )
+ return null
+}
diff --git a/src/frontend/src/features/rooms/livekit/hooks/useSyncTrackDeviceId.ts b/src/frontend/src/features/rooms/livekit/hooks/useSyncTrackDeviceId.ts
new file mode 100644
index 00000000..c4a585ed
--- /dev/null
+++ b/src/frontend/src/features/rooms/livekit/hooks/useSyncTrackDeviceId.ts
@@ -0,0 +1,44 @@
+import { useEffect } from 'react'
+import { TrackEvent, type LocalTrack } from 'livekit-client'
+
+/**
+ * Keeps the persisted device preference aligned with the device the track
+ * is ACTUALLY using — the track is the ground truth, not the store.
+ *
+ * Syncs on mount and on every TrackEvent.Restarted, which covers all the
+ * moments the underlying device can change on the join screen:
+ * - initial acquisition where LiveKit resolved the 'default' alias
+ * (getDeviceId(normalize=true) resolves it to the concrete id via
+ * livekit's DeviceManager — this replaces the former
+ * useResolveInitiallyDefaultDeviceId, which never fired after init),
+ * - a device switch via setDeviceId,
+ * - an unmute re-acquisition,
+ * - the browser falling back to another device.
+ */
+export const useSyncTrackDeviceId = (
+ track: LocalTrack | undefined,
+ save: (deviceId: string) => void
+) => {
+ useEffect(() => {
+ if (!track) return
+ let cancelled = false
+ const sync = () => {
+ track
+ .getDeviceId()
+ .then((deviceId) => {
+ if (!cancelled && deviceId && deviceId !== 'default') {
+ save(deviceId)
+ }
+ })
+ .catch(() => {
+ // A track without settings (ended, screen share) has no id to sync.
+ })
+ }
+ sync()
+ track.on(TrackEvent.Restarted, sync)
+ return () => {
+ cancelled = true
+ track.off(TrackEvent.Restarted, sync)
+ }
+ }, [track, save])
+}
diff --git a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx
index e6bfe693..1859fff3 100644
--- a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx
+++ b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx
@@ -26,6 +26,7 @@ import { PipRoomPlaceholder } from '@/features/pip/components/PipRoomPlaceholder
import { StageLayout } from '@/features/layout/components/StageLayout'
import { PinAnnouncer } from '@/features/layout/components/PinAnnouncer'
import { ChatProvider } from '@/features/chat/components/ChatProvider'
+import { SyncDevicePreferences } from '@/features/rooms/livekit/components/SyncDevicePreferences'
/**
* @public
@@ -65,6 +66,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
<>
+