diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js
index 81da1aa0d3c34e8c36815411cf3ca807ac558236..cc31044b9ec0079e6bda336ff631c4d3f023994d 100644
--- a/src/react-components/ui-root.js
+++ b/src/react-components/ui-root.js
@@ -1,6 +1,10 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import { VR_DEVICE_AVAILABILITY } from "../utils/vr-caps-detect.js";
+import queryString from "query-string";
+
+const { detect } = require("detect-browser");
+const browser = detect();
 
 const ENTRY_STEPS = {
   start: "start",
@@ -96,7 +100,8 @@ class UIRoot extends Component {
     availableVREntryTypes: PropTypes.object,
     store: PropTypes.object,
     concurrentLoadDetector: PropTypes.object,
-    disableAutoExitOnConcurrentLoad: PropTypes.bool
+    disableAutoExitOnConcurrentLoad: PropTypes.bool,
+    forcedVREntryType: PropTypes.string
   };
 
   state = {
@@ -125,6 +130,17 @@ class UIRoot extends Component {
   componentDidMount() {
     this.setupTestTone();
     this.props.concurrentLoadDetector.addEventListener("concurrentload", this.onConcurrentLoad);
+    this.handleForcedVREntryType();
+  }
+
+  handleForcedVREntryType = () => {
+    if (!this.props.forcedVREntryType) return;
+
+    if (this.props.forcedVREntryType === "daydream") {
+      this.enterDaydream();
+    } else if (this.props.forcedVREntryType === "gearvr") {
+      this.enterGearVR();
+    }
   }
 
   setupTestTone = () => { 
@@ -222,11 +238,32 @@ class UIRoot extends Component {
   }
 
   enterGearVR = async () => {
-    document.location = `ovrweb://${document.location.toString()}`;
+    this.exit();
+
+    // Launch via Oculus Browser
+    const qs = queryString.parse(document.location.search);
+    qs.vr_entry_type = "gearvr"; // Auto-choose 'gearvr' after landing in Oculus Browser
+
+    const ovrwebUrl = `ovrweb://${document.location.protocol || "http:"}//${document.location.host}${document.location.pathname || ""}?${queryString.stringify(qs)}#{document.location.hash || ""}`;
+
+    document.location = ovrwebUrl;
   }
 
   enterDaydream = async () => {
-    console.log("daydream");
+    const loc = document.location;
+
+    if (this.props.availableVREntryTypes.daydream == VR_DEVICE_AVAILABILITY.maybe) {
+      this.exit();
+
+      // We are not in mobile chrome, so launch into chrome via an Intent URL
+      const qs = queryString.parse(document.location.search);
+      qs.vr_entry_type = "daydream"; // Auto-choose 'daydream' after landing in chrome
+
+      const intentUrl = `intent://${document.location.host}${document.location.pathname || ""}?${queryString.stringify(qs)}#Intent;scheme=${(document.location.protocol || "http:").replace(":", "")};action=android.intent.action.VIEW;package=com.android.chrome;end;`;
+      document.location = intentUrl;
+    } else {
+      await this.performDirectEntryFlow(true);
+    }
   }
 
   mediaVideoConstraint = () => {
diff --git a/src/room.js b/src/room.js
index c302143ff51078945e432d09cb6a2a648c2f27ab..97e5311aaf4adbb50df42f2d2c3412f44ebc7afd 100644
--- a/src/room.js
+++ b/src/room.js
@@ -196,13 +196,19 @@ function mountUI() {
   getAvailableVREntryTypes().then(availableVREntryTypes => {
     const qs = queryString.parse(location.search);
     const disableAutoExitOnConcurrentLoad = qs.allow_multi === "true"
+    let forcedVREntryType = null;
+
+    if (qs.vr_entry_type) {
+      forcedVREntryType = qs.vr_entry_type;
+    }
 
     ReactDOM.render(<UIRoot {...{
       availableVREntryTypes,
       enterScene,
       exitScene,
       concurrentLoadDetector,
-      disableAutoExitOnConcurrentLoad
+      disableAutoExitOnConcurrentLoad,
+      forcedVREntryType
     }} />, document.getElementById("ui-root"));
 
     document.getElementById("loader").style.display = "none";
diff --git a/src/utils/vr-caps-detect.js b/src/utils/vr-caps-detect.js
index bde6cd71498aea96e6a6b22748f8d9fcb865c068..a89f589f6e44e270f5294e55d238c4c2ced1dc96 100644
--- a/src/utils/vr-caps-detect.js
+++ b/src/utils/vr-caps-detect.js
@@ -9,32 +9,12 @@ export const VR_DEVICE_AVAILABILITY = {
   maybe: "maybe" // Implies this device may support this VR platform, but may not be installed or in a compatible browser
 };
 
-function hasPhysicalScreenDimensions(w, h) {
-  const dpr = window.devicePixelRatio;
-  const width = screen.width * dpr;
-  const height = screen.height * dpr;
-
-  // Compensate for rounding error due to fractional pixel densities
-  return Math.abs(w - width) < 3 && Math.abs(h - height) < 3;
-}
-
-function matchesScreenSizesAndUserAgentRegexes(sizes, regexes) {
-  return !!(sizes.find(s => hasPhysicalScreenDimensions(...s)) && regexes.find(r => navigator.userAgent.match()));
-}
-
 function isMaybeGearVRCompatibleDevice() {
-  // Modern Samsung Galaxy devices have model numbers in the user agent of the form SX-XXXX or GT-XXXX for note 8
-  return matchesScreenSizesAndUserAgentRegexes([[1440, 2560], [1440, 2960]], [/\WS.-.....?\W/, /\WGT-.....?\W/]);
+  return navigator.userAgent.match(/\WAndroid\W/);
 }
 
 function isMaybeDaydreamCompatibleDevice() {
-  // If it might be a GearVR device, then we assume it might also be a Daydream device since S8 and higher
-  // support Daydream.
-  if (isMaybeGearVRCompatibleDevice()) return true;
-
-  // List of resolutions of Pixel line of phones as well as other announced Daydream compatible
-  // phones. This list may need to be updated as new phones roll out.
-  return matchesScreenSizesAndUserAgentRegexes([[1080, 1920], [1440, 2560], [1440, 2880]], [/\WAndroid\W/]);
+  return navigator.userAgent.match(/\WAndroid\W/);
 }
 
 // Blacklist of VR device name regex matchers that we do not want to consider as valid VR devices
@@ -60,7 +40,8 @@ const GENERIC_ENTRY_TYPE_DEVICE_BLACKLIST = [/cardboard/i];
 //
 export async function getAvailableVREntryTypes() {
   const isWebVRCapableBrowser = !!navigator.getVRDisplays;
-  const isDaydreamCapableBrowser = !!(isWebVRCapableBrowser && browser.name === "chrome");
+  const isSamsungBrowser = browser.name === "chrome" && navigator.userAgent.match(/SamsungBrowser/);
+  const isDaydreamCapableBrowser = !!(isWebVRCapableBrowser && browser.name === "chrome" && !isSamsungBrowser);
 
   let generic = VR_DEVICE_AVAILABILITY.no;