diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ba6da839414cc78716789fca34a7e3b1741ea859
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,20 @@
+before_script:
+  - git config --global url.https://.insteadOf git://
+  - mkdir -p ~/.hex
+  - printf "{key,<<\"$HEX_KEY\">>}.\n{username,<<\"$HEX_USERNAME\">>}.\n" > ~/.hex/hex.config
+
+stages:
+  - compile
+  - test
+
+compile:
+  stage: compile
+  script:
+    - mix deps.get
+    - mix compile
+
+test:
+  stage: test
+  script:
+    - mix deps.get
+    - mix test
diff --git a/GeoLite2-City.mmdb.gz b/GeoLite2-City.mmdb.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4aa5b0a7a1873ba280ad0ad73755576ebd8f751d
Binary files /dev/null and b/GeoLite2-City.mmdb.gz differ
diff --git a/GeoLite2-Country.mmdb.gz b/GeoLite2-Country.mmdb.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d9dfb035e83bebdd3c19893df09d4802064e5e79
Binary files /dev/null and b/GeoLite2-Country.mmdb.gz differ
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..20b9650eae79ef7d0ec123e0d6836d0d9ed76821
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Erik Hedenström <erik@erlang.ninja>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 9aef16fe05cb76eeb8c883c9cb4434774d647505..3a152702657abc500e45fdede559d6402eb11d4b 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,16 @@
-# Plug.GeoIP2
+# plug_geoip2
 
