diff --git a/alfred.h b/alfred.h
index 2d98a30..f442c48 100644
--- a/alfred.h
+++ b/alfred.h
@@ -94,6 +94,7 @@ enum clientmode {
 	CLIENT_CHANGE_INTERFACE,
 	CLIENT_CHANGE_BAT_IFACE,
 	CLIENT_SERVER_STATUS,
+	CLIENT_EVENT_MONITOR,
 };
 
 struct interface {
@@ -110,8 +111,15 @@ struct interface {
 	struct list_head list;
 };
 
+struct event_listener {
+	int fd;
+
+	struct list_head list;
+};
+
 struct globals {
 	struct list_head interfaces;
+	struct list_head event_listeners;
 
 	char *net_iface;
 	struct server *best_server;	/* NULL if we are a server ourselves */
@@ -157,6 +165,7 @@ int alfred_client_modeswitch(struct globals *globals);
 int alfred_client_change_interface(struct globals *globals);
 int alfred_client_change_bat_iface(struct globals *globals);
 int alfred_client_server_status(struct globals *globals);
+int alfred_client_event_monitor(struct globals *globals);
 /* recv.c */
 int recv_alfred_packet(struct globals *globals, struct interface *interface,
 		       int recv_sock);
@@ -186,6 +195,12 @@ int unix_sock_open_client(struct globals *globals);
 int unix_sock_close(struct globals *globals);
 int unix_sock_req_data_finish(struct globals *globals,
 			      struct transaction_head *head);
+int unix_sock_events_select_prepare(struct globals *globals, fd_set *fds,
+				    fd_set *errfds, int maxsock);
+void unix_sock_events_select_handle(struct globals *globals,
+				    fd_set *fds, fd_set *errfds);
+void unix_sock_events_close_all(struct globals *globals);
+void unix_sock_event_notify(struct globals *globals, uint8_t type);
 /* vis.c */
 int vis_update_data(struct globals *globals);
 /* netsock.c */
diff --git a/client.c b/client.c
index 81cdd7c..9e88f47 100644
--- a/client.c
+++ b/client.c
@@ -452,3 +452,57 @@ err:
 	unix_sock_close(globals);
 	return 0;
 }
+
+int alfred_client_event_monitor(struct globals *globals)
+{
+	struct alfred_event_register_v0 event_register;
+	struct alfred_event_notify_v0 event_notify;
+	int ret, len;
+
+	if (unix_sock_open_client(globals))
+		return -1;
+
+	len = sizeof(event_register);
+
+	event_register.header.type = ALFRED_EVENT_REGISTER;
+	event_register.header.version = ALFRED_VERSION;
+	event_register.header.length = 0;
+
+	ret = write(globals->unix_sock, &event_register, len);
+	if (ret != len) {
+		fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+			__func__, ret, len, strerror(errno));
+		goto err;
+	}
+
+	while (true) {
+		len = read(globals->unix_sock, &event_notify, sizeof(event_notify));
+		if (len == 0) {
+			fprintf(stdout, "Server closed the connection\n");
+			goto err;
+		}
+
+		if (len < 0) {
+			perror("read from unix socket failed");
+			goto err;
+		}
+
+		if (len != sizeof(event_notify)) {
+			fprintf(stderr, "notify read bytes: %d (expected: %zu)\n",
+				len, sizeof(event_notify));
+				goto err;
+		}
+
+		if (event_notify.header.version != ALFRED_VERSION)
+			continue;
+
+		if (event_notify.header.type != ALFRED_EVENT_NOTIFY)
+			continue;
+
+		fprintf(stdout, "Event: type = %d\n", event_notify.type);
+	}
+
+err:
+	unix_sock_close(globals);
+	return 0;
+}
diff --git a/main.c b/main.c
index 68d6efd..98bf64d 100644
--- a/main.c
+++ b/main.c
@@ -39,6 +39,7 @@ static void alfred_usage(void)
 	printf("  -I, --change-interface [interface]  change to the specified interface(s)\n");
 	printf("  -B, --change-bat-iface [interface]  change to the specified batman-adv interface\n");
 	printf("  -S, --server-status                 request server status info such as mode & interfaces\n");
