diff --git a/projects/player/src/app/app.component.ts b/projects/player/src/app/app.component.ts
index 2e8d2e8493af14e956917c380837960550bd9604..919dfe48d88020de823a4ee0a0bcf7b79784f34a 100644
--- a/projects/player/src/app/app.component.ts
+++ b/projects/player/src/app/app.component.ts
@@ -1,15 +1,11 @@
-import {
-  Component, EventEmitter, Input, Output
-} from '@angular/core';
+import { Component } from '@angular/core';
 import { FormGroup } from '@angular/forms';
 import { Unit } from '../../../common/unit';
 import { FormService } from '../../../common/form.service';
 import { FormControlElement, ValueChangeElement } from '../../../common/form';
-
-interface StartData {
-  unitDefinition: string;
-  unitStateData: string;
-}
+import { VeronaSubscriptionService } from './services/verona-subscription.service';
+import { VeronaPostService } from './services/verona-post.service';
+import { NativeEventService } from './services/native-event.service';
 
 @Component({
   selector: 'player-aspect',
@@ -24,9 +20,6 @@ interface StartData {
       <button class="form-item" mat-flat-button color="primary" (click)="submit()">Print
           form.value
       </button>
-      <button class="form-item" mat-flat-button color="primary" (click)="markAsTouch()" >markAsTouch
-      </button>
-      <pre>{{unit | json}}</pre>
   `
 })
 export class AppComponent {
@@ -35,19 +28,37 @@ export class AppComponent {
     pages: []
   };
 
-  @Input()
-  set startData(startData: StartData) {
-    this.unit = JSON.parse(startData.unitDefinition);
-    this.initForm();
+  constructor(private formService: FormService,
+              private veronaSubscriptionService: VeronaSubscriptionService,
+              private veronaPostService: VeronaPostService,
+              private nativeEventService: NativeEventService) {
+    this.subscribe();
+    veronaPostService.sendVopReadyNotification();
   }
 
-  @Output() valueChanged = new EventEmitter<string>();
-
-  constructor(private formService: FormService) {
-    formService.elementValueChanged
+  private subscribe(): void {
+    this.formService.elementValueChanged
       .subscribe((value: ValueChangeElement): void => this.onElementValueChanges(value));
-    formService.controlAdded
+    this.formService.controlAdded
       .subscribe((control: FormControlElement): void => this.addControl(control));
+
+    this.veronaSubscriptionService.vopStartCommand
+      .subscribe((data: any): void => this.onStart(data));
+    this.veronaSubscriptionService.vopNavigationDeniedNotification
+      .subscribe((data: any): void => this.onNavigationDenied(data));
+
+    this.nativeEventService.scrollY
+      .subscribe((y: number): void => this.onScrollY(y));
+    this.nativeEventService.focus
+      .subscribe((focused: boolean): void => this.onFocus(focused));
+  }
+
+  private onStart(data: any): void {
+    console.log('player: onStart', data);
+    this.veronaPostService.sessionId = data.sessionId;
+    this.unit = JSON.parse(data.unitDefinition);
+    // playerStartData.unitStateData = data.unitState?.dataParts?.all;
+    this.initForm();
   }
 
   private initForm(): void {
@@ -55,6 +66,11 @@ export class AppComponent {
     this.form.valueChanges.subscribe(v => this.onFormChanges(v));
   }
 
+  private onNavigationDenied(data: any): void {
+    console.log('player: onNavigationDenied', data);
+    this.form.markAllAsTouched();
+  }
+
   private addControl(control: FormControlElement): void {
     this.form.addControl(control.id, control.formControl);
   }
@@ -68,90 +84,22 @@ export class AppComponent {
     const allValues: string = JSON.stringify(value);
     // eslint-disable-next-line no-console
     console.log('Player: emit valueChanged', allValues);
-    this.valueChanged.emit(allValues);
+    this.veronaPostService.sendVopStateChangedNotification(allValues);
+  }
+
+  private onScrollY = (y: number): void => {
+    console.log('player: onScrollY', y);
+  };
+
+  // TODO
+  private onFocus(focused: boolean): void {
+    console.log('player: onFocus', focused);
+    this.veronaPostService.sendVopWindowFocusChangedNotification(focused);
   }
 
+  /// ////////////////////// only for dev
   submit(): void {
     // eslint-disable-next-line no-console
     console.log('Player: form.value', this.form.value);
   }
-
-  markAsTouch(): void {
-    this.form.markAllAsTouched();
-  }
-
-  // exampleUnit = {
-  //   pages: [
-  //     {
-  //       sections: [
-  //         {
-  //           elements: [
-  //             {
-  //               label: 'Label Dropdown',
-  //               options: [
-  //                 'op1',
-  //                 'op2'
-  //               ],
-  //               type: 'dropdown',
-  //               id: 'dummyID',
-  //               xPosition: 124,
-  //               yPosition: 26,
-  //               width: 180,
-  //               height: 60,
-  //               backgroundColor: 'grey',
-  //               fontColor: 'blue',
-  //               font: 'Arial',
-  //               fontSize: 18,
-  //               bold: true,
-  //               italic: false,
-  //               underline: false
-  //             }
-  //           ],
-  //           width: 1200,
-  //           height: 200,
-  //           backgroundColor: '#FFFAF0'
-  //         },
-  //         {
-  //           elements: [
-  //             {
-  //               label: 'Button Text',
-  //               type: 'button',
-  //               id: 'dummyID',
-  //               xPosition: 440,
-  //               yPosition: 77,
-  //               width: 180,
-  //               height: 60,
-  //               backgroundColor: 'grey',
-  //               fontColor: 'blue',
-  //               font: 'Arial',
-  //               fontSize: 18,
-  //               bold: true,
-  //               italic: false,
-  //               underline: false
-  //             }
-  //           ],
-  //           width: 1200,
-  //           height: 200,
-  //           backgroundColor: '#FFFAF0'
-  //         }
-  //       ],
-  //       width: 1200,
-  //       height: 550,
-  //       backgroundColor: '#FFFAF0'
-  //     },
-  //     {
-  //       sections: [
-  //         {
-  //           elements: [],
-  //           width: 1200,
-  //           height: 200,
-  //           backgroundColor: '#FFFAF0'
-  //         }
-  //       ],
-  //       width: 1200,
-  //       height: 550,
-  //       backgroundColor: '#FFFAF0'
-  //     }
-  //   ]
-  // };
 }
diff --git a/projects/player/src/app/services/native-event.service.ts b/projects/player/src/app/services/native-event.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8640516b4dfddf09bc0cfbcf9bef106fadf0e0d9
--- /dev/null
+++ b/projects/player/src/app/services/native-event.service.ts
@@ -0,0 +1,34 @@
+import { Inject, Injectable } from '@angular/core';
+import {
+  from, fromEvent, Observable, Subject
+} from 'rxjs';
+import { DOCUMENT } from '@angular/common';
+import { mergeMap } from 'rxjs/operators';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class NativeEventService {
+  private _scrollY = new Subject<number>();
+  private _focus = new Subject<boolean>();
+
+  constructor(@Inject(DOCUMENT) private document: Document) {
+    fromEvent(window, 'scroll')
+      .subscribe(() => this._scrollY.next(window.scrollY));
+    from(['blur', 'focus'])
+      .pipe(
+        mergeMap(event => fromEvent(window, event))
+      )
+      .subscribe(
+        () => this._focus.next(document.hasFocus())// Do something with the event here
+      );
+  }
+
+  get scrollY(): Observable<number> {
+    return this._scrollY.asObservable();
+  }
+
+  get focus(): Observable<boolean> {
+    return this._focus.asObservable();
+  }
+}
diff --git a/projects/player/src/app/services/verona-post.service.ts b/projects/player/src/app/services/verona-post.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1644be7d5010d78a8a5aa2bf03e88df6f3da15ca
--- /dev/null
+++ b/projects/player/src/app/services/verona-post.service.ts
@@ -0,0 +1,67 @@
+import { Inject, Injectable } from '@angular/core';
+import { DOCUMENT } from '@angular/common';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class VeronaPostService {
+  private playerMetadata!: any;
+  private _sessionId!: string;
+
+  constructor(@Inject(DOCUMENT) private document: Document) {
+    this.playerMetadata = document.querySelectorAll('meta')[1].attributes;
+  }
+
+  set sessionId(sessionId:string) {
+    this._sessionId = sessionId;
+  }
+
+  private isStandalone = (): boolean => window === window.parent;
+
+  private send(message: any): void {
+    // prevend posts in local dev mode
+    if (!this.isStandalone()) {
+      window.parent.postMessage(message, '*');
+    }
+  }
+
+  sendVopStateChangedNotification(value: unknown) : void {
+    this.send({
+      type: 'vopStateChangedNotification',
+      sessionId: this._sessionId,
+      timeStamp: Date.now(),
+      unitState: {
+        dataParts: {
+          all: value
+        },
+        unitStateDataType: this.playerMetadata.getNamedItem('data-supported-unit-state-data-types').value
+      }
+    });
+  }
+
+  sendVopReadyNotification(): void {
+    this.send({
+      type: 'vopReadyNotification',
+      apiVersion: this.playerMetadata.getNamedItem('data-api-version').value,
+      notSupportedApiFeatures: this.playerMetadata.getNamedItem('data-not-supported-api-features').value,
+      supportedUnitDefinitionTypes: this.playerMetadata.getNamedItem('data-supported-unit-definition-types').value,
+      supportedUnitStateDataTypes: this.playerMetadata.getNamedItem('data-supported-unit-state-data-types').value
+    });
+  }
+
+  sendVopUnitNavigationRequestedNotification = (target: string): void => {
+    this.send({
+      type: 'vopUnitNavigationRequestedNotification',
+      sessionId: this._sessionId,
+      target: target
+    });
+  };
+
+  sendVopWindowFocusChangedNotification = (focused: boolean): void => {
+    this.send({
+      type: 'vopWindowFocusChangedNotification',
+      sessionId: this._sessionId,
+      hasFocus: focused
+    });
+  };
+}
diff --git a/projects/player/src/app/services/verona-subscription.service.ts b/projects/player/src/app/services/verona-subscription.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a192d0bd409bc1a861a9fc8f6751777fa6aeb219
--- /dev/null
+++ b/projects/player/src/app/services/verona-subscription.service.ts
@@ -0,0 +1,46 @@
+import { Injectable } from '@angular/core';
+import { fromEvent, Observable, Subject } from 'rxjs';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+export class VeronaSubscriptionService {
+  private _vopStartCommand = new Subject<any>();
+  private _vopNavigationDeniedNotification = new Subject<any>();
+
+  constructor() {
+    fromEvent(window, 'message')
+      .subscribe((e: Event): void => {
+        this.handleMessage((e as MessageEvent).data);
+      });
+  }
+
+  handleMessage(messageData: any): void {
+    switch (messageData.type) {
+      case 'vopStartCommand':
+        console.log('Player: _vopStartCommand ', messageData);
+        this._vopStartCommand.next(messageData);
+        break;
+      case 'vopNavigationDeniedNotification':
+        console.log('Player: _vopNavigationDeniedNotification ', messageData);
+        this._vopNavigationDeniedNotification.next(messageData);
+        break;
+      // TODO
+      case 'vopPageNavigationCommand':
+      case 'vopGetStateRequest':
+      case 'vopStopCommand':
+      case 'vopContinueCommand':
+      default:
+        console.warn(`player: got message of unknown type ${messageData.type}`);
+    }
+  }
+
+  get vopStartCommand(): Observable<any> {
+    return this._vopStartCommand.asObservable();
+  }
+
+  get vopNavigationDeniedNotification(): Observable<any> {
+    return this._vopNavigationDeniedNotification.asObservable();
+  }
+}
diff --git a/projects/player/src/html_wrapper/index.html b/projects/player/src/html_wrapper/index.html
index 6b74a6035acc1dcc4978a959666efc1dfef5088a..c548a6bae666442cf6de228bd717e8ab3c605d43 100644
--- a/projects/player/src/html_wrapper/index.html
+++ b/projects/player/src/html_wrapper/index.html
@@ -47,97 +47,6 @@
 </head>
 <body>
 <script type="text/javascript" src="player.js"></script>
-<script>
-  let sessionId;
-  let playerMetadata = document.querySelectorAll("meta")[1].attributes;
-  let tempResponses = {};
-  let playerStartData = {
-    unitDefinition: '',
-    unitStateData: ''
-  };
-
-  function elementValueChanged(event) {
-    window.parent.postMessage({
-      type: 'vopStateChangedNotification',
-      sessionId: sessionId,
-      timeStamp: Date.now(),
-      unitState: {
-        dataParts: {
-          all: event.detail
-        },
-        unitStateDataType: playerMetadata.getNamedItem('data-supported-unit-state-data-types').value,
-      }
-    }, '*');
-  }
-
-  function navigationRequested(event) {
-    window.parent.postMessage({
-      type: 'vopUnitNavigationRequestedNotification',
-      sessionId: sessionId,
-      targetRelative: '#' + event.detail,
-      target: event.detail,
-    }, '*');
-  }
-
-  const playerComponent = document.createElement('player-aspect',{ is : 'player-aspect' });
-  playerComponent.addEventListener('valueChanged', (event) => {
-    elementValueChanged(event);
-  });
-  playerComponent.addEventListener('navigationRequested', (event) => {
-
-    navigationRequested(event);
-  });
-  document.body.appendChild(playerComponent)
-
-  window.addEventListener('message', (event) => {
-    if ('data' in event && 'type' in event.data) {
-      switch (event.data.type) {
-        case 'vopStartCommand':
-          if (event.data.sessionId) {
-            sessionId = event.data.sessionId;
-            playerStartData.unitDefinition = event.data.unitDefinition;
-            playerStartData.unitStateData = event.data.unitState?.dataParts?.all;
-            playerComponent.startData = playerStartData;
-          } else {
-            console.error('player: (vopStartCommand) no sessionId is given');
-          }
-          break;
-        case 'vopPageNavigationCommand':
-        case 'vopGetStateRequest':
-        case 'vopStopCommand':
-        case 'vopContinueCommand':
-          console.warn(`player: message of type ${event.data.type} not processed yet`);
-          break;
-        case 'vopNavigationDeniedNotification':
-          console.info(['player: got vopNavigationDeniedNotification']);
-          // playerComponent.tryLeaveNotify();
-          break;
-        default:
-          console.warn(`player: got message of unknown type ${event.data.type}`);
-      }
-    }
-  });
-  window.addEventListener('blur', () => {
-    window.parent.postMessage({
-      type: 'vopWindowFocusChangedNotification',
-      sessionId: sessionId,
-      hasFocus: document.hasFocus()
-    }, '*');
-  });
-  window.addEventListener('focus', () => {
-    window.parent.postMessage({
-      type: 'vopWindowFocusChangedNotification',
-      sessionId: sessionId,
-      hasFocus: document.hasFocus()
-    }, '*');
-  });
-  window.parent.postMessage({
-    type: 'vopReadyNotification',
-    apiVersion: playerMetadata.getNamedItem('data-api-version').value,
-    notSupportedApiFeatures: playerMetadata.getNamedItem('data-not-supported-api-features').value,
-    supportedUnitDefinitionTypes: playerMetadata.getNamedItem('data-supported-unit-definition-types').value,
-    supportedUnitStateDataTypes: playerMetadata.getNamedItem('data-supported-unit-state-data-types').value,
-  }, '*');
-</script>
+<player-aspect></player-aspect>
 </body>
 </html>
diff --git a/projects/player/src/index.html b/projects/player/src/index.html
index 8239c6239c05d61458c18ebca572c8367ca20e82..43c033de1cc778a7900634da5dac3c04fc00f31a 100644
--- a/projects/player/src/index.html
+++ b/projects/player/src/index.html
@@ -3,6 +3,15 @@
 <head>
   <meta charset="utf-8">
   <title>Player</title>
+  <meta name="application-name" content="iqb-player-aspect"
+        data-version="3.3.3"
+        data-repository-url="https://github.com/iqb-berlin/verona-modules-apect"
+        data-api-version="2.1.0"
+        data-not-supported-api-features=""
+        data-supported-unit-definition-types="iqb-scripted@1.0"
+        data-supported-unit-state-data-types="iqb-key-value@1.0.0"
+        data-supported-browsers='{"Firefox": 69, "Chrome": 72, "Edge": 79}'
+  />
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
@@ -15,22 +24,32 @@
     <input type='button' value='Load' onclick='loadUnitDefinition();'>
   </fieldset>
 </form>
+<button onclick='denyNavigation();'>Deny Navigation</button>
 <player-aspect></player-aspect>
 </body>
 
 <script type="text/javascript">
-
-  const playerComponent = document.getElementsByTagName('player-aspect').item(0);
-
-  setStartData = (e) => {
-    playerComponent.startData = {
-      unitDefinition: e.target.result,
-      unitStateData: ''
-    };
+  denyNavigation = () => {
+    window.postMessage({
+      type: 'vopNavigationDeniedNotification',
+      sessionId: 'dev',
+      reason: []
+    }, '*');
   }
 
   loadUnitDefinition = () => {
-    let input = document.getElementById('fileInput');
+    const setStartData = (e) => {
+      window.postMessage({
+        type: 'vopStartCommand',
+        sessionId: 'dev',
+        unitDefinition: e.target.result,
+        unitState: {
+          dataParts: {}
+        },
+        playerConfig: {}
+      }, '*');
+    }
+    const input = document.getElementById('fileInput');
     if (!input['files'][0]) {
       alert("Please choose a file before clicking 'Load'");
     } else {