diff --git a/platypush/backend/http/static/css/source/common/animations.scss b/platypush/backend/http/static/css/source/common/animations.scss
new file mode 100644
index 00000000..fc24399b
--- /dev/null
+++ b/platypush/backend/http/static/css/source/common/animations.scss
@@ -0,0 +1,37 @@
+.fade-in {
+    --duration: $fade-in-transition-duration;
+    opacity: 1;
+    animation-name: fadeInOpacity;
+    animation-iteration-count: 1;
+    animation-timing-function: ease-in;
+    animation-duration: var(--duration);
+}
+
+@keyframes fadeInOpacity {
+    0% {
+        opacity: 0;
+    }
+    100% {
+        opacity: 1;
+    }
+}
+
+.fade-out {
+    --duration: $fade-out-transition-duration;
+    opacity: 1;
+    animation-name: fadeOutOpacity;
+    animation-iteration-count: 1;
+    animation-timing-function: ease-out;
+    animation-duration: var(--duration);
+}
+
+@keyframes fadeOutOpacity {
+    0% {
+        opacity: 1;
+    }
+    100% {
+        opacity: 0;
+        display: none;
+    }
+}
+
diff --git a/platypush/backend/http/static/css/source/common/layout.scss b/platypush/backend/http/static/css/source/common/layout.scss
index f69d0e4c..2e6cc4ca 100644
--- a/platypush/backend/http/static/css/source/common/layout.scss
+++ b/platypush/backend/http/static/css/source/common/layout.scss
@@ -86,3 +86,10 @@ $widths: (
     align-items: center;
 }
 
+.horizontal-center {
+    display: flex;
+    justify-content: center;
+    margin-left: auto;
+    margin-right: auto;
+}
+
diff --git a/platypush/backend/http/static/css/source/common/notification.scss b/platypush/backend/http/static/css/source/common/notification.scss
deleted file mode 100644
index a0cc0bc8..00000000
--- a/platypush/backend/http/static/css/source/common/notification.scss
+++ /dev/null
@@ -1,65 +0,0 @@
-#notification-container {
-    position: fixed;
-    bottom: 0;
-    right: 0;
-    width: 25em;
-
-    .notification {
-        background: rgba(180,245,188,0.85);
-        border: 1px solid #bbb;
-        border-radius: 5px;
-        margin-bottom: 1rem;
-        margin-right: 1rem;
-        cursor: pointer;
-        display: none;
-    }
-
-    .notification:hover {
-        background: rgba(160,235,168,0.9);
-    }
-
-    .notification-title {
-        padding: 4px 10px;
-        font-weight: bold;
-        text-transform: capitalize;
-        line-height: 30px;
-        letter-spacing: .1rem;
-    }
-
-    .notification-body {
-        height: 6em;
-        overflow: hidden;
-        padding-bottom: 1rem;
-        letter-spacing: .05rem;
-    }
-
-    .notification-text {
-        margin-left: 0 !important;
-    }
-
-    .notification-image {
-        height: 100%;
-        text-align: center;
-        padding-top: .6em;
-        padding-bottom: .6em;
-
-        .notification-image-item {
-            width: 100%;
-            height: 100%;
-            margin: auto;
-        }
-
-        .fa.notification-image-item {
-            margin-top: .8em;
-            margin-left: .2em;
-            font-size: 25px;
-        }
-
-        img {
-            width: 80%;
-            height: 80%;
-        }
-    }
-}
-
-
diff --git a/platypush/backend/http/static/css/source/common/notifications.scss b/platypush/backend/http/static/css/source/common/notifications.scss
new file mode 100644
index 00000000..e568208c
--- /dev/null
+++ b/platypush/backend/http/static/css/source/common/notifications.scss
@@ -0,0 +1,73 @@
+#notifications {
+    position: fixed;
+    bottom: 0;
+    right: 0;
+    width: 25em;
+
+    .notification {
+        background: $notification-bg;
+        border: $notification-border;
+        border-radius: .5rem;
+        margin-bottom: 1rem;
+        margin-right: 1rem;
+        cursor: pointer;
+
+        &:hover {
+            background: $notification-hover-bg;
+            &.warning { background: $notification-warning-hover-bg; }
+            &.error { background: $notification-error-hover-bg; }
+        }
+
+        &.warning {
+            background: $notification-warning-bg;
+            border: $notification-warning-border;
+            .image { --color: $notification-warning-icon-color; }
+        }
+
+        &.error {
+            background: $notification-error-bg;
+            border: $notification-error-border;
+            .image { --color: $notification-error-icon-color; }
+        }
+
+        .title {
+            border-bottom: $notification-title-border;
+            padding: .4rem;
+            text-transform: uppercase;
+            line-height: 3rem;
+            letter-spacing: .1rem;
+        }
+
+        .body {
+            @extend .vertical-center;
+            height: 6em;
+            overflow: hidden;
+            padding-bottom: 1rem;
+            letter-spacing: .05rem;
+        }
+
+        .image {
+            height: 100%;
+            text-align: center;
+            --color: $notification-icon-color;
+
+            .row {
+                @extend .vertical-center;
+                @extend .horizontal-center;
+                width: 100%;
+                height: 100%;
+
+                .fa {
+                    font-size: 2.5rem;
+                    color: var(--color);
+                }
+
+                img {
+                    width: 80%;
+                    height: 80%;
+                }
+            }
+        }
+    }
+}
+
diff --git a/platypush/backend/http/static/css/source/common/vars.scss b/platypush/backend/http/static/css/source/common/vars.scss
index c87a4d2d..0ec0872a 100644
--- a/platypush/backend/http/static/css/source/common/vars.scss
+++ b/platypush/backend/http/static/css/source/common/vars.scss
@@ -19,6 +19,27 @@ $nav-date-time-shadow: 2px 2px 2px #ccc !default;
 
 $modal-bg: #f0f0f0 !default;
 
