diff --git a/frontend/src/metabase/dashboard/containers/DashboardApp.jsx b/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
index 188e6cd26572674b8ed0e5f8117b495fb1471b48..6595edce5b37bf2531254a73069bf531e2cf34df 100644
--- a/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
+++ b/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
@@ -106,7 +106,7 @@ const DashboardApp = props => {
   const [isShowingToaster, setIsShowingToaster] = useState(false);
 
   const onTimeout = useCallback(() => {
-    if (Notification.permission === "default") {
+    if ("Notification" in window && Notification.permission === "default") {
       setIsShowingToaster(true);
     }
   }, []);
@@ -123,7 +123,11 @@ const DashboardApp = props => {
   useEffect(() => {
     if (isLoadingComplete) {
       setIsShowingToaster(false);
-      if (Notification.permission === "granted" && document.hidden) {
+      if (
+        "Notification" in window &&
+        Notification.permission === "granted" &&
+        document.hidden
+      ) {
         showNotification(
           t`All Set! ${dashboard?.name} is ready.`,
           t`All questions loaded`,
diff --git a/frontend/src/metabase/hooks/use-web-notification.ts b/frontend/src/metabase/hooks/use-web-notification.ts
index 5afad1cf9685459f92b4d5d724fceaefd22e9f18..52f70665780fc6b083c3ae378129ad9bc44edb6a 100644
--- a/frontend/src/metabase/hooks/use-web-notification.ts
+++ b/frontend/src/metabase/hooks/use-web-notification.ts
@@ -1,12 +1,21 @@
-import React, { useCallback } from "react";
+import { useCallback } from "react";
+
+const hasNotificationAPI = "Notification" in window;
 
 export function useWebNotification() {
   const requestPermission = useCallback(async () => {
+    if (!hasNotificationAPI) {
+      return "denied";
+    }
     const permission = await Notification.requestPermission();
     return permission;
   }, []);
 
   const showNotification = useCallback((title: string, body: string) => {
+    if (!hasNotificationAPI) {
+      return;
+    }
+
     const notification = new Notification(title, {
       body,
       icon: "app/assets/img/favicon-32x32.png",
diff --git a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
index 2488c3eeff6d677d27b870e7f39393096e02d6fa..5d7b99d8bcdfbdd5210cd895e4162b1f7b0114dd 100644
--- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
+++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
@@ -373,7 +373,7 @@ function QueryBuilder(props) {
   const { isRunning } = uiControls;
 
   const onTimeout = useCallback(() => {
-    if (Notification.permission === "default") {
+    if ("Notification" in window && Notification.permission === "default") {
       setIsShowingToaster(true);
     }
   }, []);
@@ -389,7 +389,11 @@ function QueryBuilder(props) {
     if (isLoadingComplete) {
       setIsShowingToaster(false);
 
-      if (Notification.permission === "granted" && document.hidden) {
+      if (
+        "Notification" in window &&
+        Notification.permission === "granted" &&
+        document.hidden
+      ) {
         showNotification(
           t`All Set! Your question is ready.`,
           t`${card.name} is loaded.`,