diff --git a/alfred.h b/alfred.h
index 8bea033..127b115 100644
--- a/alfred.h
+++ b/alfred.h
@@ -99,6 +99,7 @@ enum clientmode {
 	CLIENT_CHANGE_INTERFACE,
 	CLIENT_CHANGE_BAT_IFACE,
 	CLIENT_SERVER_STATUS,
+	CLIENT_EVENT_MONITOR,
 };
 
 struct interface {
@@ -118,8 +119,16 @@ struct interface {
 	struct list_head list;
 };
 
+struct event_listener {
+	int fd;
+	struct epoll_handle epoll;
+
+	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 */
@@ -171,6 +180,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);
@@ -199,6 +209,9 @@ 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);
+void unix_sock_events_close_all(struct globals *globals);
+void unix_sock_event_notify(struct globals *globals, uint8_t type,\
+			    const uint8_t source[ETH_ALEN]);
 /* vis.c */
 int vis_update_data(struct globals *globals);
 /* netsock.c */
diff --git a/client.c b/client.c
index 81cdd7c..ace42b9 100644
--- a/client.c
+++ b/client.c
@@ -452,3 +452,61 @@ 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 = %hhu, source = %02x:%02x:%02x:%02x:%02x:%02x\n",
+			event_notify.type,
+			event_notify.source[0], event_notify.source[1],
+			event_notify.source[2], event_notify.source[3],
+			event_notify.source[4], event_notify.source[5]);
+	}
+
+err:
+	unix_sock_close(globals);
+	return 0;
+}
diff --git a/main.c b/main.c
index 30e18a5..3fe7b42 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 events\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",	no_argument,		NULL,	'S'},
+		{"event-monitor",	no_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..b8d528e 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,29 @@ 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;
+	uint8_t source[ETH_ALEN];
+} __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..75e3faf 100644
--- a/recv.c
+++ b/recv.c
@@ -76,8 +76,11 @@ 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,
+					       data->source);
+		}
 
 		/* free old buffer */
 		if (dataset->buf) {
diff --git a/server.c b/server.c
index 52cdbe7..0d792b0 100644
--- a/server.c
+++ b/server.c
@@ -518,5 +518,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 ef72aa0..ce08a51 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>
@@ -26,6 +27,8 @@
 static void unix_sock_read(struct globals *globals,
 			   struct epoll_handle *handle __unused,
 			   struct epoll_event *ev __unused);
+static int unix_sock_register_listener(struct globals *globals,
+				       int client_sock);
 
 int unix_sock_open_daemon(struct globals *globals)
 {
@@ -99,6 +102,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;
@@ -153,10 +157,18 @@ 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,
+				       data->source);
+
 	/* free old buffer */
 	free(dataset->buf);
 
@@ -554,6 +566,9 @@ static void unix_sock_read(struct globals *globals,
 	case ALFRED_SERVER_STATUS:
 		unix_sock_server_status(globals, client_sock);
 		break;
+	case ALFRED_EVENT_REGISTER:
+		unix_sock_register_listener(globals, client_sock);
+		break;
 	default:
 		/* unknown packet type */
 		goto err;
@@ -570,3 +585,124 @@ 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(&listener->list);
+	close(listener->fd);
+	free(listener);
+}
+
+static void unix_sock_event_listener_handle(struct globals *globals __unused,
+					    struct epoll_handle *handle,
+					    struct epoll_event *ev)
+{
+	struct event_listener *listener;
+	char buff[4];
+	int ret;
+
+	listener = container_of(handle, struct event_listener, epoll);
+
+	if (ev->events & EPOLLERR) {
+		fprintf(stderr, "Error on event listener detected: %d\n",
+			listener->fd);
+		unix_sock_event_listener_free(listener);
+		return;
+	}
+
+	if (ev->events & EPOLLIN) {
+		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);
+		}
+	}
+}
+
+static int unix_sock_register_listener(struct globals *globals, int client_sock)
+{
+	struct event_listener *listener;
+	struct epoll_event ev;
+	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;
+
+	ev.events = EPOLLIN;
+	ev.data.ptr = &listener->epoll;
+	listener->epoll.handler = unix_sock_event_listener_handle;
+
+	if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, client_sock,
+		      &ev) == -1) {
+		perror("Failed to add epoll for event listener");
+		goto err;
+	}
+
+	listener->fd = client_sock;
+	list_add_tail(&listener->list, &globals->event_listeners);
+	return 0;
+
+err:
+	close(client_sock);
+	return -1;
+}
+
+static void unix_sock_event_notify_listener(struct event_listener *listener,
+					    uint8_t type,
+					    const uint8_t source[ETH_ALEN])
+{
+	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;
+	memcpy(&notify.source, source, ETH_ALEN);
+
+	ret = write(listener->fd, &notify, sizeof(notify));
+	if (ret == sizeof(notify))
+		return;
+
+	unix_sock_event_listener_free(listener);
+}
+
+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,
+			    const uint8_t source[ETH_ALEN])
+{
+	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, source);
+	}
+}
