diff --git a/packages/app-shell/src/app-shell.js b/packages/app-shell/src/app-shell.js
index 95f4ed511b45ef3e73d9b0ca7016bbc68c84f179..76fd41f4bf229f012384e5856bf0516b8c854e2a 100644
--- a/packages/app-shell/src/app-shell.js
+++ b/packages/app-shell/src/app-shell.js
@@ -50,6 +50,7 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
         this.subtitle = '';
         this.description = '';
         this.routes = [];
+        this.visibleRoutes = [];
         this.metadata = {};
         this.topic = {};
         this.basePath = '/';
@@ -236,6 +237,7 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
             entryPointUrl: { type: String, attribute: 'entry-point-url' },
             keycloakConfig: { type: Object, attribute: 'keycloak-config' },
             metadata: { type: Object, attribute: false },
+            visibleRoutes:  { type: Array, attribute: false },
             topic: { type: Object, attribute: false },
             subtitle: { type: String, attribute: false },
             description: { type: String, attribute: false },
@@ -291,6 +293,11 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
                     this.subtitle = this.activeMetaDataText("short_name");
                     this.description = this.activeMetaDataText("description");
                 break;
+                case 'metadata':
+                {
+                    this._updateVisibleRoutes();
+                }
+                break;
                 case 'auth':
                 {
                     if (this.auth.person) {
@@ -298,6 +305,7 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
                     } else {
                         this._roles = [];
                     }
+                    this._updateVisibleRoutes();
 
                     const loginStatus = this.auth['login-status'];
                     if (loginStatus !== this._loginStatus) {
@@ -770,6 +778,36 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
         return elm;
     }
 
+    _updateVisibleRoutes() {
+        let visibleRoutes = [];
+
+        for (let routingName of this.routes) {
+            const data = this.metadata[routingName];
+            const requiredRoles = data['required_roles'];
+            let visible = data['visible'];
+
+            // Hide them until the user is logged in and we know the roles of the user
+            for (let role of requiredRoles) {
+                if (!this._roles.includes(role)) {
+                    visible = false;
+                    break;
+                }
+            }
+
+            if (visible) {
+                visibleRoutes.push(routingName);
+            }
+        }
+
+        this.visibleRoutes = visibleRoutes;
+
+        const event = new CustomEvent("visibility-changed", {
+            bubbles: false,
+            cancelable: true,
+        });
+        this.dispatchEvent(event);
+    }
+
     render() {
         const getSelectClasses = (name => {
             return classMap({selected: this.activeView === name});
@@ -797,22 +835,8 @@ export class AppShell extends ScopedElementsMixin(AdapterLitElement) {
 
         // build the menu
         let menuTemplates = [];
-        for (let routingName of this.routes) {
-            const data = this.metadata[routingName];
-            const requiredRoles = data['required_roles'];
-            let visible = data['visible'];
-
-            // Hide them until the user is logged in and we knwo the roles of the user
-            for (let role of requiredRoles) {
-                if (!this._roles.includes(role)) {
-                    visible = false;
-                    break;
-                }
-            }
-
-            if (visible) {
-                menuTemplates.push(html`<li><a @click="${(e) => this.onMenuItemClick(e)}" href="${this.router.getPathname({component: routingName})}" data-nav class="${getSelectClasses(routingName)}" title="${this.metaDataText(routingName, "description")}">${this.metaDataText(routingName, "short_name")}</a></li>`);
-            }
+        for (let routingName of this.visibleRoutes) {
+            menuTemplates.push(html`<li><a @click="${(e) => this.onMenuItemClick(e)}" href="${this.router.getPathname({component: routingName})}" data-nav class="${getSelectClasses(routingName)}" title="${this.metaDataText(routingName, "description")}">${this.metaDataText(routingName, "short_name")}</a></li>`);
         }
 
         const imprintUrl = this.lang === "en" ?
diff --git a/packages/app-shell/src/dbp-app-shell-welcome.js b/packages/app-shell/src/dbp-app-shell-welcome.js
index b2f1b3b17f823cbaf4dbcd41a593792c7f0f01da..2397905ba095d39b3bc977a694c1eb151e58a55c 100644
--- a/packages/app-shell/src/dbp-app-shell-welcome.js
+++ b/packages/app-shell/src/dbp-app-shell-welcome.js
@@ -11,6 +11,8 @@ class AppShellWelcome extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
         this.lang = i18n.language;
+
+        this._onVisibilityChanged = this._onVisibilityChanged.bind(this);
     }
 
     static get properties() {
@@ -54,9 +56,26 @@ class AppShellWelcome extends ScopedElementsMixin(LitElement) {
         `;
     }
 
+    _onVisibilityChanged() {
+        this.requestUpdate();
+    }
+
+    connectedCallback() {
+        super.connectedCallback();
+
+        const app = AppShellWelcome._app;
+        app.addEventListener('visibility-changed', this._onVisibilityChanged);
+    }
+
+    disconnectedCallback() {
+        const app = AppShellWelcome._app;
+        app.removeEventListener('visibility-changed', this._onVisibilityChanged);
+
+        super.disconnectedCallback();
+    }
+
     render() {
         const app = AppShellWelcome._app;
-        let metadata = app.metadata;
         let itemTemplates = [];
 
         const switchActivity = (e, data) => {
@@ -64,9 +83,10 @@ class AppShellWelcome extends ScopedElementsMixin(LitElement) {
             app.switchComponent(data.routing_name);
         };
 
-        for (let [key, data] of Object.entries(metadata)) {
+        for (let routeName of app.visibleRoutes) {
+            let data = app.metadata[routeName];
 
-            if (data['visible'] && (key !== "welcome")) {
+            if (routeName !== "welcome") {
                 itemTemplates.push(html`
                     <div class="item">
                         <h2><a href="#" @click=${(e) => {switchActivity(e, data);}}>${data.name[this.lang]}</a></h2>