+//// Animations defaults
+$transition-duration: .5s !default;
+$fade-transition-duration: .5s !default;
+$fade-in-transition-duration: $fade-transition-duration !default;
+$fade-out-transition-duration: $fade-transition-duration !default;
+
+//// Notifications
+$notification-bg: rgba(185, 255, 193, 0.85) !default;
+$notification-hover-bg: rgba(160,245,178,0.9) !default;
+$notification-warning-bg: rgba(228, 255, 78, 0.85) !default;
+$notification-warning-hover-bg: rgba(218, 245, 68, 0.9) !default;
+$notification-error-bg: rgba(255, 100, 100, 0.85) !default;
+$notification-error-hover-bg: rgba(245, 90, 90, 0.9) !default;
+$notification-border: 1px solid rgba(109, 205, 134, 0.62) !default;
+$notification-warning-border: 1px solid rgba(205, 205, 109, 0.62) !default;
+$notification-error-border: 1px solid rgba(205, 109, 109, 0.62) !default;
+$notification-title-border: 1px solid rgba(83, 158, 102, 0.43) !default;
+$notification-icon-color: black !default;
+$notification-warning-icon-color: #662 !default;
+$notification-error-icon-color: #8b0000 !default;
+
 //// Switch element
 $switch-bg-1: #f9f8f6 !default;
 $switch-bg-2: #38ffa0 !default;
diff --git a/platypush/backend/http/static/css/source/webpanel/index.scss b/platypush/backend/http/static/css/source/webpanel/index.scss
index 1403b377..f9d3a09f 100644
--- a/platypush/backend/http/static/css/source/webpanel/index.scss
+++ b/platypush/backend/http/static/css/source/webpanel/index.scss
@@ -3,8 +3,9 @@
 @import 'common/mixins';
 @import 'common/layout';
 @import 'common/elements';
+@import 'common/animations';
 @import 'common/modal';
-@import 'common/notification';
+@import 'common/notifications';
 
 @import 'header';
 @import 'nav';
diff --git a/platypush/backend/http/static/js/api.js b/platypush/backend/http/static/js/api.js
index ea2c074f..b8e08c3f 100644
--- a/platypush/backend/http/static/js/api.js
+++ b/platypush/backend/http/static/js/api.js
@@ -22,12 +22,21 @@ function execute(request) {
                 if (!response.errors.length) {
                     resolve(response.output);
                 } else {
-                    // TODO Handle error
-                    reject(response.errors[0]);
+                    const error = response.errors[0];
+                    createNotification({
+                        text: error,
+                        error: true,
+                    });
+
+                    reject(error);
                 }
             })
             .catch((error) => {
-                // TODO Handle error
+                createNotification({
+                    text: error,
+                    error: true,
+                });
+
                 reject(error);
             });
     });
diff --git a/platypush/backend/http/static/js/application.js b/platypush/backend/http/static/js/application.js
index 012da3d7..871ebd62 100644
--- a/platypush/backend/http/static/js/application.js
+++ b/platypush/backend/http/static/js/application.js
@@ -26,7 +26,7 @@ Vue.component('plugin', {
 });
 
 // Declaration of the main vue app
