diff --git a/src/app/components/home/_dialogs/cookies/cookies.component.ts b/src/app/components/home/_dialogs/cookies/cookies.component.ts
index 5d69d51863d809bd0808c1b4def2115690ef5775..0f769405fa141921c40372e8baf4547e4c9692d8 100644
--- a/src/app/components/home/_dialogs/cookies/cookies.component.ts
+++ b/src/app/components/home/_dialogs/cookies/cookies.component.ts
@@ -2,6 +2,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angula
 import { DataProtectionComponent } from '../data-protection/data-protection.component';
 import { MatDialog, MatDialogRef } from '@angular/material/dialog';
 import { DialogConfirmActionButtonType } from '../../../shared/dialog/dialog-action-buttons/dialog-action-buttons.component';
+import { EventService } from '../../../../services/util/event.service';
 
 @Component({
   selector: 'app-cookies',
@@ -18,7 +19,10 @@ export class CookiesComponent implements OnInit, AfterViewInit {
 
   confirmButtonType: DialogConfirmActionButtonType = DialogConfirmActionButtonType.Primary;
 
-  constructor(private dialog: MatDialog, private dialogRef: MatDialogRef<CookiesComponent>, private ref: ElementRef) {
+  constructor(private dialog: MatDialog,
+              private dialogRef: MatDialogRef<CookiesComponent>,
+              private ref: ElementRef<HTMLElement>,
+              private eventService: EventService) {
   }
 
   ngOnInit() {
@@ -31,13 +35,14 @@ export class CookiesComponent implements OnInit, AfterViewInit {
 
   ngAfterViewInit() {
     setTimeout(() => {
-      (<HTMLElement>(<HTMLElement>this.ref.nativeElement).getElementsByClassName('mat-dialog-title')[0]).focus();
+      (this.ref.nativeElement.getElementsByClassName('mat-dialog-title')[0] as HTMLElement).focus();
     }, 500);
   }
 
   acceptCookies() {
     localStorage.setItem('cookieAccepted', 'true');
     localStorage.setItem('dataProtectionConsent', 'true');
+    this.eventService.broadcast('dataProtectionConsentUpdate', true);
     this.dialogRef.close(true);
     setTimeout(() => {
       document.getElementById('live_announcer-button').focus();
diff --git a/src/app/components/home/home-page/home-page.component.html b/src/app/components/home/home-page/home-page.component.html
index 8c5816104828c80f81fe72fdb485f14c867d5d22..fa008117e4817c6b01bf947210a67f5dc1a19946 100644
--- a/src/app/components/home/home-page/home-page.component.html
+++ b/src/app/components/home/home-page/home-page.component.html
@@ -1,6 +1,6 @@
 <h1 style="display: none;"
     [joyrideStep]="'greeting'"
-    [appJoyrideTemplate]="true"
+    appJoyrideTemplate
     [stepPosition]="'center'">
 </h1>
 
@@ -39,11 +39,11 @@
   </div>
 
   <h2>
-    <span class="feedback"
-          [joyrideStep]="'feedbackLink'"
-          appJoyrideTemplate
-          [stepPosition]="'top'">
-      <a class="info"
+    <span class="feedback">
+      <a [joyrideStep]="'feedbackLink'"
+         appJoyrideTemplate
+         [stepPosition]="'top'"
+         class="info"
          href="https://frag.jetzt/participant/room/Feedback/comments"
          target="_blank"
          aria-labelledby="feedback-aria">{{ 'login.welcome-feedback' | translate }}
@@ -53,6 +53,7 @@
   </h2>
 
   <button id="live_announcer-button"
+          autofocus
           tabIndex="-1"
           (click)="announce()"
           class="visually-hidden">{{ 'home-page.live-announcer' | translate }}</button>
diff --git a/src/app/components/home/home-page/home-page.component.scss b/src/app/components/home/home-page/home-page.component.scss
index eb98c4c34cf60304d9a1d3a028ae02a58580f587..57268df5858112858ab237b212b972ef84b4387c 100644
--- a/src/app/components/home/home-page/home-page.component.scss
+++ b/src/app/components/home/home-page/home-page.component.scss
@@ -32,6 +32,11 @@
   font-size: 60%;
   text-align: center;
   color: var(--on-background);
+
+  > a {
+    padding: 5px;
+    display: inline;
+  }
 }
 
 @keyframes moveInLeft {
diff --git a/src/app/components/home/home-page/home-page.component.ts b/src/app/components/home/home-page/home-page.component.ts
index 52a27f1a422647c7a8aa639106afb4875eae299f..2f2f9adda75d223286c1fc3770c14fa2ba451457 100644
--- a/src/app/components/home/home-page/home-page.component.ts
+++ b/src/app/components/home/home-page/home-page.component.ts
@@ -1,20 +1,22 @@
-import { Component, OnInit, OnDestroy, Renderer2, AfterContentInit } from '@angular/core';
+import { Component, OnInit, OnDestroy, Renderer2, AfterViewInit } from '@angular/core';
 import { EventService } from '../../../services/util/event.service';
 import { LiveAnnouncer } from '@angular/cdk/a11y';
 import { KeyboardUtils } from '../../../utils/keyboard';
 import { KeyboardKey } from '../../../utils/keyboard/keys';
 import { TranslateService } from '@ngx-translate/core';
 import { OnboardingService } from '../../../services/util/onboarding.service';
+import { Subscription } from 'rxjs';
 
 @Component({
   selector: 'app-home-page',
   templateUrl: './home-page.component.html',
   styleUrls: ['./home-page.component.scss']
 })
-export class HomePageComponent implements OnInit, OnDestroy, AfterContentInit {
+export class HomePageComponent implements OnInit, OnDestroy, AfterViewInit {
 
   deviceType: string;
   listenerFn: () => void;
+  private _eventServiceSubscription: Subscription;
 
   constructor(
     private translateService: TranslateService,
@@ -25,12 +27,6 @@ export class HomePageComponent implements OnInit, OnDestroy, AfterContentInit {
   ) {
   }
 
-  ngAfterContentInit(): void {
-    setTimeout(() => {
-      document.getElementById('live_announcer-button').focus();
-    }, 500);
-  }
-
   ngOnInit() {
     this.deviceType = localStorage.getItem('deviceType');
     if (localStorage.getItem('cookieAccepted')) {
@@ -45,8 +41,22 @@ export class HomePageComponent implements OnInit, OnDestroy, AfterContentInit {
     }
   }
 
+  ngAfterViewInit() {
+    if (localStorage.getItem('dataProtectionConsent') === 'true') {
+      this.onboardingService.startDefaultTour();
+    } else {
+      this._eventServiceSubscription = this.eventService.on<boolean>('dataProtectionConsentUpdate')
+        .subscribe(b => {
+          if (b) {
+            this._eventServiceSubscription.unsubscribe();
+            this._eventServiceSubscription = null;
+            this.onboardingService.startDefaultTour();
+          }
+        });
+    }
+  }
+
   loadListener() {
-    this.onboardingService.startDefaultTour();
     this.listenerFn = this._r.listen(document, 'keyup', (event) => {
       if (KeyboardUtils.isKeyEvent(event, KeyboardKey.Digit1) === true && this.eventService.focusOnInput === false) {
         document.getElementById('session_id-input').focus();
@@ -68,6 +78,9 @@ export class HomePageComponent implements OnInit, OnDestroy, AfterContentInit {
   ngOnDestroy() {
     this.listenerFn();
     this.eventService.makeFocusOnInputFalse();
+    if (this._eventServiceSubscription) {
+      this._eventServiceSubscription.unsubscribe();
+    }
   }
 
   public announce() {
diff --git a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.html b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.html
index 9d8f9ff1d85910c63561220dd7e81c3d29f1354b..463b92d49172d08d1757d7c0ae5862fa998d3d97 100644
--- a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.html
+++ b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.html
@@ -1,14 +1,14 @@
-<ng-template #translateText>
+<ng-template #translateText class="textContainer">
   <h3 *ngIf="title">{{title}}</h3>
   {{text}}
 </ng-template>
 <ng-template #nextButton>
-  <button mat-button class="joy-primary">
+  <button mat-button class="joy-primary" (click)="handle($event, 1)">
     {{'joyride.next' | translate}}
   </button>
 </ng-template>
 <ng-template #prevButton>
-  <button mat-button class="joy-secondary">
+  <button mat-button class="joy-secondary" (click)="handle($event, -1)">
     {{'joyride.prev' | translate}}
   </button>
 </ng-template>
diff --git a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.scss b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.scss
index 268d8d4715f8e471aab058608c4f384bbd46c3c2..8dd983ea0a686d0b6944cf8a06ea34a5174facdf 100644
--- a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.scss
+++ b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.scss
@@ -57,6 +57,10 @@
       stroke: var(--on-dialog);
     }
   }
+
+  .joyride-step__body {
+    hyphens: auto;
+  }
 }
 
 .joy-primary {
diff --git a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.ts b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.ts
index de2b072741651ed3c27f623a92a8e2ecefd37c98..d9657421aac6498d9321ae36e13aed917213ed22 100644
--- a/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.ts
+++ b/src/app/components/shared/_dialogs/joyride-template/joyride-template.component.ts
@@ -2,6 +2,8 @@ import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'
 import { LanguageService } from '../../../../services/util/language.service';
 import { TranslateService } from '@ngx-translate/core';
 import { EventService } from '../../../../services/util/event.service';
+import { OnboardingService } from '../../../../services/util/onboarding.service';
+import { Router } from '@angular/router';
 
 @Component({
   selector: 'app-joyride-template',
@@ -23,7 +25,9 @@ export class JoyrideTemplateComponent implements OnInit {
 
   constructor(private langService: LanguageService,
               private eventService: EventService,
-              private translateService: TranslateService) {
+              private router: Router,
+              private translateService: TranslateService,
+              private onboardingService: OnboardingService) {
     this.langService.langEmitter.subscribe(lang => {
       this.translateService.use(lang);
     });
@@ -39,4 +43,12 @@ export class JoyrideTemplateComponent implements OnInit {
     this.eventService.broadcast('onboarding', 'finished');
   }
 
+  handle(e: MouseEvent, dir: number) {
+    if (this.onboardingService.doStep(dir)) {
+      e.preventDefault();
+      e.stopPropagation();
+    }
+    return false;
+  }
+
 }
diff --git a/src/app/components/shared/comment-list/comment-list.component.html b/src/app/components/shared/comment-list/comment-list.component.html
index 0f38c14e5a693db574fda6d8156ec4282e1a7bb2..0b41ad4d82e2674ab4c4d266e588d64433f87f85 100644
--- a/src/app/components/shared/comment-list/comment-list.component.html
+++ b/src/app/components/shared/comment-list/comment-list.component.html
@@ -36,6 +36,7 @@
   </button>
 
   <div class="button-bar"
+       [ngClass]="{'joyrideActive': isJoyrideActive}"
        [joyrideStep]="'commentFilter'"
        [stepPosition]="'bottom'"
        appJoyrideTemplate
@@ -243,7 +244,7 @@
   <mat-icon>arrow_upward</mat-icon>
 </button>
 
-<div class="fab_add_comment"
+<div id="createCommentJoyrideWrapper"
      [joyrideStep]="'createQuestion'"
      [stepPosition]="'center'"
      appJoyrideTemplate>
diff --git a/src/app/components/shared/comment-list/comment-list.component.scss b/src/app/components/shared/comment-list/comment-list.component.scss
index 7915ecddacd039af8f0fa13cbcbfa97d0d74873b..9dc447656b6f0344c40a348a1f39c4d9fb888670 100644
--- a/src/app/components/shared/comment-list/comment-list.component.scss
+++ b/src/app/components/shared/comment-list/comment-list.component.scss
@@ -1,3 +1,5 @@
+$joyrideElementPadding: 5px;
+
 app-comment {
   overflow: auto;
   overflow-wrap: break-word;
@@ -115,6 +117,11 @@ app-comment {
   margin-right: 2%;
 }
 
+.button-bar.joyrideActive {
+  padding: 15px;
+  margin: unset;
+}
+
 .correct-icon {
   color: var(--green);
 }
@@ -226,9 +233,12 @@ h3 {
   transition: all 0.1s ease-in-out;
 }
 
-div.fab_add_comment {
-  width: 40px;
-  height: 40px;
+#createCommentJoyrideWrapper {
+  position: fixed;
+  width: 56px + 2 * $joyrideElementPadding;
+  height: 56px + 2 * $joyrideElementPadding;
+  right: 17px - $joyrideElementPadding;
+  bottom: 57px - $joyrideElementPadding;
   visibility: hidden;
 }
 
diff --git a/src/app/components/shared/comment-list/comment-list.component.ts b/src/app/components/shared/comment-list/comment-list.component.ts
index 1e577d55b157899c65f92dc36cc705ec10c64830..87dbbd3fd7943fbef55860bc7f14f0c2caaa9d0e 100644
--- a/src/app/components/shared/comment-list/comment-list.component.ts
+++ b/src/app/components/shared/comment-list/comment-list.component.ts
@@ -31,6 +31,7 @@ import { TopicCloudAdminService } from '../../../services/util/topic-cloud-admin
 import { RoomDataService } from '../../../services/util/room-data.service';
 import { WsRoomService } from '../../../services/websockets/ws-room.service';
 import { ActiveUserService } from '../../../services/http/active-user.service';
+import { OnboardingService } from '../../../services/util/onboarding.service';
 
 export interface CommentListData {
   comments: Comment[];
@@ -101,6 +102,7 @@ export class CommentListComponent implements OnInit, OnDestroy {
   commentsEnabled: boolean;
   userNumberSelection = 0;
   createCommentWrapper: CreateCommentWrapper = null;
+  isJoyrideActive = false;
   private _subscriptionEventServiceTagConfig = null;
   private _subscriptionEventServiceRoomData = null;
   private _subscriptionRoomService = null;
@@ -126,7 +128,8 @@ export class CommentListComponent implements OnInit, OnDestroy {
     private topicCloudAdminService: TopicCloudAdminService,
     private roomDataService: RoomDataService,
     private wsRoomService: WsRoomService,
-    private activeUserService: ActiveUserService
+    private activeUserService: ActiveUserService,
+    private onboardingService: OnboardingService
   ) {
     langService.langEmitter.subscribe(lang => {
       translateService.use(lang);
@@ -273,6 +276,7 @@ export class CommentListComponent implements OnInit, OnDestroy {
               this.comments = comments;
               this.getComments();
               this.eventService.broadcast('commentListCreated', null);
+              this.isJoyrideActive = this.onboardingService.startDefaultTour();
             });
             this.subscribeCommentStream();
           });
diff --git a/src/app/components/shared/comment/comment.component.html b/src/app/components/shared/comment/comment.component.html
index 0f7a1c195a3fe506c7a64781e900a14122bb6bb2..1e7139434735eeec40b98ef61076bd1ea165b4b6 100644
--- a/src/app/components/shared/comment/comment.component.html
+++ b/src/app/components/shared/comment/comment.component.html
@@ -328,7 +328,7 @@
           &nbsp;{{comment.tag}}
         </span>
       </div>
-      <div class="user-number"
+      <div class="user-number joyrideActive"
            *ngIf="usesJoyride"
            [joyrideStep]="'commentUserNumber'"
            [stepPosition]="'right'"
diff --git a/src/app/components/shared/comment/comment.component.scss b/src/app/components/shared/comment/comment.component.scss
index 3f20f61d7156e93063d5e860d87d05f7b805a8e1..d4016d05999df61fb84d7b36bfdc227bc7dcfa1b 100644
--- a/src/app/components/shared/comment/comment.component.scss
+++ b/src/app/components/shared/comment/comment.component.scss
@@ -232,6 +232,10 @@ mat-card-content > :first-child {
   color: var(--on-surface);
 }
 
+.user-number.joyrideActive {
+  padding: 5px;
+}
+
 .commentExpanderButton {
   color: var(--on-surface);
 }
diff --git a/src/app/components/shared/header/header.component.html b/src/app/components/shared/header/header.component.html
index 316c6ede2fcfeba0d19d64f80a7a6554f313c052..9385f0ecd22885fda5eb209b88345951db0d0e8d 100644
--- a/src/app/components/shared/header/header.component.html
+++ b/src/app/components/shared/header/header.component.html
@@ -1,6 +1,5 @@
 <mat-toolbar class="mat-elevation-z2">
   <mat-toolbar-row
-
     [ngClass]="{'mat-toolbar-moderation': router.url.endsWith('/moderator/comments')}">
 
     <button id="back-button"
@@ -11,6 +10,14 @@
       <mat-icon class="header-icons">arrow_back</mat-icon>
     </button>
 
+    <button id="tour-button"
+            mat-icon-button
+            aria-labelledby="tour-label"
+            *ngIf="router.url.endsWith('/home')"
+            (click)="startTour()">
+      <mat-icon class="header-icons">tour</mat-icon>
+    </button>
+
     <ng-container *ngIf="toggleUserActivity">
       <div class="userActivityIcon"
            matTooltip="{{'header.users-online' | translate}}"></div>
@@ -545,5 +552,6 @@
 <div class="visually-hidden">
   <div id="login-label">{{'header.accessibility-login' | translate}}</div>
   <div id="back-label">{{'header.accessibility-back' | translate}}</div>
+  <div id="tour-label">{{'header.accessibility-tour' | translate}}</div>
   <div id="session-label">{{'header.accessibility-session' | translate}}</div>
 </div>
diff --git a/src/app/components/shared/header/header.component.scss b/src/app/components/shared/header/header.component.scss
index 5dcd0476fe51e7936cf143fe1940ac38400a3b86..580b3a549e3f93d6dd8e7d71755815fbccea4964 100644
--- a/src/app/components/shared/header/header.component.scss
+++ b/src/app/components/shared/header/header.component.scss
@@ -1,3 +1,5 @@
+@import url("https://fonts.googleapis.com/icon?family=Material+Icons");
+
 .app-title {
   cursor: pointer;
   margin: 0 auto;
diff --git a/src/app/components/shared/header/header.component.ts b/src/app/components/shared/header/header.component.ts
index 5d4f28400e46bf5718af7e647803a3b9018be4f7..8bf64ce5745a23bb16723a140fbd32a84c50a12b 100644
--- a/src/app/components/shared/header/header.component.ts
+++ b/src/app/components/shared/header/header.component.ts
@@ -28,6 +28,7 @@ import { WorkerDialogComponent } from '../_dialogs/worker-dialog/worker-dialog.c
 import { WsRoomService } from '../../../services/websockets/ws-room.service';
 import { TopicCloudAdminService } from '../../../services/util/topic-cloud-admin.service';
 import { HeaderService } from '../../../services/util/header.service';
+import { OnboardingService } from '../../../services/util/onboarding.service';
 
 @Component({
   selector: 'app-header',
@@ -66,7 +67,8 @@ export class HeaderComponent implements OnInit {
               private roomService: RoomService,
               private wsRoomService: WsRoomService,
               private topicCloudAdminService: TopicCloudAdminService,
-              private headerService: HeaderService
+              private headerService: HeaderService,
+              private onboardingService: OnboardingService
   ) {
   }
 
@@ -231,6 +233,9 @@ export class HeaderComponent implements OnInit {
     this.location.back();
   }
 
+  startTour() {
+    this.onboardingService.startDefaultTour(true);
+  }
 
   login(isLecturer: boolean) {
     const dialogRef = this.dialog.open(LoginComponent, {
diff --git a/src/app/components/shared/room-join/room-join.component.html b/src/app/components/shared/room-join/room-join.component.html
index e86844278de8e3cadccdc84828e1c52be5ca8293..7162f3412ca36ad111d80c3e962bbe58a3965eb2 100644
--- a/src/app/components/shared/room-join/room-join.component.html
+++ b/src/app/components/shared/room-join/room-join.component.html
@@ -6,6 +6,7 @@
     <div fxLayout="row"
          fxLayoutAlign="center"
          fxLayoutGap="10px"
+         class="layoutWrapper"
          [joyrideStep]="'roomJoin'"
          [stepPosition]="'top'"
          appJoyrideTemplate>
diff --git a/src/app/components/shared/room-join/room-join.component.scss b/src/app/components/shared/room-join/room-join.component.scss
index a32c24a5eed86efd84e68854473675bda2813fe4..78b98bb606c6e686fb3eaab684e51ee526d4da88 100644
--- a/src/app/components/shared/room-join/room-join.component.scss
+++ b/src/app/components/shared/room-join/room-join.component.scss
@@ -2,6 +2,10 @@ mat-form-field {
   color: var(--on-surface);
 }
 
+.layoutWrapper {
+  padding-left: 15px;
+}
+
 form {
   padding-top: 5%;
 }
diff --git a/src/app/components/shared/shared.module.ts b/src/app/components/shared/shared.module.ts
index 377b1b31c6018b3b6b499188db61a466e92da367..82b50527451336214fe2459ae6948a0b6d789042 100644
--- a/src/app/components/shared/shared.module.ts
+++ b/src/app/components/shared/shared.module.ts
@@ -117,7 +117,8 @@ import { MatSpinnerOverlayComponent } from './mat-spinner-overlay/mat-spinner-ov
     TagCloudPopUpComponent,
     ActiveUserComponent,
     MatSpinnerOverlayComponent,
-    JoyrideTemplateDirective
+    JoyrideTemplateDirective,
+    AutofocusDirective
   ]
 })
 export class SharedModule {
diff --git a/src/app/directives/joyride-template.directive.ts b/src/app/directives/joyride-template.directive.ts
index 49a50531c5893c5ad27819451fe747da16cb940b..78b18a019cc10ce6d24ddeff70a8ae003d94af00 100644
--- a/src/app/directives/joyride-template.directive.ts
+++ b/src/app/directives/joyride-template.directive.ts
@@ -14,8 +14,6 @@ import { EventService } from '../services/util/event.service';
 })
 export class JoyrideTemplateDirective implements OnInit {
 
-  @Input('appJoyrideTemplate') applyStyles = false;
-
   constructor(private viewContainerRef: ViewContainerRef,
               public joyrideDirective: JoyrideDirective,
               private eventService: EventService,
@@ -26,12 +24,10 @@ export class JoyrideTemplateDirective implements OnInit {
     const factory = this.componentFactory.resolveComponentFactory(JoyrideTemplateComponent);
     const templates = this.viewContainerRef.createComponent(factory);
     templates.instance.name = this.joyrideDirective.name;
-    if (this.applyStyles) {
-      this.joyrideDirective.doneTemplate = templates.instance.doneButton;
-      this.joyrideDirective.nextTemplate = templates.instance.nextButton;
-      this.joyrideDirective.prevTemplate = templates.instance.prevButton;
-      this.joyrideDirective.counterTemplate = templates.instance.counter;
-    }
+    this.joyrideDirective.doneTemplate = templates.instance.doneButton;
+    this.joyrideDirective.nextTemplate = templates.instance.nextButton;
+    this.joyrideDirective.prevTemplate = templates.instance.prevButton;
+    this.joyrideDirective.counterTemplate = templates.instance.counter;
     this.joyrideDirective.stepContent = templates.instance.translateText;
     this.joyrideDirective.done.subscribe(_ => {
       this.eventService.broadcast('onboarding', 'canceled');
diff --git a/src/app/services/util/onboarding.service.ts b/src/app/services/util/onboarding.service.ts
index 4b1ef705bdfb4766f5f2ca8bf539b84be179f967..a82e1abd6cc738ee05e5f6e7231b946f2ea3384e 100644
--- a/src/app/services/util/onboarding.service.ts
+++ b/src/app/services/util/onboarding.service.ts
@@ -3,112 +3,162 @@ import { JoyrideService } from 'ngx-joyride';
 import { AppComponent } from '../../app.component';
 import { EventService } from './event.service';
 import { AuthenticationService } from '../http/authentication.service';
-import { UserRole } from '../../models/user-roles.enum';
 import { Router } from '@angular/router';
-
-type OnboardingTourFunction = (isNext: boolean) => void;
-
-interface OnboardingTourFunctionObject {
-  [key: string]: OnboardingTourFunction;
-}
-
-interface OnboardingTour {
-  name: string;
-  tour: string[];
-  tourActions?: OnboardingTourFunctionObject;
-  doneAction?: (finished: boolean) => void;
-}
+import { DataStoreService } from './data-store.service';
+import { Subscription } from 'rxjs';
+import { initDefaultTour, OnboardingTour, OnboardingTourStepInteraction } from './onboarding.tours';
+import { JoyrideStepInfo } from 'ngx-joyride/lib/models/joyride-step-info.class';
 
 @Injectable({
   providedIn: 'root'
 })
 export class OnboardingService {
 
+  private _activeTour: OnboardingTour;
+  private _eventServiceSubscription: Subscription;
+  private _tourSubscription: Subscription;
+  private _currentStep: number;
+
   constructor(private joyrideService: JoyrideService,
               private eventService: EventService,
+              private dataStoreService: DataStoreService,
               private authenticationService: AuthenticationService,
               private router: Router) {
   }
 
-  startDefaultTour() {
-    const isLoggedIn = this.authenticationService.isLoggedIn();
-    this.startOnboardingTour({
-      name: 'default',
-      tour: [
-        'greeting@home',
-        'loginButtonHeader@home',
-        'roomJoin@home',
-        'createRoom@home',
-        'introduction@home',
-        'feedbackLink@home',
-        'createQuestion@participant/room/Feedback/comments',
-        'voting@participant/room/Feedback/comments',
-        'commentFilter@participant/room/Feedback/comments',
-        'commentUserNumber@participant/room/Feedback/comments',
-        'optionHeader@participant/room/Feedback/comments'
-      ],
-      tourActions: {
-        feedbackLink: (isNext) => {
-          if (isLoggedIn) {
-            return;
-          }
-          if (isNext) {
-            this.authenticationService.guestLogin(UserRole.PARTICIPANT).subscribe();
-          } else {
-            this.authenticationService.logout();
-          }
-        }
-      },
-      doneAction: (_) => {
-        if (!isLoggedIn) {
-          this.authenticationService.logout();
-        }
-        this.router.navigate(['/home']);
+  startDefaultTour(ignoreDone = false): boolean {
+    return this.startOnboardingTour(
+      initDefaultTour(this.authenticationService, this.dataStoreService, this.router), ignoreDone);
+  }
+
+  doStep(stepDirection: number): boolean {
+    if (!this._activeTour) {
+      return false;
+    }
+    const previous = this._activeTour.tour[this._currentStep - 1].split('@');
+    const current = this._activeTour.tour[this._currentStep - 1 + stepDirection].split('@');
+    if (this._activeTour.tourActions) {
+      const prevObj = this._activeTour.tourActions[previous[0]];
+      const currentObj = this._activeTour.tourActions[current[0]];
+      if (prevObj && prevObj.beforeUnload) {
+        prevObj.beforeUnload(stepDirection === 1);
       }
-    });
+      if (currentObj && currentObj.beforeLoad) {
+        currentObj.beforeLoad(stepDirection === 1);
+      }
+    }
+    if (previous.length < current.length || previous[1] !== current[1]) {
+      //Route gets switched
+      this.dataStoreService.set('onboarding_' + this._activeTour.name, JSON.stringify({
+        state: 'running',
+        step: this._currentStep + stepDirection
+      }));
+      this.cleanup();
+      document.querySelector('joyride-step').remove();
+      document.querySelector('body > div.backdrop-container').remove();
+      this.joyrideService.closeTour();
+      this.router.navigate([current[1]]);
+      return true;
+    }
+    return false;
   }
 
-  private startOnboardingTour(tour: OnboardingTour) {
-    const tourInfo = JSON.parse(localStorage.getItem('onboarding_' + tour.name));
+  private startOnboardingTour(tour: OnboardingTour, ignoreDone = false): boolean {
+    if (this._activeTour) {
+      this.cleanup();
+      return false;
+    }
+    if (ignoreDone) {
+      this.dataStoreService.remove('onboarding_' + tour.name);
+    }
+    const tourInfo = JSON.parse(this.dataStoreService.get('onboarding_' + tour.name));
     if (tourInfo && tourInfo.state !== 'running') {
-      return;
+      return false;
     }
-    let lastNumber = 0;
-    let lastName = '';
     AppComponent.rescale.setDefaultScale(1);
-    const tourSubscription = this.joyrideService.startTour({
+    this._currentStep = tourInfo && tourInfo.step ? tourInfo.step : 1;
+    const firstStepRoute = tour.tour[this._currentStep - 1].split('@');
+    if (firstStepRoute.length > 1 && !this.router.url.endsWith('/' + firstStepRoute[1])) {
+      this.router.navigate([firstStepRoute[1]]);
+      return false;
+    }
+    this._activeTour = tour;
+    if (!tourInfo && this._activeTour.startupAction) {
+      this._activeTour.startupAction();
+    }
+    this.emulateWalkthrough();
+    this._tourSubscription = this.joyrideService.startTour({
       steps: tour.tour,
       logsEnabled: true,
       stepDefaultPosition: 'center',
-      waitingTime: 100,
-      startWith: tourInfo ? tour.tour[tourInfo.step - 1] : undefined
-    }).subscribe(step => {
-      AppComponent.rescale.setDefaultScale(1);
-      localStorage.setItem('onboarding_' + tour.name, JSON.stringify({ state: 'running', step: step.number }));
-      const container: HTMLElement = document.querySelector('.joyride-step__holder');
-      if (container.style.position === 'fixed') {
-        container.classList.add('center');
+      startWith: this._activeTour.tour[this._currentStep - 1]
+    }).subscribe(step => this.afterStepMade(step));
+    this._eventServiceSubscription = this.eventService.on<string>('onboarding')
+      .subscribe(action => this.checkTourEnding(action));
+    return true;
+  }
+
+  private afterStepMade(step: JoyrideStepInfo) {
+    AppComponent.rescale.setDefaultScale(1);
+    this.dataStoreService.set('onboarding_' + this._activeTour.name, JSON.stringify({
+      state: 'running',
+      step: step.number
+    }));
+    const container: HTMLElement = document.querySelector('.joyride-step__holder');
+    if (container.style.position === 'fixed') {
+      container.classList.add('center');
+    }
+    if (!this._activeTour.tourActions) {
+      return;
+    }
+    const previous = this._activeTour.tourActions[this._activeTour.tour[this._currentStep - 1].split('@')[0]];
+    const current = this._activeTour.tourActions[step.name];
+    const isNext = this._currentStep < step.number;
+    this._currentStep = step.number;
+    if (previous && previous.afterUnload) {
+      previous.afterUnload(isNext);
+    }
+    if (current && current.afterLoad) {
+      current.afterLoad(isNext);
+    }
+  }
+
+  private emulateWalkthrough() {
+    if (!this._activeTour.tourActions) {
+      return;
+    }
+    let lastTourObject: OnboardingTourStepInteraction = null;
+    let currentTourObject: OnboardingTourStepInteraction;
+    for (let i = 0; i < this._currentStep; i++) {
+      currentTourObject = this._activeTour.tourActions[this._activeTour.tour[i].split('@')[0]];
+      if (lastTourObject && lastTourObject.beforeUnload) {
+        lastTourObject.beforeUnload(true);
+      }
+      if (currentTourObject && currentTourObject.beforeLoad) {
+        currentTourObject.beforeLoad(true);
       }
-      const isNext = step.number > lastNumber;
-      lastNumber = step.number;
-      const name = lastName;
-      lastName = step.name;
-      if (tour.tourActions) {
-        if (isNext && tour.tourActions[step.name]) {
-          tour.tourActions[step.name](true);
-        } else if (!isNext && tour.tourActions[name]) {
-          tour.tourActions[name](false);
-        }
+      if (lastTourObject && lastTourObject.afterUnload) {
+        lastTourObject.afterUnload(true);
       }
-    });
-    const eventServiceSubscription = this.eventService.on<string>('onboarding').subscribe(action => {
-      localStorage.setItem('onboarding_' + tour.name, JSON.stringify({ state: action }));
-      AppComponent.rescale.setDefaultScale(AppComponent.rescale.getInitialScale());
-      tourSubscription.unsubscribe();
-      eventServiceSubscription.unsubscribe();
-      if (tour.doneAction) {
-        tour.doneAction(action === 'finished');
+      if (currentTourObject && currentTourObject.afterLoad) {
+        currentTourObject.afterLoad(true);
       }
-    });
+      lastTourObject = currentTourObject;
+    }
+  }
+
+  private checkTourEnding(action: string) {
+    this.dataStoreService.set('onboarding_' + this._activeTour.name, JSON.stringify({ state: action }));
+    AppComponent.rescale.setDefaultScale(AppComponent.rescale.getInitialScale());
+    if (this._activeTour.doneAction) {
+      this._activeTour.doneAction(action === 'finished');
+    }
+    this.cleanup();
+  }
+
+  private cleanup() {
+    this._tourSubscription.unsubscribe();
+    this._eventServiceSubscription.unsubscribe();
+    this._activeTour = null;
   }
 }
diff --git a/src/app/services/util/onboarding.tours.ts b/src/app/services/util/onboarding.tours.ts
new file mode 100644
index 0000000000000000000000000000000000000000..947f388e106e3e5f3e5c8a4c69ac7901a455a576
--- /dev/null
+++ b/src/app/services/util/onboarding.tours.ts
@@ -0,0 +1,71 @@
+import { AuthenticationService } from '../http/authentication.service';
+import { UserRole } from '../../models/user-roles.enum';
+import { DataStoreService } from './data-store.service';
+import { Router } from '@angular/router';
+
+export interface OnboardingTourStepInteraction {
+  beforeLoad?: (isNext: boolean) => void;
+  afterLoad?: (isNext: boolean) => void;
+  beforeUnload?: (isNext: boolean) => void;
+  afterUnload?: (isNext: boolean) => void;
+}
+
+export interface OnboardingTourStepInteractionObject {
+  [key: string]: OnboardingTourStepInteraction;
+}
+
+export interface OnboardingTour {
+  name: string;
+  tour: string[];
+  tourActions?: OnboardingTourStepInteractionObject;
+  startupAction?: () => void;
+  doneAction?: (finished: boolean) => void;
+}
+
+export const initDefaultTour = (authenticationService: AuthenticationService,
+                                dataStoreService: DataStoreService,
+                                router: Router): OnboardingTour => ({
+  name: 'default',
+  tour: [
+    'greeting@home',
+    'loginButtonHeader@home',
+    'roomJoin@home',
+    'createRoom@home',
+    'introduction@home',
+    'feedbackLink@home',
+    'createQuestion@participant/room/Feedback/comments',
+    'voting@participant/room/Feedback/comments',
+    'commentFilter@participant/room/Feedback/comments',
+    'commentUserNumber@participant/room/Feedback/comments',
+    'optionHeader@participant/room/Feedback/comments'
+  ],
+  tourActions: {
+    feedbackLink: {
+      beforeLoad: (isNext: boolean) => {
+        if (isNext && dataStoreService.get('onboarding-default-meta') === 'false' && !authenticationService.isLoggedIn()) {
+          authenticationService.guestLogin(UserRole.PARTICIPANT).subscribe();
+        }
+      },
+      beforeUnload: (isNext: boolean) => {
+        if (!isNext && dataStoreService.get('onboarding-default-meta') === 'false' && authenticationService.isLoggedIn()) {
+          authenticationService.logout();
+        }
+      }
+    },
+    voting: {
+      beforeLoad: () => {
+        document.getElementById('scroll_container').scrollTop = 0;
+      }
+    }
+  },
+  doneAction: (_) => {
+    if (dataStoreService.get('onboarding-default-meta') === 'false') {
+      authenticationService.logout();
+    }
+    dataStoreService.remove('onboarding-default-meta');
+    router.navigate(['/home']);
+  },
+  startupAction: () => {
+    dataStoreService.set('onboarding-default-meta', String(authenticationService.isLoggedIn()));
+  }
+});
diff --git a/src/assets/i18n/home/de.json b/src/assets/i18n/home/de.json
index 553c6646fc89592b942ca678ac9257e3b7044454..3ccabd1c7d3ea3a9fbfeafeefb9c6c54487da172 100644
--- a/src/assets/i18n/home/de.json
+++ b/src/assets/i18n/home/de.json
@@ -62,6 +62,7 @@
   "header": {
     "abort": "Abbrechen",
     "accessibility-back": "Führt zur vorherigen Seite",
+    "accessibility-tour": "Startet die Onboarding Tour",
     "accessibility-login": "Öffnet das Anmeldungs-Fenster.",
     "accessibility-session": "Öffnet das Options-Menü. Hier kannst du deine besuchten Sitzungen einsehen oder die aktuelle Sitzung verlassen.",
     "account-deleted": "Dein Konto wurde gelöscht.",
diff --git a/src/assets/i18n/home/en.json b/src/assets/i18n/home/en.json
index 2d0ae2a9675119717d879b5629dfc570b37f5157..054d7a82b60e6dcfac52021cf873149a6ba74547 100644
--- a/src/assets/i18n/home/en.json
+++ b/src/assets/i18n/home/en.json
@@ -49,6 +49,7 @@
   "header": {
     "abort": "Cancel",
     "accessibility-back": "Go back to the previous page",
+    "accessibility-tour": "Starts the onboarding tour",
     "accessibility-login": "Open the login window",
     "accessibility-session": "Open the session menu. Here you can view the sessions you have attended or leave the current session.",
     "account-deleted": "Your account has been deleted.",
diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json
index 1f5f514f7636a35c4081f74631453bcf9e6b57f4..0a1067aaa48fab2313d48f3cde53c04f4466f2c0 100644
--- a/src/assets/i18n/participant/de.json
+++ b/src/assets/i18n/participant/de.json
@@ -165,13 +165,17 @@
     "please-enter": "Bitte Raum-Code eingeben."
   },
   "joyride": {
+    "next": "Weiter",
+    "prev": "Zurück",
+    "step": "{{step}} / {{total}}",
+    "done": "Fertig",
     "createQuestion": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "createQuestionTitle": "Fragenerstellung",
     "voting": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "votingTitle": "Fragenbewertung",
     "commentFilter": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "commentFilterTitle": "Kommentarfilter",
-    "commentUserNumber": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
+    "commentUserNumber": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum!",
     "commentUserNumberTitle": "Anonymer User"
   },
   "room-page": {
diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json
index 990a6574b31ebc9f4fa3a5ed34c4816308d2c463..71ec990a036b6c9d0676d1d463483fa58106a2ae 100644
--- a/src/assets/i18n/participant/en.json
+++ b/src/assets/i18n/participant/en.json
@@ -174,13 +174,17 @@
     "please-enter": "Please enter a session key"
   },
   "joyride": {
+    "next": "Next",
+    "prev": "Previous",
+    "step": "{{step}} / {{total}}",
+    "done": "Finish",
     "createQuestion": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "createQuestionTitle": "Create questions",
     "voting": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "votingTitle": "Question rating",
     "commentFilter": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
     "commentFilterTitle": "Comment filter",
-    "commentUserNumber": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum! Provident similique accusantium nemo autem.",
+    "commentUserNumber": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum!",
     "commentUserNumberTitle": "Anonym user"
   },
   "room-page": {