Created: 2012-03-20 05:49
Updated: 2018-09-21 20:46
License: mit

Google Custom Search

This project is a Ruby lib for Google's Custom Search ENgine API ( There seem to be quite a few cse libs out there that don't work so I rolled this up quickly.

Questions/comments, etc:


Add to your Gemfile:

gem "google_custom_search_api"


bundle install


You need to configure GOOGLE_SEARCH_CX and GOOGLE_API_KEY to config/initializers/google_cse_api.rb:

  GOOGLE_API_KEY = "..."

Google's API management is confusing at best. At the time of this writing you codes like so:


  • Go to Google Projects
  • Create a project, open it
  • Under Explore other services choose Enable APIs and get credentials like keys
  • Search for custom search and click on it
  • In the left column click on Credentials
  • Under API keys grab your key. This is your GOOGLE_API_KEY


  • Go to Google CSE
  • Create a search engine and click on it
  • Under Setup > Tabs > Basic find Details and click Search engine ID
  • This is your GOOGLE_SEARCH_CX
  • Make sure to add a site under Sites to search



To perform a search:

  results ="poker")

Results now contains a raw version and a class'ed version of the data show in Sample results below.

This means you can do:

  results["items"].each do |item|
  	puts item["title"], item["link"]


  results.items.each do |item|
    puts item.title,


Google only returns 10 results at a time and a maximum of 100 results. The easiest way to page through results if to use :page. Paging is 1 based (1-10). The default page is 1

  results ="poker", page: 2)
  results.pages == 10
  results.current_page == 2
  results.next_page == 3
  results.previous_page == 1

  results ="poker", page: 1)
  results.pages == 10
  results.current_page == 1
  results.next_page == 2
  results.previous_page == nil

  results ="poker", page: 10)
  results.pages == 10
  results.current_page == 10
  results.next_page == nil
  results.previous_page == 9

You can also use :start - which can be any number between 1 and 99. The :page helpers won't be accurate with :start

Example: get results 13-23

  results ='poker', start: 13)

See Custom Search documentation for an explanation of all fields available.

Search and return all results

This method isn't so useful because it's pretty slow (do to fetching up to 10 pages from Google). Helpful for testing sometimes.

  results = search_and_return_all_results('poker')
  results.first.items.size # == 10
  search_and_resturn_all_results('poker') do |results|
    results.items.size # == 10  10 times
    '"California cult winery known for its Rhône"') do |results|
    results.items.size # == 3  1 time


Custom Search only returns a maximum of 100 results so - if you try something like

  results ='poker', start: 101)

You get error and empty items.

	  "error"=> {
	    "errors"=> [
	         "message"=>"Invalid Value"
	    "message"=>"Invalid Value"

So check for:

  if results.try(:error) || results.items.empty?

Rails example

In Gemfile

gem "google_custom_search_api"

In config/initializers/google_search.rb


In config/routes.rb

  get '/search' => 'search#index'

In app/controllers/search_controller.rb you'd have something like this:

class SearchController < ApplicationController
  def index
    if params[:q]
      page = params[:page] || 1
      @results =[:q],
                                              page: page)

And a simple view might look like this app/search/index.html.erb (this is using bootstrap styling)

<section class='search-section'>
  <div class='text-center titles-with-yellow'>
  <div class='container'>
    <div class='text-center search-bar'>
      <%= form_tag search_path, method: :get  do %>
        <div class="inner-addon right-addon">
          <i class="glyphicon glyphicon-search"></i>
          <%= text_field_tag :q, params[:q], class: 'form-control' %>
      <% end %>

  <% if @results && !@results.items.empty? %>
    <div class='container'>
      <% @results.items.each do |item| %>
        <div class='row'>
          <h4><%= link_to item.htmlTitle.html_safe, %></h4>
            <% if item['pagemap'] &&
                  item['pagemap']['cse_thumbnail'] &&
                  img = item.pagemap.cse_thumbnail.first %>
              <div class='col-sm-2'>
                <%= image_tag(img.src, width: '200px') %>
              <div class='col-sm-10'>
                <%= item.htmlSnippet.html_safe %>
            <% else %>
              <%= item.htmlSnippet.html_safe %>
            <% end %>
      <% end %>
    <div class='container search-prev-next'>
      <div class='row text-center'>
        <% if @results.previous_page %>
          <%= link_to '<< Previous',
            search_path(q: params[:q], page: @results.previous_page),
            class: 'btn' %>
        <% end %>
        <% @results.pages.times do |i| %>
          <%= link_to i + 1,
            search_path(q: params[:q], page: i+1),
            class: 'btn btn-page' %>
        <% end %>
        <% if @results.next_page %>
          <%= link_to 'Next >>',
            search_path(q: params[:q],
                        page: @results.next_page),
            class: 'btn' %>
        <% end %>
  <% else %>
    <h4>No results</h4>
  <% end %>

Encoding issues

TODO - this section needs work

CSE will return non utf-8 results which can be problematic. I might add in a config value that you can explicitly set encoding. Until then a work around is doing stuff like:


More on this here:

Contributing - Running tests

Pull requests welcome.

To run tests

  git clone
  cd google_custom_search_api
  bundle install
  bundle exec rspec spec


Copyright (c) 2012 Ben Wiseley, released under the MIT license

Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more