diff --git a/src/providers/views.py b/src/providers/views.py
index eb08c6242bcdfd2b374db046b5d629afd48a104a..462598af26736975f58a0049ab14210548d2594a 100644
--- a/src/providers/views.py
+++ b/src/providers/views.py
@@ -335,6 +335,52 @@ class CheckAnalyticsTokenNameAvailable(APIView):
         )
 
 
+def get_system_statement_query(providers=[]):
+    """
+    :param providers: optional list of providers to filter system statements by
+    :return: query object which filters for system statements and optionally the supplied providers
+    """
+    query = {"$and": [
+            {"actor.mbox": {"$exists": True}}
+        ]}
+    if len(providers) > 0:
+        provider_filters = []
+        for provider in providers:
+            provider_filters.append("system:" + str(provider.id))
+        query["$and"].append({"actor.mbox": {"$in": provider_filters}})
+    else:
+        query["$and"].append({"actor.mbox": {"$regex": "^system"}})
+
+    return query
+
+
+def get_system_statements(collection, providers=[]):
+    """
+    Filters statements in LRS db by special system user and optionally a list of providers.
+
+    :param providers: optional list of provider objects used for selecting relevant system statements
+    :param collection: lrs database containing xapi statements
+    :return: all relevant statements
+    """
+
+    system_statement_query = get_system_statement_query(providers)
+    return collection.find(system_statement_query)
+
+
+def replace_provider_id(statement, providers):
+    if statement.get("actor", {}).get("mbox", "").startswith("system:"):
+        provider_id = int((statement.get("actor", {}).get("mbox", "").split("system:"))[1])
+        provider = next((x for x in providers if x.id == provider_id), None)
+        if provider:
+            statement["actor"]["mbox"] = "system:" + provider.name
+        else:
+            # fallback - return unmodified statement
+            return statement
+    else:
+        return statement
+
+
+
 class GetProviderData(APIView):
     """
     Endpoint that allows an analytics engine to obtain provider statements from the lrs.
@@ -403,7 +449,7 @@ class GetProviderData(APIView):
                             anon_verbs.append(verb)
 
             # selects for anonymized statements of which there are enough different actors
-            # or explicitly non-anonymized statements
+            # or explicitly non-anonymized statements / system statements
             anon_query = {"$or": [
                             # current statement is anonymized and
                             # enough anonymized statements for this verb exist
@@ -418,7 +464,9 @@ class GetProviderData(APIView):
                                 {"$and": [
                                     {"actor.mbox": {"$exists": False}},
                                     {"actor.mbox": {"$regex": "^mailto"}},
-                                ]}
+                                ]},
+                                # also query for system statements added by relevant providers
+                                get_system_statement_query(providers)
                             ]}
                         ]}
 
@@ -443,7 +491,7 @@ class GetProviderData(APIView):
             cursor = collection.find(query).limit(page_size)
             data = {
                 "verbs": list(set(active_verbs)),
-                "statements": list(cursor),
+                "statements": list(map(replace_provider_id, list(cursor))),
                 "page_size": page_size,
             }
 
diff --git a/src/xapi/tests/tests.py b/src/xapi/tests/tests.py
index 1279ad164e23af1a3422257304eec707397c844b..4467c61f5627b96c6fad2bd447ec25ee79594841 100644
--- a/src/xapi/tests/tests.py
+++ b/src/xapi/tests/tests.py
@@ -2,6 +2,7 @@ import json
 import os
 from datetime import datetime
 from io import StringIO
+from unittest import mock
 from unittest.mock import patch
 
 from django.core.exceptions import ObjectDoesNotExist
@@ -173,6 +174,43 @@ class XAPITestCase(TestCase):
         # )
         # self.assertEqual(response.status_code, 403)
 
+    @patch("xapi.views.store_in_db", mock_store_in_lrs)
+    def test_system_user(self):
+        try:
+            provider = Provider.objects.order_by("id").first()
+        except ObjectDoesNotExist:
+            self.assertTrue(False)  # provider was not created when uploading schema
+
+        keys = [
+            auth.key for auth in ProviderAuthorization.objects.filter(provider=provider)
+        ]
+        self.assertTrue(len(keys) > 0)  # keys were not created
+        key = keys[0]
+
+        provider_client = APIClient()
+        provider_client.credentials(HTTP_AUTHORIZATION="Basic " + key)
+
+
+        response = provider_client.post(
+            "/xapi/statements",
+            {
+                "actor": {"mbox": f"system:{provider.id}"},
+                "verb": {"id": "some_id"},
+                "object": {
+                    "id": "some_other_id",
+                    "objectType": "Activity",
+                    "definition": "object_definition",
+                },
+                "timestamp": datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"),
+            },
+            format="json",
+        )
+        self.assertEqual(response.status_code, 200)
+
+        # {'message': 'processed', 'provider': 'H5P'}
+        self.assertEqual(
+            response.json()["message"], "xAPI statements successfully stored in LRS"
+        )
 
 class TestxAPIWithDataRecordingPause(BaseTestCase):
     @patch("xapi.views.store_in_db", mock_store_in_lrs)
diff --git a/src/xapi/views.py b/src/xapi/views.py
index 3c4550f7f427d37a8ecb7d95815f65241f97a060..4af3b782062a9b77b3e71a87599925342ff3a361 100644
--- a/src/xapi/views.py
+++ b/src/xapi/views.py
@@ -56,6 +56,13 @@ def process_statement(x_api_statement, provider, latest_schema):
     except ValidationError as e:
         return {"valid": False, "accepted": False, "reason": e.message}
 
+    # system statements are directly stored without checking for consent
+    if x_api_statement.get("actor", {}).get("mbox", "").startswith("system:"):
+        if int((x_api_statement.get("actor", {}).get("mbox", "").split("system:"))[1]) == provider.id:
+            return {"valid": True, "accepted": True}
+        else:
+            return {"valid": False, "accepted": False, "reason": "Wrong provider ID"}
+
     mbox = dict(
         enumerate(x_api_statement.get("actor", {}).get("mbox", "").split("mailto:"))
     ).get(1)
@@ -85,7 +92,7 @@ def process_statement(x_api_statement, provider, latest_schema):
 
     # essential verbs do not require consent
     if not verb in [verb["id"] for verb in latest_schema.essential_verbs]:
-	
+
         anon_verbs = [verb["id"] for verblist in [group["verbs"] for group in latest_schema.groups] for verb in verblist if verb.get("allowAnonymizedCollection", False)]
 
         # has the user paused data collection altogether?