-var app = new Vue({
+window.vm = new Vue({
     el: '#app',
     // Override {{ }} delimiters to prevent clash with Flask templates
     delimiters: ['[[',']]'],
diff --git a/platypush/backend/http/static/js/notifications.js b/platypush/backend/http/static/js/notifications.js
new file mode 100644
index 00000000..8b8b1767
--- /dev/null
+++ b/platypush/backend/http/static/js/notifications.js
@@ -0,0 +1,63 @@
+Vue.component('notifications', {
+    template: '#tmpl-notifications',
+    props: {
+        duration: {
+            // Default notification duration in milliseconds
+            type: Number,
+            default: 10000,
+        }
+    },
+
+    data: function() {
+        return {
+            index: 0,
+            notifications: {},
+            timeouts: {},
+        };
+    },
+
+    methods: {
+        create: function(args) {
+            var id = this.index++;
+            Vue.set(this.notifications, id, args);
+
+            if (args.duration == null) {
+                args.duration = this.duration;
+            }
+
+            if (args.duration != 0) {
+                this.timeouts[id] = setTimeout(this.destroy.bind(null, id), args.duration);
+            }
+        },
+
+        destroy: function(id) {
+            Vue.delete(this.notifications, id);
+            delete this.timeouts[id];
+        },
+    },
+});
+
+Vue.component('notification', {
+    template: '#tmpl-notification',
+    props: ['id','text','html','title','image','link','error','warning'],
+
+    methods: {
+        mousein: function(event) {
+        },
+
+        mouseout: function(event) {
+        },
+        clicked: function(event) {
+            if (this.link) {
+                window.open(this.link, '_blank');
+            }
+
+            this.$emit('clicked', this.id);
+        },
+    },
+});
+
+function createNotification(args) {
+    window.vm.$refs.notifications.create(args);
+}
+
diff --git a/platypush/backend/http/templates/index.html b/platypush/backend/http/templates/index.html
index acdd962d..0028a780 100644
--- a/platypush/backend/http/templates/index.html
+++ b/platypush/backend/http/templates/index.html
@@ -14,6 +14,7 @@
 
     <script type="text/javascript" src="{{ url_for('static', filename='js/api.js') }}"></script>
     <script type="text/javascript" src="{{ url_for('static', filename='js/events.js') }}"></script>
+    <script type="text/javascript" src="{{ url_for('static', filename='js/notifications.js') }}"></script>
 
     {% for style in styles.values() %}
     <link rel="stylesheet" href="{{ url_for('static', filename=style['_style_file']) }}">
@@ -60,6 +61,8 @@
                 {% endfor %}
             </div>
         </main>
+
+        {% include 'notifications.html' %}
     </div>
 
     {% include 'plugins/template.html' %}
diff --git a/platypush/backend/http/templates/notifications.html b/platypush/backend/http/templates/notifications.html
new file mode 100644
index 00000000..3eeb46c7
--- /dev/null
+++ b/platypush/backend/http/templates/notifications.html
@@ -0,0 +1,41 @@
+<script type="text/x-template" id="tmpl-notifications">
+    <div id="notifications">
+        <notification v-for="(notification, id, index) in notifications"
+                      :key="index"
+                      :id="id"
+                      :text="notification.text"
+                      :html="notification.html"
+                      :title="notification.title"
+                      :link="notification.link"
+                      :image="notification.image"
+                      :warning="notification.warning"
+                      :error="notification.error"
+                      @clicked="destroy">
+        </notification>
+    </div>
+</script>
+
+<script type="text/x-template" id="tmpl-notification">
+    <div class="notification fade-in" :class="{warning: warning, error: error}"
+         @mouseover="mousein" @mouseleave="mouseout" @click="clicked">
+        <div class="title" v-if="title" v-text="title"></div>
+        <div class="body">
+            <div class="image col-3" v-if="image || warning || error">
+                <div class="row">
+                    <img :src="image.src" v-if="image && image.src">
+                    <i :class="['fa', 'fa-' + image.icon]" :style="image.color ? '--color: ' + image.color : ''"
+                       v-else-if="image && image.icon"></i>
+                    <i class="fa fa-exclamation" v-else-if="warning"></i>
+                    <i class="fa fa-times" v-else-if="error"></i>
+                </div>
+            </div>
+            <div class="text col-9" v-if="text && !!image" v-text="text"></div>
+            <div class="text col-9" v-if="html && !!image" v-html="html"></div>
+            <div class="text row horizontal-center" v-if="text && !image" v-text="text"></div>
+            <div class="text row horizontal-center" v-if="html && !image" v-html="html"></div>
+        </div>
+    </div>
+</script>
+
+<notifications ref="notifications"></notifications>
+