-**TODO: Add description**
+[![Hex.pm Version](http://img.shields.io/hexpm/v/plug_cloudflare.svg)](https://hex.pm/packages/plug_geoip2)
+[![Build Status](https://gitlab.hedenstroem.com/ci/projects/7/status.png?ref=master)](https://gitlab.hedenstroem.com/ci/projects/7?ref=master)
 
-## Installation
+## Setup
 
-If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:
+To use plug_geoip2 in your projects, edit your `mix.exs` file and add plug_geoip2 as a dependency:
 
-  1. Add plug_geoip2 to your list of dependencies in `mix.exs`:
-
-        def deps do
-          [{:plug_geoip2, "~> 0.0.1"}]
-        end
-
-  2. Ensure plug_geoip2 is started before your application:
-
-        def application do
-          [applications: [:plug_geoip2]]
-        end
+```elixir
+defp deps do
+  [
+    {:plug_geoip2, "~> 0.1"}
+  ]
+end
+```
diff --git a/config/config.exs b/config/config.exs
index 36a0977c1f8d8e8d8e2b10dea5ac213eff032a6a..aa4d73b3e876b2c34689ef795b250c6fbc27f919 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -28,3 +28,8 @@ use Mix.Config
 # here (which is why it is important to import them last).
 #
 #     import_config "#{Mix.env}.exs"
+config :geolix,
+  databases: [
+    { :city,    "GeoLite2-City.mmdb.gz" },
+    { :country, "GeoLite2-Country.mmdb.gz" }
+  ]
diff --git a/lib/mix/tasks/update_geolite2.ex b/lib/mix/tasks/update_geolite2.ex
new file mode 100644
index 0000000000000000000000000000000000000000..89d499b1d7a3e40dce31987af5b775776616e7ae
--- /dev/null
+++ b/lib/mix/tasks/update_geolite2.ex
@@ -0,0 +1,14 @@
+defmodule Mix.Tasks.Update.GeoLite2 do
+  use Mix.Task
+
+  @shortdoc "Fetches the latest GeoLite2 DBs from MaxMind."
+
+  def run(_) do
+    File.rm('GeoLite2-City.mmdb.gz')
+    File.rm('GeoLite2-Country.mmdb.gz')
+    :inets.start
+    :httpc.request(:get, {'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz', []}, [], [{:stream, 'GeoLite2-City.mmdb.gz'}])
+    :httpc.request(:get, {'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz', []}, [], [{:stream, 'GeoLite2-Country.mmdb.gz'}])
+  end
+
+end
diff --git a/lib/plug_geoip2.ex b/lib/plug_geoip2.ex
index 44e69f43d2bf654597a5bf65f823f7a52b927efd..96c95b99bdf1640f15da24c8ec7aa689f482b03c 100644
--- a/lib/plug_geoip2.ex
+++ b/lib/plug_geoip2.ex
@@ -1,2 +1,28 @@
 defmodule Plug.GeoIP2 do
+
+  @moduledoc """
+  Adds geo location to a Plug connection based upon the client IP address by using MaxMind's GeoIP2 database.
+
+  To use it, just plug it into the desired module. The lookup uses the remote_ip field of the connection.
+
+    plug Plug.GeoIP2, as: :raw, where: :city
+
+  ## Options
+
+    * `:as` - Return the result as a `:struct` or `:raw` (plain map)
+    * `:locale` - Language (atom) to fetch information for.
+      Only affects "top level" struct values.
+    * `:where` - Lookup information in a single registered database
+  """
+
+  @doc "Callback implementation for Plug.init/1"
+  def init(options) do
+    options
+  end
+
+  @doc "Callback implementation for Plug.call/2"
+  def call(conn, options) do
+    conn |> Plug.Conn.assign(:geolocation, Geolix.lookup(conn.remote_ip, options))
+  end
+
 end
diff --git a/mix.exs b/mix.exs
index b388d2470fe8f65fb1ea0be0e76f6e93b0846bdc..6ba3e0e6b4ddaafab48a502232e2dc14b551bf9b 100644
--- a/mix.exs
+++ b/mix.exs
@@ -7,26 +7,44 @@ defmodule Plug.GeoIP2.Mixfile do
      elixir: "~> 1.1",
      build_embedded: Mix.env == :prod,
      start_permanent: Mix.env == :prod,
-     deps: deps]
+     deps: deps,
+     package: package,
+     description: description]
   end
 
-  # Configuration for the OTP application
-  #
-  # Type "mix help compile.app" for more information
   def application do
-    [applications: [:logger]]
+    [applications: [ :geolix ]]
   end
 
-  # Dependencies can be Hex packages:
-  #
-  #   {:mydep, "~> 0.3.0"}
-  #
-  # Or git/path repositories:
-  #
-  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
-  #
-  # Type "mix help deps" for more examples and options
   defp deps do
-    []
+    [
+      {:plug, "~> 1.0"},
+      {:geolix, "~> 0.9"}
+    ]
   end
+
+  defp description do
+    """
+    Adds geo location to a Plug connection based upon the client IP address by using MaxMind's GeoIP2 database.
+    """
+  end
+
+  defp package do
+    %{
+      maintainers: ["Erik Hedenström"],
+      files: [
+        "GeoLite2-City.mmdb.gz",
+        "GeoLite2-Country.mmdb.gz",
+        "lib",
+        "mix.exs",
+        "LICENSE",
+        "README.md"
+      ],
+      licenses: ["MIT"],
+      links: %{
+        "GitLab" => "https://gitlab.hedenstroem.com/phoenix/plug_geoip2"
+      }
+    }
+  end
+
 end
diff --git a/mix.lock b/mix.lock
new file mode 100644
index 0000000000000000000000000000000000000000..f0f074b7fda548ae8834ffc686cbb76ee40017be
--- /dev/null
+++ b/mix.lock
@@ -0,0 +1,11 @@
+%{"certifi": {:hex, :certifi, "0.3.0"},
+  "coverex": {:hex, :coverex, "1.4.8"},
+  "geolix": {:hex, :geolix, "0.9.0"},
+  "hackney": {:hex, :hackney, "1.4.5"},
+  "httpoison": {:hex, :httpoison, "0.8.0"},
+  "idna": {:hex, :idna, "1.0.2"},
+  "mimerl": {:hex, :mimerl, "1.0.0"},
+  "plug": {:hex, :plug, "1.0.2"},
+  "poison": {:hex, :poison, "1.5.0"},
+  "poolboy": {:hex, :poolboy, "1.5.1"},
+  "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}}
diff --git a/test/plug_geoip2_test.exs b/test/plug_geoip2_test.exs
index ac774bc53579cc0cbc475623c3f0df1fd30d2b31..7533930291c318dffa608977b6bab406a0c5735e 100644
--- a/test/plug_geoip2_test.exs
+++ b/test/plug_geoip2_test.exs
@@ -1,8 +1,45 @@
+defmodule TestRouter do
+  use Plug.Router
+
+  plug :match
+  plug :dispatch
+  plug Plug.GeoIP2, as: :struct, locale: :en, where: :city
+
+  get "/" do
+    send_resp(conn, 200, "test")
+  end
+
+  match _, do: send_resp(conn, 404, "not found")
+
+end
+
 defmodule Plug.GeoIP2Test do
-  use ExUnit.Case
+  use ExUnit.Case, async: true
+  use Plug.Test
+
   doctest Plug.GeoIP2
 
-  test "the truth" do
-    assert 1 + 1 == 2
+  @opts TestRouter.init([])
+
+  test "sets location correctly" do
+    conn = conn(:get, "/")
+    conn = %Plug.Conn{conn | remote_ip: {92, 244, 7, 86}}
+    conn = check_http(conn)
+    assert conn.assigns.geolocation.city.name == "Solna"
+  end
+
+  test "handles localhost correctly" do
+    conn = conn(:get, "/")
+    conn = check_http(conn)
+    assert conn.assigns.geolocation == nil
   end
+
+  defp check_http(conn) do
+    conn = TestRouter.call(conn, @opts)
+    assert conn.state == :sent
+    assert conn.status == 200
+    assert conn.resp_body == "test"
+    conn
+  end
+
 end