diff --git a/Makefile b/Makefile
index 63557f7087aabf66b1061fa96339ba268ba73431..88f9f38a0b3d64f69e168c089014251631a27284 100644
--- a/Makefile
+++ b/Makefile
@@ -56,7 +56,7 @@ generate-csbi-yang-models: install-tools
 	../../$(TOOLS_DIR)/go-ygot-generator-generator config.yaml gostructs.go &&\
 	go generate
 
-build: pre build-gosdn build-gosdnc build-orchestrator build-venv-manager build-arista-routing-engine-app build-hostname-checker-app
+build: pre build-gosdn build-gosdnc build-orchestrator build-venv-manager build-arista-routing-engine-app build-hostname-checker-app build-basic-interface-monitoring-app
 
 build-gosdn: pre
 	$(GOBUILD) -trimpath -o $(BUILD_ARTIFACTS_PATH)/gosdn ./controller/cmd/gosdn
@@ -76,6 +76,9 @@ build-arista-routing-engine-app: pre
 build-hostname-checker-app: pre
 	$(GOBUILD) -trimpath -o $(BUILD_ARTIFACTS_PATH)/hostname-checker ./applications/hostname-checker
 
+build-basic-interface-monitoring-app: pre
+	$(GOBUILD) -trimpath -o $(BUILD_ARTIFACTS_PATH)/basic-interface-monitoring ./applications/basic-interface-monitoring
+
 containerize-all: containerize-gosdn containerize-gosdnc containerize-orchestrator containerize-target
 
 containerize-gosdn:
diff --git a/application-framework/event/eventService.go b/application-framework/event/eventService.go
index b71c0541e790124603cc4d3f6dc65123d5fa70fc..9edf6b7096a22f59b17dbd6092db15df8874df55 100644
--- a/application-framework/event/eventService.go
+++ b/application-framework/event/eventService.go
@@ -115,9 +115,7 @@ func (e *Service) setupQueueConsume(topic string, stopChan chan os.Signal) error
 
 			val, ok := e.subscriber[parseTypeString(event.Type)]
 			if ok {
-				fmt.Print("Executing Callback: ")
 				val(event)
-				fmt.Println()
 			}
 		}
 	}()
