diff --git a/Core/Bridge/UpdateBridge.cs b/Core/Bridge/UpdateBridge.cs
new file mode 100644
index 00000000..f2b72680
--- /dev/null
+++ b/Core/Bridge/UpdateBridge.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Windows.Forms;
+using TweetDuck.Core.Controls;
+using TweetDuck.Updates;
+
+namespace TweetDuck.Core.Bridge{
+    class UpdateBridge{
+        private readonly UpdateHandler updates;
+        private readonly Control sync;
+
+        private UpdateInfo nextUpdate = null;
+
+        public event EventHandler<UpdateInfo> UpdateAccepted;
+        public event EventHandler<UpdateInfo> UpdateDelayed;
+        public event EventHandler<UpdateInfo> UpdateDismissed;
+
+        public UpdateBridge(UpdateHandler updates, Control sync){
+            this.sync = sync;
+
+            this.updates = updates;
+            this.updates.CheckFinished += updates_CheckFinished;
+        }
+
+        internal void Cleanup(){
+            updates.CheckFinished -= updates_CheckFinished;
+            nextUpdate?.DeleteInstaller();
+        }
+
+        private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
+            UpdateInfo foundUpdate = e.Result.HasValue ? e.Result.Value : null;
+
+            if (nextUpdate != null && !nextUpdate.Equals(foundUpdate)){
+                nextUpdate.DeleteInstaller();
+            }
+
+            nextUpdate = foundUpdate;
+        }
+
+        private void HandleInteractionEvent(EventHandler<UpdateInfo> eventHandler){
+            UpdateInfo tmpInfo = nextUpdate;
+
+            if (tmpInfo != null){
+                sync.InvokeAsyncSafe(() => eventHandler?.Invoke(this, tmpInfo));
+            }
+        }
+
+        // Bridge methods
+
+        public void TriggerUpdateCheck(){
+            updates.Check(false);
+        }
+
+        public void OnUpdateAccepted(){
+            HandleInteractionEvent(UpdateAccepted);
+        }
+
+        public void OnUpdateDelayed(){
+            HandleInteractionEvent(UpdateDelayed);
+        }
+
+        public void OnUpdateDismissed(){
+            HandleInteractionEvent(UpdateDismissed);
+
+            nextUpdate?.DeleteInstaller();
+            nextUpdate = null;
+        }
+    }
+}
diff --git a/Core/FormBrowser.cs b/Core/FormBrowser.cs
index 61a2c4a0..667d8ba2 100644
--- a/Core/FormBrowser.cs
+++ b/Core/FormBrowser.cs
@@ -17,7 +17,6 @@
 using TweetDuck.Plugins.Enums;
 using TweetDuck.Plugins.Events;
 using TweetDuck.Updates;
