diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
 [![Hackage](https://img.shields.io/hackage/v/ghcjs-base-stub.svg)](https://hackage.haskell.org/package/ghcjs-base-stub)
+[![Build Status](https://secure.travis-ci.org/louispan/ghcjs-base-stub.png?branch=master)](http://travis-ci.org/louispan/ghcjs-base-stub)
 
 Fake stubs for GHCJS base to allow GHCJS projects to be compiled using GHC.
 This also allows developing under intero, and generating haddocks.
@@ -24,3 +25,6 @@
 
 * 0.1.0.3
   - Added Javascript.Web.Storage
+
+* 0.1.0.4
+  - Added Javascript.Web.Location
diff --git a/ghcjs-base-stub.cabal b/ghcjs-base-stub.cabal
--- a/ghcjs-base-stub.cabal
+++ b/ghcjs-base-stub.cabal
@@ -1,5 +1,5 @@
 name:                ghcjs-base-stub
-version:             0.1.0.3
+version:             0.1.0.4
 synopsis:            Allow GHCJS projects to compile under GHC and develop using intero.
 description:         Allow GHCJS projects to compile under GHC and develop using intero.
 homepage:            https://github.com/louispan/javascript-stub#readme
@@ -44,6 +44,7 @@
                        JavaScript.Cast
                        JavaScript.Object
                        JavaScript.Object.Internal
+                       JavaScript.Web.Location
                        JavaScript.Web.Storage
       build-depends:   aeson >= 0.11 && < 2
                      , attoparsec >= 0.13 && < 1
diff --git a/src/JavaScript/Web/Location.hs b/src/JavaScript/Web/Location.hs
new file mode 100644
--- /dev/null
+++ b/src/JavaScript/Web/Location.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module JavaScript.Web.Location ( Location
+                               , getWindowLocation
+                               , getHref
+                               , setHref
+                               , getProtocol
+                               , setProtocol
+                               , getHost
+                               , setHost
+                               , getHostname
+                               , setHostname
+                               , getPort
+                               , setPort
+                               , getPathname
+                               , setPathname
+                               , getSearch
+                               , setSearch
+                               , getHash
+                               , setHash
+                               , getUsername
+                               , setUsername
+                               , getPassword
+                               , setPassword
+                               , getOrigin
+                               , assign
+                               , reload
+                               , replace
+                               ) where
+
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import Data.IORef (IORef, modifyIORef, newIORef, readIORef)
+import Data.JSString hiding (replace)
+import System.IO.Unsafe (unsafePerformIO)
+
+newtype Location = Location (IORef (Map JSString JSString))
+
+windowLocation :: Location
+windowLocation = Location . unsafePerformIO $ newIORef mempty
+{-# NOINLINE windowLocation #-}
+
+getWindowLocation :: IO Location
+getWindowLocation = pure windowLocation
+
+getHref :: Location -> IO JSString
+getHref (Location l) = (M.! "href") <$> readIORef l
+
+setHref :: JSString -> Location -> IO ()
+setHref v (Location l) = modifyIORef l $ M.insert "href" v
+
+getProtocol :: Location -> IO JSString
+getProtocol (Location l) = (M.! "protocol") <$> readIORef l
+
+setProtocol :: JSString -> Location -> IO ()
+setProtocol v (Location l) = modifyIORef l $ M.insert "protocol" v
+
+getHost :: Location -> IO JSString
+getHost (Location l) = (M.! "host") <$> readIORef l
+
+setHost :: JSString -> Location -> IO ()
+setHost v (Location l) = modifyIORef l $ M.insert "host" v
+
+getHostname :: Location -> IO JSString
+getHostname (Location l) = (M.! "hostname") <$> readIORef l
+
+setHostname :: JSString -> Location -> IO ()
+setHostname v (Location l) = modifyIORef l $ M.insert "hostname" v
+
+getPort :: Location -> IO JSString
+getPort (Location l) = (M.! "port") <$> readIORef l
+
+setPort :: JSString -> Location -> IO ()
+setPort v (Location l) = modifyIORef l $ M.insert "port" v
+
+getPathname :: Location -> IO JSString
+getPathname (Location l) = (M.! "pathname") <$> readIORef l
+
+setPathname :: JSString -> Location -> IO ()
+setPathname v (Location l) = modifyIORef l $ M.insert "pathname" v
+
+getSearch :: Location -> IO JSString
+getSearch (Location l) = (M.! "search") <$> readIORef l
+
+setSearch :: JSString -> Location -> IO ()
+setSearch v (Location l) = modifyIORef l $ M.insert "search" v
+
+getHash :: Location -> IO JSString
+getHash (Location l) = (M.! "hash") <$> readIORef l
+
+setHash :: JSString -> Location -> IO ()
+setHash v (Location l) = modifyIORef l $ M.insert "hash" v
+
+getUsername :: Location -> IO JSString
+getUsername (Location l) = (M.! "username") <$> readIORef l
+
+setUsername :: JSString -> Location -> IO ()
+setUsername v (Location l) = modifyIORef l $ M.insert "username" v
+
+getPassword :: Location -> IO JSString
+getPassword (Location l) = (M.! "password") <$> readIORef l
+
+setPassword :: JSString -> Location -> IO ()
+setPassword v (Location l) = modifyIORef l $ M.insert "password" v
+
+getOrigin :: Location -> IO JSString
+getOrigin (Location l) = (M.! "origin") <$> readIORef l
+
+assign :: JSString -> Location -> IO ()
+assign _ _ = pure ()
+
+reload :: Bool -> Location -> IO ()
+reload _ _ = pure ()
+
+replace :: JSString -> Location -> IO ()
+replace _ _ = pure ()
