Client library for the Google Ads API providing comprehensive access to advertising management, reporting, and analytics capabilities.
—
Comprehensive reporting capabilities using the Google Ads Query Language (GAQL) for data retrieval, performance analysis, and custom reporting. The GoogleAdsService provides the primary interface for querying Google Ads data with flexible search and streaming options.
The GoogleAdsService provides powerful search functionality using GAQL (Google Ads Query Language) for retrieving campaign, ad group, keyword, and performance data.
class GoogleAdsService:
"""Main service for searching and reporting Google Ads data."""
def search(
self,
customer_id: str,
query: str,
page_size: int = None,
return_total_results_count: bool = False,
summary_row_setting: str = None
) -> SearchGoogleAdsResponse:
"""
Search for Google Ads data using GAQL.
Parameters:
- customer_id: Customer ID to search within
- query: GAQL query string
- page_size: Number of results per page (max 10,000)
- return_total_results_count: Include total results count
- summary_row_setting: Include summary row (NO_SUMMARY_ROW, SUMMARY_ROW_WITH_RESULTS, SUMMARY_ROW_ONLY)
Returns:
SearchGoogleAdsResponse with query results
Raises:
- GoogleAdsException: If query is invalid or access denied
"""
def search_stream(
self,
customer_id: str,
query: str,
summary_row_setting: str = None
) -> Iterator[SearchGoogleAdsStreamResponse]:
"""
Stream search results for large data sets.
Parameters:
- customer_id: Customer ID to search within
- query: GAQL query string
- summary_row_setting: Include summary row setting
Returns:
Iterator of SearchGoogleAdsStreamResponse objects
Raises:
- GoogleAdsException: If query is invalid or access denied
"""Bulk mutation operations for creating, updating, and deleting multiple resources in a single request.
def mutate(
self,
customer_id: str,
mutate_operations: list,
partial_failure: bool = False,
validate_only: bool = False,
response_content_type: str = None
) -> MutateGoogleAdsResponse:
"""
Perform multiple mutations in a single request.
Parameters:
- customer_id: Customer ID for mutations
- mutate_operations: List of MutateOperation objects
- partial_failure: Continue on individual operation failures
- validate_only: Validate operations without executing
- response_content_type: Response content type (MUTABLE_RESOURCE, RESOURCE_NAME_ONLY)
Returns:
MutateGoogleAdsResponse with operation results
Raises:
- GoogleAdsException: If operations fail
"""Metadata service for discovering available fields, their types, and relationships for GAQL queries.
class GoogleAdsFieldService:
"""Service for Google Ads field metadata."""
def get_google_ads_field(
self,
resource_name: str
) -> GoogleAdsField:
"""
Get metadata for a specific Google Ads field.
Parameters:
- resource_name: Resource name of the field
Returns:
GoogleAdsField with field metadata
"""
def search_google_ads_fields(
self,
query: str,
page_size: int = None
) -> SearchGoogleAdsFieldsResponse:
"""
Search for Google Ads fields using query.
Parameters:
- query: Search query for fields
- page_size: Number of results per page
Returns:
SearchGoogleAdsFieldsResponse with field results
"""from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
googleads_service = client.get_service("GoogleAdsService")
# Basic campaign performance query
query = """
SELECT
campaign.id,
campaign.name,
campaign.status,
campaign.advertising_channel_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.ctr,
metrics.average_cpc
FROM campaign
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.clicks DESC
LIMIT 50
"""
try:
response = googleads_service.search(
customer_id="1234567890",
query=query,
page_size=50
)
for row in response:
campaign = row.campaign
metrics = row.metrics
print(f"Campaign: {campaign.name} (ID: {campaign.id})")
print(f"Status: {campaign.status.name}")
print(f"Type: {campaign.advertising_channel_type.name}")
print(f"Impressions: {metrics.impressions}")
print(f"Clicks: {metrics.clicks}")
print(f"Cost: ${metrics.cost_micros / 1_000_000:.2f}")
print(f"CTR: {metrics.ctr:.2%}")
print("---")
except GoogleAdsException as ex:
print(f"Request failed: {ex.error.code().name}")
for error in ex.error.details:
print(f"Error: {error.message}")# Stream large data sets efficiently
query = """
SELECT
keyword_view.resource_name,
ad_group.id,
ad_group.name,
ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros
FROM keyword_view
WHERE segments.date DURING LAST_7_DAYS
AND metrics.impressions > 0
"""
try:
stream = googleads_service.search_stream(
customer_id="1234567890",
query=query
)
keyword_count = 0
for batch in stream:
for row in batch.results:
keyword = row.ad_group_criterion.keyword
metrics = row.metrics
print(f"Keyword: {keyword.text}")
print(f"Match Type: {keyword.match_type.name}")
print(f"Impressions: {metrics.impressions}")
print(f"Clicks: {metrics.clicks}")
keyword_count += 1
print(f"Total keywords processed: {keyword_count}")
except GoogleAdsException as ex:
print(f"Stream failed: {ex.error.code().name}")# Multi-dimensional reporting with segments
query = """
SELECT
campaign.id,
campaign.name,
ad_group.id,
ad_group.name,
segments.device,
segments.date,
segments.hour,
metrics.impressions,
metrics.clicks,
metrics.conversions,
metrics.cost_micros
FROM ad_group
WHERE campaign.advertising_channel_type = 'SEARCH'
AND segments.date DURING LAST_14_DAYS
AND metrics.impressions > 100
ORDER BY segments.date DESC, metrics.clicks DESC
"""
response = googleads_service.search(
customer_id="1234567890",
query=query,
return_total_results_count=True
)
print(f"Total results: {response.total_results_count}")
for row in response:
segments = row.segments
metrics = row.metrics
print(f"Date: {segments.date}")
print(f"Hour: {segments.hour}")
print(f"Device: {segments.device.name}")
print(f"Campaign: {row.campaign.name}")
print(f"Ad Group: {row.ad_group.name}")
print(f"Performance: {metrics.clicks} clicks, {metrics.conversions} conversions")
print("---")# Discover available fields for reporting
field_service = client.get_service("GoogleAdsFieldService")
# Search for campaign-related fields
field_query = """
SELECT
name,
category,
data_type,
selectable,
filterable,
sortable
FROM google_ads_field
WHERE name LIKE 'campaign.%'
AND selectable = true
ORDER BY name
"""
field_response = field_service.search_google_ads_fields(
query=field_query,
page_size=100
)
print("Available campaign fields:")
for field in field_response.results:
print(f"- {field.name} ({field.data_type.name})")
if field.filterable:
print(" [Filterable]")
if field.sortable:
print(" [Sortable]")# Reporting with custom date ranges and comparisons
query = """
SELECT
campaign.id,
campaign.name,
segments.date,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value
FROM campaign
WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'
AND campaign.status IN ('ENABLED', 'PAUSED')
ORDER BY segments.date, campaign.name
"""
response = googleads_service.search(
customer_id="1234567890",
query=query,
summary_row_setting=client.enums.SummaryRowSettingEnum.SUMMARY_ROW_WITH_RESULTS
)
# Process regular results
campaign_data = {}
for row in response:
if hasattr(row, 'campaign'): # Regular row
campaign_id = row.campaign.id
date = row.segments.date
if campaign_id not in campaign_data:
campaign_data[campaign_id] = {
'name': row.campaign.name,
'daily_data': {}
}
campaign_data[campaign_id]['daily_data'][date] = {
'impressions': row.metrics.impressions,
'clicks': row.metrics.clicks,
'cost': row.metrics.cost_micros / 1_000_000,
'conversions': row.metrics.conversions
}
# Process summary row
if hasattr(response, 'summary_row') and response.summary_row:
summary = response.summary_row.metrics
print(f"Total Summary:")
print(f"Impressions: {summary.impressions}")
print(f"Clicks: {summary.clicks}")
print(f"Cost: ${summary.cost_micros / 1_000_000:.2f}")
print(f"Conversions: {summary.conversions}")class SearchGoogleAdsResponse:
"""Response from search operations."""
results: list # List of GoogleAdsRow objects
next_page_token: str # Token for pagination
total_results_count: int # Total number of results
field_mask: object # Field mask for the query
summary_row: GoogleAdsRow # Summary row if requested
class GoogleAdsRow:
"""Individual result row from search."""
# Available attributes depend on SELECT fields in query
campaign: object # Campaign data if selected
ad_group: object # Ad group data if selected
ad_group_ad: object # Ad group ad data if selected
metrics: object # Metrics data if selected
segments: object # Segments data if selected
# ... many other resource types
class GoogleAdsField:
"""Metadata for a Google Ads field."""
name: str # Field name
category: str # Field category
data_type: str # Data type (STRING, INT64, DOUBLE, etc.)
selectable: bool # Can be used in SELECT
filterable: bool # Can be used in WHERE
sortable: bool # Can be used in ORDER BY
attribute_resources: list # Related resources# GAQL syntax examples
GAQL_PATTERNS = {
'basic_select': "SELECT field1, field2 FROM resource",
'with_where': "SELECT * FROM campaign WHERE campaign.status = 'ENABLED'",
'with_segments': "SELECT campaign.name, segments.date, metrics.clicks FROM campaign",
'with_order': "SELECT * FROM campaign ORDER BY metrics.clicks DESC",
'with_limit': "SELECT * FROM campaign LIMIT 100",
'date_range': "WHERE segments.date DURING LAST_30_DAYS",
'custom_date': "WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'",
'multiple_conditions': "WHERE campaign.status = 'ENABLED' AND metrics.clicks > 100",
'in_operator': "WHERE campaign.status IN ('ENABLED', 'PAUSED')",
'like_operator': "WHERE campaign.name LIKE '%brand%'"
}# Summary row settings
SUMMARY_ROW_SETTINGS = {
'NO_SUMMARY_ROW': 'Do not include summary row',
'SUMMARY_ROW_WITH_RESULTS': 'Include summary row with results',
'SUMMARY_ROW_ONLY': 'Return only summary row'
}
# Response content types
RESPONSE_CONTENT_TYPES = {
'RESOURCE_NAME_ONLY': 'Return only resource names',
'MUTABLE_RESOURCE': 'Return full mutable resource data'
}
# Maximum page size
MAX_PAGE_SIZE = 10000Install with Tessl CLI
npx tessl i tessl/pypi-google-ads