+	printf("  -E, --event-monitor                 monitor alfred data record update eventss\n");
 	printf("\n");
 	printf("server mode options:\n");
 	printf("  -i, --interface                     specify the interface (or comma separated list of interfaces) to listen on\n");
@@ -164,6 +165,7 @@ static struct globals *alfred_init(int argc, char *argv[])
 		{"change-interface",	required_argument,	NULL,	'I'},
 		{"change-bat-iface",	required_argument,	NULL,	'B'},
 		{"server-status",	required_argument,	NULL,	'S'},
+		{"event-monitor",	required_argument,	NULL,	'E'},
 		{"unix-path",		required_argument,	NULL,	'u'},
 		{"update-command",	required_argument,	NULL,	'c'},
 		{"version",		no_argument,		NULL,	'v'},
@@ -181,6 +183,7 @@ static struct globals *alfred_init(int argc, char *argv[])
 	memset(globals, 0, sizeof(*globals));
 
 	INIT_LIST_HEAD(&globals->interfaces);
+	INIT_LIST_HEAD(&globals->event_listeners);
 	globals->net_iface = NULL;
 	globals->opmode = OPMODE_SECONDARY;
 	globals->clientmode = CLIENT_NONE;
@@ -198,7 +201,7 @@ static struct globals *alfred_init(int argc, char *argv[])
 
 	time_random_seed();
 
