diff --git a/briar-desktop/build.gradle.kts b/briar-desktop/build.gradle.kts
index 7dd010d2197471a3cfe48fdb7d16889207d3f16f..895a312416a298dd16db6c885820bbd4eb079f8b 100644
--- a/briar-desktop/build.gradle.kts
+++ b/briar-desktop/build.gradle.kts
@@ -35,9 +35,11 @@ val versionCode = "0.3.1"
 val buildType = if (project.hasProperty("buildType")) project.properties["buildType"] else "snapshot"
 group = "app.briar.desktop"
 version = "$versionCode-$buildType"
+val windowsAumiName = "Briar"
 
 buildData {
     packageName = "org.briarproject.briar.desktop"
+    windowsAumi = windowsAumiName
 }
 
 dependencies {
@@ -53,9 +55,10 @@ dependencies {
     implementation(project(path = ":briar-core", configuration = "default"))
     implementation(project(path = ":bramble-java", configuration = "default"))
 
-    implementation("io.github.microutils:kotlin-logging-jvm:2.1.21")
-    implementation("org.slf4j:jul-to-slf4j:1.7.36")
-    implementation("ch.qos.logback:logback-classic:1.2.11")
+    implementation("io.github.microutils:kotlin-logging-jvm:3.0.4")
+    implementation("org.slf4j:jul-to-slf4j:2.0.5")
+    implementation("ch.qos.logback:logback-classic:1.4.5")
+    implementation("de.mobanisto:toast4j:0.2.0")
 
     val daggerVersion = "2.24"
     kapt("com.google.dagger:dagger-compiler:$daggerVersion")
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt
index c9a278ad372bfd8b01ee008cb6a9aded7e358e71..c69e24bafeb28fb44490cc0e9129a00009bd2fe4 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt
@@ -49,6 +49,7 @@ import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
 import org.briarproject.bramble.system.DesktopSecureRandomModule
 import org.briarproject.bramble.system.JavaSystemModule
 import org.briarproject.bramble.util.OsUtils.isLinux
+import org.briarproject.bramble.util.OsUtils.isWindows
 import org.briarproject.briar.attachment.AttachmentModule
 import org.briarproject.briar.desktop.attachment.media.ImageCompressor
 import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl
@@ -56,6 +57,7 @@ import org.briarproject.briar.desktop.notification.SoundNotificationProvider
 import org.briarproject.briar.desktop.notification.StubNotificationProvider
 import org.briarproject.briar.desktop.notification.VisualNotificationProvider
 import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider
+import org.briarproject.briar.desktop.notification.windows.Toast4jNotificationProvider
 import org.briarproject.briar.desktop.settings.Configuration
 import org.briarproject.briar.desktop.settings.ConfigurationImpl
 import org.briarproject.briar.desktop.settings.EncryptedSettings
@@ -191,7 +193,11 @@ internal class DesktopCoreModule(
     @Provides
     @Singleton
     internal fun provideVisualNotificationProvider(): VisualNotificationProvider =
-        if (isLinux()) LibnotifyNotificationProvider else StubNotificationProvider
+        when {
+            isLinux() -> LibnotifyNotificationProvider
+            isWindows() -> Toast4jNotificationProvider
+            else -> StubNotificationProvider
+        }
 
     @Provides
     @Singleton
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/notification/windows/Toast4jNotificationProvider.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/notification/windows/Toast4jNotificationProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0690e220208a4d3581ade2bda8a146ad71d14540
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/notification/windows/Toast4jNotificationProvider.kt
@@ -0,0 +1,88 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.briarproject.briar.desktop.notification.windows
+
+import de.mobanisto.toast4j.ToastBuilder
+import de.mobanisto.toast4j.ToastHandle
+import de.mobanisto.toast4j.Toaster
+import de.mobanisto.wintoast.WinToastTemplate.WinToastTemplateType
+import mu.KotlinLogging
+import org.briarproject.briar.desktop.BuildData
+import org.briarproject.briar.desktop.notification.VisualNotificationProvider
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nF
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP
+import org.briarproject.briar.desktop.utils.KLoggerUtils.e
+
+object Toast4jNotificationProvider : VisualNotificationProvider {
+
+    private val LOG = KotlinLogging.logger {}
+
+    private lateinit var toaster: Toaster
+
+    override var available: Boolean = false
+        private set
+
+    private enum class Error { NONE, INIT }
+
+    private var error = Error.NONE
+
+    override val errorMessage: String
+        get() = when (error) {
+            Error.INIT -> i18n("settings.notifications.visual.error.toast4j.init")
+            else -> ""
+        }
+
+    override fun init() {
+        toaster = Toaster.forAumi(BuildData.WINDOWS_AUMI)
+        available = toaster.initialize()
+        if (!available) {
+            error = Error.INIT
+            LOG.e { "unable to initialize toast4j" }
+            return
+        }
+    }
+
+    override fun uninit() {
+        currentToast?.hide()
+    }
+
+    var currentToast: ToastHandle? = null
+
+    private fun sendNotification(text: String) {
+        currentToast?.hide()
+        currentToast = toaster.showToast(
+            ToastBuilder(WinToastTemplateType.ToastText01).setSilent()
+                .setLine1(text).build()
+        )
+    }
+
+    override fun notifyPrivateMessages(num: Int, contacts: Int) = sendNotification(
+        if (contacts == 1)
+            i18nP("notifications.message.private.one_chat", num)
+        else
+            i18nF("notifications.message.private.several_chats", num, contacts)
+    )
+
+    override fun notifyForumPosts(num: Int, forums: Int) = sendNotification(
+        if (forums == 1)
+            i18nP("notifications.message.forum.one_forum", num)
+        else
+            i18nF("notifications.message.forum.several_forums", num, forums)
+    )
+}
diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
index 3b77ccf202c81b684f1f333309ae938a5299c3e0..0ce9d2ea98168a3a8ee7cb7198ccab277599d181 100644
--- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties
+++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
@@ -331,6 +331,7 @@ settings.notifications.visual.title=Visual notifications
 settings.notifications.visual.error.unsupported=Visual notifications are currently not supported on your system. You can still enable sound notifications.
 settings.notifications.visual.error.libnotify.load=Notifications can only be shown visually if libnotify is available. Please consider installing it following the usual installation procedure for your system.
 settings.notifications.visual.error.libnotify.init=Briar Desktop could not connect to any notification server. Please make sure to have a freedesktop.org-compliant notification server installed and configured properly.
+settings.notifications.visual.error.toast4j.init=Briar Desktop could not initialize the notification system.
 settings.notifications.sound.title=Sound notifications
 
 # Settings Actions
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/notification/windows/TestNativeNotifications.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/notification/windows/TestNativeNotifications.kt
new file mode 100644
index 0000000000000000000000000000000000000000..993f8d3df67499eaa9fc2347f34a1208404922ea
--- /dev/null
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/notification/windows/TestNativeNotifications.kt
@@ -0,0 +1,35 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.briarproject.briar.desktop.notification.windows
+
+/**
+ * Small program to test notification support for Windows.
+ */
+fun main() {
+    Toast4jNotificationProvider.apply {
+        init()
+
+        notifyPrivateMessages(5, 2)
+        Thread.sleep(3000)
+
+        notifyPrivateMessages(6, 3)
+        Thread.sleep(3000)
+
+        uninit()
+    }
+}
diff --git a/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.kt b/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.kt
index 81407a40ce1d5227e79dbed4959021a1dfcc8ed2..3fa28ed2a09343b8e8391276a69a22a497680b13 100644
--- a/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.kt
+++ b/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.kt
@@ -28,4 +28,7 @@ open class BuildDataPluginExtension {
     @Input
     @Optional
     var className: String? = null
+
+    @Input
+    var windowsAumi: String? = null
 }
diff --git a/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.kt b/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.kt
index 725bed04d51b9b1d103c57111416e7ecc419c6ae..66fe1d44ea5ce20729dd9682fc2f437c5d590cac 100644
--- a/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.kt
+++ b/buildSrc/src/main/kotlin/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.kt
@@ -112,6 +112,10 @@ open class GenerateBuildDataSourceTask : AbstractBuildDataTask() {
         if (className == null) {
             className = "BuildData"
         }
+        val windowsAumi = configuration?.windowsAumi
+
+        checkNotNull(packageName) { "Please specify 'packageName'." }
+        checkNotNull(windowsAumi) { "Please specify 'windowsAumi'." }
 
         // Get version from Gradle project information
         val version = project.version.toString()
@@ -187,7 +191,6 @@ open class GenerateBuildDataSourceTask : AbstractBuildDataTask() {
         artifacts.sortWith(compareBy<VersionedArtifact> { it.group }.thenBy { it.artifact })
 
         // Generate output file
-        checkNotNull(packageName) { "Please specify 'packageName'." }
         val parts = packageName.split("\\.".toRegex()).toTypedArray()
         val pathBuildDir = project.buildDir.toPath()
         val source = Util.getSourceDir(pathBuildDir)
@@ -200,7 +203,8 @@ open class GenerateBuildDataSourceTask : AbstractBuildDataTask() {
         val content = createSource(
             packageName, className, version,
             commitTime, gitHash, gitBranch, gitTag,
-            coreGitHash, coreVersion, artifacts
+            coreGitHash, coreVersion, artifacts,
+            windowsAumi
         )
         val input: InputStream = ByteArrayInputStream(
             content.toByteArray(StandardCharsets.UTF_8)
@@ -268,6 +272,7 @@ open class GenerateBuildDataSourceTask : AbstractBuildDataTask() {
         coreGitHash: String,
         coreVersion: String,
         artifacts: List<VersionedArtifact>,
+        windowsAumi: String,
     ) = FileBuilder().apply {
         val branch = if (gitBranch == null) "null" else "\"$gitBranch\""
         val tag = if (gitTag == null) "null" else "\"$gitTag\""
@@ -284,6 +289,7 @@ open class GenerateBuildDataSourceTask : AbstractBuildDataTask() {
         line("    val GIT_TAG: String? = $tag")
         line("    val CORE_HASH = \"$coreGitHash\"")
         line("    val CORE_VERSION = \"$coreVersion\"")
+        line("    val WINDOWS_AUMI = \"$windowsAumi\"")
         line()
         line("    val ARTIFACTS: List<Artifact> = buildList {")
         for (artifact in artifacts) {