diff --git a/applications/basic-interface-monitoring/app.go b/applications/basic-interface-monitoring/app.go
new file mode 100644
index 0000000000000000000000000000000000000000..9f82cca697694241c8016bfec2df56fd016632ce
--- /dev/null
+++ b/applications/basic-interface-monitoring/app.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/signal"
+	"syscall"
+
+	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"
+
+	"code.fbi.h-da.de/danet/gosdn/application-framework/event"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+)
+
+// Application is an example for a sdn application.
+type Application struct {
+	eventServiceNetworkElements event.ServiceInterface
+	stopChannel                 chan os.Signal
+	grpcClientConn              *grpc.ClientConn
+}
+
+// Run runs the application.
+func (a *Application) Run(controllerAddress string) {
+	statusMap = make(map[string]map[string]*InterfaceStatus)
+
+	signal.Notify(a.stopChannel, os.Interrupt, syscall.SIGTERM)
+
+	a.eventServiceNetworkElements.SubscribeToEventType([]event.TypeToCallbackTuple{
+		{Type: event.Update, Callback: a.NetworkElementCallback},
+	})
+	a.eventServiceNetworkElements.SetupEventReciever(a.stopChannel)
+
+	conn, err := grpc.Dial(controllerAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		panic(err)
+	}
+
+	a.grpcClientConn = conn
+
+	var forever chan struct{}
+
+	go func() {
+		for {
+			select {
+			case <-a.stopChannel:
+				close(forever)
+				_ = a.grpcClientConn.Close()
+
+				return
+			}
+		}
+	}()
+
+	if err := StartHTTPServer(); err != nil {
+		panic(err)
+	}
+
+	<-forever
+}
+
+// NetworkElementCallback is the callback function for network element changes.
+func (a *Application) NetworkElementCallback(event *event.Event) {
+	networkElementServer := networkelement.NewNetworkElementServiceClient(a.grpcClientConn)
+
+	changedInterfaces, err := checkIfOperationStateHasChanged(networkElementServer, event.EntityID)
+	if err != nil {
+		fmt.Printf("Error %+v\n ", err)
+	}
+
+	if changedInterfaces != nil {
+		for _, changedInterface := range changedInterfaces {
+			fmt.Printf("Change on %s: status of interface %s has changed to %s\n", changedInterface.NetworkElementName, changedInterface.Name, changedInterface.Status)
+		}
+	}
+}
diff --git a/applications/basic-interface-monitoring/http.go b/applications/basic-interface-monitoring/http.go
new file mode 100644
index 0000000000000000000000000000000000000000..6e7d35f868958bbcc07290d5ec9664c87e7571b3
--- /dev/null
+++ b/applications/basic-interface-monitoring/http.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+)
+
+// based on https://community.hetzner.com/tutorials/real-time-apps-with-go-and-reactjs/server-sent-events
+
+var clientChannels = make(map[chan []byte]bool)
+
+// StartHTTPServer starts the HTTP server to provide the monitoring page.
+func StartHTTPServer() error {
+	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		http.ServeFile(w, r, indexPath)
+	})
+	http.HandleFunc("/sse", sseHandler)
+
+	if err := http.ListenAndServe(":4000", nil); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func sseHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Connection", "keep-alive")
+	w.Header().Set("Content-Type", "text/event-stream")
+	w.Header().Set("Access-Control-Allow-Origin", "*")
+
+	clientChannel := make(chan []byte)
+	clientChannels[clientChannel] = true
+
+	for {
+		select {
+		case update := <-clientChannel:
+			test := fmt.Sprintf("data: %s\n\n", string(update))
+			w.Write([]byte(test))
+			w.(http.Flusher).Flush()
+		case <-r.Context().Done():
+			delete(clientChannels, clientChannel)
+			return
+		}
+	}
+}
diff --git a/applications/basic-interface-monitoring/main.go b/applications/basic-interface-monitoring/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..5f451c99a2287e7be7a3e3cd46b42c6dc39d6f5e
--- /dev/null
+++ b/applications/basic-interface-monitoring/main.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+	"flag"
+	"os"
+
+	"code.fbi.h-da.de/danet/gosdn/application-framework/event"
+	"code.fbi.h-da.de/danet/gosdn/application-framework/registration"
+	"github.com/sirupsen/logrus"
+)
+
+var controllerAddress string
+var indexPath string
+
+func main() {
+	flag.StringVar(&indexPath, "path", "webpage/index.html", "path to the webpage index.html file")
+	flag.StringVar(&controllerAddress, "controller-address", "localhost:55055", "the address to the controller")
+
+	flag.Parse()
+
+	queueCredentials, err := registration.Register(controllerAddress, "basic-interface-monitoring", "SecurePresharedToken")
+	if err != nil {
+		logrus.Errorf("failed to register application on control plane. %v", err)
+		os.Exit(1)
+	}
+
+	eventServiceNetworkElements, err := event.NewEventService(
+		queueCredentials,
+		[]event.Topic{event.ManagedNetworkElement},
+	)
+	if err != nil {
+		logrus.Errorf("failed to create event service. %v", err)
+		os.Exit(1)
+	}
+
+	app := &Application{
+		eventServiceNetworkElements: eventServiceNetworkElements,
+		stopChannel:                 make(chan os.Signal, 1),
+	}
+
+	app.Run(controllerAddress)
+}
diff --git a/applications/basic-interface-monitoring/network-element.go b/applications/basic-interface-monitoring/network-element.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2993a25a680e46528133f4123d185dd3710fa63
--- /dev/null
+++ b/applications/basic-interface-monitoring/network-element.go
@@ -0,0 +1,137 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"
+	"code.fbi.h-da.de/danet/gosdn/application-framework/models"
+	"code.fbi.h-da.de/danet/gosdn/models/generated/arista"
+
+	"github.com/google/uuid"
+	"github.com/openconfig/ygot/ygot"
+	"github.com/openconfig/ygot/ytypes"
+)
+
+var statusMap map[string]map[string]*InterfaceStatus
+
+// NetworkElement is a NetworkElement.
+type NetworkElement struct {
+	// UUID represents the network element's UUID
+	UUID uuid.UUID
+
+	// Name is the network element's human readable Name
+	Name string
+
+	// Model embeds a ygot.GoStruct containing the network element details
+	Model arista.Device
+}
+
+// NewNetworkElement creates a new NetworkElement.
+func NewNetworkElement(id uuid.UUID, name string, networkElementModel string) *NetworkElement {
+	d := &NetworkElement{
+		UUID:  id,
+		Model: arista.Device{},
+		Name:  name,
+	}
+
+	// Create 'root' path to be able to load the whole model from the store.
+	path, err := ygot.StringToPath("/", ygot.StructuredPath)
+	if err != nil {
+		panic(err)
+	}
+
+	opts := []ytypes.UnmarshalOpt{
+		&ytypes.IgnoreExtraFields{},
+	}
+	// Use unmarshall from the network elements model to unmarshall ygot json in go struct.
+	err = models.Unmarshal([]byte(networkElementModel), path, &d.Model, opts...)
+	if err != nil {
+		panic(err)
+	}
+
+	return d
+}
+
+// InterfaceStatus contains information of an interface.
+type InterfaceStatus struct {
+	NetworkElementName string
+	Name               string
+	Status             string
+}
+
+func checkIfOperationStateHasChanged(networkElementServer networkelement.NetworkElementServiceClient, networkElementID uuid.UUID) ([]InterfaceStatus, error) {
+	ctx := context.Background()
+
+	request := &networkelement.GetNetworkElementRequest{
+		Timestamp:        time.Now().UnixNano(),
+		NetworkElementId: networkElementID.String(),
+	}
+
+	resp, err := networkElementServer.Get(ctx, request)
+	if err != nil {
+		return nil, err
+	}
+
+	networkElement := NewNetworkElement(uuid.MustParse(resp.NetworkElement.Id), resp.NetworkElement.Name, resp.NetworkElement.Model)
+
+	storedInterfaces, ok := statusMap[networkElement.Name]
+	if !ok {
+		addNetworkElementToStatusMap(networkElement.Name, networkElement.Model.Interfaces.Interface)
+		return nil, nil
+	}
+
+	return walkThroughInterfaces(networkElement.Model.Interfaces.Interface, storedInterfaces)
+}
+
+func addNetworkElementToStatusMap(networkElementName string, interfaces map[string]*arista.OpenconfigInterfaces_Interfaces_Interface) {
+	statusList := make(map[string]*InterfaceStatus)
+
+	for _, receivedInterface := range interfaces {
+		statusList[*receivedInterface.Name] = &InterfaceStatus{
+			NetworkElementName: networkElementName,
+			Name:               *receivedInterface.Name,
+			Status:             receivedInterface.State.OperStatus.String(),
+		}
+	}
+
+	statusMap[networkElementName] = statusList
+}
+
+func walkThroughInterfaces(interfaces map[string]*arista.OpenconfigInterfaces_Interfaces_Interface, storedInterfaces map[string]*InterfaceStatus) ([]InterfaceStatus, error) {
+	statusList := make([]InterfaceStatus, 0)
+
+	for _, receivedInterface := range interfaces {
+		storedInterface, ok := storedInterfaces[*receivedInterface.Name]
+		if !ok {
+			return statusList, fmt.Errorf("could not find %s in stored interfaces", *receivedInterface.Name)
+		}
+
+		if storedInterface.Status != receivedInterface.State.OperStatus.String() {
+			statusList = append(statusList, InterfaceStatus{
+				NetworkElementName: storedInterface.NetworkElementName,
+				Name:               *receivedInterface.Name,
+				Status:             receivedInterface.State.OperStatus.String(),
+			})
+
+			storedInterface.Status = receivedInterface.State.OperStatus.String()
+
+			statusMapCopy := statusMap
+
+			go func() {
+				b, err := json.Marshal(statusMapCopy)
+				if err != nil {
+					fmt.Println("error: ", err)
+					return
+				}
+				for clientChannel := range clientChannels {
+					clientChannel <- []byte(b)
+				}
+			}()
+		}
+	}
+
+	return statusList, nil
+}
diff --git a/applications/basic-interface-monitoring/webpage/index.html b/applications/basic-interface-monitoring/webpage/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..7e8d3fc2d528471a8bed7950a2059f87fb90d6ed
--- /dev/null
+++ b/applications/basic-interface-monitoring/webpage/index.html
@@ -0,0 +1,111 @@
+<script type="text/javascript">
+    let lastStateNetworkElementMap = new Map()
+
+    const eventListener = new EventSource("http://localhost:4000/sse")
+    eventListener.onmessage = (event) => {
+        const content = document.querySelector('.content');
+
+        data = JSON.parse(event.data);
+
+        contentInnerHTML = "";
+
+        for (let networkElementName in data) {
+            let interfaces = data[networkElementName];
+
+            contentInnerHTML += "<h1>" + networkElementName + "</h1>";
+
+            contentInnerHTML += '<div class="flex-container">';
+
+            let interfaceArray = new Array()
+            for (let interfaceName in interfaces) {
+                interfaceArray.push(interfaces[interfaceName])
+            }
+
+            interfaceArray = interfaceArray.filter((interface) => {
+                return !interface.Name.includes("/")
+            })
+
+            interfaceArray.sort((a,b) => {
+                interfaceA = parseInt(a.Name.split("Ethernet")[1])
+                interfaceB = parseInt(b.Name.split("Ethernet")[1])
+                return interfaceB < interfaceA
+            })
+
+            console.log(lastStateNetworkElementMap.get(networkElementName))
+
+
+            const lastStateArray = lastStateNetworkElementMap.get(networkElementName)
+
+            interfaceArray.forEach( (interface, index) => {
+                contentInnerHTML += "<div"
+                if (lastStateArray != undefined) {
+                    if (interface.Status != lastStateArray[index].Status) {
+                        contentInnerHTML += ` class="changed"`
+                    }
+                }
+                contentInnerHTML += "><p>" + interface.Name + "</p>";
+                if (interface.Status == "UP") {
+                    contentInnerHTML += '<p class="green">' + interface.Status + "</p>";
+                } else {
+                    contentInnerHTML += '<p class="red">' + interface.Status + "</p>";
+                }
+                contentInnerHTML += "</div>";
+            })
+
+            lastStateNetworkElementMap.set(networkElementName, interfaceArray)
+
+            contentInnerHTML += "</div>";
+        }
+
+        content.innerHTML = contentInnerHTML;
+    }
+</script>
+
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.flex-container {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.flex-container > div {
+  background-color: grey;
+  width: 250px;
+  margin: 10px;
+  text-align: center;
+  font-size: 30px;
+}
+
+.red {
+    color: white;
+    background-color: red;
+}
+
+.green {
+    color: white;
+    background-color: green;
+}
+
+.changed {
+    outline:10px dashed transparent;
+    animation: changed 1s step-end 12;
+}
+
+@keyframes changed {
+    from, to {
+        outline-color: transparent
+    }
+    50% {
+        outline-color: blue
+    }
+}
+</style>
+</head>
+<body>
+
+<div class="content"></div>
+
+</body>
+</html>
diff --git a/go.mod b/go.mod
index 96832340527fb2e276790b86347497b971aa9c11..ebd186120a587195b9340d514202208c5374b69c 100644
--- a/go.mod
+++ b/go.mod
@@ -90,7 +90,7 @@ require (
 	go.opencensus.io v0.23.0 // indirect
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
 	golang.org/x/net v0.0.0-20220728030405-41545e8bf201
-	golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
+	golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
diff --git a/go.sum b/go.sum
index 0b4b959c6f001f7bc317e200ddabe2f4b67bc521..58d7445567bb55cbf4f109bb8fb4486f93cc7f4c 100644
--- a/go.sum
+++ b/go.sum
@@ -1282,8 +1282,8 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
-golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM=
+golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=