Facebook Ads Reports Helper
A Python ETL driver for Facebook Marketing API v25 data extraction and transformation. Simplifies the process of extracting Facebook Ads data and converting it to structured data formats with comprehensive utility functions.
Features
- Facebook Marketing API v25: Latest API version support with full compatibility
- Robust Error Handling: Comprehensive error handling with retry logic and specific exceptions
- Multiple Report Types: Pre-configured report models for common use cases
- Custom Reports: Create custom report configurations
- Flexible Data Export: Built-in CSV and JSON export utilities
- Date Range Utilities: Helper functions to break date ranges into monthly or weekly periods
- Lightweight Architecture: No pandas dependency for faster installations and smaller footprint
- Type Hints: Full type hint support with strict mypy compliance for better IDE experience
- Data Processing Utilities: Helper functions for data transformation and export
- Token Verification:
verify_token()reports validity, type, expiry, and scopes via/debug_token - Unicode-Safe Text Cleaning: Response cleanup preserves accents and Unicode while removing null bytes and unsafe control characters
- Warehouse-Safe Column Names: Flattened action columns are sanitized to valid identifiers, so
offsite_conversion.fb_pixel_purchaselands asoffsite_conversion_fb_pixel_purchase - Conversion-Scope Filtering:
ad_insights_reportships anaction_typesallow-list keeping Meta's deduplicatedomni_*metrics and dropping the overlapping attribution scopes that duplicate them
Installation
pip install facebook-ads-reports
Using uv:
uv add facebook-ads-reports
Quick Start
1. Set up credentials
Option A: Configuration file
Create a secrets/fb_business_config.json file with your Facebook Ads API credentials:
{
"app_id": "YOUR_APP_ID",
"app_secret": "YOUR_APP_SECRET",
"access_token": "YOUR_ACCESS_TOKEN",
"ad_account_id": "act_1234567890",
"base_url": "https://graph.facebook.com/v25.0"
}
access_token is required. app_id and app_secret are optional but recommended --
verify_token() uses them to authenticate its /debug_token call. base_url is ignored;
the API version is pinned to v25.0 in the client.
For unattended extraction, use a Business Manager system user token rather than a Graph
API Explorer token: user tokens are invalidated by password changes and expire in ~60 days,
and this package has no token-refresh logic. verify_token() reports type: SYSTEM_USER
and never_expires: True for a correctly issued one.
Option B: Environment variable
Set the FACEBOOK_ADS_CONFIG_JSON environment variable with your credentials as JSON:
export FACEBOOK_ADS_CONFIG_JSON='{"app_id": "YOUR_APP_ID", "app_secret": "YOUR_APP_SECRET", "access_token": "YOUR_ACCESS_TOKEN", "ad_account_id": "act_1234567890", "base_url": "https://graph.facebook.com/v25.0"}'
2. Basic usage
from datetime import date, timedelta
from facebook_ads_reports import MetaAdsReport, MetaAdsReportModel
from facebook_ads_reports.utils import load_credentials, save_report_to_csv, save_report_to_json
# Load credentials
credentials = load_credentials()
client = MetaAdsReport(credentials_dict=credentials)
# Fail fast on a bad token instead of hitting an opaque 401 mid-extraction
client.verify_token(required_scopes=["ads_read"])
# Configure report parameters
ad_account_id = "act_1234567890"
start_date = date.today() - timedelta(days=7)
end_date = date.today() - timedelta(days=1)
# Extract report data
data = client.get_report(
ad_account_id=ad_account_id,
report_model=MetaAdsReportModel.ad_insights_report,
start_date=start_date,
end_date=end_date,
flatten=True,
limit=200,
)
# Save to CSV using utility function
save_report_to_csv(data, "ad_insights_report.csv")
# Save to JSON using utility function
save_report_to_json(data, "ad_insights_report.json")
With flatten=True, ad_insights_report expands each action_type into its own column.
The action_types allow-list in the model caps which columns are possible -- 48 on a live
extract, down from 102 unfiltered -- but a column still only appears when that action
occurred in the window, so absent is not zero and loaders must tolerate missing keys.
See docs/REPORT_FIELDS.md.
Conversion columns use Meta's deduplicated omni_* family (omni_purchase,
value_omni_purchase, roas_omni_purchase). The overlapping offsite_conversion.*,
onsite_web_* and legacy bare scopes are commented out in models.py -- uncomment a block
to restore them. See
docs/REPORT_FIELDS.md.
Available Report Models
| Model | Returns | Grain (one row per) |
|---|---|---|
ad_accounts_report |
Account metadata for every account the token can reach | ad account |
campaigns_report |
Campaign setup, objective, budget | campaign |
adsets_report |
Ad set config, targeting, learning stage | ad set |
ad_summary_report |
Ad metadata, status, targeting | ad |
ad_dimensions_report |
Ad attributes with no metrics | ad |
ad_insights_report |
Metrics and actions over time | ad x day x publisher platform x platform position |
ad_performance_report |
Backward-compatible alias of ad_insights_report |
same as above |
Only ad_insights_report uses start_date / end_date; the other models rely on the
date_preset in their own params and ignore the dates you pass. ad_accounts_report
ignores ad_account_id as well.
You can also list models dynamically with MetaAdsReportModel.list_available_reports().
Full field lists, flattening behavior, and output schemas: docs/REPORT_FIELDS.md.
Custom Reports
Create custom model metadata templates:
from facebook_ads_reports import create_custom_report
custom_report = create_custom_report(
report_name="my_custom_report",
select=["ad_id", "impressions", "spend"],
from_table="ad_insights"
)
# This helper is intended for custom ETL metadata flows and CANNOT be passed to
# get_report() -- it has no endpoint/fields/params. To define a real custom extraction,
# build a dict in the same shape as the built-in models. See docs/REPORT_FIELDS.md.
Examples
Check the examples/ directory for comprehensive usage examples:
basic_usage.py- Simple report extraction
Requirements
- Python 3.11-3.14
- requests >= 2.32.4
- python-dotenv >= 1.1.1
Development & Publishing
# install runtime + dev dependencies
uv sync --all-groups
# quality gates
uv run pytest
uv run mypy facebook_ads_reports
# local build check
uv build
Note: there is no tests/ directory yet, so pytest collects nothing (exit code 5).
mypy is the effective quality gate.
Publishing is automated through .github/workflows/release.yml, which runs on every push
to main: a Python 3.11-3.14 test matrix, then a build-and-publish job that skips PyPI if
the version in pyproject.toml already exists. In practice, releasing is a version bump
merged to main.
For internals and known behaviors, see docs/ARCHITECTURE.md. For the release runbook, see docs/RELEASE_PIPELINE_SKILL.md (note: it documents a release-triggered design that does not match the current workflow).
License
GPL License. See LICENSE file for details.
Support
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Metadata
Release files for facebook-ads-reports 2.4.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 | |
|---|---|---|---|
| facebook_ads_reports-2.4.0.tar.gz | 76.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| facebook_ads_reports-2.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 113.6 kB
Release files / facebook_ads_reports-2.4.0.tar.gz
| Download URL | facebook_ads_reports-2.4.0.tar.gz |
|---|---|
| Size | 76.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d5d2be350c035d29bfa090e7cde52f0f0cf077a486e81a895c8373e7e492cdae
|
|
BLAKE2b-256 checksum How to use checksums |
704c45e513b9830cea93fb8a1a17dae578a4e9575cd561af98b36d91850cae77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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 / facebook_ads_reports-2.4.0-py3-none-any.whl
| Download URL | facebook_ads_reports-2.4.0-py3-none-any.whl |
|---|---|
| Size | 36.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e6c84fcd2d25b45a0904c58600076281c376b2f07bdfd656217328172a94cac2
|
|
BLAKE2b-256 checksum How to use checksums |
1b74d7899aaf604fe552f3a74ef3b533df3b87149dd4158b76cd6de7ca531c6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}
|