diff --git a/app/fileManager.js b/app/fileManager.js
index 3ab7033e..9e77aae0 100644
--- a/app/fileManager.js
+++ b/app/fileManager.js
@@ -5,6 +5,7 @@ import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
 import * as metrics from './metrics';
 import Archive from './archive';
 import { bytes } from './utils';
+import okDialog from './templates/okDialog';
 
 export default function(state, emitter) {
   let lastRender = 0;
@@ -95,7 +96,7 @@ export default function(state, emitter) {
     try {
       state.archive.addFiles(files, maxSize);
     } catch (e) {
-      alert(
+      state.modal = okDialog(
         state.translate(e.message, {
           size: bytes(maxSize),
           count: LIMITS.MAX_FILES_PER_ARCHIVE
@@ -108,11 +109,12 @@ export default function(state, emitter) {
   emitter.on('upload', async ({ type, dlimit, password }) => {
     if (!state.archive) return;
     if (state.storage.files.length >= LIMITS.MAX_ARCHIVES_PER_USER) {
-      return alert(
+      state.modal = okDialog(
         state.translate('tooManyArchives', {
           count: LIMITS.MAX_ARCHIVES_PER_USER
         })
       );
+      return render();
     }
     const size = state.archive.size;
     if (!state.timeLimit) state.timeLimit = DEFAULTS.EXPIRE_SECONDS;
diff --git a/app/main.css b/app/main.css
index afc2040b..71d87247 100644
--- a/app/main.css
+++ b/app/main.css
@@ -1,23 +1,25 @@
 @import './base.css';
-@import './templates/activeBackground/activeBackground.css';
-@import './templates/header/header.css';
-@import './templates/downloadButton/downloadButton.css';
-@import './templates/passwordInput/passwordInput.css';
-@import './templates/downloadPassword/downloadPassword.css';
-@import './templates/setPasswordSection/setPasswordSection.css';
-@import './templates/footer/footer.css';
-@import './templates/fxPromo/fxPromo.css';
-@import './templates/selectbox/selectbox.css';
-@import './templates/fileList/fileList.css';
-@import './templates/file/file.css';
-@import './templates/uploadedFile/uploadedFile.css';
-@import './templates/uploadedFileList/uploadedFileList.css';
-@import './templates/popup/popup.css';
-@import './templates/title/title.css';
-@import './templates/fileIcon/fileIcon.css';
-@import './templates/signupPromo/signupPromo.css';
-@import './templates/userAccount/userAccount.css';
-@import './pages/welcome/welcome.css';
 @import './pages/share/share.css';
 @import './pages/signin/signin.css';
 @import './pages/unsupported/unsupported.css';
+@import './pages/welcome/welcome.css';
+@import './templates/activeBackground/activeBackground.css';
+@import './templates/downloadButton/downloadButton.css';
+@import './templates/downloadPassword/downloadPassword.css';
+@import './templates/file/file.css';
+@import './templates/fileIcon/fileIcon.css';
+@import './templates/fileList/fileList.css';
+@import './templates/footer/footer.css';
+@import './templates/fxPromo/fxPromo.css';
+@import './templates/header/header.css';
+@import './templates/modal/modal.css';
+@import './templates/okDialog/okDialog.css';
+@import './templates/passwordInput/passwordInput.css';
+@import './templates/popup/popup.css';
+@import './templates/selectbox/selectbox.css';
+@import './templates/setPasswordSection/setPasswordSection.css';
+@import './templates/signupPromo/signupPromo.css';
+@import './templates/title/title.css';
+@import './templates/uploadedFile/uploadedFile.css';
+@import './templates/uploadedFileList/uploadedFileList.css';
+@import './templates/userAccount/userAccount.css';
diff --git a/app/main.js b/app/main.js
index e13c12d8..3efb1102 100644
--- a/app/main.js
+++ b/app/main.js
@@ -31,6 +31,7 @@ import User from './user';
     state.raven = Raven;
     state.user = new User(storage);
     window.appState = state;
+    window.appEmit = emitter.emit.bind(emitter);
     let unsupportedReason = null;
     if (
       // Firefox < 50
diff --git a/app/routes/index.js b/app/routes/index.js
index 09551cdf..d7db4a36 100644
--- a/app/routes/index.js
+++ b/app/routes/index.js
@@ -8,6 +8,7 @@ const signupPromo = require('../templates/signupPromo');
 const activeBackground = require('../templates/activeBackground');
 const fileList = require('../templates/fileList');
 const profile = require('../templates/userAccount');
+const modal = require('../templates/modal');
 
 nanotiming.disabled = true;
 const app = choo();
@@ -18,9 +19,16 @@ function banner(state, emit) {
   }
 }
 
+function modalDialog(state, emit) {
+  if (state.modal) {
+    return modal(state, emit);
+  }
+}
+
 function body(template) {
   return function(state, emit) {
     const b = html`<body class="background ${activeBackground(state)}">
+      ${modalDialog(state, emit)}
       ${banner(state, emit)}
       <main class="main">
         <noscript>
diff --git a/app/serviceWorker.js b/app/serviceWorker.js
index a90785bc..e110487d 100644
--- a/app/serviceWorker.js
+++ b/app/serviceWorker.js
@@ -71,7 +71,7 @@ async function decryptStream(id) {
     return new Response(null, {
       status: 302,
       headers: {
-        Location: `/download/${id}`
+        Location: `/download/${id}/#${file.key}`
       }
     });
   }
diff --git a/app/templates/expireInfo/index.js b/app/templates/expireInfo/index.js
index fa7a91b8..c9df258d 100644
--- a/app/templates/expireInfo/index.js
+++ b/app/templates/expireInfo/index.js
@@ -2,6 +2,7 @@ const html = require('choo/html');
 const raw = require('choo/html/raw');
 const selectbox = require('../selectbox');
 const timeLimitText = require('../timeLimitText');
+const okDialog = require('../okDialog');
 
 module.exports = function(state, emit) {
   const el = html`<div> ${raw(
@@ -25,7 +26,7 @@ module.exports = function(state, emit) {
       value => {
         const max = state.user.maxDownloads;
         if (value > max) {
-          alert('todo: this setting requires an account');
+          state.modal = okDialog('todo: this setting requires an account');
           value = max;
         }
         state.downloadCount = value;
@@ -44,7 +45,7 @@ module.exports = function(state, emit) {
       value => {
         const max = state.user.maxExpireSeconds;
         if (value > max) {
-          alert('todo: this setting requires an account');
+          state.modal = okDialog('todo: this setting requires an account');
           value = max;
         }
         state.timeLimit = value;
diff --git a/app/templates/modal/index.js b/app/templates/modal/index.js
new file mode 100644
index 00000000..94f184c3
--- /dev/null
+++ b/app/templates/modal/index.js
@@ -0,0 +1,15 @@
+const html = require('choo/html');
+
+module.exports = function(state, emit) {
+  return html`
+  <div class="modal" onclick=${close}>
+    <div class="modal__box" onclick=${e => e.stopPropagation()}>
+      ${state.modal(state, close)}
+    </div>
+  </div>`;
+
+  function close(event) {
+    state.modal = null;
+    emit('render');
+  }
+};
diff --git a/app/templates/modal/modal.css b/app/templates/modal/modal.css
new file mode 100644
index 00000000..947ea39a
--- /dev/null
+++ b/app/templates/modal/modal.css
@@ -0,0 +1,22 @@
+.modal {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  z-index: 100;
+  background: rgba(0, 0, 0, 0.7);
+  animation: fade-in 0.5s forwards;
+}
+
+.modal__box {
+  max-width: 480px;
+  max-height: 300px;
+  background: var(--pageBGColor);
+  border-radius: 4px;
+  color: var(--textColor);
+}
diff --git a/app/templates/okDialog/index.js b/app/templates/okDialog/index.js
new file mode 100644
index 00000000..93015ac7
--- /dev/null
+++ b/app/templates/okDialog/index.js
@@ -0,0 +1,13 @@
+const html = require('choo/html');
+
+module.exports = function(message) {
+  return function(state, close) {
+    return html`
+    <div class="okDialog">
+      <div class="okDialog__message">${message}</div>
+      <button class="btn" onclick=${close}>${state.translate(
+      'okButton'
+    )}</button>
+    </div>`;
+  };
+};
diff --git a/app/templates/okDialog/okDialog.css b/app/templates/okDialog/okDialog.css
new file mode 100644
index 00000000..b03fdfa5
--- /dev/null
+++ b/app/templates/okDialog/okDialog.css
@@ -0,0 +1,11 @@
+.okDialog {
+  display: flex;
+  flex-direction: column;
+  height: 100px;
+  font-weight: 400;
+  padding: 10px;
+}
+
+.okDialog__message {
+  margin-bottom: 10px;
+}
diff --git a/public/locales/en-US/send.ftl b/public/locales/en-US/send.ftl
index fc462745..26d94646 100644
--- a/public/locales/en-US/send.ftl
+++ b/public/locales/en-US/send.ftl
@@ -172,3 +172,4 @@ accountBenefitNotify = Be notified when your files are downloaded
 accountBenefitMore = Do a lot more!
 manageAccount = Manage Account
 logOut = Sign Out
+okButton = Ok