Waze GeoRedirect
GeoRedirect
is a Rack middleware that can be configured to
redirect incoming clients to different hosts based on their
geo-location data.
For instance, we use it for our advertisers site to redirect users to:
- biz.waze.co.il for Israel-incoming traffic.
- biz.waze.com for US and Canada incoming traffic.
- biz-world.waze.com for any other sources.
The server stores a session variable with the server it decided on, for future traffic from the same client.
In addition, you can override these redirects by adding ?redirect=1
to any
URL, and by that forcing the server to host from the current domain (and saving
that domain to the user's session variable).
To skip geo-redirection completely, pass a ?skip_geo=true
argument (this would
avoid saving any session value and/or HTTP redirects).
Installation
Add this line to your application's Gemfile:
gem 'geo_redirect'
And then execute:
$ bundle
Usage
These usage instructions were written for Rails products, although I'm pretty sure you could use the gem with any other Rack-based solution.
You'll need to add this to your production.rb
:
Rails.application.middleware.use GeoRedirect::Middleware
This will make sure GeoRedirect
runs before your application gets rolling.
The middleware requires two additional files to be present:
1. Configuration YML
This should be a YML file representing your redirection rules.
Here's a template that we use for the setup described above:
:us:
:host: 'biz.waze.com'
:countries: ['US', 'CA']
:il:
:host: 'biz.waze.co.il'
:countries: ['IL']
:world: &default
:host: 'biz-world.waze.com'
:default: *default
Note that:
- Every main item is a location, and must have a
host
configured. - A location can have a
countries
array. This will cause a redirect to this location for users from that country code. For available country codes, see ISO 3166 Country Codes list from MaxMind (the Geo IP providerGeoRedirect
uses). - There must be a
default
location that would be used in case the client can't be geo-located.
2. GeoIP Countries database
GeoRedirect
uses the geoip
gem for its
geo-location functionality. In particular, it requires the GeoLite country
free database from MaxMind.
You can download the database file directly from
MaxMind
and unzip it into db/
in your project, or you could use the following
rake
task designed just for that:
$ rake geo_redirect:fetch_db
It'd be a good idea to use this task on your (Capistrano or whatever) deployment scripts.
Scoping redirects for certain URLs
By default, GeoRedirect runs on all incoming requests and redirects accordingly.
You may want GeoRedirect to either ignore some URLs (a blacklist), or only run
the redirection logic over a certain list of URLs (a whitelist). This can be
done through the :exclude
and :include
options.
Rails.application.middleware.use GeoRedirect::Middleware, include: '/'
will only redirect incoming requests to 'example.org/', and ignore any other paths.
Rails.application.middleware.use GeoRedirect::Middleware, exclude: '/excluded_path'
will ignore requests to 'example.org/excluded_path' but redirect all other incoming requests.
The value for both options can be either a single path string or an array of paths. All should include the leading slash.
Custom paths
The default paths for these files are:
config/geo_redirect.yml
db/GeoIP.dat
If that doesn't suit you, you can customize these when adding GeoRedirect
to
your project:
Rails.application.middleware.use GeoRedirect::Middleware, {
db: 'db/geo_database.dat',
config: 'geo_cfg.yml'
}
Custom logic to skip the redirection
You can pass a block to the :skip_if
option to provide custom logic to skip the redirection.
Rails.application.middleware.use GeoRedirect::Middleware, skip_if: ->(req) { req.bot? }
will ignore requests from bots (the code inside the block is just pseudo-code).
Skipping
As mentioned, skipping Geo-redirection is done either by:
-
redirect=1
to force a new domain and remember it in the user's session variable. -
skip_geo=true
for a one-time force (with no memory).
If the :remember_when_skipping
option flag is set to true, the server will
always remember the current domain, even after skipping.
Debugging
You can add a logfile
path string when adding the middleware if you want it to
log some of its decision process into the file.
This is useful when working on your configuration YAML.
Rails.application.middleware.use GeoRedirect::Middleware, logfile: 'log/geo_redirect.log'
GeoRedirect
's log messages will always be prefixed with [GeoRedirect]
.
Accessing discovered country
The country code discovered for the current user is available for your
convenience, under session['geo_redirect.country']
.
You can use it to make content decisions, or whatever.
Known Issues
A couple issues I know about but haven't had the time to fix:
- Cross-domain session var is required. In particular, if your stubborn user
goes to more than 1 server with
?redirect=1
, all of these servers will never redirect them again (until the session is expired). - When a client accesses your site from an unknown hostname (one that was not
configured in the
yml
file) with?redirect=1
, they will stay in that hostname for the current session, but in the future would be redirected to the configured default hostname (because it was saved on their session var).
Contributing
- Fork it!
- Create your feature branch! (
git checkout -b my-new-feature
) - Commit your changes! (
git commit -am 'Add some feature'
) - Push to the branch! (
git push origin my-new-feature
) - Create new Pull Request!