Google Ads Reports Helper
A Python ETL driver for Google Ads API v24 data extraction and transformation. Simplifies the process of extracting Google Ads data and converting it to database-ready list of dictionaries with comprehensive optimization features.
Features
- Google Ads API v24: Latest API version support with full compatibility
- Pure Python Output: Returns
list[dict[str, Any]]- perfect for databases and JSON APIs - Serverless Optimized: No pandas dependency, faster cold starts, lower memory usage
- Modern Python 3.11+: Uses latest type hints and language features (supports 3.11-3.13)
- Flexible Column Naming: Choose between snake_case or camelCase column conventions
- Smart Zero Filtering: Robust filtering with automatic column detection
- Custom Reports: Create custom report configurations with full GAQL support
- Automatic Retries: Built-in retry logic for API reliability
- Comprehensive Error Handling: Specific exceptions for different failure types
- Type Safe: Full type hint support for better IDE experience
Installation
pip install google-ads-reports
Quick Start
1. Set up credentials
Create a secrets/google-ads.yaml file with your Google Ads API credentials:
developer_token: "YOUR_DEVELOPER_TOKEN"
client_id: "YOUR_CLIENT_ID"
client_secret: "YOUR_CLIENT_SECRET"
refresh_token: "YOUR_REFRESH_TOKEN"
References:
2. Basic usage
from datetime import date, timedelta
from google_ads_reports import GAdsReport, GAdsReportModel, load_credentials, get_records_info
# Load credentials
credentials = load_credentials()
client = GAdsReport(credentials)
# Configure report parameters
customer_id = "1234567890"
start_date = date.today() - timedelta(days=7)
end_date = date.today() - timedelta(days=1)
# Extract report data - returns list[dict[str, Any]]
records = client.get_gads_report(
customer_id=customer_id,
report_model=GAdsReportModel.keyword_report,
start_date=start_date,
end_date=end_date,
filter_zero_impressions=True, # Remove rows with zero impressions
column_naming="snake_case" # Choose: "snake_case" or "camelCase"
)
# Get dataset information
info = get_records_info(records)
print(f"Shape: {info['shape']}") # (rows, columns)
print(f"Columns: {info['columns']}")
# Save to CSV or JSON
from google_ads_reports import save_report_to_csv, save_report_to_json
save_report_to_csv(records, "keyword_report.csv")
save_report_to_json(records, "keyword_report.json")
Working with the Data
The library returns list[dict[str, Any]] which is perfect for:
# Database insertion
import sqlite3
conn = sqlite3.connect('reports.db')
for record in records:
columns = ', '.join(record.keys())
placeholders = ', '.join(['?' for _ in record])
values = list(record.values())
conn.execute(f"INSERT INTO campaigns ({columns}) VALUES ({placeholders})", values)
# JSON APIs
import json
json_data = json.dumps(records)
# Pandas (if needed)
import pandas as pd
df = pd.DataFrame(records)
Column Naming Options
Choose between snake_case (database-friendly) or camelCase (API-consistent):
# Snake case (default) - metrics.impressions → impressions
records_snake = client.get_gads_report(
customer_id=customer_id,
report_model=GAdsReportModel.keyword_report,
start_date=start_date,
end_date=end_date,
column_naming="snake_case" # Default
)
# CamelCase - metrics.impressions → metricsImpressions
records_camel = client.get_gads_report(
customer_id=customer_id,
report_model=GAdsReportModel.keyword_report,
start_date=start_date,
end_date=end_date,
column_naming="camelCase"
)
Available Report Models
GAdsReportModel.adgroup_ad_report- Ad group ad performanceGAdsReportModel.keyword_report- Keyword performanceGAdsReportModel.search_terms_report- Search terms analysisGAdsReportModel.conversions_report- Conversion trackingGAdsReportModel.video_report- Video ad performanceGAdsReportModel.assetgroup_report- Asset group performance
Custom Reports
Create custom report configurations:
from google_ads_reports import create_custom_report
custom_report = create_custom_report(
report_name="campaign_performance",
select=[
"campaign.name",
"campaign.status",
"segments.date",
"metrics.impressions",
"metrics.clicks",
"metrics.cost_micros"
],
from_table="campaign",
where="metrics.impressions > 100"
)
records = client.get_gads_report(customer_id, custom_report, start_date, end_date)
Data Processing Features
The package automatically processes data for optimal usability:
Smart Zero Filtering
Handles multiple zero representations and automatically detects if impression data is available:
records = client.get_gads_report(
customer_id=customer_id,
report_model=report_model,
start_date=start_date,
end_date=end_date,
filter_zero_impressions=True # Removes: 0, "0", 0.0, "0.0", None
)
# Note: Filtering only applied if 'metrics.impressions' column exists in data
Character Encoding Cleanup
- ASCII Sanitization: Removes non-ASCII characters for database compatibility
- Null Byte Removal: Strips problematic null bytes (
\x00) - Length Limiting: Truncates text to 255 characters
- Whitespace Normalization: Normalizes whitespace characters
Flexible Column Naming
Choose your preferred column naming convention:
Snake Case (Default - Database Friendly):
metrics.impressions→impressionssegments.date→dateadGroupCriterion.keyword→keyword
CamelCase (API Consistent):
metrics.impressions→metricsImpressionssegments.date→segmentsDateadGroupCriterion.keyword→adGroupCriterionKeyword
Data Output Format
The library returns list[dict[str, Any]] which provides maximum flexibility:
# Example output structure
records = [
{
"campaign_name": "Summer Campaign",
"impressions": 1000,
"clicks": 50,
"cost": 25.50,
"date": "2025-10-01"
},
{
"campaign_name": "Winter Campaign",
"impressions": 2000,
"clicks": 100,
"cost": 45.75,
"date": "2025-10-01"
}
]
# Easy conversion to other formats
import pandas as pd
df = pd.DataFrame(records) # If you need pandas
import json
json_str = json.dumps(records) # For APIs
# Direct database insertion
for record in records:
pass
Error Handling
The package provides specific exception types for different scenarios:
from google_ads_reports import (
GAdsReport,
AuthenticationError,
ValidationError,
APIError,
DataProcessingError,
ConfigurationError
)
try:
records = client.get_gads_report(customer_id, report_model, start_date, end_date)
except AuthenticationError:
pass
except ValidationError:
pass
except DataProcessingError:
pass
Migration Guide
v2.1.0 — Google Ads API v21 → v24
Library dependency: google-ads>=31.0.0 is now required (previously >=24.0.0).
Video report metric renames (Google Ads API v24 deprecations):
| Old field (≤v21) | New field (v24) |
|---|---|
metrics.video_views |
metrics.video_trueview_views |
metrics.video_view_rate |
metrics.video_trueview_view_rate |
After snake_case transformation:
video_views→video_trueview_viewsvideo_view_rate→video_trueview_view_rate
Update any downstream tables, dashboards, or queries that reference the old column names.
Examples
Check the examples/ directory for comprehensive usage examples:
basic_usage.py- Simple report extractionmultiple_reports.py- Batch report processingcustom_reports.py- Custom report creation
Configuration
Retry Settings
API calls automatically retry on transient errors with configurable settings:
- Max attempts: 3 (default)
- Base delay: 1 second
- Backoff factor: 2x exponential
- Max delay: 30 seconds
Logging
Configure logging level:
from google_ads_reports import setup_logging
import logging
setup_logging(level=logging.DEBUG) # Enable debug logging
Requirements
- Python 3.11-3.13
- google-ads >= 31.0.0 (Google Ads API v24 support)
- PyYAML >= 6.0.0
- python-dotenv >= 1.0.0
- tqdm >= 4.65.0
License
MIT License - see LICENSE file for details.
Development
For development installation:
git clone https://github.com/machado000/google-ads-reports
cd google-ads-reports
pip install -e ".[dev]"
Support
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Metadata
Release files for google-ads-reports 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| google_ads_reports-2.1.0.tar.gz | 31.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| google_ads_reports-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.9 kB
Release files / google_ads_reports-2.1.0.tar.gz
| Download URL | google_ads_reports-2.1.0.tar.gz |
|---|---|
| Size | 31.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
01e3251adf09bc1ed54ee55d0f23bbf02eb4eb561520a162fbbb5553ca00ebc6
|
|
BLAKE2b-256 checksum How to use checksums |
93dfb071d0d398ce8f993db1d40b794eff0167401f1009c6689f7de7d492b08b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / google_ads_reports-2.1.0-py3-none-any.whl
| Download URL | google_ads_reports-2.1.0-py3-none-any.whl |
|---|---|
| Size | 31.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d6f7b73a8f19d7735fec5baeb4b0f006f7e06634e3055dcd7d838c871ec3bfb6
|
|
BLAKE2b-256 checksum How to use checksums |
51c283fcf944b1f42d8c993c9bd695c47d48214f7b645f011c58ce9a0b8fa123
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|