diff --git a/compendium_v2/routes/survey.py b/compendium_v2/routes/survey.py
index 4781ba8b098e42b363c8c03d062982e4a9773019..daa3921c827ec8509988f37ee377daf243cd0249 100644
--- a/compendium_v2/routes/survey.py
+++ b/compendium_v2/routes/survey.py
@@ -266,6 +266,19 @@ def get_survey(year, all_visible) -> Any:
 
     survey_json = prepare_survey_model(survey.survey, year, all_visible)
 
+    def visible_visitor(object, items):
+        for key, value in items:
+            if type(value) == dict:
+                visible_visitor(value, value.items())
+            elif type(value) == list:
+                visible_visitor(value, enumerate(value))
+            elif key == 'visibleIf':
+                object['title'] = object['title'] + ' (visibleif: [' + value.replace('{', '#').replace('}', '#') + '])'
+                object[key] = 'true'
+
+    if all_visible:
+        visible_visitor(survey, survey.items())
+
     return jsonify({
         "model": survey_json,
         "data": None,
@@ -337,32 +350,6 @@ def prepare_survey_model(survey, year, all_visible=False):
         with p.open('r') as f:
             survey = json.load(f)
 
-    replacements = {
-        "[%websiteurlregex%]":
-            r"^(https?:\/\/)?([\da-zA-Z\.-]+\.[a-zA-Z\.]{2,6}|[\d\.]+)([\/:?=&#%]{1}[\d_a-zA-Z\.-]+)*[\/\?]?$",
-        "[%lastyear%]": str(year - 1),
-        "[%surveyyear%]": str(year)
-    }
-
-    def replacer(string):
-        for key, replacement in replacements.items():
-            string = string.replace(key, replacement)
-        return string
-
-    def visitor(object, items):
-        for key, value in items:
-            if type(value) == dict:
-                visitor(value, value.items())
-            elif type(value) == list:
-                visitor(value, enumerate(value))
-            elif all_visible and key == 'visibleIf':
-                object['title'] = object['title'] + ' (visibleif: [' + value.replace('{', '#').replace('}', '#') + '])'
-                object[key] = 'true'
-            elif type(value) == str:
-                object[key] = replacer(value)
-
-    visitor(survey, survey.items())
-
     return survey
 
 
diff --git a/compendium_v2/routes/survey_model.json b/compendium_v2/routes/survey_model.json
index a8ef9d65e8f1fec02e17a7b9433a5ef6a1bb080f..fd177aeab6376fd96fc91e1d317b6422f250eec5 100644
--- a/compendium_v2/routes/survey_model.json
+++ b/compendium_v2/routes/survey_model.json
@@ -13,8 +13,8 @@
       {
        "type": "text",
        "name": "budget",
-       "title": "What is your NRENs budget for [%lastyear%] or [%lastyear%]/[%surveyyear%] in million euro?",
-       "description": "If your budget is not per calendar year, please provide figures for the budget that covers the largest part of [%lastyear%] including GEANT subsidy.",
+       "title": "What is your NRENs budget for {previousyear} or {previousyear}/{surveyyear} in million euro?",
+       "description": "If your budget is not per calendar year, please provide figures for the budget that covers the largest part of {previousyear} including GEANT subsidy.",
        "validators": [
         {
          "type": "numeric",
@@ -25,7 +25,7 @@
       {
        "type": "multipletext",
        "name": "income_sources",
-       "title": "Estimate (in % of income) the sources of your NREN-related income for [%lastyear%] or [%lastyear%]/[%surveyyear%].",
+       "title": "Estimate (in % of income) the sources of your NREN-related income for {previousyear} or {previousyear}/{surveyyear}.",
        "description": "European Funding should include GÉANT funding.",
        "validators": [
         {
@@ -342,9 +342,9 @@
        "inputType": "url",
        "validators": [
         {
-         "type": "regex",
-         "text": "Please provide a single valid url",
-         "regex": "[%websiteurlregex%]"
+         "type": "expression",
+         "text": "Please provide a single valid website url including http:// or https://",
+         "expression": "validateWebsiteUrl({website})"
         }
        ]
       }
@@ -383,9 +383,9 @@
        "inputType": "url",
        "validators": [
         {
-         "type": "regex",
-         "text": "Please provide a single valid url",
-         "regex": "[%websiteurlregex%]"
+         "type": "expression",
+         "text": "Please provide a single valid website url including http:// or https://",
+         "expression": "validateWebsiteUrl({corporate_strategy_url})"
         }
        ]
       },
@@ -414,9 +414,9 @@
          "inputType": "url",
          "validators": [
           {
-           "type": "regex",
-           "text": "Please provide a single valid url",
-           "regex": "[%websiteurlregex%]"
+           "type": "expression",
+           "text": "Please provide a single valid website url including http:// or https://",
+           "expression": "validateWebsiteUrl({row.url})"
           }
          ]
         }
@@ -469,7 +469,7 @@
        "name": "central_procurement_amount",
        "visibleIf": "{central_software_procurement} = 'yes'",
        "indent": 1,
-       "title": "What is the total amount (in Euro) that you procured in [%lastyear%] or [%lastyear%]/[%surveyyear%] on behalf of your customers?",
+       "title": "What is the total amount (in Euro) that you procured in {previousyear} or {previousyear}/{surveyyear} on behalf of your customers?",
        "validators": [
         {
          "type": "numeric",
@@ -789,9 +789,9 @@
          "inputType": "url",
          "validators": [
           {
-           "type": "regex",
-           "text": "Please provide a single valid url",
-           "regex": "[%websiteurlregex%]"
+           "type": "expression",
+           "text": "Please provide a single valid website url including http:// or https://",
+           "expression": "validateWebsiteUrl({row.connected_sites_url})"
           }
          ]
         }
@@ -1563,10 +1563,10 @@
          "inputType": "url",
          "validators": [
           {
-           "type": "regex",
-           "text": "Please provide a single valid url",
-           "regex": "[%websiteurlregex%]"
-            }
+           "type": "expression",
+           "text": "Please provide a single valid website url including http:// or https://",
+           "expression": "validateWebsiteUrl({row.network_map_url})"
+          }
          ]
         }
        ],
@@ -1665,10 +1665,10 @@
          "inputType": "url",
          "validators": [
           {
-           "type": "regex",
-           "text": "Please provide a single valid url",
-           "regex": "[%websiteurlregex%]"
-            }
+           "type": "expression",
+           "text": "Please provide a single valid website url including http:// or https://",
+           "expression": "validateWebsiteUrl({row.traffic_statistics_url})"
+          }
          ]
         }
        ],
