diff --git a/app/app.js b/app/app.js
index 78395642373a95242e61982fd099c7eaa35e2169..892f6f7a41db025b77febd1628d844d62c55aace 100644
--- a/app/app.js
+++ b/app/app.js
@@ -1,4 +1,5 @@
 import Ember from 'ember';
+import EmberData from 'ember-data';
 import Resolver from './resolver';
 import loadInitializers from 'ember-load-initializers';
 import config from './config/environment';
@@ -22,6 +23,11 @@ loadInitializers(App, config.modulePrefix);
 
 export default App;
 
+// TODO: just for development purposes
+window.App = App;
+window.Ember = Ember;
+window.EmberData = EmberData;
+
 // ember (via ember-runtime) sets native prototype enhancements like .property/.observer, but as enumerable
 // we need to fix enumerability since it breaks cose-bilkent and sometimes cytoscape
 function avoidEnumerableNativeExtensions(proto) {
diff --git a/app/index.html b/app/index.html
index 35d1ce45157d17d80b756835b895f6b11ff6ccb1..56f96a908e1f64f1234d795f1cded0e05c1f6235 100644
--- a/app/index.html
+++ b/app/index.html
@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <title>FrontendPrototype</title>
+    <title>iObserve UI</title>
     <meta name="description" content="">
     <meta name="viewport" content="width=device-width, initial-scale=1">
 
diff --git a/app/routes/deployments/single.js b/app/routes/deployments/single.js
index cd7c872bbad8fe0eba11682aa195cbb6df411a3b..7ef6e2b59efdef4b569491b5d3a0475b5903fe57 100644
--- a/app/routes/deployments/single.js
+++ b/app/routes/deployments/single.js
@@ -3,8 +3,13 @@ import Ember from 'ember';
 export default Ember.Route.extend({
   session: Ember.inject.service(), // loads services/session.js
   graphingService: Ember.inject.service(),
+  changelogStream: Ember.inject.service(),
   model(params) {
-    this.set('session.systemId', params.systemId); // add the system to all requests
+    const systemId = params.systemId;
+    this.set('session.systemId', systemId); // add the system to all requests
+    const changelogStream = this.get('changelogStream'); // lazy loaded, requires session id
+    changelogStream.connect(systemId);
+
     const graphingService = this.get('graphingService');
     const createGraph = graphingService.createGraph.bind(graphingService);
 
@@ -44,6 +49,9 @@ export default Ember.Route.extend({
             entityId
         });
         this.transitionTo(url);
+    },
+    willTransition() {
+        this.get('changelogStream').disconnect();
     }
   }
 });
diff --git a/app/services/changelog-stream.js b/app/services/changelog-stream.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d97072c537b402d545660e531bab2234a8c02d9
--- /dev/null
+++ b/app/services/changelog-stream.js
@@ -0,0 +1,60 @@
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+    shouldClose: false,
+    init() {
+        this._super(...arguments);
+        this.debug('session', this.get('systemId'));
+    },
+    connect(systemId) {
+        this.set('shouldClose', false);
+
+        this.debug('setting up websocket', systemId);
+        const socket = new WebSocket(`ws://localhost:8080/v1/changelogstream/${systemId}`);
+        this.set('socket', socket);
+
+        socket.onopen = this.get('events.onOpen').bind(this);
+        socket.onerror = this.get('events.onError').bind(this);
+        socket.onmessage = this.get('events.onMessage').bind(this);
+
+        // automatically reconnect
+        socket.onclose = () => {
+            if(!this.get('shouldClose')) {
+                this.debug('connection lost, reconnecting!');
+                this.set('reconnectionTimeout', setTimeout(() => {
+                    this.connect(systemId);
+                    this.set('reconnectionTimeout', null);
+                }, 500));
+            }
+        };
+
+        // close socket connection when the user closes the window/tab or nagivates to a different website
+        window.onbeforeunload = this.get('disconnect').bind(this);
+    },
+    disconnect() {
+        this.debug('disconnect');
+        this.set('shouldClose', true);
+        this.get('socket').close();
+
+        // just in case it disconnected right before disconnect() was called.
+        clearTimeout(this.get('reconnectionTimeout'));
+    },
+    events: {
+        onError(err) {
+            this.debug('socket connection encountered an error', err);
+        },
+        onOpen() {
+            this.debug('connection established');
+        },
+        onMessage(message) {
+            const changelogJson = message.data;
+            this.debug('new changelog received', changelogJson);
+            try {
+                const changelog = JSON.parse(changelogJson);
+                this.debug('changelog converted', changelog);
+            } catch (e) {
+                console.error('could not parse changelog json', e, changelogJson);
+            }
+        }
+    }
+});