diff --git a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
index f24a9cad65..c4f9f9ea2b 100644
--- a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
@@ -235,6 +235,7 @@
         />
 
         <SettingAccordion
+          key="hardware-acceleration"
           title="Hardware Acceleration"
           subtitle="Experimental; much faster, but will have lower quality at the same bitrate"
         >
@@ -296,7 +297,11 @@
           </div>
         </SettingAccordion>
 
-        <SettingAccordion title="Advanced" subtitle="Options most users should not need to change">
+        <SettingAccordion
+          key="advanced-options"
+          title="Advanced"
+          subtitle="Options most users should not need to change"
+        >
           <div class="ml-4 mt-4 flex flex-col gap-4">
             <SettingInputField
               inputType={SettingInputFieldType.NUMBER}
diff --git a/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte
index fbcfe68b4c..27e3c3f7ca 100644
--- a/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte
@@ -26,7 +26,12 @@
 
 <div>
   <div in:fade={{ duration: 500 }}>
-    <SettingAccordion title="Library watching (EXPERIMENTAL)" subtitle="Automatically watch for changed files" isOpen>
+    <SettingAccordion
+      key="library-watching"
+      title="Library watching (EXPERIMENTAL)"
+      subtitle="Automatically watch for changed files"
+      isOpen
+    >
       <form autocomplete="off" on:submit|preventDefault>
         <div class="ml-4 mt-4 flex flex-col gap-4">
           <SettingSwitch
@@ -70,7 +75,12 @@
       </form>
     </SettingAccordion>
 
-    <SettingAccordion title="Periodic Scanning" subtitle="Configure periodic library scanning" isOpen>
+    <SettingAccordion
+      key="library-scanning"
+      title="Periodic Scanning"
+      subtitle="Configure periodic library scanning"
+      isOpen
+    >
       <form autocomplete="off" on:submit|preventDefault>
         <div class="ml-4 mt-4 flex flex-col gap-4">
           <SettingSwitch
diff --git a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte
index 90f74950db..9362da60cd 100644
--- a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte
@@ -42,7 +42,11 @@
         />
       </div>
 
-      <SettingAccordion title="Smart Search" subtitle="Search for images semantically using CLIP embeddings">
+      <SettingAccordion
+        key="smart-search"
+        title="Smart Search"
+        subtitle="Search for images semantically using CLIP embeddings"
+      >
         <div class="ml-4 mt-4 flex flex-col gap-4">
           <SettingSwitch
             title="ENABLED"
@@ -69,7 +73,11 @@
         </div>
       </SettingAccordion>
 
-      <SettingAccordion title="Facial Recognition" subtitle="Detect, recognize and group faces in images">
+      <SettingAccordion
+        key="facial-recognition"
+        title="Facial Recognition"
+        subtitle="Detect, recognize and group faces in images"
+      >
         <div class="ml-4 mt-4 flex flex-col gap-4">
           <SettingSwitch
             title="ENABLED"
diff --git a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte
index 8cc83f8070..80c59f5778 100644
--- a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte
@@ -21,7 +21,7 @@
   <div in:fade={{ duration: 500 }}>
     <form autocomplete="off" on:submit|preventDefault>
       <div class="flex flex-col gap-4">
-        <SettingAccordion title="Map Settings" subtitle="Manage map settings">
+        <SettingAccordion key="map" title="Map Settings" subtitle="Manage map settings">
           <div class="ml-4 mt-4 flex flex-col gap-4">
             <SettingSwitch
               title="ENABLED"
@@ -51,7 +51,7 @@
           </div></SettingAccordion
         >
 
-        <SettingAccordion title="Reverse Geocoding Settings">
+        <SettingAccordion key="reverse-geocoding" title="Reverse Geocoding Settings">
           <svelte:fragment slot="subtitle">
             <p class="text-sm dark:text-immich-dark-fg">
               Manage <a
