diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index d2fd9a8..22e8d94 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -1240,6 +1240,30 @@ version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
+[[package]]
+name = "libappindicator"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
+dependencies = [
+ "glib",
+ "gtk",
+ "gtk-sys",
+ "libappindicator-sys",
+ "log",
+]
+
+[[package]]
+name = "libappindicator-sys"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
+dependencies = [
+ "gtk-sys",
+ "libloading",
+ "once_cell",
+]
+
 [[package]]
 name = "libc"
 version = "0.2.138"
@@ -1255,6 +1279,16 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
 [[package]]
 name = "line-wrap"
 version = "0.1.1"
@@ -2561,6 +2595,7 @@ dependencies = [
  "core-foundation",
  "core-graphics",
  "crossbeam-channel",
+ "dirs-next",
  "dispatch",
  "gdk",
  "gdk-pixbuf",
@@ -2574,6 +2609,7 @@ dependencies = [
  "instant",
  "jni",
  "lazy_static",
+ "libappindicator",
  "libc",
  "log",
  "ndk",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index a7f089b..fa3f53b 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -16,8 +16,8 @@ tauri-build = { version = "1.2.1", features = [] }
 
 [dependencies]
 serde_json = "1.0.91"
-serde = { version = "1.0.152", features = ["derive"] }
-tauri = { version = "1.2.3", features = ["api-all", "devtools", "updater"] }
+serde = { version = "1.0.147", features = ["derive"] }
+tauri = { version = "1.2.3", features = ["api-all", "devtools", "system-tray", "updater"] }
 
 [features]
 # by default Tauri runs in production mode
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index eee64e1..4a2f602 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,18 +1,32 @@
 #![cfg_attr(
-  all(not(debug_assertions), target_os = "windows"),
-  windows_subsystem = "windows"
+    all(not(debug_assertions), target_os = "windows"),
+    windows_subsystem = "windows"
 )]
-
 #[cfg(target_os = "macos")]
 mod menu;
+mod tray;
 
 fn main() {
-  let builder = tauri::Builder::default();
+    let builder = tauri::Builder::default();
 
-  #[cfg(target_os = "macos")]
-  let builder = builder.menu(menu::menu());
+    #[cfg(target_os = "macos")]
+    let builder = builder.menu(menu::menu());
 
-  builder
-    .run(tauri::generate_context!())
-    .expect("error while running tauri application");
-}
\ No newline at end of file
+    let builder = builder
+        .system_tray(tray::system_tray())
+        .on_system_tray_event(tray::system_tray_handler);
+
+    builder
+        .build(tauri::generate_context!())
+        .expect("error while building tauri application")
+        .run(run_event_handler)
+}
+
+fn run_event_handler<R: tauri::Runtime>(app: &tauri::AppHandle<R>, event: tauri::RunEvent) {
+    match event {
+        tauri::RunEvent::WindowEvent { label, event, .. } => {
+            tray::window_event_handler(app, &label, &event);
+        }
+        _ => {}
+    }
+}
diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs
new file mode 100644
index 0000000..2d43c8c
--- /dev/null
+++ b/src-tauri/src/tray.rs
@@ -0,0 +1,87 @@
+use tauri::{
+    CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu,
+    SystemTrayMenuItem, WindowEvent, SystemTrayHandle, Window,
+};
+
+const TRAY_LABEL: &'static str = "main-tray";
+
+pub fn window_event_handler<R: tauri::Runtime>(
+    app: &tauri::AppHandle<R>,
+    label: &str,
+    event: &WindowEvent,
+) {
+    match event {
+        // Prevent Cinny from closing, instead hide it and let it be
+        // reopened through the tray.
+        WindowEvent::CloseRequested { api, .. } => {
+            api.prevent_close();
+            app.get_window(&label).unwrap().hide().unwrap();
+            app.tray_handle_by_id(TRAY_LABEL)
+                .unwrap()
+                .get_item("toggle")
+                .set_title("Show Cinny")
+                .unwrap();
+        }
+        _ => {}
+    }
+}
+
+/// Build the system tray object
+pub fn system_tray() -> SystemTray {
+    let toggle = CustomMenuItem::new("toggle".to_owned(), "Hide Cinny");
+    let quit = CustomMenuItem::new("quit".to_owned(), "Quit");
+    let menu = SystemTrayMenu::new()
+        .add_item(toggle)
+        .add_native_item(SystemTrayMenuItem::Separator)
+        .add_item(quit);
+
+    tauri::SystemTray::new()
+        .with_menu(menu)
+        .with_id(TRAY_LABEL.to_owned())
+}
+
+pub fn toggle_window_state<R: tauri::Runtime>(window: Window<R>, tray_handle: SystemTrayHandle<R>) {
+    // Hide the window if it's visible, show it if not
+    // `is_visible` returns true for minimized state for whatever reason
+    if window.is_visible().unwrap() {
+        window.hide().unwrap();
+        tray_handle
+            .get_item("toggle")
+            .set_title("Show Cinny")
+            .unwrap();
+    } else {
+        window.unminimize().unwrap();
+        window.show().unwrap();
+        window.set_focus().unwrap();
+        tray_handle
+            .get_item("toggle")
+            .set_title("Hide Cinny")
+            .unwrap();
+    };
+}
+
+pub fn system_tray_handler<R: tauri::Runtime>(app: &tauri::AppHandle<R>, event: SystemTrayEvent) {
+    let tray_handle = match app.tray_handle_by_id(TRAY_LABEL) {
+        Some(h) => h,
+        None => return,
+    };
+    let window = app.get_window("main").unwrap();
+
+    match event {
+        SystemTrayEvent::LeftClick { .. } => {
+            toggle_window_state(window, tray_handle);
+        }
+        SystemTrayEvent::MenuItemClick { id, .. } => {
+            match id.as_str() {
+                "quit" => {
+                    app.exit(0);
+                }
+                "toggle" => {
+                    toggle_window_state(window, tray_handle)
+                }
+                _ => {}
+            }
+        }
+        _ => {}
+    }
+}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 4af35c5..dc4ce1e 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -72,6 +72,11 @@
     ],
     "security": {
       "csp": "script-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
+    },
+    "systemTray": {
+      "iconPath": "icons/32x32.png",
+      "iconAsTemplate": true,
+      "menuOnLeftClick": false
     }
   }
 }