diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,84 @@
+# Revision history for reflex-dom
+
+## 0.6.3.4
+
+* Fix WASM related issues
+
+## 0.6.3.3
+
+* Support GHC 9.12
+
+## 0.6.3.2-r1
+
+* Require reflex-dom-core >= 0.8.1.0
+
+## 0.6.3.2
+
+* Build with GHC 9.10
+
+## 0.6.3.1-r1
+
+* Require reflex-dom-core >= 0.8.1.0
+
+## 0.6.3.1
+
+* Don't depend on webkit2gtk on android
+
+## 0.6.3.0
+
+* Use android-activity 0.2
+* Fix bug in android back button handler
+
+## 0.6.2.0
+
+* [#452](https://github.com/reflex-frp/reflex-dom/pull/452) Allow file access on newer android, following usage recommended by the [official docs](https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader)
+* [#453](https://github.com/reflex-frp/reflex-dom/pull/453) History management for android
+
+## 0.6.1.1-r1
+
+* Loosen reflex-dom-core version bounds to allow reflex-dom-core 0.7.*
+
+## 0.6.1.1
+
+* Compile with -fPIC
+
+## 0.6.1.0-r1
+
+* Loosen reflex-dom-core version bounds
+
+## 0.6.1.0
+
+* Update for new dependent-map and dependent-sum (after the "some" package split)
+
+## 0.6.0.0
+
+* ([#379](https://github.com/reflex-frp/reflex-dom/pull/379)) Re-export all modules from `reflex-dom-core`. The newly re-exported modules are:
+    * `Foreign.JavaScript.Utils`
+    * `Reflex.Dom.Builder.Hydratable`
+    * `Reflex.Dom.Modals.Class`
+    * `Reflex.Dom.Prerender`
+    * `Reflex.Dom.Time`
+    * `Reflex.Dom.WebSocket.Query`
+    * `Reflex.Dom.Xhr.FormData`
+* ([#366](https://github.com/reflex-frp/reflex-dom/pull/366)) Bump bounds for `reflex` to include 0.7.
+
+## 0.5.3
+
+* On Android, enable prompting the user for geolocation
+  permissions on demand by default. See
+  https://developer.android.com/reference/android/webkit/WebChromeClient.html#onGeolocationPermissionsShowPrompt(java.lang.String,%20android.webkit.GeolocationPermissions.Callback)
+  for details.
+
+ * Add `< 0.7` upper bound for reflex
+
+## 0.5.2
+
+* The default jsaddle backend on macOS when built from nix
+  is now jsaddle-wkwebview, matching the behaviour of cabal
+  builds.
+
+## 0.5
+
+* Re-export new hydration widget "mainWidget" functions.
+
+* The use-warp flag now properly takes precedence on macOS.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2015, Obsidian Systems LLC
+Copyright (c) 2020, Obsidian Systems LLC
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/benchmark.hs b/benchmark.hs
--- a/benchmark.hs
+++ b/benchmark.hs
@@ -15,8 +15,9 @@
 import Reflex.Dom
 import System.Random
 import qualified Data.Map as Map
-import Data.Dependent.Map (DMap (..), DSum (..))
+import Data.Dependent.Map (DMap (..))
 import qualified Data.Dependent.Map as DMap
+import Data.Dependent.Sum (DSum (..))
 import Data.Functor.Misc
 import Data.Functor.Identity
 import Data.Functor.Compose
diff --git a/benchmarks/krausest.hs b/benchmarks/krausest.hs
--- a/benchmarks/krausest.hs
+++ b/benchmarks/krausest.hs
@@ -28,15 +28,15 @@
   seed <- randomIO
   mainWidgetWithHead' (\_ -> headW, \_ -> bodyW seed)
 
-titleW :: MonadWidget t m => m ()
+titleW :: DomBuilder t m => m ()
 titleW = text "Reflex-dom keyed"
 
-headW :: MonadWidget t m => m ()
+headW :: DomBuilder t m => m ()
 headW = do
   el "title" titleW
   elAttr "link" ("href" =: "/css/currentStyle.css" <> "rel" =: "stylesheet") blank
 
-bodyW :: forall t m. MonadWidget t m => Entropy -> m ()
+bodyW :: forall t m. (MonadFix m, MonadHold t m, DomBuilder t m) => Entropy -> m ()
 bodyW seed = divClass "main" $ divClass "container" $ mdo
   buttonEvents <- divClass "jumbotron" $ divClass "row" $ do
     divClass "col-md-6" $ el "h1" titleW
@@ -75,14 +75,14 @@
     (m', dt) = f (m, t)
     t' = applyAlways dt t
 
-buttonW :: MonadWidget t m => Text -> Text -> a -> m (Event t a)
+buttonW :: DomBuilder t m => Text -> Text -> a -> m (Event t a)
 buttonW id txt val = divClass "col-sm-6 smallpad" $ buttonW' ("class" =: "btn btn-primary btn-block" <> "id" =: id)
   where
     buttonW' attrs = do
       (b, _) <- elAttr' "button" attrs $ text txt
       pure $ val <$ domEvent Click b
 
-tableW :: MonadWidget t m => Event t TableDiff -> m (Event t (IntMap Step))
+tableW :: (MonadHold t m, DomBuilder t m) => Event t TableDiff -> m (Event t (IntMap Step))
 tableW diff = do
   elClass "table" "table table-hover table-striped test-data" $ do
     el "tbody" $ do
@@ -90,7 +90,7 @@
       rowEvents <- holdIncremental v0 v'
       return $ mergeIntIncremental rowEvents
 
-rowW :: MonadWidget t m => Row -> m (Event t Step)
+rowW :: DomBuilder t m => Row -> m (Event t Step)
 rowW row = elClass "tr" (if selected row then "danger" else "") $
   do
     elClass "td" "col-md-1" $ do
@@ -102,7 +102,7 @@
   where
     tagClick f el = f row <$ (domEvent Click el)
 
-deleteW :: MonadWidget t m => m ()
+deleteW :: DomBuilder t m => m ()
 deleteW = el "a" $ elAttr "span" ("aria-hidden" =: "true" <> "class" =: "glyphicon glyphicon-remove") blank
 
 
diff --git a/cbits/MainWidget.c b/cbits/MainWidget.c
--- a/cbits/MainWidget.c
+++ b/cbits/MainWidget.c
@@ -53,6 +53,40 @@
   (*env)->PopLocalFrame(env, 0);
 }
 
+void Reflex_Dom_Android_MainWidget_back(jobject jsExecutor) {
+  JNIEnv *env;
+  jint attachResult = (*HaskellActivity_jvm)->AttachCurrentThread(HaskellActivity_jvm, &env, NULL);
+  assert (attachResult == JNI_OK);
+
+  (*env)->PushLocalFrame(env, 5);
+
+  //TODO: Don't search for this method every time
+  jclass cls = (*env)->GetObjectClass(env, jsExecutor);
+  assert(cls);
+  jmethodID evaluateJavascript = (*env)->GetMethodID(env, cls, "goBack", "()V");
+  assert(evaluateJavascript);
+  (*env)->CallVoidMethod(env, jsExecutor, evaluateJavascript);
+
+  (*env)->PopLocalFrame(env, 0);
+}
+
+void Reflex_Dom_Android_MainWidget_clearHistory(jobject jsExecutor) {
+  JNIEnv *env;
+  jint attachResult = (*HaskellActivity_jvm)->AttachCurrentThread(HaskellActivity_jvm, &env, NULL);
+  assert (attachResult == JNI_OK);
+
+  (*env)->PushLocalFrame(env, 5);
+
+  //TODO: Don't search for this method every time
+  jclass cls = (*env)->GetObjectClass(env, jsExecutor);
+  assert(cls);
+  jmethodID evaluateJavascript = (*env)->GetMethodID(env, cls, "clearHistory", "()V");
+  assert(evaluateJavascript);
+  (*env)->CallVoidMethod(env, jsExecutor, evaluateJavascript);
+
+  (*env)->PopLocalFrame(env, 0);
+}
+
 JNIEXPORT void JNICALL Java_org_reflexfrp_reflexdom_MainWidget_00024JSaddleCallbacks_startProcessing (JNIEnv *env, jobject thisObj, jlong callbacksLong) {
   const JSaddleCallbacks *callbacks = (const JSaddleCallbacks *)callbacksLong;
   (*(callbacks->jsaddleStart))();
diff --git a/examples/sortableList.hs b/examples/sortableList.hs
--- a/examples/sortableList.hs
+++ b/examples/sortableList.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -5,21 +6,22 @@
 {-# LANGUAGE RecursiveDo #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 import Control.Lens
-import Control.Monad.Identity
+import Control.Monad.Fix
 import Control.Monad.IO.Class
-import Data.Dependent.Map (DMap)
-import Data.Functor.Constant
-import Data.Functor.Misc
 import Data.List
 import Data.Map (Map)
 import qualified Data.Map as Map
-import Data.Monoid
 import Data.Ord
+import Data.Patch.MapWithMove
 import qualified Data.Text as T
 import Data.Time.Clock
 import Reflex.Dom
 import System.Random
 
+#if defined(wasm32_HOST_ARCH)
+foreign export javascript "hs_start" main :: IO ()
+#endif
+
 main :: IO ()
 main = mainWidget $ do
   let f _ (a, b, c) = el "tr" $ do
@@ -71,7 +73,7 @@
 simpleSortableList f m0 resortFunc resortSlowFunc = do
   rec let resortPatchFast = attachWith (flip patchThatSortsMapWith) (currentIncremental m) resortFunc
           redrawPatch :: Map k v -> (v -> v -> Ordering) -> PatchMapWithMove k v
-          redrawPatch d cmp = unsafePatchMapWithMove $ fmap (MapEdit_Insert False) $ Map.fromList $ zip (Map.keys d) (sortBy cmp $ Map.elems d)
+          redrawPatch d cmp = patchMapWithMoveInsertAll $ Map.fromList $ zip (Map.keys d) (sortBy cmp $ Map.elems d)
           resortPatchSlow = attachWith redrawPatch (currentIncremental m) resortSlowFunc
           resortPatch = leftmost
             [ resortPatchFast
diff --git a/java/org/reflexfrp/reflexdom/MainWidget.java b/java/org/reflexfrp/reflexdom/MainWidget.java
--- a/java/org/reflexfrp/reflexdom/MainWidget.java
+++ b/java/org/reflexfrp/reflexdom/MainWidget.java
@@ -8,6 +8,7 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
 import android.webkit.CookieManager;
+import android.webkit.GeolocationPermissions;
 import android.webkit.JavascriptInterface;
 import android.webkit.MimeTypeMap;
 import android.webkit.PermissionRequest;
@@ -22,6 +23,7 @@
 import java.io.InputStream;
 import android.content.Intent;
 import android.content.ActivityNotFoundException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import java.nio.charset.StandardCharsets;
 
@@ -39,24 +41,29 @@
     a.setContentView(wv);
     final WebSettings ws = wv.getSettings();
     ws.setJavaScriptEnabled(true);
-    ws.setAllowFileAccessFromFileURLs(true);
-    ws.setAllowUniversalAccessFromFileURLs(true);
     ws.setDomStorageEnabled(true);
     wv.setWebContentsDebuggingEnabled(true);
     // allow video to play without user interaction
     wv.getSettings().setMediaPlaybackRequiresUserGesture(false);
+    final AtomicBoolean jsaddleLoaded = new AtomicBoolean(false);
 
     wv.setWebViewClient(new WebViewClient() {
         @Override
         public void onPageFinished(WebView _view, String _url) {
-          wv.evaluateJavascript(initialJS, null);
+          Log.i("reflex", "onPageFinished");
+          boolean alreadyLoaded = jsaddleLoaded.getAndSet(true);
+          if(!alreadyLoaded) {
+            Log.i("reflex", "loading jsaddle");
+            wv.evaluateJavascript(initialJS, null);
+          }
         }
 
         // Re-route / to /android_asset
         @Override
         public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) {
             Uri uri = request.getUrl();
-            if(!uri.getScheme().equals("file"))
+	    Log.i("reflex", uri.toString());
+            if(!uri.getScheme().equals("file") && !uri.getEncodedAuthority().equals("appassets.androidplatform.net"))
                 return null;
 
             String path = uri.getPath();
@@ -79,7 +86,7 @@
 
         @Override
         public boolean shouldOverrideUrlLoading(WebView view, String url) {
-            if( url != null && !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("file://")) {
+            if( url != null && !url.startsWith("http://appassets.androidplatform.net") && !url.startsWith("https://appassets.androidplatform.net") && !url.startsWith("file://")) {
                 try {
                     view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
                 }
@@ -115,6 +122,11 @@
         public Bitmap getDefaultVideoPoster() {
             return Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
         }
+
+        @Override
+        public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
+            callback.invoke(origin, true, false);
+        }
     });
 
     wv.addJavascriptInterface(new JSaddleCallbacks(jsaddleCallbacks), "jsaddle");
@@ -131,6 +143,16 @@
               wv.evaluateJavascript(jsStr, null);
             }
           });
+      }
+      public final void goBack() {
+        hnd.post(new Runnable() {
+          @Override
+	  public void run() {
+            if(wv.canGoBack()) {
+              wv.goBack();
+            }
+	  }
+	});
       }
     };
   }
diff --git a/reflex-dom.cabal b/reflex-dom.cabal
--- a/reflex-dom.cabal
+++ b/reflex-dom.cabal
@@ -1,10 +1,20 @@
+cabal-version: 1.24
 Name: reflex-dom
-Version: 0.4
+Version: 0.6.3.4
 Synopsis: Functional Reactive Web Apps with Reflex
 Description:
-  Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine.
+  Web applications without callbacks or side-effects.
+  Reflex-DOM brings the power of functional reactive programming (FRP) to the web.
+  Build HTML and other Document Object Model (DOM) data with a pure functional interface.
   .
-  For hackage documentation, please see: <https://hackage.haskell.org/package/reflex-dom-core>.
+  Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine: <https://reflex-frp.org/>.
+  .
+  The @reflex-dom@ package is a small wrapper around the @reflex-dom-core@ package. It pulls in the
+  correct set of dependencies for each target platform (GHCJS, WebKitGTK, WASM, mobile, etc.).
+  Libraries should depend on @reflex-dom-core@ and executables will usually depend on @reflex-dom@.
+  All of @reflex-dom-core@'s modules are re-exported by @reflex-dom@.
+  .
+  For Hackage documentation, please see: <https://hackage.haskell.org/package/reflex-dom-core>.
 License: BSD3
 License-file: LICENSE
 Author: Ryan Trinkle
@@ -12,8 +22,9 @@
 Stability: Experimental
 Category: FRP, Web, GUI, HTML, Javascript, Reactive, Reactivity, User Interfaces, User-interface
 Build-type: Simple
-cabal-version: >=1.24
-extra-source-files: java/org/reflexfrp/reflexdom/MainWidget.java
+extra-source-files:
+  java/org/reflexfrp/reflexdom/MainWidget.java
+  ChangeLog.md
 
 flag use-warp
   description: Use jsaddle-warp server
@@ -39,60 +50,59 @@
   default: False
   manual: True
 
-flag android
-  description: Build an Android app
-  default: False
-  manual: True
-
 library
   hs-source-dirs: src
-  if flag(android)
+  if os(android)
     hs-source-dirs: src-android
     other-modules: Reflex.Dom.Android.MainWidget
     build-depends:
-      aeson,
-      android-activity == 0.1.*,
-      data-default == 0.7.*,
-      jsaddle
+      aeson >= 1.4 && < 2.3,
+      android-activity == 0.2.*,
+      data-default >= 0.7 && < 0.9,
+      jsaddle >= 0.9.6 && < 0.10
     c-sources: cbits/MainWidget.c
     include-dirs: cbits/include
     install-includes: MainWidget.h
     cpp-options: -DANDROID
     build-tools: hsc2hs
   build-depends:
-    base >= 4.7 && < 4.12,
-    bytestring == 0.10.*,
-    reflex == 0.5.*,
-    reflex-dom-core >=0.4 && <0.5,
-    text == 1.2.*
+    base >= 4.7 && < 4.22,
+    bytestring >= 0.10 && < 0.13,
+    reflex >= 0.8 && < 1,
+    reflex-dom-core >= 0.8.1.0 && <0.9,
+    text >= 1.2 && < 2.2
   if !impl(ghcjs)
-    if os(osx) || os(ios)
+    if flag(use-warp)
       build-depends:
-        data-default == 0.7.*,
-        jsaddle,
-        jsaddle-wkwebview
+        jsaddle >= 0.9.6 && < 0.10,
+        jsaddle-warp >= 0.9.6 && < 0.10
     else
-      if flag(use-warp)
+      if os(osx) || os(ios)
         build-depends:
-          jsaddle,
-          jsaddle-warp
+          data-default >= 0.7 && < 0.9,
+          jsaddle >= 0.9.6 && < 0.10,
+          jsaddle-wkwebview >= 0.9.6 && < 0.10
       else
-        if flag(webkit2gtk)
+        if arch(wasm32)
           build-depends:
-            jsaddle-webkit2gtk
+            jsaddle >= 0.9.6 && < 0.10,
+            jsaddle-wasm >= 0.1 && < 0.2
         else
-          if !flag(android)
+          if flag(webkit2gtk) && !os(android)
             build-depends:
-              jsaddle-webkit2gtk
+              jsaddle-webkit2gtk >= 0.9.6 && < 0.10
 
   exposed-modules:
     Reflex.Dom
     Reflex.Dom.Internal
+    Reflex.Dom.Location.Platform
   reexported-modules:
-      Foreign.JavaScript.TH
-    , Foreign.JavaScript.Orphans
+      Foreign.JavaScript.Orphans
+    , Foreign.JavaScript.TH
+    , Foreign.JavaScript.Utils
     , Reflex.Dom.Builder.Class
     , Reflex.Dom.Builder.Class.Events
+    , Reflex.Dom.Builder.Hydratable
     , Reflex.Dom.Builder.Immediate
     , Reflex.Dom.Builder.InputDisabled
     , Reflex.Dom.Builder.Static
@@ -100,15 +110,21 @@
     , Reflex.Dom.Core
     , Reflex.Dom.Location
     , Reflex.Dom.Main
+    , Reflex.Dom.Modals.Class
     , Reflex.Dom.Old
+    , Reflex.Dom.Prerender
+    , Reflex.Dom.Time
     , Reflex.Dom.WebSocket
+    , Reflex.Dom.WebSocket.Query
     , Reflex.Dom.Widget
     , Reflex.Dom.Widget.Basic
     , Reflex.Dom.Widget.Input
     , Reflex.Dom.Widget.Lazy
     , Reflex.Dom.Widget.Resize
     , Reflex.Dom.Xhr
-  ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
+    , Reflex.Dom.Xhr.FormData
+  ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans -fPIC
+  cc-options: -fPIC
   if flag(expose-all-unfoldings)
     ghc-options: -fexpose-all-unfoldings
   if flag(use-reflex-optimizer)
@@ -121,6 +137,7 @@
                , dependent-map
                , lens
                , mtl
+               , patch
                , random
                , reflex
                , reflex-dom
@@ -137,9 +154,23 @@
   if flag(use-reflex-optimizer)
     ghc-options: -fplugin=Reflex.Optimizer
   default-language: Haskell2010
+  if arch(wasm32)
+    ghc-options: -no-hs-main -optl-mexec-model=reactor "-optl-Wl,--export=hs_start"
 
 executable benchmark
-  build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum
+  build-depends: base
+               , containers
+               , dependent-map
+               , dependent-sum
+               , ghc-prim
+               , ghcjs-dom
+               , mtl
+               , prim-uniq
+               , random
+               , reflex
+               , reflex-dom
+               , text
+               , transformers
   hs-source-dirs: .
   main-is: benchmark.hs
   ghc-options: -O2 -fspecialise-aggressively
@@ -148,7 +179,20 @@
   default-language: Haskell2010
 
 executable krausest
-  build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum, vector
+  build-depends: base
+               , containers
+               , dependent-map
+               , dependent-sum
+               , ghc-prim
+               , ghcjs-dom
+               , mtl
+               , prim-uniq
+               , random
+               , reflex
+               , reflex-dom
+               , text
+               , transformers
+               , vector
   hs-source-dirs: benchmarks
   main-is: krausest.hs
   ghc-options: -O2 -fspecialise-aggressively
diff --git a/src-android/Reflex/Dom/Android/MainWidget.hsc b/src-android/Reflex/Dom/Android/MainWidget.hsc
--- a/src-android/Reflex/Dom/Android/MainWidget.hsc
+++ b/src-android/Reflex/Dom/Android/MainWidget.hsc
@@ -2,11 +2,15 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Reflex.Dom.Android.MainWidget
   ( startMainWidget
+  , goBack
+  , JSExecutor(..)
+  , withGlobalJSExecutor
   ) where
 
 import Android.HaskellActivity
 import Control.Concurrent
 import Control.Monad
+import Control.Monad.IO.Class
 import Data.Aeson
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as BS
@@ -23,10 +27,10 @@
 import Language.Javascript.JSaddle (JSM)
 import Language.Javascript.JSaddle.Run (runJavaScript)
 import Language.Javascript.JSaddle.Run.Files (initState, runBatch, ghcjsHelpers)
+import System.IO.Unsafe
 
 #include "MainWidget.h"
 
-
 startMainWidget :: HaskellActivity -> ByteString -> JSM () -> IO ()
 startMainWidget a url jsm = do
   --TODO: Find a way to eventually release this
@@ -57,13 +61,27 @@
         \jsaddle.postReady();\n"
     }
   BS.useAsCString url $ \curl -> do
-    writeIORef executorRef =<< startMainWidget_ a curl callbacks
+    executor <- startMainWidget_ a curl callbacks
+    writeIORef executorRef executor
+    writeIORef globalJSExecutor $ Just executor
 
 newtype JSExecutor = JSExecutor { unJSExecutor :: Ptr JSExecutor }
 
+-- Ugh. But not doing this is also unfortunate for being able to clear the history so that the "back" list is good.
+globalJSExecutor :: IORef (Maybe JSExecutor)
+globalJSExecutor = unsafePerformIO $ newIORef Nothing
+
+withGlobalJSExecutor :: MonadIO m => (JSExecutor -> IO ()) -> m ()
+withGlobalJSExecutor f = liftIO $ do
+  executor <- readIORef globalJSExecutor
+  case executor of
+    Just e -> f e
+    _ -> pure ()
+
 foreign import ccall safe "Reflex_Dom_Android_MainWidget_start" startMainWidget_ :: HaskellActivity -> CString -> Ptr JSaddleCallbacksPtrs -> IO JSExecutor
 
 foreign import ccall safe "Reflex_Dom_Android_MainWidget_runJS" runJS :: JSExecutor -> CString -> CSize -> IO ()
+foreign import ccall safe "Reflex_Dom_Android_MainWidget_back" goBack :: JSExecutor -> IO ()
 
 data JSaddleCallbacks = JSaddleCallbacks
   { _jsaddleCallbacks_jsaddleStart :: IO ()
diff --git a/src/Reflex/Dom.hs b/src/Reflex/Dom.hs
--- a/src/Reflex/Dom.hs
+++ b/src/Reflex/Dom.hs
@@ -6,5 +6,6 @@
 
 import Foreign.JavaScript.Orphans ()
 import Reflex.Dom.Core as X hiding (mainWidget, mainWidgetInElementById, mainWidgetWithCss,
-                             mainWidgetWithHead, mainWidgetWithHead', runApp')
+                             mainWidgetWithHead, mainWidgetWithHead', runApp',
+                             mainHydrationWidgetWithHead, mainHydrationWidgetWithHead')
 import Reflex.Dom.Internal as X
diff --git a/src/Reflex/Dom/Internal.hs b/src/Reflex/Dom/Internal.hs
--- a/src/Reflex/Dom/Internal.hs
+++ b/src/Reflex/Dom/Internal.hs
@@ -4,25 +4,28 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE TypeFamilies #-}
 module Reflex.Dom.Internal
-       (module Main, run, mainWidget, mainWidgetWithHead, mainWidgetWithCss,
-        mainWidgetWithHead', mainWidgetInElementById, runApp') where
+  ( module Main
+  , run
+  , mainWidget
+  , mainWidgetWithHead, mainWidgetWithCss, mainWidgetWithHead', mainWidgetInElementById, runApp'
+  , mainHydrationWidgetWithHead, mainHydrationWidgetWithHead'
+  ) where
 
 import Data.ByteString (ByteString)
 import Data.Text (Text)
-import Reflex.Dom.Core (Widget)
 import Reflex.Dom.Main as Main hiding
        (mainWidget, mainWidgetWithHead, mainWidgetWithCss,
-        mainWidgetWithHead', mainWidgetInElementById, runApp')
+        mainWidgetWithHead', mainWidgetInElementById, runApp',
+        mainHydrationWidgetWithHead, mainHydrationWidgetWithHead')
 import qualified Reflex.Dom.Main as Main
        (mainWidget, mainWidgetWithHead, mainWidgetWithCss,
-        mainWidgetWithHead', mainWidgetInElementById, runApp')
+        mainWidgetWithHead', mainWidgetInElementById, runApp',
+        mainHydrationWidgetWithHead, mainHydrationWidgetWithHead')
 
 #if defined(ghcjs_HOST_OS)
 run :: a -> a
 run = id
 #elif defined(MIN_VERSION_jsaddle_warp)
-import Data.Maybe (maybe)
-import Data.Monoid ((<>))
 import Language.Javascript.JSaddle (JSM)
 import qualified Language.Javascript.JSaddle.Warp as JW
 import System.Environment (lookupEnv)
@@ -32,6 +35,7 @@
   port <- maybe 3003 read <$> lookupEnv "JSADDLE_WARP_PORT"
   putStrLn $ "Running jsaddle-warp server on port " <> show port
   JW.run port jsm
+
 #elif defined(MIN_VERSION_jsaddle_wkwebview)
 #if defined(ios_HOST_OS)
 import Data.Default
@@ -50,18 +54,24 @@
       return ""
     Just p -> return $ "file://" <> p <> "/index.html"
   run' def $ jsaddleMainHTMLWithBaseURL indexHtml baseUrl jsm
+
 #else
 import Language.Javascript.JSaddle.WKWebView (run)
 #endif
 #elif defined(ANDROID)
 import Android.HaskellActivity
 import Control.Monad
+import Control.Monad.IO.Class (liftIO, MonadIO)
 import Control.Concurrent
+import Language.Javascript.JSaddle (JSM)
 import Data.Default
+import Data.IORef
+import Data.Maybe
 import Data.String
 import Reflex.Dom.Android.MainWidget
 import System.IO
-import Language.Javascript.JSaddle (JSM)
+import System.IO.Unsafe
+import Language.Javascript.JSaddle (JSM, eval)
 
 run :: JSM () -> IO ()
 run jsm = do
@@ -70,12 +80,24 @@
   continueWithCallbacks $ def
     { _activityCallbacks_onCreate = \_ -> do
         a <- getHaskellActivity
-        let startPage = fromString "file:///android_asset/index.html"
+        let startPage = fromString "https://appassets.androidplatform.net/index.html"
         startMainWidget a startPage jsm
+    , _activityCallbacks_onBackPressed = triggerBackButton
     }
   forever $ threadDelay 1000000000
+
+triggerBackButton :: MonadIO m => m ()
+triggerBackButton = withGlobalJSExecutor goBack
+
+#elif defined(wasm32_HOST_ARCH)
+import qualified Language.Javascript.JSaddle.Wasm as Wasm (run)
+import Language.Javascript.JSaddle (JSM)
+run :: JSM () -> IO ()
+run = Wasm.run
+
 #else
 import Language.Javascript.JSaddle.WebKitGTK (run)
+
 #endif
 
 mainWidget :: (forall x. Widget x ()) -> IO ()
@@ -101,3 +123,11 @@
 runApp' :: (forall x. AppInput DomTimeline -> Widget x (AppOutput DomTimeline)) -> IO ()
 runApp' app = run $ Main.runApp' app
 {-# INLINE runApp' #-}
+
+mainHydrationWidgetWithHead :: (forall x. HydrationWidget x ()) -> (forall x. HydrationWidget x ()) -> IO ()
+mainHydrationWidgetWithHead h b = run $ Main.mainHydrationWidgetWithHead h b
+{-# INLINE mainHydrationWidgetWithHead #-}
+
+mainHydrationWidgetWithHead' :: HydrationWidget () () -> HydrationWidget () () -> IO ()
+mainHydrationWidgetWithHead' h b = run $ Main.mainHydrationWidgetWithHead' h b
+{-# INLINE mainHydrationWidgetWithHead' #-}
diff --git a/src/Reflex/Dom/Location/Platform.hs b/src/Reflex/Dom/Location/Platform.hs
new file mode 100644
--- /dev/null
+++ b/src/Reflex/Dom/Location/Platform.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+#if defined(ANDROID)
+module Reflex.Dom.Location.Platform where
+
+import Reflex
+import Control.Monad.IO.Class
+import Reflex.Dom.Android.MainWidget
+
+popHistoryState
+  :: (PerformEvent t m, MonadIO (Performable m))
+  => Event t ()
+  -> m ()
+popHistoryState evt = performEvent_ $ withGlobalJSExecutor goBack <$ evt
+#else
+module Reflex.Dom.Location.Platform (Reflex.Dom.Location.popHistoryState) where
+import qualified Reflex.Dom.Location
+
+#endif
+