diff --git a/web/src/lib/components/admin-page/settings/setting-accordion.svelte b/web/src/lib/components/admin-page/settings/setting-accordion.svelte
index 1d9290e617..76f29b1f6e 100755
--- a/web/src/lib/components/admin-page/settings/setting-accordion.svelte
+++ b/web/src/lib/components/admin-page/settings/setting-accordion.svelte
@@ -1,10 +1,24 @@
 <script lang="ts">
+  import { page } from '$app/stores';
+  import { QueryParameter } from '$lib/constants';
+  import { hasParamValue, updateParamList } from '$lib/utils';
   import { slide } from 'svelte/transition';
+
   export let title: string;
   export let subtitle = '';
-
+  export let key: string;
   export let isOpen = false;
-  const toggle = () => (isOpen = !isOpen);
+
+  const syncFromUrl = () => (isOpen = hasParamValue(QueryParameter.IS_OPEN, key));
+  const syncToUrl = (isOpen: boolean) => updateParamList({ param: QueryParameter.IS_OPEN, value: key, add: isOpen });
+
+  isOpen ? syncToUrl(true) : syncFromUrl();
+  $: $page.url && syncFromUrl();
+
+  const toggle = () => {
+    isOpen = !isOpen;
+    syncToUrl(isOpen);
+  };
 </script>
 
 <div class="border-b-[1px] border-gray-200 py-4 dark:border-gray-700">
diff --git a/web/src/lib/components/user-settings-page/user-settings-list.svelte b/web/src/lib/components/user-settings-page/user-settings-list.svelte
index e00cac83b5..60a5871775 100644
--- a/web/src/lib/components/user-settings-page/user-settings-list.svelte
+++ b/web/src/lib/components/user-settings-page/user-settings-list.svelte
@@ -27,32 +27,33 @@
   }
 </script>
 
-<SettingAccordion title="Appearance" subtitle="Manage your Immich appearance">
+<SettingAccordion key="appearance" title="Appearance" subtitle="Manage your Immich appearance">
   <AppearanceSettings />
 </SettingAccordion>
 
-<SettingAccordion title="Account" subtitle="Manage your account">
+<SettingAccordion key="account" title="Account" subtitle="Manage your account">
   <UserProfileSettings user={$user} />
 </SettingAccordion>
 
-<SettingAccordion title="API Keys" subtitle="Manage your API keys">
+<SettingAccordion key="api-keys" title="API Keys" subtitle="Manage your API keys">
   <UserAPIKeyList bind:keys />
 </SettingAccordion>
 
-<SettingAccordion title="Authorized Devices" subtitle="Manage your logged-in devices">
+<SettingAccordion key="authorized-devices" title="Authorized Devices" subtitle="Manage your logged-in devices">
   <DeviceList bind:devices />
 </SettingAccordion>
 
-<SettingAccordion title="Libraries" subtitle="Manage your asset libraries">
+<SettingAccordion key="libraries" title="Libraries" subtitle="Manage your asset libraries">
   <LibraryList />
 </SettingAccordion>
 