-using TweetDuck.Updates.Events;
 
 namespace TweetDuck.Core{
     sealed partial class FormBrowser : Form, AnalyticsFile.IProvider{
@@ -50,6 +49,7 @@ public bool IsWaiting{
         private readonly UpdateHandler updates;
         private readonly FormNotificationTweet notification;
         private readonly ContextMenu contextMenu;
+        private readonly UpdateBridge updateBridge;
 
         private bool isLoaded;
         private FormWindowState prevState;
@@ -62,7 +62,7 @@ public FormBrowser(){
             InitializeComponent();
 
             Text = Program.BrandName;
-
+            
             this.plugins = new PluginManager(Program.PluginPath, Program.PluginConfigFilePath);
             this.plugins.Reloaded += plugins_Reloaded;
             this.plugins.Executed += plugins_Executed;
@@ -71,7 +71,15 @@ public FormBrowser(){
             this.notification = new FormNotificationTweet(this, plugins);
             this.notification.Show();
             
-            this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
+            this.updates = new UpdateHandler(Program.InstallerPath);
+            this.updates.CheckFinished += updates_CheckFinished;
+
+            this.updateBridge = new UpdateBridge(updates, this);
+            this.updateBridge.UpdateAccepted += updateBridge_UpdateAccepted;
+            this.updateBridge.UpdateDelayed += updateBridge_UpdateDelayed;
+            this.updateBridge.UpdateDismissed += updateBridge_UpdateDismissed;
+
+            this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification), updateBridge);
             this.contextMenu = ContextMenuBrowser.CreateMenu(this);
 
             this.plugins.Register(browser, PluginEnvironment.Browser, this, true);
@@ -103,11 +111,6 @@ public FormBrowser(){
                 UpdateFormIcon();
             }
 
-            this.updates = new UpdateHandler(browser, Program.InstallerPath);
-            this.updates.CheckFinished += updates_CheckFinished;
-            this.updates.UpdateAccepted += updates_UpdateAccepted;
-            this.updates.UpdateDismissed += updates_UpdateDismissed;
-
             if (Config.AllowDataCollection){
                 analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
             }
@@ -207,7 +210,7 @@ private void FormBrowser_FormClosing(object sender, FormClosingEventArgs e){
 
         private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e){
             if (isLoaded && UpdateInstallerPath == null){
-                updates.CleanupDownload();
+                updateBridge.Cleanup();
             }
         }
 
@@ -252,7 +255,7 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
                 string tag = update.VersionTag;
 
                 if (tag != Program.VersionTag && tag != Config.DismissedUpdate){
-                    updates.PrepareUpdate(update);
+                    update.BeginSilentDownload();
                     browser.ShowUpdateNotification(tag, update.ReleaseNotes);
                 }
                 else{
@@ -268,38 +271,61 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
             ignoreUpdateCheckError = true;
         }
 
-        private void updates_UpdateAccepted(object sender, UpdateEventArgs e){
-            this.InvokeAsyncSafe(() => {
-                FormManager.CloseAllDialogs();
+        private void updateBridge_UpdateAccepted(object sender, UpdateInfo update){
+            FormManager.CloseAllDialogs();
 
-                if (!string.IsNullOrEmpty(Config.DismissedUpdate)){
-                    Config.DismissedUpdate = null;
-                    Config.Save();
+            if (!string.IsNullOrEmpty(Config.DismissedUpdate)){
+                Config.DismissedUpdate = null;
+                Config.Save();
+            }
+
+            void OnFinished(){
+                UpdateDownloadStatus status = update.DownloadStatus;
+
+                if (status == UpdateDownloadStatus.Done){
+                    UpdateInstallerPath = update.InstallerPath;
+                    ForceClose();
                 }
+                else if (status != UpdateDownloadStatus.Canceled && FormMessage.Error("Update Has Failed", "Could not automatically download the update: "+(update.DownloadError?.Message ?? "unknown error")+"\n\nWould you like to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
+                    BrowserUtils.OpenExternalBrowser(Program.Website);
+                    ForceClose();
+                }
+                else{
+                    Show();
+                }
+            }
+            
+            if (update.DownloadStatus.IsFinished(true)){
+                OnFinished();
+            }
+            else{
+                FormUpdateDownload downloadForm = new FormUpdateDownload(update);
 
-                updates.BeginUpdateDownload(this, e.UpdateInfo, update => {
-                    UpdateDownloadStatus status = update.DownloadStatus;
+                downloadForm.VisibleChanged += (sender2, args2) => {
+                    downloadForm.MoveToCenter(this);
+                    Hide();
+                };
 
-                    if (status == UpdateDownloadStatus.Done){
-                        UpdateInstallerPath = update.InstallerPath;
-                        ForceClose();
+                downloadForm.FormClosed += (sender2, args2) => {
+                    if (downloadForm.DialogResult != DialogResult.OK){
+                        update.CancelDownload();
                     }
-                    else if (status != UpdateDownloadStatus.Canceled && FormMessage.Error("Update Has Failed", "Could not automatically download the update: "+(update.DownloadError?.Message ?? "unknown error")+"\n\nWould you like to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
-                        BrowserUtils.OpenExternalBrowser(Program.Website);
-                        ForceClose();
-                    }
-                    else{
-                        Show();
-                    }
-                });
-            });
+
+                    downloadForm.Dispose();
+                    OnFinished();
+                };
+
+                downloadForm.Show();
+            }
         }
 
-        private void updates_UpdateDismissed(object sender, UpdateEventArgs e){
-            this.InvokeAsyncSafe(() => {
-                Config.DismissedUpdate = e.UpdateInfo.VersionTag;
-                Config.Save();
-            });
+        private void updateBridge_UpdateDelayed(object sender, UpdateInfo update){
+            // stops the timer
+        }
+
+        private void updateBridge_UpdateDismissed(object sender, UpdateInfo update){
+            Config.DismissedUpdate = update.VersionTag;
+            Config.Save();
         }
 
         protected override void WndProc(ref Message m){
diff --git a/Core/Other/Settings/TabSettingsGeneral.cs b/Core/Other/Settings/TabSettingsGeneral.cs
index 5bbb3ba4..66d3a121 100644
--- a/Core/Other/Settings/TabSettingsGeneral.cs
+++ b/Core/Other/Settings/TabSettingsGeneral.cs
@@ -7,7 +7,6 @@
 using TweetDuck.Core.Other.Settings.Dialogs;
 using TweetDuck.Core.Utils;
 using TweetDuck.Updates;
-using TweetDuck.Updates.Events;
 
 namespace TweetDuck.Core.Other.Settings{
     sealed partial class TabSettingsGeneral : BaseTabSettings{
@@ -210,11 +209,6 @@ private void btnCheckUpdates_Click(object sender, EventArgs e){
 
             btnCheckUpdates.Enabled = false;
             updateCheckEventId = updates.Check(true);
-
-            if (updateCheckEventId == UpdateHandler.CheckCodeNotOnTweetDeck){
-                FormMessage.Error("Update Check", "Updates can only be checked once TweetDeck is fully loaded.", FormMessage.OK);
-                btnCheckUpdates.Enabled = true;
-            }
         }
 
         private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
@@ -225,6 +219,8 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
                     if (update.VersionTag == Program.VersionTag){
                         FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
                     }
+
+                    // TODO allow outside TweetDeck
                 }, ex => {
                     Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
                 });
diff --git a/Core/TweetDeckBrowser.cs b/Core/TweetDeckBrowser.cs
index bb79dd74..d45e089c 100644
--- a/Core/TweetDeckBrowser.cs
+++ b/Core/TweetDeckBrowser.cs
@@ -9,7 +9,6 @@
 using TweetDuck.Core.Controls;
 using TweetDuck.Core.Handling;
 using TweetDuck.Core.Handling.General;
-using TweetDuck.Core.Management;
 using TweetDuck.Core.Notification;
 using TweetDuck.Core.Other.Interfaces;
 using TweetDuck.Core.Utils;
@@ -40,7 +39,7 @@ public bool IsTweetDeckWebsite{
 
         private string prevSoundNotificationPath = null;
 
-        public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
+        public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge tdBridge, UpdateBridge updateBridge){
             RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
             
             this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
@@ -58,7 +57,8 @@ public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
             this.browser.FrameLoadEnd += browser_FrameLoadEnd;
             this.browser.LoadError += browser_LoadError;
 
-            this.browser.RegisterAsyncJsObject("$TD", bridge);
+            this.browser.RegisterAsyncJsObject("$TD", tdBridge);
+            this.browser.RegisterAsyncJsObject("$TDU", updateBridge);
             
             this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
             this.browser.Dock = DockStyle.None;
diff --git a/TweetDuck.csproj b/TweetDuck.csproj
index 5ade89de..846eba1d 100644
--- a/TweetDuck.csproj
+++ b/TweetDuck.csproj
@@ -58,6 +58,7 @@
     <Compile Include="Configuration\SystemConfig.cs" />
     <Compile Include="Configuration\UserConfig.cs" />
     <Compile Include="Core\Bridge\PropertyBridge.cs" />
+    <Compile Include="Core\Bridge\UpdateBridge.cs" />
     <Compile Include="Core\Controls\ControlExtensions.cs" />
     <Compile Include="Core\Controls\FlatButton.cs">
       <SubType>Component</SubType>
@@ -283,7 +284,7 @@
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
     <Compile Include="Reporter.cs" />
-    <Compile Include="Updates\Events\UpdateCheckEventArgs.cs" />
+    <Compile Include="Updates\UpdateCheckEventArgs.cs" />
     <Compile Include="Updates\FormUpdateDownload.cs">
       <SubType>Form</SubType>
     </Compile>
@@ -306,7 +307,6 @@
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Resources\ScriptLoader.cs" />
-    <Compile Include="Updates\Events\UpdateEventArgs.cs" />
   </ItemGroup>
   <ItemGroup>
     <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
diff --git a/Updates/Events/UpdateEventArgs.cs b/Updates/Events/UpdateEventArgs.cs
deleted file mode 100644
index b3421a38..00000000
--- a/Updates/Events/UpdateEventArgs.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace TweetDuck.Updates.Events{
-    sealed class UpdateEventArgs : EventArgs{
-        public UpdateInfo UpdateInfo { get; }
-        
-        public UpdateEventArgs(UpdateInfo updateInfo){
-            this.UpdateInfo = updateInfo;
-        }
-    }
-}
diff --git a/Updates/FormUpdateDownload.cs b/Updates/FormUpdateDownload.cs
index d90c3979..6d00ca4a 100644
--- a/Updates/FormUpdateDownload.cs
+++ b/Updates/FormUpdateDownload.cs
@@ -20,7 +20,7 @@ private void btnCancel_Click(object sender, EventArgs e){
         }
 
         private void timerDownloadCheck_Tick(object sender, EventArgs e){
-            if (updateInfo.DownloadStatus.IsFinished()){
+            if (updateInfo.DownloadStatus.IsFinished(false)){
                 timerDownloadCheck.Stop();
                 DialogResult = DialogResult.OK;
                 Close();
diff --git a/Updates/Events/UpdateCheckEventArgs.cs b/Updates/UpdateCheckEventArgs.cs
similarity index 90%
rename from Updates/Events/UpdateCheckEventArgs.cs
rename to Updates/UpdateCheckEventArgs.cs
index a5a49485..7938290e 100644
--- a/Updates/Events/UpdateCheckEventArgs.cs
+++ b/Updates/UpdateCheckEventArgs.cs
@@ -1,7 +1,7 @@
 using System;
 using TweetDuck.Data;
 
-namespace TweetDuck.Updates.Events{
+namespace TweetDuck.Updates{
     sealed class UpdateCheckEventArgs : EventArgs{
         public int EventId { get; }
         public Result<UpdateInfo> Result { get; }
diff --git a/Updates/UpdateDownloadStatus.cs b/Updates/UpdateDownloadStatus.cs
index 85de1b66..3b4d7c17 100644
--- a/Updates/UpdateDownloadStatus.cs
+++ b/Updates/UpdateDownloadStatus.cs
@@ -9,8 +9,8 @@ public enum UpdateDownloadStatus{
     }
 
     public static class UpdateDownloadStatusExtensions{
-        public static bool IsFinished(this UpdateDownloadStatus status){
-            return status == UpdateDownloadStatus.AssetMissing || status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.Failed;
+        public static bool IsFinished(this UpdateDownloadStatus status, bool canRetry){
+            return status == UpdateDownloadStatus.AssetMissing || status == UpdateDownloadStatus.Done || (status == UpdateDownloadStatus.Failed && !canRetry);
         }
     }
 }
diff --git a/Updates/UpdateHandler.cs b/Updates/UpdateHandler.cs
index d9463d0a..c88c22fc 100644
--- a/Updates/UpdateHandler.cs
+++ b/Updates/UpdateHandler.cs
@@ -1,38 +1,24 @@
 using System;
 using System.Threading;
 using System.Threading.Tasks;
-using System.Windows.Forms;
-using TweetDuck.Core.Controls;
-using TweetDuck.Core.Other.Interfaces;
 using TweetDuck.Data;
-using TweetDuck.Updates.Events;
 using Timer = System.Windows.Forms.Timer;
 
 namespace TweetDuck.Updates{
     sealed class UpdateHandler : IDisposable{
         public const int CheckCodeUpdatesDisabled = -1;
-        public const int CheckCodeNotOnTweetDeck = -2;
         
         private readonly UpdateCheckClient client;
         private readonly TaskScheduler scheduler;
-        private readonly ITweetDeckBrowser browser;
         private readonly Timer timer;
-
-        public event EventHandler<UpdateEventArgs> UpdateAccepted;
-        public event EventHandler<UpdateEventArgs> UpdateDelayed;
-        public event EventHandler<UpdateEventArgs> UpdateDismissed;
+        
         public event EventHandler<UpdateCheckEventArgs> CheckFinished;
-
         private ushort lastEventId;
-        private UpdateInfo lastUpdateInfo;
 
-        public UpdateHandler(ITweetDeckBrowser browser, string installerFolder){
+        public UpdateHandler(string installerFolder){
             this.client = new UpdateCheckClient(installerFolder);
             this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
             
-            this.browser = browser;
-            this.browser.RegisterBridge("$TDU", new Bridge(this));
-
             this.timer = new Timer();
             this.timer.Tick += timer_Tick;
         }
@@ -68,10 +54,6 @@ public void StartTimer(){
 
         public int Check(bool force){
             if (Program.UserConfig.EnableUpdateCheck || force){
-                if (!browser.IsTweetDeckWebsite){
-                    return CheckCodeNotOnTweetDeck;
-                }
-                
                 int nextEventId = unchecked(++lastEventId);
                 Task<UpdateInfo> checkTask = client.Check();
 
@@ -84,46 +66,6 @@ public int Check(bool force){
             return CheckCodeUpdatesDisabled;
         }
 
-        public void PrepareUpdate(UpdateInfo info){
-            CleanupDownload();
-            lastUpdateInfo = info;
-            lastUpdateInfo.BeginSilentDownload();
-        }
-
-        public void BeginUpdateDownload(Form ownerForm, UpdateInfo updateInfo, Action<UpdateInfo> onFinished){
-            UpdateDownloadStatus status = updateInfo.DownloadStatus;
-
-            if (status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.AssetMissing){
-                onFinished(updateInfo);
-            }
-            else{
-                FormUpdateDownload downloadForm = new FormUpdateDownload(updateInfo);
-
-                downloadForm.VisibleChanged += (sender, args) => {
-                    downloadForm.MoveToCenter(ownerForm);
-                    ownerForm.Hide();
-                };
-
-                downloadForm.FormClosed += (sender, args) => {
-                    if (downloadForm.DialogResult != DialogResult.OK){
-                        updateInfo.CancelDownload();
-                    }
-
-                    downloadForm.Dispose();
-                    onFinished(updateInfo);
-                };
-
-                downloadForm.Show();
-            }
-        }
-
-        public void CleanupDownload(){
-            if (lastUpdateInfo != null){
-                lastUpdateInfo.DeleteInstaller();
-                lastUpdateInfo = null;
-            }
-        }
-
         private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
             CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(info)));
         }
@@ -131,48 +73,5 @@ private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
         private void HandleUpdateCheckFailed(int eventId, Exception exception){
             CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(exception)));
         }
-
-        private void TriggerUpdateAcceptedEvent(){
-            if (lastUpdateInfo != null){
-                UpdateAccepted?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
-            }
-        }
-
-        private void TriggerUpdateDelayedEvent(){
-            if (lastUpdateInfo != null){
-                UpdateDelayed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
-            }
-        }
-
-        private void TriggerUpdateDismissedEvent(){
-            if (lastUpdateInfo != null){
-                UpdateDismissed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
-                CleanupDownload();
-            }
-        }
-
-        public sealed class Bridge{
-            private readonly UpdateHandler owner;
-
-            public Bridge(UpdateHandler owner){
-                this.owner = owner;
-            }
-
-            public void TriggerUpdateCheck(){
-                owner.Check(false);
-            }
-
-            public void OnUpdateAccepted(){
-                owner.TriggerUpdateAcceptedEvent();
-            }
-
-            public void OnUpdateDelayed(){
-                owner.TriggerUpdateDelayedEvent();
-            }
-
-            public void OnUpdateDismissed(){
-                owner.TriggerUpdateDismissedEvent();
-            }
-        }
     }
 }
diff --git a/Updates/UpdateInfo.cs b/Updates/UpdateInfo.cs
index f92aafd2..380755bb 100644
--- a/Updates/UpdateInfo.cs
+++ b/Updates/UpdateInfo.cs
@@ -26,6 +26,11 @@ public UpdateInfo(string versionTag, string releaseNotes, string downloadUrl, st
         }
 
         public void BeginSilentDownload(){
+            if (File.Exists(InstallerPath)){
+                DownloadStatus = UpdateDownloadStatus.Done;
+                return;
+            }
+
             if (DownloadStatus == UpdateDownloadStatus.None || DownloadStatus == UpdateDownloadStatus.Failed){
                 DownloadStatus = UpdateDownloadStatus.InProgress;