Geo::Coder::HostIP - get geocoding info for an IP address


  use strict;
  use CGI;
  use Geo::Coder::HostIP;
  my $cgi = new CGI;
  my $geo = new Geo::Coder::HostIP;
  print $cgi->header;
  my ($lat, $long);
  if ($cgi->param('ip')) {
      ($lat, $long) = $geo->FetchIP($cgi->param('ip'));
  else {
      ($lat, $long) = $geo->FetchRemoteAddr;
  my $zoom = $cgi->param('zoom') || 13;
  if (defined $lat && defined $long) {
      print $geo->GoogleMap({apikey => 'reallylongstringthatgooglegivesyou',
                             control => 'small',
                             scalecontrol => 1,
                             typecontrol => 1,
                             overviewcontrol => 1});
  else {
      print "I can't find you.";


Geo::Coder::HostIP is an Object-Oriented module intended to make use of the HostIP API documented at

It's useful for web stuff, but it's useful for other stuff too, like figuring out if, for instance, the majority of people hitting your spanish language webpage are Spanish or Mexican, for instance, and thus deciding whether to say 'auto' or 'carro'.

This module requires LWP.


You create a Geo::Coder::HostIP object, which I'm calling 'geo' because it's a relatively simple thing to call it, but you can call it anything you want. Except 'menlo' because I hate that word and I don't know why.

new() can be called void. If you want, you can give it one argument to override the default server of '' with something else. However, that something else had better have the same scripts in the same places with the same arguments wanted, etc. Else it will break.

At the time of thos writing, it only works in about 40-50% of cases depending on the IP's locale.

Public Methods

Several nice convenience methods are supplied, so you can make the module do the thinking and you can get back to drinking... or whatever. Why is the rum always gone?

new($addr=null) (constructor)

As stated above, this creates a new Geo::Coder::HostIP object. That's it. It doesn't do any getting of infos until you tell it to. This is to make it so you have to deliberately choose to navigate this great series of tubes.

  my $geo = new Geo::Coder::HostIP;

Takes any string and makes that be the UserAgent string used by LWP.


Takes any string that is an IP address and attempts to retrieve the data from for it. If successful, it returns either a list containing the Latitude and Longitude thus found, or, if called in scalar context, a string that says "Lat: ###, Long: ###" where the ##s denote the values thereof.

Latitude and Longitude are returned in decimal format.

Don't try to use private network IP addresses. That's just a bit daft.

  my ($lat, $long) = $geo->FetchIP('');

If it fails, the list context returns the empty list, and scalar returns the string "Coordinates Not Found".

Remember that print() implies list mode, not scalar mode, before you just print right off this!

Also, this populates the data itcan find into the object, up to Country, Country Code, City, State (US only), Latitude and Longitude.


Works like FetchIP above, but expects a domain name. Returns the same stuff and populates the properties just the same. Matter of fact, it just gets the IP address and then passes that on to FetchIP and returns whatever it gets.

  my ($lat, $long) = $geo->FetchName('');

Works like FetchIP above, but automatically uses the value stored in $ENV{REMOTE_ADDR} if present and defined.

Lat(), Latitude()

After something is fetched using any of the above three methods, returns the latitude numerically. Returns undef if the latitude is not set. Returns 0 if latitude is set to something non-numeric.

Long(), Longitude()

See Lat() above and try and guess really hard.


Returns the City property if set, or undef if not. Doesn't let you set it though. Set the property for that, though that's... Well, how should I know? You might have a reason.


Gee, guess what this does?


Again... obvious as hell.


La la la.

item Coords()

returns the same thing the preceding Fetch*() method would have returned, but doesn't take an argument and doesn't do any fetching. Rather it uses the current values in the hash.

item GoogleMap($ip=null, ${apikey, id='googlemap', func_name='load', width=500, height=300, zoom=13, control='small', scalecontrol=0, typecontrol=0, overviewcontrol=0})

Okay, this one's pretty cool... GoogleMap() gives you back HTML code for -- you guessed it. A Google map.

It takes an optional IP address, which it will fetch if provided. Note that if you do not provide an IP address, do NOT supply 'undef' as an argument! Just leave it out altogether, otherwise it will depopulate the object.

Next (or first and last and only if you leave out th IP address), it takes a hashref of parmetres, which MUST contain a true string keyed by 'apikey' or it will not bother and return undef. Of course, the idea here is that you give it your google maps API key, so that the results actually work on your page.

This hashref may also contain several other parametres. Among them are height and width, which will set the height and width of the map in pixels and default to 300 and 500 respectively, id which will set the HTML element id of the map itself and defaults to 'googlemap', and fname which will determine the name to be used for the onLoad JavaScript function in case you want to change it from the default of 'load'.

Also there's 'zoom' which sets the default zoom, which defaults to 13, about normal city-level street view.

Next there's control, which can be set to 'large', 'small', or any other true value. If 'large' the map will get the large google scale/pan control. If 'small' it will get the smaller version, and if set to some other true value it will get the little scale-only control up in the left upper corner.

Then there are the other controls, which are booleans (defaulting to 0, i.e. false). If present and true, 'scalecontrol' will add the little scale meter, 'typecontrol' will give the user the buttons that let them switch to aerial photography view and hybrid type maps, and 'overviewcontrol' will give the little inset map in the lower right corner that shows how the rest of the map fits into its surroundings.

You can, of course, parse the HTML resulting and do things to it, or just run a regex on it to make it different. It does include a BODY and /BODY tag, so you may want to. The HTMl thus output has two HTML comments embedded in it, which contain ' {{ADDITIONAL HEAD}} ' and ' {{ADDITIONAL BODY}} ' inside a proper HTML comment tag, for your convenience in this regard.

Private Methods


Goes and grabs the data and calls _parse if successful.


Parses out the results of _request



The object is a hashref of properties once populated. These are set by the _parse() method. You get to these with:


These are case sensitive, capitalised, and potentially contain: Country, Country_Code, City, State, Latitude, Longitude

There's also 'ip' which isn't capitalised, and it set whenever you call a Fetch*() method.

There are also some private properties, which you shouldn't aughtta muck about with without good reason, including: _server, _agent, and _ua. _server is the address of the server (as may be set in new()), _agent is the UserAgent string (as set in Agent()), and _ua is an LWP object.


  • Make GoogleMap more robust

  • Add YahooMap and, if they make an API, MapQuestMap

  • Add GetWeather function. That'd be cool. And maybe some other fun toy methods, like MeasureDistance(ip, ip), and Traceroute(ip) the latter of which might actually do a traceroute on every IP along the way and work out how many miles the packets actually travelled. Altitude() is another thought, and possible to get from public info as long as Latitude and Longitude are populated.


As of 0.03 the module is now maintained by Neil Bowers <>.

Dodger -





This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.