@@ -1725,9 +1725,9 @@
        "inputType": "url",
        "validators": [
         {
-         "type": "regex",
-         "text": "Please provide a single valid url",
-         "regex": "[%websiteurlregex%]"
+         "type": "expression",
+         "text": "Please provide a single valid website url including http:// or https://",
+         "expression": "validateWebsiteUrl({network_weather_url})"
         }
        ]
       },
@@ -1905,7 +1905,7 @@
       {
        "type": "multipletext",
        "name": "traffic_estimate",
-       "title": "Please supply an estimate of the total amount of traffic in Terabyte from January to December ([%lastyear%]) for the following: ",
+       "title": "Please supply an estimate of the total amount of traffic in Terabyte from January to December ({previousyear}) for the following: ",
        "items": [
         {
          "name": "from_customers",
diff --git a/survey-frontend/src/SurveyComponent.tsx b/survey-frontend/src/SurveyComponent.tsx
index 511473ac70545580d000b311d19f4363179b06f0..e07d016a896a7bcc67465ea296559dc8bdf0dbc9 100644
--- a/survey-frontend/src/SurveyComponent.tsx
+++ b/survey-frontend/src/SurveyComponent.tsx
@@ -1,5 +1,5 @@
 import React, { useState, useEffect, useRef } from "react";
-import { Model, Serializer, ComputedUpdater, Question } from "survey-core";
+import { Model, Serializer, ComputedUpdater, Question, FunctionFactory } from "survey-core";
 import { Survey } from "survey-react-ui";
 import "survey-core/modern.min.css";
 import './survey.scss';
@@ -100,6 +100,23 @@ function SurveyComponent({ loadFrom, saveTo = '', readonly = false}) {
       survey.mode = 'display';
     }
 
+    function validateWebsiteUrl (params) {
+      const value = params[0];
+      if (value === undefined || value == null || value == '') {
+        return true;
+      }
+      try {
+        const url = new URL(value);
+        return url.protocol === 'http:' || url.protocol === 'https:';
+      } catch (err) {
+        return false;
+      }
+    }
+
+    FunctionFactory.Instance.register("validateWebsiteUrl", validateWebsiteUrl);
+    survey.setVariable('surveyyear', year);
+    survey.setVariable('previousyear', parseInt(year!) - 1);
+
     if (json['data'] !== null) {
       survey.data = json['data'];
       survey.clearIncorrectValues(true);  // TODO test if this really removes all old values and such