Class: Seo::GoogleKeywordPlannerClient

Inherits:
Object
  • Object
show all
Defined in:
app/services/seo/google_keyword_planner_client.rb

Overview

Client for Google Keyword Planner API to get search volume data.
Uses the KeywordPlanIdeaService to fetch historical search metrics.

This is the authoritative source for keyword search volume since it comes
directly from Google. Unlike Ahrefs, there are no severe API rate limits.

Examples:

Get search volume for keywords

client = Seo::GoogleKeywordPlannerClient.new
result = client.get_search_volume(['floor heating', 'radiant heat'])
# => [{ keyword: 'floor heating', avg_monthly_searches: 12100, ... }, ...]

Constant Summary collapse

LANGUAGE_EN =

Language and location constants for US English

'languageConstants/1000'
GEO_US =

English

'geoTargetConstants/2840'
GEO_CA =

United States

'geoTargetConstants/2124'
API_TIMEOUT =

Timeout for API calls (seconds). The Google Ads gRPC client has no
built-in timeout, so we wrap calls with Ruby's Timeout to prevent
indefinitely blocking Sidekiq workers.

30

Instance Method Summary collapse

Constructor Details

#initializeGoogleKeywordPlannerClient

Returns a new instance of GoogleKeywordPlannerClient.



28
29
30
31
32
33
# File 'app/services/seo/google_keyword_planner_client.rb', line 28

def initialize
  @config = Heatwave::Configuration.fetch(:google_ads_client)
  @customer_id = @config[:login_customer_id]
  @client = build_client
  @logger = Rails.logger
end

Instance Method Details

#get_search_volume(keywords, geo_target: GEO_US) ⇒ Array<Hash>

Get search volume metrics for a list of keywords

Parameters:

  • keywords (Array<String>)

    Keywords to look up

  • geo_target (String) (defaults to: GEO_US)

    Geography target (default: US)

Returns:

  • (Array<Hash>)

    Array of keyword metrics



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/services/seo/google_keyword_planner_client.rb', line 39

def get_search_volume(keywords, geo_target: GEO_US)
  return [] if keywords.blank?

  @logger.info "[GoogleKeywordPlannerClient] Fetching search volume for #{keywords.size} keywords"

  Timeout.timeout(API_TIMEOUT, Timeout::Error, "Google Ads API call timed out after #{API_TIMEOUT}s") do
    service = @client.service.keyword_plan_idea

    response = service.generate_keyword_historical_metrics(
      customer_id: @customer_id,
      keywords: keywords.map(&:to_s),
      language: LANGUAGE_EN,
      geo_target_constants: [geo_target]
    )

    parse_response(response)
  end
rescue Timeout::Error => e
  @logger.error "[GoogleKeywordPlannerClient] #{e.message}"
  []
rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
  @logger.error "[GoogleKeywordPlannerClient] API error: #{e.message}"
  e.failure.errors.each do |error|
    @logger.error "  - #{error.error_code}: #{error.message}"
  end
  []
rescue StandardError => e
  @logger.error "[GoogleKeywordPlannerClient] Error: #{e.class} - #{e.message}"
  []
end

#test_connectionHash

Test connection and API access

Returns:

  • (Hash)

    Test result with status and message



72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/services/seo/google_keyword_planner_client.rb', line 72

def test_connection
  # Try a simple keyword lookup
  result = get_search_volume(['test'])

  if result.any?
    { success: true, message: 'Keyword Planner API accessible', sample: result.first }
  else
    { success: false, message: 'No results returned - check API permissions' }
  end
rescue StandardError => e
  { success: false, message: e.message }
end