diff --git a/lib/models/Courseware/BlockTypes/IFrame.json b/lib/models/Courseware/BlockTypes/IFrame.json
index c631e24896208ffce46705432339573a7fd6a5aa..0737ab0536f42f7c8475a4455386cb67a2e5ad3e 100644
--- a/lib/models/Courseware/BlockTypes/IFrame.json
+++ b/lib/models/Courseware/BlockTypes/IFrame.json
@@ -3,7 +3,8 @@
     "type": "object",
     "properties": {
         "url": {
-            "type": "string"
+            "type": "string",
+            "format": "uri"
         },
         "title": {
             "type": "string"
@@ -36,4 +37,4 @@
     "required": [
     ],
     "additionalProperties": true
-}
\ No newline at end of file
+}
diff --git a/resources/vue/components/courseware/blocks/CoursewareIframeBlock.vue b/resources/vue/components/courseware/blocks/CoursewareIframeBlock.vue
index d628b12e78c24e99b855d64d6694e2b18643b7b0..be56ab413f201a82c29a41286dc6559e9d31ea2d 100644
--- a/resources/vue/components/courseware/blocks/CoursewareIframeBlock.vue
+++ b/resources/vue/components/courseware/blocks/CoursewareIframeBlock.vue
@@ -39,7 +39,7 @@
                             </label>
                             <label>
                                 {{ $gettext('URL') }}
-                                <input type="text" v-model="currentUrl" @change="setProtocol" />
+                                <input type="text" v-model="currentUrl" @change="updateUrl" />
                             </label>
                             <label>
                                 {{ $gettext('Höhe') }}
@@ -139,6 +139,7 @@ export default {
         return {
             currentTitle: '',
             currentUrl: '',
+            currentUrlIsValid: true,
             currentHeight: '',
             currentSubmitUserId: '',
             currentSubmitParam: '',
@@ -198,6 +199,7 @@ export default {
     },
     methods: {
         ...mapActions({
+            companionError: 'companionError',
             updateBlock: 'updateBlockInContainer',
         }),
         initCurrentData() {
@@ -228,8 +230,35 @@ export default {
                 }
             }
         },
+        validateUrl() {
+            this.currentUrlIsValid = this.isValidUrl(this.currentUrl);
+        },
+        isValidUrl(urlString) {
+            const urlPattern = new RegExp(
+                '^(https?:\\/\\/)?' + // validate protocol
+                    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
+                    '((\\d{1,3}\\.){3}\\d{1,3}))' + // validate OR ip (v4) address
+                    '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
+                    '(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
+                    '(\\#[-a-z\\d_]*)?$',
+                'i'
+            ); // validate fragment locator
+
+            return !!urlPattern.test(urlString);
+        },
+
+        updateUrl() {
+            this.setProtocol();
+            this.validateUrl();
+        },
 
         storeBlock() {
+            if (!this.currentUrlIsValid) {
+                this.companionError({
+                    info: this.$gettext('Bitte geben Sie eine gültige URL ein.')
+                });
+                return false;
+            }
             let attributes = {};
             attributes.payload = {};
             attributes.payload.title = this.currentTitle;