-	while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:I:B:Su:dc:p:4:f", long_options,
+	while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:I:B:SEu:dc:p:4:f", long_options,
 				  &opt_ind)) != -1) {
 		switch (opt) {
 		case 'r':
@@ -263,6 +266,9 @@ static struct globals *alfred_init(int argc, char *argv[])
 		case 'S':
 			globals->clientmode = CLIENT_SERVER_STATUS;
 			break;
+		case 'E':
+			globals->clientmode = CLIENT_EVENT_MONITOR;
+			break;
 		case 'u':
 			globals->unix_path = optarg;
 			break;
@@ -328,6 +334,8 @@ int main(int argc, char *argv[])
 		return alfred_client_change_bat_iface(globals);
 	case CLIENT_SERVER_STATUS:
 		return alfred_client_server_status(globals);
+	case CLIENT_EVENT_MONITOR:
+		return alfred_client_event_monitor(globals);
 	}
 
 	return 0;
diff --git a/man/alfred.8 b/man/alfred.8
index cf0eafc..ca83f02 100644
--- a/man/alfred.8
+++ b/man/alfred.8
@@ -97,6 +97,9 @@ Change the alfred server to use the new \fBbatman-adv interface\fP
 .TP
 \fB\-S\fP, \fB\-\-server\-status\fP
 Request server status information such as mode & interfaces\fP
+.TP
+\fB\-E\fP, \fB\-\-event\-monitor\fP
+Start alfred event monitor connecting to the alfred server and reporting update events\fP
 .
 .SH SERVER OPTIONS
 .TP
diff --git a/packet.h b/packet.h
index 0c1a2eb..84b027f 100644
--- a/packet.h
+++ b/packet.h
@@ -59,6 +59,8 @@ struct alfred_transaction_mgmt {
  * @ALFRED_STATUS_ERROR: Error was detected during the transaction
  * @ALFRED_MODESWITCH: Switch between different operation modes
  * @ALFRED_CHANGE_INTERFACE: Change the listening interface
+ * @ALFRED_EVENT_REGISTER: Request to be notified about alfred update events
+ * @ALFRED_EVENT_NOTIFY: Data record update has been received
  */
 enum alfred_packet_type {
 	ALFRED_PUSH_DATA = 0,
@@ -70,6 +72,8 @@ enum alfred_packet_type {
 	ALFRED_CHANGE_INTERFACE = 6,
 	ALFRED_CHANGE_BAT_IFACE = 7,
 	ALFRED_SERVER_STATUS = 8,
+	ALFRED_EVENT_REGISTER = 9,
+	ALFRED_EVENT_NOTIFY = 10,
 };
 
 /* packets */
@@ -229,6 +233,28 @@ struct alfred_server_status_rep_v0 {
 	struct alfred_tlv header;
 } __packed;
 
+/**
+ * struct alfred_event_register_v0 - event registration message
+ * @header: TLV header describing the complete packet
+ *
+ * Sent by the client to daemon to register for data record updates
+ */
+struct alfred_event_register_v0 {
+	struct alfred_tlv header;
+} __packed;
+
+/**
+ * struct alfred_event_notify_v0 - event notification message
+ * @header: TLV header describing the complete packet
+ * @type: Type of the data triggering the event
+ *
+ * Sent by the daemon to client on data record update
+ */
+struct alfred_event_notify_v0 {
+	struct alfred_tlv header;
+	uint8_t type;
+} __packed;
+
 /**
  * struct alfred_status_v0 - Status info of a transaction
  * @header: TLV header describing the complete packet
diff --git a/recv.c b/recv.c
index 8acad10..36b3a49 100644
--- a/recv.c
+++ b/recv.c
@@ -76,8 +76,10 @@ static int finish_alfred_push_data(struct globals *globals,
 		/* check that data was changed */
 		if (new_entry_created ||
 		    dataset->data.header.length != data_len ||
-		    memcmp(dataset->buf, data->data, data_len) != 0)
+		    memcmp(dataset->buf, data->data, data_len) != 0) {
 			changed_data_type(globals, data->header.type);
+			unix_sock_event_notify(globals, data->header.type);
+		}
 
 		/* free old buffer */
 		if (dataset->buf) {
diff --git a/server.c b/server.c
index bfc37bc..4078fe6 100644
--- a/server.c
+++ b/server.c
@@ -442,6 +442,8 @@ int alfred_server(struct globals *globals)
 
 		maxsock = netsock_prepare_select(globals, &fds, maxsock);
 		maxsock = netsock_prepare_select(globals, &errfds, maxsock);
+		maxsock = unix_sock_events_select_prepare(globals, &fds,
+							  &errfds, maxsock);
 
 		ret = pselect(maxsock + 1, &fds, NULL, &errfds, &tv, NULL);
 
@@ -450,6 +452,8 @@ int alfred_server(struct globals *globals)
 		} else if (ret) {
 			netsock_check_error(globals, &errfds);
 
+			unix_sock_events_select_handle(globals, &fds, &errfds);
+
 			if (FD_ISSET(globals->unix_sock, &fds)) {
 				unix_sock_read(globals);
 				continue;
@@ -478,5 +482,6 @@ int alfred_server(struct globals *globals)
 
 	netsock_close_all(globals);
 	unix_sock_close(globals);
+	unix_sock_events_close_all(globals);
 	return 0;
 }
diff --git a/unix_sock.c b/unix_sock.c
index 3894736..c45564d 100644
--- a/unix_sock.c
+++ b/unix_sock.c
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/un.h>
@@ -84,6 +85,7 @@ static int unix_sock_add_data(struct globals *globals,
 			      struct alfred_push_data_v0 *push,
 			      int client_sock)
 {
+	bool new_entry_created = false;
 	struct alfred_data *data;
 	struct dataset *dataset;
 	int len, data_len, ret = -1;
@@ -138,10 +140,17 @@ static int unix_sock_add_data(struct globals *globals,
 			free(dataset);
 			goto err;
 		}
+		new_entry_created = true;
 	}
 	dataset->data_source = SOURCE_LOCAL;
 	clock_gettime(CLOCK_MONOTONIC, &dataset->last_seen);
 
+	/* check that data was changed */
+	if (new_entry_created ||
+	    dataset->data.header.length != data_len ||
+	    memcmp(dataset->buf, data->data, data_len) != 0)
+		unix_sock_event_notify(globals, data->header.type);
+
 	/* free old buffer */
 	free(dataset->buf);
 
@@ -472,6 +481,37 @@ err:
 	return ret;
 }
 
+static int unix_sock_register_listener(struct globals *globals, int client_sock)
+{
+	struct event_listener *listener;
+	int ret;
+
+	ret = fcntl(client_sock, F_GETFL, 0);
+	if (ret < 0) {
+		perror("failed to get file status flags");
+		goto err;
+	}
+
+	ret = fcntl(client_sock, F_SETFL, ret | O_NONBLOCK);
+	if (ret < 0) {
+		perror("failed to set file status flags");
+		goto err;
+	}
+
+	listener = malloc(sizeof(*listener));
+	if (!listener)
+		goto err;
+
+	listener->fd = client_sock;
+	INIT_LIST_HEAD(&listener->list);
+	list_add_tail(&listener->list, &globals->event_listeners);
+	return 0;
+
+err:
+	close(client_sock);
+	return -1;
+}
+
 int unix_sock_read(struct globals *globals)
 {
 	int client_sock;
@@ -537,6 +577,9 @@ int unix_sock_read(struct globals *globals)
 	case ALFRED_SERVER_STATUS:
 		ret = unix_sock_server_status(globals, client_sock);
 		break;
+	case ALFRED_EVENT_REGISTER:
+		ret = unix_sock_register_listener(globals, client_sock);
+		break;
 	default:
 		/* unknown packet type */
 		ret = -1;
@@ -555,3 +598,102 @@ int unix_sock_close(struct globals *globals)
 	close(globals->unix_sock);
 	return 0;
 }
+
+static void unix_sock_event_listener_free(struct event_listener *listener)
+{
+	list_del_init(&listener->list);
+	close(listener->fd);
+	free(listener);
+}
+
+static void unix_sock_event_notify_listener(struct event_listener *listener,
+					    uint8_t type)
+{
+	struct alfred_event_notify_v0 notify;
+	int ret;
+
+	notify.header.type = ALFRED_EVENT_NOTIFY;
+	notify.header.version = ALFRED_VERSION;
+	notify.header.length = FIXED_TLV_LEN(notify);
+	notify.type = type;
+
+	ret = write(listener->fd, &notify, sizeof(notify));
+	if (ret == sizeof(notify))
+		return;
+
+	unix_sock_event_listener_free(listener);
+}
+
+int unix_sock_events_select_prepare(struct globals *globals, fd_set *fds,
+				    fd_set *errfds, int maxsock)
+{
+	struct event_listener *listener;
+
+	list_for_each_entry(listener, &globals->event_listeners, list) {
+		if (listener->fd < 0)
+			continue;
+
+		FD_SET(listener->fd, fds);
+		FD_SET(listener->fd, errfds);
+
+		if (maxsock < listener->fd)
+			maxsock = listener->fd;
+	}
+
+	return maxsock;
+}
+
+void unix_sock_events_select_handle(struct globals *globals,
+				    fd_set *fds, fd_set *errfds)
+{
+	struct event_listener *listener, *tmp;
+	char buff[4];
+	int ret;
+
+	list_for_each_entry_safe(listener, tmp,
+				 &globals->event_listeners, list) {
+		if (FD_ISSET(listener->fd, fds)) {
+			ret = recv(listener->fd, buff, sizeof(buff),
+				   MSG_PEEK | MSG_DONTWAIT);
+			/* listener has hung up */
+			if (ret == 0)
+				unix_sock_event_listener_free(listener);
+			else if (ret > 0) {
+				fprintf(stderr, "Event listener has written to socket: %d - closing\n",
+					listener->fd);
+				unix_sock_event_listener_free(listener);
+			}
+
+			if (ret >= 0)
+				continue;
+		}
+
+		if (FD_ISSET(listener->fd, errfds)) {
+			fprintf(stderr, "Error on event listener detected: %d\n",
+				listener->fd);
+			unix_sock_event_listener_free(listener);
+			continue;
+		}
+	}
+}
+
+void unix_sock_events_close_all(struct globals *globals)
+{
+	struct event_listener *listener, *tmp;
+
+	list_for_each_entry_safe(listener, tmp,
+				 &globals->event_listeners, list) {
+		unix_sock_event_listener_free(listener);
+	}
+}
+
+void unix_sock_event_notify(struct globals *globals, uint8_t type)
+{
+	struct event_listener *listener, *tmp;
+
+	/* if event notify is unsuccessful, listener socket is closed */
+	list_for_each_entry_safe(listener, tmp,
+				 &globals->event_listeners, list) {
+		unix_sock_event_notify_listener(listener, type);
+	}
+}
