diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb
index 7f4f927d913d635b10e7a2a5f1153d7a940599a1..104de94ce816189cac2bb113013aeeefa9d1b944 100644
--- a/lib/geocoder/lookup.rb
+++ b/lib/geocoder/lookup.rb
@@ -34,6 +34,7 @@ module Geocoder
         :mapquest,
         :ovi,
         :baidu,
+        :cloudmade,
         :test
       ]
     end
diff --git a/lib/geocoder/lookups/cloudmade.rb b/lib/geocoder/lookups/cloudmade.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a5d36177d2e80e08b89b26093e3239bd4b2bd5f0
--- /dev/null
+++ b/lib/geocoder/lookups/cloudmade.rb
@@ -0,0 +1,35 @@
+require 'geocoder/lookups/base'
+require 'geocoder/results/cloudmade'
+
+module Geocoder::Lookup
+  class Cloudmade < Base
+
+    def name
+      "Cloudmade"
+    end
+
+    def query_url(query)
+      "http://geocoding.cloudmade.com/#{configuration.api_key}/geocoding/v2/find.js?#{url_query_string(query)}"
+    end
+
+    def required_api_key_parts
+      ["key"]
+    end
+
+    private
+
+    def results(query)
+      data = fetch_data(query)
+      (data && data['features']) || []
+    end
+
+    def query_url_params(query)
+      params = {
+        :query => query.sanitized_text,
+        :return_location => true,
+        :return_geometry => false
+      }.merge(super)
+    end
+
+  end
+end
diff --git a/lib/geocoder/results/cloudmade.rb b/lib/geocoder/results/cloudmade.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4f62146e0b17236dd8c55d1e071bae898996b39b
--- /dev/null
+++ b/lib/geocoder/results/cloudmade.rb
@@ -0,0 +1,39 @@
+require 'geocoder/results/base'
+
+module Geocoder::Result
+  class Cloudmade < Base
+
+    def coordinates
+      @data["centroid"]["coordinates"]
+    end
+
+    def street
+      @data["location"]["road"]
+    end
+
+    def city
+      @data["location"]["city"]
+    end
+    
+    def state
+      @data["location"]["county"]
+    end
+    alias_method :state_code, :state
+
+    def country
+      @data["location"]["country"]
+    end
+    alias_method :country_code, :country
+
+    def postal_code
+      @data["location"]["postcode"]
+    end
+
+    def address
+      [street, city, state, postal_code, country].compact.reject{|s| s.length == 0 }.join(", ")
+    end
+
+  end
+end
+
+
diff --git a/test/fixtures/cloudmade_invalid_key b/test/fixtures/cloudmade_invalid_key
new file mode 100644
index 0000000000000000000000000000000000000000..0b133da566155c8f3e45f634d0863436135f5a93
--- /dev/null
+++ b/test/fixtures/cloudmade_invalid_key
@@ -0,0 +1 @@
+Forbidden request
diff --git a/test/fixtures/cloudmade_madison_square_garden b/test/fixtures/cloudmade_madison_square_garden
new file mode 100644
index 0000000000000000000000000000000000000000..6fa280de07fe40eeb1ec81c7decd6fec807295b3
--- /dev/null
+++ b/test/fixtures/cloudmade_madison_square_garden
@@ -0,0 +1 @@
+{"found": 2, "bounds": [[40.74983, -73.99433], [40.75116, -73.99266]], "features": [{"id": 32891803,"centroid": {"type":"POINT","coordinates":[40.75111, -73.99345]},"bounds": [[40.74983, -73.99433], [40.75116, -73.99266]],"properties": {"osm_element": "way", "sport": "hockey;basketball;lacrosse", "name": "Madison Square Garden", "leisure": "stadium", "osm_id": "24801588"},"location": {"county": "New York", "country": "United States of America", "postcode": "10119", "road": "West 31st Street", "city": "New York"},"type": "Feature"},{"id": 12977552,"centroid": {"type":"POINT","coordinates":[40.75066, -73.99347]},"bounds": [[40.75066, -73.99347], [40.75066, -73.99347]],"properties": {"building": "yes", "osm_element": "node", "name": "Madison Square Garden Center", "addr:state": "NY", "osm_id": "368045579"},"location": {"county": "New York", "country": "United States of America", "postcode": "10119", "road": "West 33rd Street", "city": "New York"},"type": "Feature"}], "type": "FeatureCollection", "crs": {"type": "EPSG", "properties": {"code": 4326, "coordinate_order": [0, 1]}}}
diff --git a/test/fixtures/cloudmade_no_results b/test/fixtures/cloudmade_no_results
new file mode 100644
index 0000000000000000000000000000000000000000..0967ef424bce6791893e9a57bb952f80fd536e93
--- /dev/null
+++ b/test/fixtures/cloudmade_no_results
@@ -0,0 +1 @@
+{}
diff --git a/test/lookup_test.rb b/test/lookup_test.rb
index 56ccf99294ffc1fc03fb240b28ef82a1ff1ba756..c52a2154ed129223b407ed8cd2326ffd93c73c91 100644
--- a/test/lookup_test.rb
+++ b/test/lookup_test.rb
@@ -70,7 +70,7 @@ class LookupTest < Test::Unit::TestCase
     # keep test output clean: suppress timeout warning
     orig = $VERBOSE; $VERBOSE = nil
     #Geocoder::Lookup.all_services_except_test.each do |l|
-    [:bing, :yahoo, :yandex, :maxmind].each do |l|
+    [:bing, :yahoo, :yandex, :maxmind, :cloudmade].each do |l|
       Geocoder.configure(:lookup => l)
       set_api_key!(l)
       assert_equal [], Geocoder.search("invalid key")