diff --git a/amadeus/src/app.rs b/amadeus/src/app.rs
index af869c13c7d22c42b3085b94f2c0778654f0a7f7..fde30c99b9cbde913aefff656a87af02fb23fd06 100644
--- a/amadeus/src/app.rs
+++ b/amadeus/src/app.rs
@@ -650,7 +650,7 @@ impl Application for Amadeus {
                         Message::RefreshRequest(RefreshRequest::Playlists),
                         Message::ConfigMessage(config::Message::Infos(Some(infos))),
                     ]),
-                    Err(_) => Message::ConnectionStatus(true),
+                    Err(_) => Message::ConnectionStatus(false),
                 })
             }
             Message::SmollTick(instant) => {
@@ -858,8 +858,8 @@ impl Application for Amadeus {
     fn subscription(&self) -> iced::Subscription<Self::Message> {
         use iced::time::{every, Duration};
         let (smoll_time, big_time) = either!(self.is_connected =>
-            (Some(Duration::new(1, 0)), Duration::new(20, 0));
-            (None, Duration::new(30, 0))
+            (Some(Duration::new(1, 0)), self.config.amadeus.retry_time_interval());
+            (None,                      self.config.amadeus.retry_time_interval())
         );
         let keycodes = iced::subscription::events().map(|event| match event {
             Event::Keyboard(KbdEvent::KeyReleased {
diff --git a/amadeus/src/components/config/mod.rs b/amadeus/src/components/config/mod.rs
index 9b21e81bf7a707436d64ee06e3b3876e0227a649..e0ef98f6b7e434d97f7d25ff8622dee2a7e6e769 100644
--- a/amadeus/src/components/config/mod.rs
+++ b/amadeus/src/components/config/mod.rs
@@ -18,6 +18,7 @@ use iced::{
 use lektor_payloads::Infos;
 use lektor_utils::{
     config::{SocketScheme, UserConfig},
+    either,
     log::{self, Level as LogLevel},
     logger,
 };
@@ -29,6 +30,7 @@ pub struct State {
     scroll_id: scrollable::Id,
     current_scroll_offset: scrollable::RelativeOffset,
 
+    tmp_retry_time: u16,
     tmp_scheme: String,
     tmp_host: String,
     tmp_port: u16,
@@ -38,6 +40,14 @@ pub struct State {
     system_informations: Option<iced::system::Information>,
 }
 
+fn clamp_scale_factor(scale: impl Into<f64>) -> f64 {
+    scale.into().clamp(0.5, 1.5)
+}
+
+fn clamp_time_interval(time: impl Into<i64>) -> u16 {
+    time.into().clamp(10, u16::MAX as i64) as u16
+}
+
 /// Amadeus configuration.
 #[derive(Debug, Deserialize, Serialize, Clone)]
 pub struct AmadeusConfig {
@@ -58,8 +68,16 @@ pub struct UIConfig {
     pub theme: theme::Message,
 
     #[serde(default = "serde_utils::get_1_f64")]
+    #[serde(serialize_with = "serde_utils::serialize_scale_factor")]
+    #[serde(deserialize_with = "serde_utils::deserialize_scale_factor")]
     scale_factor: f64,
 
+    /// Retry interval in seconds.
+    #[serde(default = "serde_utils::get_20_u16")]
+    #[serde(serialize_with = "serde_utils::serialize_interval")]
+    #[serde(deserialize_with = "serde_utils::deserialize_interval")]
+    retry_interval_sec: u16,
+
     #[serde(default = "serde_utils::get_true")]
     pub open_config_if_init_ping_failed: bool,
 }
@@ -70,6 +88,7 @@ pub struct RemoteConfig {
     pub scheme: SocketScheme,
     pub host: SocketAddr,
     pub user: UserConfig,
+    pub kurisu_token: Option<String>,
 }
 
 /// Messages used to update the config file
@@ -121,12 +140,19 @@ pub enum Message {
     /// holded a connection we now need to reconnect for sure.
     TokenChanged(String),
 
+    /// The token for kurisu changed. We do this so that we can override the token from lektord
+    /// config with one supplied by amadeus.
+    KurisuTokenChanged(String),
+
     /// Open the settings page if lektord was offline when we launched amadeus.
     OpenConfigIfInitPingFailed(bool),
 
     /// The scale factor changed.
     ScaleFactorChanged(f64),
 
+    /// The retry interval time changed.
+    RetryIntervalChanged(u16),
+
     /// The config was scrolled.
     Scrolled(Viewport),
 
@@ -158,15 +184,61 @@ pub enum Request {
 impl UIConfig {
     /// Get the scale factor, should only be between 0.5 and 2.0
     pub fn scale_factor(&self) -> f64 {
-        self.scale_factor.clamp(0.5, 2.0)
+        clamp_scale_factor(self.scale_factor)
+    }
+
+    /// Get the retry time for when we are offline.
+    pub fn retry_time_interval(&self) -> iced::time::Duration {
+        iced::time::Duration::new(clamp_time_interval(self.retry_interval_sec).into(), 0)
     }
 }
 
 #[rustfmt::skip]
 mod serde_utils {
-    pub(super) fn get_1_f64() -> f64  { 1.0  }
-    pub(super) fn get_true()  -> bool { true }
-    pub(super) fn get_false() -> bool { true }
+    pub(super) fn get_1_f64()  -> f64  { 1.0  }
+    pub(super) fn get_20_u16() -> u16  { 20   }
+    pub(super) fn get_true()   -> bool { true }
+    pub(super) fn get_false()  -> bool { true }
+
+    pub(super) fn serialize_scale_factor<S: serde::Serializer>(v: &f64, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_f64(*v) }
+    pub(super) fn deserialize_scale_factor<'de, D: serde::Deserializer<'de>>(de: D) -> Result<f64, D::Error> {
+        struct FloadVisitor;
+        impl<'de> serde::de::Visitor<'de> for FloadVisitor {
+            type Value = f64;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("f32 or f64") }
+            fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+            fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
+        }
+        de.deserialize_any(FloadVisitor)
+    }
+
+    pub(super) fn serialize_interval<S: serde::Serializer>(v: &u16, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_u16(*v) }
+    pub(super) fn deserialize_interval<'de, D: serde::Deserializer<'de>>(de: D) -> Result<u16, D::Error> {
+        struct FloadVisitor;
+        impl<'de> serde::de::Visitor<'de> for FloadVisitor {
+            type Value = u16;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("u16") }
+            fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
+            fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
+                Ok(super::clamp_time_interval(v.clamp(0, i64::MAX as u64) as i64))
+            }
+        }
+        de.deserialize_any(FloadVisitor)
+    }
 }
 
 impl Default for State {
@@ -175,6 +247,7 @@ impl Default for State {
             scroll_id: scrollable::Id::unique(),
             current_scroll_offset: scrollable::RelativeOffset::START,
             config: Default::default(),
+            tmp_retry_time: serde_utils::get_20_u16(),
             tmp_scheme: Default::default(),
             tmp_host: Default::default(),
             tmp_port: Default::default(),
@@ -198,6 +271,7 @@ impl Default for RemoteConfig {
         Self {
             scheme: SocketScheme::Http,
             host: SocketAddr::new([127, 0, 0, 1].into(), 6600),
+            kurisu_token: None,
             user: UserConfig {
                 admin: false,
                 ..Default::default()
@@ -243,7 +317,8 @@ impl State {
             });
         };
         macro_rules! connect_to {
-            () => {
+            ($expr: expr) => {{
+                $expr;
                 match self.tmp_host.parse() {
                     Ok(host) => {
                         config.connect.host = SocketAddr::new(host, self.tmp_port);
@@ -251,7 +326,13 @@ impl State {
                     }
                     _ => return Command::none(),
                 }
-            };
+            }};
+        }
+        macro_rules! write_config {
+            ($reload: expr, $expr: expr) => {{
+                $expr;
+                self.write_config($reload)
+            }};
         }
         match message {
             Message::None | Message::OpenLinkInBrowser(_) => {
@@ -270,6 +351,7 @@ impl State {
                     SocketAddr::V6(v6) => (v6.ip().to_string(), v6.port()),
                 };
                 self.tmp_scheme = new.connect.scheme.to_string();
+                self.tmp_retry_time = clamp_time_interval(new.amadeus.retry_interval_sec);
                 *config = new;
                 // Some times we add things to the config, we need to re-write the config when we
                 // load it completly to apply the new defaults.
@@ -282,53 +364,50 @@ impl State {
                 Command::none()
             }
 
-            Message::OpenConfigIfInitPingFailed(flag) => {
-                config.amadeus.open_config_if_init_ping_failed = flag;
-                self.write_config(Request::None)
-            }
-            Message::ScaleFactorChanged(scale) => {
-                config.amadeus.scale_factor = scale.clamp(0.5, 2.0);
-                self.write_config(Request::None)
-            }
+            Message::OpenConfigIfInitPingFailed(flag) => write_config!(
+                Request::None,
+                config.amadeus.open_config_if_init_ping_failed = flag
+            ),
+            Message::RetryIntervalChanged(interval) => write_config!(Request::None, {
+                config.amadeus.retry_interval_sec = interval;
+                self.tmp_retry_time = interval;
+            }),
+            Message::ScaleFactorChanged(scale) => write_config!(
+                Request::None,
+                config.amadeus.scale_factor = clamp_scale_factor(scale)
+            ),
             Message::ThemeChanged(theme) => {
-                config.amadeus.theme = theme;
-                self.write_config(Request::None)
+                write_config!(Request::None, config.amadeus.theme = theme)
             }
             Message::UserChanged(user) => {
-                config.connect.user.user = user;
-                self.write_config(Request::Reconnect)
+                write_config!(Request::Reconnect, config.connect.user.user = user)
             }
             Message::TokenChanged(token) => {
-                config.connect.user.token = token;
-                self.write_config(Request::Reconnect)
-            }
-            Message::LogLevelChanged(level) => {
-                config.log = level;
-                logger::level(level);
-                self.write_config(Request::None)
+                write_config!(Request::Reconnect, config.connect.user.token = token)
             }
+            Message::KurisuTokenChanged(token) => write_config!(
+                Request::Reconnect,
+                config.connect.kurisu_token = either!(token.is_empty() => None; Some(token))
+            ),
             Message::MprisFlagChanged(flag) => {
-                config.mpris = flag;
-                self.write_config(Request::ToggleMprisServer(flag))
+                write_config!(Request::ToggleMprisServer(flag), config.mpris = flag)
             }
+            Message::LogLevelChanged(level) => write_config!(Request::None, {
+                config.log = level;
+                logger::level(level);
+            }),
 
             Message::SchemeChanged(scheme) => {
                 self.tmp_scheme = scheme.to_string();
                 if let Ok(scheme) = scheme.parse() {
-                    config.connect.scheme = scheme;
-                    return self.write_config(Request::None);
+                    write_config!(Request::None, config.connect.scheme = scheme)
+                } else {
+                    Command::none()
                 }
-                Command::none()
             }
 
-            Message::PortChanged(port) => {
-                self.tmp_port = port;
-                connect_to!()
-            }
-            Message::HostChanged(host) => {
-                self.tmp_host = host;
-                connect_to!()
-            }
+            Message::PortChanged(port) => connect_to!(self.tmp_port = port),
+            Message::HostChanged(host) => connect_to!(self.tmp_host = host),
 
             Message::Scrolled(viewport) => {
                 self.current_scroll_offset = viewport.relative_offset();
@@ -342,10 +421,16 @@ impl State {
             ($name: literal => [ $($content: expr),+ $(,)? ]) => {
                 Some(container(column![
                     text(concat!("# ", $name)).size(SIZE_FONT_MEDIUM),
-                    vertical_space(10),
+                    vertical_space(5),
                     $($content),+,
-                    vertical_space(20)
-                ]).width(Length::Fixed(500.0)))
+                    vertical_space(15)
+                ].spacing(5)).width(Length::Fixed(500.0)))
+            };
+        }
+
+        macro_rules! elem_row {
+            ($title: literal, $what: expr) => {
+                row![text($title), horizontal_space(Length::Fill), $what]
             };
         }
 
@@ -358,20 +443,21 @@ impl State {
                     ]
                     .align_items(Alignment::Start),
                     input!(@$what $($portion)?; $($args),+ => $event),
-                    vertical_space(10),
+                    vertical_space(5),
                 ]
             };
 
-            (@number $($portion: literal)?; $tip: expr, $value: expr, $min: expr, $max: expr => $event: ident) => {
+            (@number $($portion: literal)?; $tip: expr, $value: expr => $event: ident) => {
                 text_input($tip, &$value.to_string())
                     $(.width(Length::Fixed($portion)))?
                     .size(SIZE_FONT_NORMAL)
                     .padding(5)
-                    .on_input(|str| {
-                        match str.parse() {
-                            Ok(int) if ($min..=$max).contains(&int) => Message::$event(int),
-                            _ => Message::None,
-                        }
+                    .on_input(|str| if str.trim().is_empty() {
+                        Message::$event(Default::default())
+                    } else {
+                        str.trim().parse()
+                            .map(Message::$event)
+                            .unwrap_or(Message::None)
                     })
             };
 
@@ -393,10 +479,6 @@ impl State {
             };
         }
 
-        let token_link =
-            icon!(SIZE_FONT_SMALL | Link -> Message::OpenLinkInBrowser(KURISU_TOKEN_LINK))
-                .padding(0);
-
         macro_rules! scale_factor {
             ($factor: literal, $($factors: literal),+) => {
                 row![scale_factor!($factor), $(scale_factor!($factors)),+]
@@ -416,18 +498,19 @@ impl State {
             };
         }
 
+        let token_link =
+            icon!(SIZE_FONT_SMALL | Link -> Message::OpenLinkInBrowser(KURISU_TOKEN_LINK))
+                .padding(0);
+
         let content = container([
             section![ "Misc" => [
                 self.loglevel.view(self.config.log).map(Message::LogLevelChanged),
-                vertical_space(5),
                 toggler(Some("MPRIS server".into()), self.config.mpris, Message::MprisFlagChanged)
-                    .spacing(15)
                     .text_size(SIZE_FONT_NORMAL)
                     .size(SIZE_FONT_NORMAL),
             ]],
             section![ "Amadeus" => [
                 self.theme.view(&self.config.amadeus.theme).map(Message::ThemeChanged),
-                vertical_space(5),
                 toggler(
                     Some("Open settings when lektord is offline on launch".into()),
                     self.config.amadeus.open_config_if_init_ping_failed,
@@ -435,21 +518,14 @@ impl State {
                 )
                 .text_size(SIZE_FONT_NORMAL)
                 .size(SIZE_FONT_NORMAL),
-                vertical_space(5),
-                row![
-                    text("Scale factor").size(SIZE_FONT_NORMAL),
-                    horizontal_space(Length::Fill),
-                    scale_factor! { 0.5, 1.0, 1.5, 2.0 }
-                ],
+                elem_row!["Scale factor", scale_factor! { 0.5, 0.75, 1.0, 1.25, 1.5 }],
+                input!(number! "Retry interval (sec)", "seconds", self.tmp_retry_time => RetryIntervalChanged),
             ]],
             section![ "Remote" => [
                 row![
-                    input!(text! (100.0) "Scheme", "http", &self.tmp_scheme => SchemeChanged),
-                    horizontal_space(Length::Fixed(1.0)),
-                    input!(text! (270.0) "Host",   "host", &self.tmp_host => HostChanged),
-                    horizontal_space(Length::Fixed(1.0)),
-                    input!(number! (100.0) "Port", "6600", self.tmp_port, 1024, u16::max_value() => PortChanged),
-                    horizontal_space(Length::Fill),
+                    input!(text!   (100.0) "Scheme", "http", &self.tmp_scheme => SchemeChanged),
+                    input!(text!   (270.0) "Host",   "host", &self.tmp_host   => HostChanged),
+                    input!(number! (100.0) "Port",   "6600", self.tmp_port    => PortChanged),
                     column![
                         tip!(button(text(iced_aw::graphics::icons::icon_to_char(iced_aw::graphics::icons::Icon::Check))
                             .horizontal_alignment(Horizontal::Center)
@@ -463,66 +539,34 @@ impl State {
                                 None => Box::<SquareButtonStyleSheet>::default(),
                             }
                         )).on_press(Message::TryConnect) => Right | " Try to connect"),
-                        vertical_space(10)
+                        vertical_space(5)
                     ]
                 ]
+                .spacing(1)
                 .align_items(Alignment::End)
                 .width(Length::Fixed(500.0)),
-                input!(text!     "User",             "user",            &self.config.connect.user.user  => UserChanged),
-                input!(password! "Token" token_link, KURISU_TOKEN_LINK, &self.config.connect.user.token => TokenChanged),
+                input!(text!     "User",        "user",  &self.config.connect.user.user  => UserChanged),
+                input!(password! "Token",       "token", &self.config.connect.user.token => TokenChanged),
+                input!(password! "Kurisu Token" token_link, KURISU_TOKEN_LINK,
+                   self.config.connect.kurisu_token.as_ref().map(|token| token.as_str()).unwrap_or_default()
+                   => KurisuTokenChanged
+                ),
             ]],
             match &self.remote_infos {
                 Some(Some(infos)) => section![ "Remote Infos" => [
-                    row![
-                        text("Server version").size(SIZE_FONT_NORMAL),
-                        horizontal_space(Length::Fill),
-                        text(&infos.version).size(SIZE_FONT_NORMAL),
-                    ],
-                    row![
-                        text("Database epoch").size(SIZE_FONT_NORMAL),
-                        horizontal_space(Length::Fill),
-                        text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None"))).size(SIZE_FONT_NORMAL),
-                    ],
+                    elem_row!["Server version", text(&infos.version)],
+                    elem_row!["Database epoch", text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None")))],
                 ]],
                 _ => None,
             },
             match &self.system_informations {
                 Some(sys) => section! [ "System Infos" => [
-                    row![
-                        text("System name"),
-                        horizontal_space(Length::Fill),
-                        text(sys.system_name.as_deref().unwrap_or("...")),
-                    ],
-                    vertical_space(5),
-                    row![
-                        text("Kernel name"),
-                        horizontal_space(Length::Fill),
-                        text(sys.system_kernel.as_deref().unwrap_or("..")),
-                    ],
-                    vertical_space(5),
-                    row![
-                        text("System version"),
-                        horizontal_space(Length::Fill),
-                        text(sys.system_version.as_deref().unwrap_or("..")),
-                    ],
-                    vertical_space(5),
-                    row![
-                        text("CPU"),
-                        horizontal_space(Length::Fill),
-                        text(format!("{}, {} cores", sys.cpu_brand.as_str(), sys.cpu_cores.unwrap_or(1))),
-                    ],
-                    vertical_space(5),
-                    row![
-                        text("Total memory"),
-                        horizontal_space(Length::Fill),
-                        text(format!("{}GiB", sys.memory_total / (1024 * 1024 * 1024))),
-                    ],
-                    vertical_space(5),
-                    row![
-                        text("Graphics backend and adapter"),
-                        horizontal_space(Length::Fill),
-                        text(format!("{}, {}", sys.graphics_backend, sys.graphics_adapter)),
-                    ],
+                    elem_row!["System name",    text(sys.system_name.as_deref().unwrap_or("..."))],
+                    elem_row!["Kernel name",    text(sys.system_kernel.as_deref().unwrap_or("..."))],
+                    elem_row!["System version", text(sys.system_version.as_deref().unwrap_or("..."))],
+                    elem_row!["CPU",            text(format!("{}, {} cores", sys.cpu_brand.as_str(), sys.cpu_cores.unwrap_or(1)))],
+                    elem_row!["Total memory",   text(format!("{}GiB", sys.memory_total / (1024 * 1024 * 1024)))],
+                    elem_row!["Graphics backend and adapter", text(format!("{}, {}", sys.graphics_backend, sys.graphics_adapter))],
                 ]],
                 _ => None,
             }