Insights and Reporting
Chapter 19 — Insights and Reporting
Insights are exposed at four scopes, all with the same response envelope:
GET /ad_account/insightsGET /campaigns/{campaign_id}/insightsGET /ad_groups/{ad_group_id}/insightsGET /ads/{ad_id}/insights
Pick the scope that matches the question. Account-level for portfolio overview, campaign-level for budget pacing, ad-group level for bid analysis, ad-level for creative performance.
Query parameters
| Parameter | Type | Notes |
|---|---|---|
time_granularity | string | daily (one row per day) or none (one aggregated row over the time range). |
aggregation_level | string | ad_account, campaign, ad_group, or ad. Lets you query an account-level endpoint and group results by ad. |
limit | integer | 1–10000. |
before | string | Pagination cursor. |
after | string | Pagination cursor. |
time_ranges | string[] | Filter by time. Format: {"type":"date_range","since":"2026-04-25","until":"2026-05-01"}. |
filters | string[] | One or more filter expressions. |
fields | string[] | Which columns to return per row. |
sort | string[] | Sort expressions, e.g. {"field":"clicks","direction":"desc"}. |
Available row fields (non-exhaustive)
| Field | Notes |
|---|---|
id | Row identifier (encodes scope + time bucket). |
start_time, end_time | Bucket bounds (Unix seconds). |
readable_time | Human-readable bucket label, e.g. 2026-04-02. |
timezone | Bucket timezone (matches Ad Account timezone). |
impressions | Delivered impressions. |
clicks | Clicks. |
spend | Spend in account currency (decimal in responses, e.g. 42.75). |
ctr | Click-through rate. |
cpc | Cost per click. |
cpm | Cost per thousand impressions. |
ad_id, ad_name | Ad scope. |
ad_group_id, ad_group_name | Ad group scope. |
campaign_id, campaign_name | Campaign scope. |
Pass the fields you actually need in fields[]. Don’t pull every field by default — large queries with all fields can hit pagination quickly.
Example: best-performing ad in a campaign over a week
Find the top ad first.
curl -sS -G "https://api.ads.openai.com/v1/campaigns/cmpn_101/insights"
-H "Authorization: Bearer $OPENAI_ADS_API_KEY"
--data-urlencode 'time_granularity=none'
--data-urlencode 'aggregation_level=ad'
--data-urlencode 'limit=1'
--data-urlencode 'fields[]=ad_id'
--data-urlencode 'fields[]=ad_name'
--data-urlencode 'fields[]=clicks'
--data-urlencode 'fields[]=impressions'
--data-urlencode 'time_ranges[]={"type":"date_range","since":"2026-04-25","until":"2026-05-01"}'
--data-urlencode 'sort[]={"field":"clicks","direction":"desc"}' Then pull a daily breakdown for that ad.
curl -sS -G "https://api.ads.openai.com/v1/ads/$AD_ID/insights"
-H "Authorization: Bearer $OPENAI_ADS_API_KEY"
--data-urlencode 'time_granularity=daily'
--data-urlencode 'fields[]=readable_time'
--data-urlencode 'fields[]=clicks'
--data-urlencode 'fields[]=impressions'
--data-urlencode 'fields[]=ctr'
--data-urlencode 'time_ranges[]={"type":"date_range","since":"2026-04-25","until":"2026-05-01"}' Example: last 7 days of campaign performance
curl -sS -G "https://api.ads.openai.com/v1/campaigns/cmpn_101/insights"
-H "Authorization: Bearer $OPENAI_ADS_API_KEY"
--data-urlencode 'time_granularity=daily'
--data-urlencode 'fields[]=readable_time'
--data-urlencode 'fields[]=clicks'
--data-urlencode 'fields[]=impressions'
--data-urlencode 'fields[]=spend'
--data-urlencode 'time_ranges[]={"type":"date_range","since":"2026-04-25","until":"2026-05-01"}' Sample response
{
"object": "list",
"count": 1,
"data": [
{
"id": "start=1775088000:end=1775174400:entity_id=ad_501",
"readable_time": "2026-04-02",
"timezone": "UTC",
"impressions": 15548,
"clicks": 312,
"spend": 42.75,
"start_time": 1775088000,
"end_time": 1775174400
}
],
"first_id": "start=1775088000:end=1775174400:entity_id=ad_501",
"last_id": "start=1775088000:end=1775174400:entity_id=ad_501",
"has_more": false
} Closing the attribution loop
For accurate revenue reporting on a Shopify store, three things must be true at once:
- The Insights API is delivering delivery and cost metrics (this chapter).
- The pixel is firing on every relevant page (Chapter 8):
page_viewed,contents_viewed,items_added,checkout_started,order_created. - The Conversions API is dual-shipping the same conversion events from the Shopify backend with shared
event_idvalues (Chapter 12), andopprefis captured at landing and forwarded.
Without all three, attribution drifts — and a percentage-of-revenue commercial model becomes undefendable.
The Insights endpoint tells you what you spent. The pixel + CAPI tell you what came back. Together they let you compute an honest CPA and ROAS. Either one alone gives you a partial picture that breaks under audit.
Reading the data into a warehouse
Every Insights response is paginated (first_id, last_id, has_more). For warehouse pulls — Looker Studio, BigQuery, Snowflake, etc. — paginate until has_more is false, store rows keyed by id, and run incrementally on start_time to avoid re-pulling history. This is the same pattern the Advertiser API supports for every list endpoint, so the warehouse pipeline shape is uniform across resources.