diff --git a/.ci/generateIndex.py b/.ci/generateIndex.py
index 13239c37a783621599cc2ba63379dff4bcfd386c..c4d18bc653b46cdc488f56e5ba25a0894f5cffdf 100644
--- a/.ci/generateIndex.py
+++ b/.ci/generateIndex.py
@@ -76,7 +76,10 @@ sections = list(set(sections))
 sections.sort()
 
 # Index contains the generated content, init it with an empty container
-index = '\n<div class="index-box-container">\n'
+index = '<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>\n'
+index += '<script type="text/javascript" src="router.js"></script>\n\n'
+index += '\n<div class="index-box-container">\n'
+
 localIndexArr = [[]] * len(sections)
 for folder in cardDirs:
 
diff --git a/index.md b/index.md
index 2ad3b9d71e845292b2f78ba1e95636aaf2db3b65..5e3919362ac538abd7f2058f9c05caf4cec7a74c 100644
--- a/index.md
+++ b/index.md
@@ -4,6 +4,10 @@ title: Home
 order: 1
 ---
 
+<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
+<script type="text/javascript" src="router.js"></script>
+
+
 # LCSB How-to Cards
 
 The Bioinformatics Core and Lab Support teams assist researchers from the Luxembourg Centre for Systems Biomedicine ([LCSB](https://www.uni.lu/lcsb)) with the organization, management, and curation of research data through its R3 initiative.
@@ -62,4 +66,4 @@ The How-to cards are intended to provide practical guidance in implementing Data
 
 		</ul>
 	</div>
-</div>
\ No newline at end of file
+</div>
diff --git a/router.js b/router.js
new file mode 100644
index 0000000000000000000000000000000000000000..42fc78b321523f0b262fadbe5eafa6f762ae8eeb
--- /dev/null
+++ b/router.js
@@ -0,0 +1,56 @@
+---
+---
+
+function UrlExists(url, cb) {
+    jQuery.ajax({
+        url:      url,
+        dataType: 'text',
+        type:     'GET',
+        cache:    false,
+        complete:  function(xhr){
+            if(typeof cb === 'function')
+            cb.apply(this, [xhr.status]);
+        }
+    });
+}
+
+function GetShortcutDestination() {
+    var s = window.location.href;
+    var pathArray = s.split('?');
+
+    // Cut the query if it exists
+    if (pathArray.length > 1) {
+        return pathArray[1];
+    } else {
+        return '';
+    }
+}
+
+function RedirectTo(newLocation) {
+    document.location.replace(newLocation);
+}
+
+// Pick the shortcut link destination from URL, like: `category:subcategory:card-name`
+var sub = GetShortcutDestination();
+
+
+// If there's a shortcut to handle
+if (sub.length > 0) {
+    var externalCardURL = '/external/cards/' + sub;
+    var internalCardURL = '/internal/cards/' + sub;
+
+    UrlExists(externalCardURL, function(status){
+        if (status == 200) { // The sub-card is external and accessible
+            RedirectTo(externalCardURL);
+        } else {
+            UrlExists(internalCardURL, function(status){
+                if (status == 200) { // The sub-card is internal and accessible
+                    RedirectTo(internalCardURL);
+                } else {
+                    // No external, no internal - probably no access
+                    RedirectTo('/404.html');
+                }
+            })
+        }
+    });
+}