0
# Reporting and Search
1
2
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.
3
4
## Capabilities
5
6
### Search Operations
7
8
The GoogleAdsService provides powerful search functionality using GAQL (Google Ads Query Language) for retrieving campaign, ad group, keyword, and performance data.
9
10
```python { .api }
11
class GoogleAdsService:
12
"""Main service for searching and reporting Google Ads data."""
13
14
def search(
15
self,
16
customer_id: str,
17
query: str,
18
page_size: int = None,
19
return_total_results_count: bool = False,
20
summary_row_setting: str = None
21
) -> SearchGoogleAdsResponse:
22
"""
23
Search for Google Ads data using GAQL.
24
25
Parameters:
26
- customer_id: Customer ID to search within
27
- query: GAQL query string
28
- page_size: Number of results per page (max 10,000)
29
- return_total_results_count: Include total results count
30
- summary_row_setting: Include summary row (NO_SUMMARY_ROW, SUMMARY_ROW_WITH_RESULTS, SUMMARY_ROW_ONLY)
31
32
Returns:
33
SearchGoogleAdsResponse with query results
34
35
Raises:
36
- GoogleAdsException: If query is invalid or access denied
37
"""
38
39
def search_stream(
40
self,
41
customer_id: str,
42
query: str,
43
summary_row_setting: str = None
44
) -> Iterator[SearchGoogleAdsStreamResponse]:
45
"""
46
Stream search results for large data sets.
47
48
Parameters:
49
- customer_id: Customer ID to search within
50
- query: GAQL query string
51
- summary_row_setting: Include summary row setting
52
53
Returns:
54
Iterator of SearchGoogleAdsStreamResponse objects
55
56
Raises:
57
- GoogleAdsException: If query is invalid or access denied
58
"""
59
```
60
61
### Mutate Operations
62
63
Bulk mutation operations for creating, updating, and deleting multiple resources in a single request.
64
65
```python { .api }
66
def mutate(
67
self,
68
customer_id: str,
69
mutate_operations: list,
70
partial_failure: bool = False,
71
validate_only: bool = False,
72
response_content_type: str = None
73
) -> MutateGoogleAdsResponse:
74
"""
75
Perform multiple mutations in a single request.
76
77
Parameters:
78
- customer_id: Customer ID for mutations
79
- mutate_operations: List of MutateOperation objects
80
- partial_failure: Continue on individual operation failures
81
- validate_only: Validate operations without executing
82
- response_content_type: Response content type (MUTABLE_RESOURCE, RESOURCE_NAME_ONLY)
83
84
Returns:
85
MutateGoogleAdsResponse with operation results
86
87
Raises:
88
- GoogleAdsException: If operations fail
89
"""
90
```
91
92
### Google Ads Field Service
93
94
Metadata service for discovering available fields, their types, and relationships for GAQL queries.
95
96
```python { .api }
97
class GoogleAdsFieldService:
98
"""Service for Google Ads field metadata."""
99
100
def get_google_ads_field(
101
self,
102
resource_name: str
103
) -> GoogleAdsField:
104
"""
105
Get metadata for a specific Google Ads field.
106
107
Parameters:
108
- resource_name: Resource name of the field
109
110
Returns:
111
GoogleAdsField with field metadata
112
"""
113
114
def search_google_ads_fields(
115
self,
116
query: str,
117
page_size: int = None
118
) -> SearchGoogleAdsFieldsResponse:
119
"""
120
Search for Google Ads fields using query.
121
122
Parameters:
123
- query: Search query for fields
124
- page_size: Number of results per page
125
126
Returns:
127
SearchGoogleAdsFieldsResponse with field results
128
"""
129
```
130
131
### Usage Examples
132
133
#### Basic Search Query
134
135
```python
136
from google.ads.googleads.client import GoogleAdsClient
137
from google.ads.googleads.errors import GoogleAdsException
138
139
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
140
googleads_service = client.get_service("GoogleAdsService")
141
142
# Basic campaign performance query
143
query = """
144
SELECT
145
campaign.id,
146
campaign.name,
147
campaign.status,
148
campaign.advertising_channel_type,
149
metrics.impressions,
150
metrics.clicks,
151
metrics.cost_micros,
152
metrics.ctr,
153
metrics.average_cpc
154
FROM campaign
155
WHERE campaign.status = 'ENABLED'
156
AND segments.date DURING LAST_30_DAYS
157
ORDER BY metrics.clicks DESC
158
LIMIT 50
159
"""
160
161
try:
162
response = googleads_service.search(
163
customer_id="1234567890",
164
query=query,
165
page_size=50
166
)
167
168
for row in response:
169
campaign = row.campaign
170
metrics = row.metrics
171
172
print(f"Campaign: {campaign.name} (ID: {campaign.id})")
173
print(f"Status: {campaign.status.name}")
174
print(f"Type: {campaign.advertising_channel_type.name}")
175
print(f"Impressions: {metrics.impressions}")
176
print(f"Clicks: {metrics.clicks}")
177
print(f"Cost: ${metrics.cost_micros / 1_000_000:.2f}")
178
print(f"CTR: {metrics.ctr:.2%}")
179
print("---")
180
181
except GoogleAdsException as ex:
182
print(f"Request failed: {ex.error.code().name}")
183
for error in ex.error.details:
184
print(f"Error: {error.message}")
185
```
186
187
#### Streaming Large Results
188
189
```python
190
# Stream large data sets efficiently
191
query = """
192
SELECT
193
keyword_view.resource_name,
194
ad_group.id,
195
ad_group.name,
196
ad_group_criterion.keyword.text,
197
ad_group_criterion.keyword.match_type,
198
metrics.impressions,
199
metrics.clicks,
200
metrics.cost_micros
201
FROM keyword_view
202
WHERE segments.date DURING LAST_7_DAYS
203
AND metrics.impressions > 0
204
"""
205
206
try:
207
stream = googleads_service.search_stream(
208
customer_id="1234567890",
209
query=query
210
)
211
212
keyword_count = 0
213
for batch in stream:
214
for row in batch.results:
215
keyword = row.ad_group_criterion.keyword
216
metrics = row.metrics
217
218
print(f"Keyword: {keyword.text}")
219
print(f"Match Type: {keyword.match_type.name}")
220
print(f"Impressions: {metrics.impressions}")
221
print(f"Clicks: {metrics.clicks}")
222
223
keyword_count += 1
224
225
print(f"Total keywords processed: {keyword_count}")
226
227
except GoogleAdsException as ex:
228
print(f"Stream failed: {ex.error.code().name}")
229
```
230
231
#### Advanced Segmentation Query
232
233
```python
234
# Multi-dimensional reporting with segments
235
query = """
236
SELECT
237
campaign.id,
238
campaign.name,
239
ad_group.id,
240
ad_group.name,
241
segments.device,
242
segments.date,
243
segments.hour,
244
metrics.impressions,
245
metrics.clicks,
246
metrics.conversions,
247
metrics.cost_micros
248
FROM ad_group
249
WHERE campaign.advertising_channel_type = 'SEARCH'
250
AND segments.date DURING LAST_14_DAYS
251
AND metrics.impressions > 100
252
ORDER BY segments.date DESC, metrics.clicks DESC
253
"""
254
255
response = googleads_service.search(
256
customer_id="1234567890",
257
query=query,
258
return_total_results_count=True
259
)
260
261
print(f"Total results: {response.total_results_count}")
262
263
for row in response:
264
segments = row.segments
265
metrics = row.metrics
266
267
print(f"Date: {segments.date}")
268
print(f"Hour: {segments.hour}")
269
print(f"Device: {segments.device.name}")
270
print(f"Campaign: {row.campaign.name}")
271
print(f"Ad Group: {row.ad_group.name}")
272
print(f"Performance: {metrics.clicks} clicks, {metrics.conversions} conversions")
273
print("---")
274
```
275
276
#### Field Discovery
277
278
```python
279
# Discover available fields for reporting
280
field_service = client.get_service("GoogleAdsFieldService")
281
282
# Search for campaign-related fields
283
field_query = """
284
SELECT
285
name,
286
category,
287
data_type,
288
selectable,
289
filterable,
290
sortable
291
FROM google_ads_field
292
WHERE name LIKE 'campaign.%'
293
AND selectable = true
294
ORDER BY name
295
"""
296
297
field_response = field_service.search_google_ads_fields(
298
query=field_query,
299
page_size=100
300
)
301
302
print("Available campaign fields:")
303
for field in field_response.results:
304
print(f"- {field.name} ({field.data_type.name})")
305
if field.filterable:
306
print(" [Filterable]")
307
if field.sortable:
308
print(" [Sortable]")
309
```
310
311
#### Custom Date Range Reporting
312
313
```python
314
# Reporting with custom date ranges and comparisons
315
query = """
316
SELECT
317
campaign.id,
318
campaign.name,
319
segments.date,
320
metrics.impressions,
321
metrics.clicks,
322
metrics.cost_micros,
323
metrics.conversions,
324
metrics.conversions_value
325
FROM campaign
326
WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'
327
AND campaign.status IN ('ENABLED', 'PAUSED')
328
ORDER BY segments.date, campaign.name
329
"""
330
331
response = googleads_service.search(
332
customer_id="1234567890",
333
query=query,
334
summary_row_setting=client.enums.SummaryRowSettingEnum.SUMMARY_ROW_WITH_RESULTS
335
)
336
337
# Process regular results
338
campaign_data = {}
339
for row in response:
340
if hasattr(row, 'campaign'): # Regular row
341
campaign_id = row.campaign.id
342
date = row.segments.date
343
344
if campaign_id not in campaign_data:
345
campaign_data[campaign_id] = {
346
'name': row.campaign.name,
347
'daily_data': {}
348
}
349
350
campaign_data[campaign_id]['daily_data'][date] = {
351
'impressions': row.metrics.impressions,
352
'clicks': row.metrics.clicks,
353
'cost': row.metrics.cost_micros / 1_000_000,
354
'conversions': row.metrics.conversions
355
}
356
357
# Process summary row
358
if hasattr(response, 'summary_row') and response.summary_row:
359
summary = response.summary_row.metrics
360
print(f"Total Summary:")
361
print(f"Impressions: {summary.impressions}")
362
print(f"Clicks: {summary.clicks}")
363
print(f"Cost: ${summary.cost_micros / 1_000_000:.2f}")
364
print(f"Conversions: {summary.conversions}")
365
```
366
367
## Response Types
368
369
```python { .api }
370
class SearchGoogleAdsResponse:
371
"""Response from search operations."""
372
results: list # List of GoogleAdsRow objects
373
next_page_token: str # Token for pagination
374
total_results_count: int # Total number of results
375
field_mask: object # Field mask for the query
376
summary_row: GoogleAdsRow # Summary row if requested
377
378
class GoogleAdsRow:
379
"""Individual result row from search."""
380
# Available attributes depend on SELECT fields in query
381
campaign: object # Campaign data if selected
382
ad_group: object # Ad group data if selected
383
ad_group_ad: object # Ad group ad data if selected
384
metrics: object # Metrics data if selected
385
segments: object # Segments data if selected
386
# ... many other resource types
387
388
class GoogleAdsField:
389
"""Metadata for a Google Ads field."""
390
name: str # Field name
391
category: str # Field category
392
data_type: str # Data type (STRING, INT64, DOUBLE, etc.)
393
selectable: bool # Can be used in SELECT
394
filterable: bool # Can be used in WHERE
395
sortable: bool # Can be used in ORDER BY
396
attribute_resources: list # Related resources
397
```
398
399
## Query Language (GAQL)
400
401
```python { .api }
402
# GAQL syntax examples
403
GAQL_PATTERNS = {
404
'basic_select': "SELECT field1, field2 FROM resource",
405
'with_where': "SELECT * FROM campaign WHERE campaign.status = 'ENABLED'",
406
'with_segments': "SELECT campaign.name, segments.date, metrics.clicks FROM campaign",
407
'with_order': "SELECT * FROM campaign ORDER BY metrics.clicks DESC",
408
'with_limit': "SELECT * FROM campaign LIMIT 100",
409
'date_range': "WHERE segments.date DURING LAST_30_DAYS",
410
'custom_date': "WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'",
411
'multiple_conditions': "WHERE campaign.status = 'ENABLED' AND metrics.clicks > 100",
412
'in_operator': "WHERE campaign.status IN ('ENABLED', 'PAUSED')",
413
'like_operator': "WHERE campaign.name LIKE '%brand%'"
414
}
415
```
416
417
## Constants
418
419
```python { .api }
420
# Summary row settings
421
SUMMARY_ROW_SETTINGS = {
422
'NO_SUMMARY_ROW': 'Do not include summary row',
423
'SUMMARY_ROW_WITH_RESULTS': 'Include summary row with results',
424
'SUMMARY_ROW_ONLY': 'Return only summary row'
425
}
426
427
# Response content types
428
RESPONSE_CONTENT_TYPES = {
429
'RESOURCE_NAME_ONLY': 'Return only resource names',
430
'MUTABLE_RESOURCE': 'Return full mutable resource data'
431
}
432
433
# Maximum page size
434
MAX_PAGE_SIZE = 10000
435
```