Chapter 47 - 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. Reporting still centers on delivery and cost buckets, even as ChatGPT Ads targeting expands across three platforms (PPC Land, 2026).
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 36):
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 40), 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.
