or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ad-management.mdasset-management.mdaudience-management.mdbatch-operations.mdcampaign-management.mdclient-setup.mdconversion-tracking.mdindex.mdreporting-search.mdtargeting-keywords.md

reporting-search.mddocs/

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

```