diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java
index 6a0d7bde5fdc71e57f17b988124d9865e4e4b0f7..619d28c86c904fe6d92f5d6a4fa9f2d90b016cd9 100644
--- a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java
+++ b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java
@@ -34,6 +34,7 @@ import de.vipra.util.model.Topic;
 import de.vipra.util.model.TopicFull;
 import de.vipra.util.service.MongoService;
 import de.vipra.util.service.Service.QueryBuilder;
+import de.vipra.ws.WebSocket;
 
 @Path("topics")
 public class TopicResource {
@@ -137,6 +138,7 @@ public class TopicResource {
 
 		try {
 			dbTopics.replaceSingle(topic);
+			WebSocket.sendToState("topics.show", "{\"msg\":\"topic updated\"}");
 			return res.ok(topic);
 		} catch (DatabaseException e) {
 			e.printStackTrace();
diff --git a/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java b/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java
index 5db32f50194a4d371ca7c8861ed9a4e50967f3db..5e7fa899b8441c656cef0393d7a3697b1e09e3d1 100644
--- a/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java
+++ b/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java
@@ -1,6 +1,9 @@
 package de.vipra.ws;
 
 import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.websocket.OnClose;
 import javax.websocket.OnError;
@@ -12,33 +15,69 @@ import javax.websocket.server.ServerEndpoint;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.vipra.util.MultiMap;
+import de.vipra.ws.msg.InitMessage;
+import de.vipra.ws.msg.WebSocketMessage;
+
 @ServerEndpoint("/ws")
 public class WebSocket {
 
 	public static final Logger log = LogManager.getLogger(WebSocket.class);
 
+	public static final ObjectMapper mapper = new ObjectMapper();
+	public static final Set<Session> sessions = new HashSet<>();
+	public static final MultiMap<String, Session> states = new MultiMap<>();
+
 	@OnOpen
 	public void open(Session session) {
-		log.info("open");
+		log.debug("connect");
+		sessions.add(session);
 	}
 
 	@OnClose
 	public void close(Session session) {
-		log.info("close");
+		log.debug("disconnect");
+		sessions.remove(session);
 	}
 
 	@OnError
-	public void onError(Throwable error) {
-		log.info("error");
-	}
+	public void onError(Throwable error) {}
 
 	@OnMessage
-	public void handleMessage(String message, Session session) {
-		log.info(message);
+	public void handleMessage(String input, Session session)
+			throws JsonParseException, JsonMappingException, IOException {
+		log.trace("message received");
 		try {
-			session.getBasicRemote().sendText(message);
+			WebSocketMessage msg = mapper.readValue(input, WebSocketMessage.class);
+			switch (msg.getType()) {
+				case 1:
+					handleInitMessage(mapper.readValue(msg.getData(), InitMessage.class), session);
+					break;
+			}
 		} catch (IOException e) {
-			e.printStackTrace();
+			log.error(e);
+		}
+	}
+
+	public void handleInitMessage(InitMessage message, Session session) {
+		log.debug("init message received. state = " + message.getState());
+		states.put(message.getState(), session);
+	}
+
+	public static void sendToState(String state, String message) {
+		Collection<Session> sessions = states.get(state);
+		if (sessions != null) {
+			for (Session session : sessions) {
+				try {
+					session.getBasicRemote().sendText(message);
+				} catch (IOException e) {
+					log.error(e);
+				}
+			}
 		}
 	}
 
diff --git a/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java b/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab5054001839622fb68e2d57b16dc1f5153944b7
--- /dev/null
+++ b/vipra-backend/src/main/java/de/vipra/ws/msg/InitMessage.java
@@ -0,0 +1,15 @@
+package de.vipra.ws.msg;
+
+public class InitMessage extends WebSocketMessage {
+
+	private String state;
+
+	public String getState() {
+		return state;
+	}
+
+	public void setState(String state) {
+		this.state = state;
+	}
+
+}
diff --git a/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java b/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c2b586ae3270551a4b0c66489e6ee2e75cde61b
--- /dev/null
+++ b/vipra-backend/src/main/java/de/vipra/ws/msg/WebSocketMessage.java
@@ -0,0 +1,25 @@
+package de.vipra.ws.msg;
+
+public class WebSocketMessage {
+
+	private int type;
+
+	private String data;
+
+	public int getType() {
+		return type;
+	}
+
+	public void setType(int type) {
+		this.type = type;
+	}
+
+	public String getData() {
+		return data;
+	}
+
+	public void setData(String data) {
+		this.data = data;
+	}
+
+}
diff --git a/vipra-ui/app/js/config.js b/vipra-ui/app/js/config.js
index 50df7e92d2b6b2f912a8aa287bb73a98c83688bd..e57dd2d136d48076a8f2371e62539307ed3b4995 100644
--- a/vipra-ui/app/js/config.js
+++ b/vipra-ui/app/js/config.js
@@ -4,7 +4,7 @@
 
   Vipra.config = {
     restUrl: '//' + location.hostname + ':8080/vipra/rest',
-    websocketUrl: '//' + location.hostname + ':8080/vipra/ws'
+    websocketUrl: 'ws://' + location.hostname + ':8080/vipra/ws'
   };
 
 })();
\ No newline at end of file
diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js
index cbe753d031d6c67f79a400d9cf3382e3c82f5369..326c167905ce52582fad717935b19d4a27495be6 100644
--- a/vipra-ui/app/js/controllers.js
+++ b/vipra-ui/app/js/controllers.js
@@ -371,8 +371,8 @@
   /**
    * Topic Show route
    */
-  app.controller('TopicsShowController', ['$scope', '$stateParams', '$timeout', 'TopicFactory',
-    function($scope, $stateParams, $timeout, TopicFactory) {
+  app.controller('TopicsShowController', ['$scope', '$stateParams', '$timeout', 'TopicFactory', 'WebSocketService',
+    function($scope, $stateParams, $timeout, TopicFactory, WebSocketService) {
 
     $scope.wordSort = $scope.wordSort || 'likeliness';
     $scope.wordSortRev = typeof $scope.wordSortRev === 'undefined' ? true : $scope.wordSortRev;
@@ -412,7 +412,6 @@
         $event.preventDefault();
       }
     };
-
   }]);
 
   /**
diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js
index 54b50fe55f4b5681cc1e7e35444216ab9acd54f4..a88b88b98c341d8e374b28b13dd62da437883469 100644
--- a/vipra-ui/app/js/factories.js
+++ b/vipra-ui/app/js/factories.js
@@ -99,4 +99,25 @@
     };
   }]);
 
+  app.service('WebSocketService', ['$websocket', '$state', function($websocket, $state) {
+    var socket = $websocket(Vipra.config.websocketUrl),
+        callback = null;
+
+    socket.onMessage(function(message) {
+      var data = JSON.parse(message.data);
+      if(callback)
+        callback(data);
+    });
+
+    this.send = function(type, data) {
+      socket.send(JSON.stringify({ type: type, data: JSON.stringify(data) }));
+    };
+
+    this.receive = function(fn) {
+      callback = fn;
+    };
+
+    this.send(1, {state: $state.current.name});
+  }]);
+
 })();
\ No newline at end of file
diff --git a/vipra-util/src/main/java/de/vipra/util/MultiMap.java b/vipra-util/src/main/java/de/vipra/util/MultiMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f0fe47f3f1784eec7c695bdb0ebf47b38f83999
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/MultiMap.java
@@ -0,0 +1,104 @@
+package de.vipra.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class MultiMap<T, U> implements Map<T, Collection<U>> {
+
+	private final Map<T, Collection<U>> map;
+	private final boolean unique;
+
+	public MultiMap() {
+		this(false);
+	}
+
+	public MultiMap(boolean unique) {
+		this.map = new HashMap<>();
+		this.unique = unique;
+	}
+
+	@Override
+	public int size() {
+		return map.size();
+	}
+
+	@Override
+	public boolean isEmpty() {
+		return map.isEmpty();
+	}
+
+	@Override
+	public boolean containsKey(Object key) {
+		return map.containsKey(key);
+	}
+
+	@Override
+	public boolean containsValue(Object value) {
+		return map.containsValue(value);
+	}
+
+	@Override
+	public Collection<U> get(Object key) {
+		return map.get(key);
+	}
+
+	public Iterator<U> each(Object key) {
+		Collection<U> c = map.get(key);
+		if (c == null)
+			return null;
+		return c.iterator();
+	}
+
+	@Override
+	public Collection<U> put(T key, Collection<U> value) {
+		return map.put(key, value);
+	}
+
+	public void put(T key, U value) {
+		Collection<U> c = map.get(key);
+		if (c == null) {
+			if (unique)
+				c = new HashSet<>();
+			else
+				c = new ArrayList<>();
+		}
+		c.add(value);
+		map.put(key, c);
+	}
+
+	@Override
+	public Collection<U> remove(Object key) {
+		return map.remove(key);
+	}
+
+	@Override
+	public void putAll(Map<? extends T, ? extends Collection<U>> m) {
+		map.putAll(m);
+	}
+
+	@Override
+	public void clear() {
+		map.clear();
+	}
+
+	@Override
+	public Set<T> keySet() {
+		return map.keySet();
+	}
+
+	@Override
+	public Collection<Collection<U>> values() {
+		return map.values();
+	}
+
+	@Override
+	public Set<java.util.Map.Entry<T, Collection<U>>> entrySet() {
+		return map.entrySet();
+	}
+
+}