-<SettingAccordion title="Memories" subtitle="Manage what you see in your memories.">
+<SettingAccordion key="memories" title="Memories" subtitle="Manage what you see in your memories.">
   <MemoriesSettings user={$user} />
 </SettingAccordion>
 
 {#if $featureFlags.loaded && $featureFlags.oauth}
   <SettingAccordion
+    key="oauth"
     title="OAuth"
     subtitle="Manage your OAuth connection"
     isOpen={oauthOpen ||
@@ -62,18 +63,18 @@
   </SettingAccordion>
 {/if}
 
-<SettingAccordion title="Password" subtitle="Change your password">
+<SettingAccordion key="password" title="Password" subtitle="Change your password">
   <ChangePasswordSettings />
 </SettingAccordion>
 
-<SettingAccordion title="Sharing" subtitle="Manage sharing with partners">
+<SettingAccordion key="sharing" title="Sharing" subtitle="Manage sharing with partners">
   <PartnerSettings user={$user} />
 </SettingAccordion>
 
-<SettingAccordion title="Sidebar" subtitle="Manage sidebar settings">
+<SettingAccordion key="sidebar" title="Sidebar" subtitle="Manage sidebar settings">
   <SidebarSettings />
 </SettingAccordion>
 
-<SettingAccordion title="Trash" subtitle="Manage trash settings">
+<SettingAccordion key="trash" title="Trash" subtitle="Manage trash settings">
   <TrashSettings />
 </SettingAccordion>
diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts
index a1ac68c216..295bd99433 100644
--- a/web/src/lib/constants.ts
+++ b/web/src/lib/constants.ts
@@ -63,14 +63,15 @@ export const dateFormats = {
 export enum QueryParameter {
   ACTION = 'action',
   ASSET_INDEX = 'assetIndex',
-  SMART_SEARCH = 'smartSearch',
+  IS_OPEN = 'isOpen',
   MEMORY_INDEX = 'memoryIndex',
   ONBOARDING_STEP = 'step',
   OPEN_SETTING = 'openSetting',
-  QUERY = 'query',
   PREVIOUS_ROUTE = 'previousRoute',
+  QUERY = 'query',
   SEARCHED_PEOPLE = 'searchedPeople',
   SEARCH_TERM = 'q',
+  SMART_SEARCH = 'smartSearch',
 }
 
 export enum OpenSettingQueryParameterValue {
diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts
new file mode 100644
index 0000000000..059b526508
--- /dev/null
+++ b/web/src/lib/utils.ts
@@ -0,0 +1,33 @@
+import { goto } from '$app/navigation';
+import { page } from '$app/stores';
+import { get } from 'svelte/store';
+
+interface UpdateParamAction {
+  param: string;
+  value: string;
+  add: boolean;
+}
+
+const getParamValues = (param: string) =>
+  new Set((get(page).url.searchParams.get(param) || '').split(' ').filter((x) => x !== ''));
+
+export const hasParamValue = (param: string, value: string) => getParamValues(param).has(value);
+
+export const updateParamList = async ({ param, value, add }: UpdateParamAction) => {
+  const values = getParamValues(param);
+
+  if (add) {
+    values.add(value);
+  } else {
+    values.delete(value);
+  }
+
+  const searchParams = new URLSearchParams(get(page).url.searchParams);
+  searchParams.set(param, [...values.values()].join(' '));
+
+  if (values.size === 0) {
+    searchParams.delete(param);
+  }
+
+  await goto(`?${searchParams.toString()}`, { replaceState: true, noScroll: true, keepFocus: true });
+};
diff --git a/web/src/routes/admin/system-settings/+page.svelte b/web/src/routes/admin/system-settings/+page.svelte
index a52f797ccb..8bf63d58c6 100644
--- a/web/src/routes/admin/system-settings/+page.svelte
+++ b/web/src/routes/admin/system-settings/+page.svelte
@@ -1,5 +1,4 @@
 <script lang="ts">
-  import { page } from '$app/stores';
   import FFmpegSettings from '$lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte';
   import JobSettings from '$lib/components/admin-page/settings/job-settings/job-settings.svelte';
   import MachineLearningSettings from '$lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte';
@@ -17,7 +16,7 @@
   import { downloadManager } from '$lib/stores/download';
   import { featureFlags } from '$lib/stores/server-config.store';
   import { downloadBlob } from '$lib/utils/asset-utils';
-  import { type SystemConfigDto, copyToClipboard } from '@api';
+  import { copyToClipboard } from '@api';
   import Icon from '$lib/components/elements/icon.svelte';
   import type { PageData } from './$types';
   import NewVersionCheckSettings from '$lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte';
@@ -29,7 +28,22 @@
   export let data: PageData;
 
   let config = data.configs;
-  let openSettings = ($page.url.searchParams.get('open')?.split(',') || []) as Array<keyof SystemConfigDto>;
+
+  type Settings =
+    | typeof JobSettings
+    | typeof LibrarySettings
+    | typeof LoggingSettings
+    | typeof MachineLearningSettings
+    | typeof MapSettings
+    | typeof OAuthSettings
+    | typeof PasswordLoginSettings
+    | typeof ServerSettings
+    | typeof StorageTemplateSettings
+    | typeof ThemeSettings
+    | typeof ThumbnailSettings
+    | typeof TrashSettings
+    | typeof NewVersionCheckSettings
+    | typeof FFmpegSettings;
 
   const downloadConfig = () => {
     const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
@@ -40,90 +54,95 @@
     setTimeout(() => downloadManager.clear(downloadKey), 5000);
   };
 
-  const settings = [
+  const settings: Array<{
+    item: Settings;
+    title: string;
+    subtitle: string;
+    key: string;
+  }> = [
     {
       item: JobSettings,
       title: 'Job Settings',
       subtitle: 'Manage job concurrency',
-      isOpen: openSettings.includes('job'),
+      key: 'job',
     },
     {
       item: LibrarySettings,
       title: 'Library',
       subtitle: 'Manage library settings',
-      isOpen: openSettings.includes('library'),
+      key: 'library',
     },
     {
       item: LoggingSettings,
       title: 'Logging',
       subtitle: 'Manage log settings',
-      isOpen: openSettings.includes('logging'),
+      key: 'logging',
     },
     {
       item: MachineLearningSettings,
       title: 'Machine Learning Settings',
       subtitle: 'Manage machine learning features and settings',
-      isOpen: openSettings.includes('machineLearning'),
+      key: 'machine-learning',
     },
     {
       item: MapSettings,
       title: 'Map & GPS Settings',
       subtitle: 'Manage map related features and setting',
-      isOpen: openSettings.some((key) => ['map', 'reverseGeocoding'].includes(key)),
+      key: 'location',
     },
     {
       item: OAuthSettings,
       title: 'OAuth Authentication',
       subtitle: 'Manage the login with OAuth settings',
-      isOpen: openSettings.includes('oauth'),
+      key: 'oauth',
     },
     {
       item: PasswordLoginSettings,
       title: 'Password Authentication',
       subtitle: 'Manage the login with password settings',
-      isOpen: openSettings.includes('passwordLogin'),
+      key: 'password',
     },
     {
       item: ServerSettings,
       title: 'Server Settings',
       subtitle: 'Manage server settings',
-      isOpen: openSettings.includes('server'),
+      key: 'server',
     },
     {
       item: StorageTemplateSettings,
       title: 'Storage Template',
       subtitle: 'Manage the folder structure and file name of the upload asset',
-      isOpen: openSettings.includes('storageTemplate'),
+      key: 'storage-template',
     },
     {
       item: ThemeSettings,
       title: 'Theme Settings',
       subtitle: 'Manage customization of the Immich web interface',
-      isOpen: openSettings.includes('theme'),
+      key: 'theme',
     },
     {
       item: ThumbnailSettings,
       title: 'Thumbnail Settings',
       subtitle: 'Manage the resolution of thumbnail sizes',
-      isOpen: openSettings.includes('thumbnail'),
+      key: 'thumbnail',
     },
     {
       item: TrashSettings,
       title: 'Trash Settings',
       subtitle: 'Manage trash settings',
-      isOpen: openSettings.includes('trash'),
+      key: 'trash',
     },
     {
       item: NewVersionCheckSettings,
       title: 'Version Check',
       subtitle: 'Enable/disable the new version notification',
-      isOpen: openSettings.includes('newVersionCheck'),
+      key: 'version-check',
     },
     {
       item: FFmpegSettings,
       title: 'Video Transcoding Settings',
       subtitle: 'Manage the resolution and encoding information of the video files',
-      isOpen: openSettings.includes('ffmpeg'),
+      key: 'video-transcoding',
     },
   ];
 </script>
@@ -157,8 +176,8 @@
     <AdminSettings bind:config let:handleReset let:handleSave let:savedConfig let:defaultConfig>
       <section id="setting-content" class="flex place-content-center sm:mx-4">
         <section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
-          {#each settings as { item, title, subtitle, isOpen }}
-            <SettingAccordion {title} {subtitle} {isOpen}>
+          {#each settings as { item, title, subtitle, key }}
+            <SettingAccordion {title} {subtitle} {key}>
               <svelte:component
                 this={item}
                 on:save={({ detail }) => handleSave(detail)}