The Facebook Ads Insights API is the Meta Marketing API interface for retrieving performance data from ad accounts, campaigns, ad sets, and ads. A basic request is a GET call to the /insights edge with an access token, selected fields, and a date range. The examples below use seven-day and September 1 through September 21, 2026 reporting periods.
| Requirement | Value |
|---|---|
| API | Meta Marketing API Insights API |
| Endpoint | /{ad-account-id}/insights |
| Ad account format | act_<AD_ACCOUNT_ID> |
| Authentication | Meta access token with access to the ad account |
| Reporting levels | account, campaign, adset, ad |
| Common metrics | impressions, reach, clicks, spend, ctr, cpm, cpc, actions |
| Large reports | Use asynchronous report jobs |
For read-only advertising reports, the ads_read permission is normally required. The token must also have access to the relevant ad account.
You need:
ads_read for read-only reporting.act_<AD_ACCOUNT_ID>.Meta's Business SDK uses access tokens to authenticate Marketing API requests and represents ad accounts with the act_ prefix.
Keep long-lived access tokens out of browser JavaScript and public source code. Store them in a server-side secret manager or environment variable.
This request retrieves campaign-level performance for the last seven days:
curl --get \
"\
--data-urlencode "level=campaign" \
--data-urlencode "date_preset=last_7d" \
--data-urlencode "fields=campaign_id,campaign_name,impressions,reach,clicks,spend,ctr,cpm,cpc" \
--data-urlencode "access_token=<ACCESS_TOKEN>"Replace:
vXX.X with the Graph API version supported by your application.<AD_ACCOUNT_ID> with the numeric Meta ad account ID.<ACCESS_TOKEN> with your access token.The Insights API accepts fields, date presets, levels, breakdowns, filters, and time-range parameters. Meta's Business SDK exposes these parameters through its get_insights methods.
A response can look like this:
{
"data": [
{
"campaign_id": "120000000000000",
"campaign_name": "Spring Campaign",
"impressions": "12500",
"reach": "9800",
"clicks": "430",
"spend": "275.45",
"ctr": "3.44",
"cpm": "22.04",
"cpc": "0.64",
"date_start": "2026-09-15",
"date_stop": "2026-09-21"
}
],
"paging": {
"cursors": {
"before": "...",
"after": "..."
}
}
}The API may return numeric values as strings. Convert them in your application before using them in calculations.
The level parameter controls the report's granularity.
| Level | Use it to answer |
|---|---|
account | How did the entire ad account perform? |
campaign | Which campaigns generated the results? |
adset | Which audiences, budgets, or placements performed best? |
ad | Which individual creative produced the result? |
For example:
## Campaign-level data
--data-urlencode "level=campaign"
## Ad set-level data
--data-urlencode "level=adset"
## Ad-level data
--data-urlencode "level=ad"Request the lowest level that answers the reporting question. Ad-level reports usually return more rows than account-level reports, which means more pagination and, in some cases, longer processing times.
The fields parameter controls which metrics and identifiers the API returns.
impressions
reach
frequency
spend
cpmclicks
ctr
cpc
outbound_clicks
outbound_clicks_ctr
inline_link_clicks
website_ctractions
action_values
conversions
conversion_values
cost_per_action_type
purchase_roas
website_purchase_roasaccount_id
account_name
campaign_id
campaign_name
adset_id
adset_name
ad_id
ad_name
date_start
date_stopA campaign report might use:
campaign_id,
campaign_name,
impressions,
reach,
clicks,
spend,
actions,
action_values,
purchase_roas,
date_start,
date_stopThe official Meta Python SDK includes these fields on the AdsInsights object, including identifiers, delivery metrics, actions, conversions, spend, and ROAS fields.
Use time_range when the report must cover exact dates:
curl --get \
"\
--data-urlencode "level=campaign" \
--data-urlencode 'time_range={"since":"2026-09-01","until":"2026-09-21"}' \
--data-urlencode "fields=campaign_name,impressions,clicks,spend" \
--data-urlencode "access_token=<ACCESS_TOKEN>"Use date_preset for rolling periods:
today
yesterday
last_7d
last_30d
this_month
last_month
this_yearUse one date strategy per request. time_range works well for dashboards and scheduled pipelines because each request continues to represent the same reporting period.
time_incrementTo receive one row per campaign per day, add:
--data-urlencode "time_increment=1"Example:
curl --get \
"\
--data-urlencode "level=campaign" \
--data-urlencode "time_range={\"since\":\"2026-09-01\",\"until\":\"2026-09-21\"}" \
--data-urlencode "time_increment=1" \
--data-urlencode "fields=campaign_id,campaign_name,date_start,date_stop,impressions,clicks,spend" \
--data-urlencode "access_token=<ACCESS_TOKEN>"Without time_increment, the API normally aggregates the selected date range into the report rows. With time_increment=1, your application can chart daily spend, clicks, and conversions.
Breakdowns divide the report into dimensions such as:
age
gender
country
device_platform
impression_device
publisher_platform
platform_position
regionExample:
curl --get \
"\
--data-urlencode "level=campaign" \
--data-urlencode "date_preset=last_30d" \
--data-urlencode "breakdowns=publisher_platform,platform_position" \
--data-urlencode "fields=campaign_name,publisher_platform,platform_position,impressions,clicks,spend,ctr" \
--data-urlencode "access_token=<ACCESS_TOKEN>"Breakdowns can increase the row count quickly. Some fields and breakdown combinations are incompatible, so start with one breakdown and add others one at a time. The Meta Business SDK exposes breakdowns and action breakdowns as separate Insights parameters.
The following example uses the requests library:
import os
import requests
API_VERSION = "vXX.X"
AD_ACCOUNT_ID = "act_<AD_ACCOUNT_ID>"
ACCESS_TOKEN = os.environ["META_ACCESS_TOKEN"]
url = f"params = {
"level": "campaign",
"time_range": {
"since": "2026-09-01",
"until": "2026-09-21"
},
"fields": ",".join([
"campaign_id",
"campaign_name",
"impressions",
"reach",
"clicks",
"spend",
"ctr",
"cpm",
"cpc"
]),
"limit": 100,
"access_token": ACCESS_TOKEN
}
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
payload = response.json()
for row in payload.get("data", []):
print({
"campaign": row.get("campaign_name"),
"impressions": int(row.get("impressions", 0)),
"clicks": int(row.get("clicks", 0)),
"spend": float(row.get("spend", 0)),
"ctr": float(row.get("ctr", 0))
})The official Meta Python Business SDK also supports account, campaign, ad set, and ad Insights requests through get_insights, using the same types of fields and parameters.
An Insights response can contain a paging.next URL when more results are available. A production integration should continue requesting pages until the response no longer includes a next URL.
import os
import requests
url = "params = {
"level": "ad",
"date_preset": "last_30d",
"fields": "ad_id,ad_name,impressions,clicks,spend",
"limit": 100,
"access_token": os.environ["META_ACCESS_TOKEN"]
}
rows = []
while url:
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
payload = response.json()
rows.extend(payload.get("data", []))
url = payload.get("paging", {}).get("next")
params = None
print(f"Downloaded {len(rows)} rows")Meta's Business SDK handles cursor-based pagination for collection requests. When calling the Graph API directly, follow the returned pagination cursor or paging.next value instead of assuming that one response contains the full report.
An asynchronous Insights report can help when a query covers:
The workflow is:
POST request to the ad account's /insights edge.report_run_id./{report_run_id}/insights.Create a report run:
curl -X POST \
"\
-d "level=ad" \
-d "date_preset=last_30d" \
-d "fields=ad_id,ad_name,impressions,clicks,spend,actions" \
-d "breakdowns=age,gender" \
-d "access_token=<ACCESS_TOKEN>"A successful response includes a report identifier:
{
"report_run_id": "123456789012345"
}Poll the report:
curl --get \
"\
--data-urlencode "access_token=<ACCESS_TOKEN>"When the report is complete, request its results:
curl --get \
"\
--data-urlencode "access_token=<ACCESS_TOKEN>"Meta's Insights API collection documents asynchronous jobs for large requests. The Business SDK also exposes asynchronous Insights methods such as get_insights_async.
Check that:
data ResponsesCheck whether:
Remove optional fields and breakdowns, then add them back one at a time. The Insights API does not support every combination of fields, action breakdowns, and standard breakdowns.
Reduce the date range, request fewer fields, remove breakdowns, or use an asynchronous report. Large Insights queries are more likely to time out than small account-level or campaign-level requests.
The actions and action_values fields return nested action data rather than one scalar value. Your application must inspect the action_type values and select the conversion event used by the business, such as purchase, lead, or complete_registration.
For most reporting integrations:
time_range for scheduled reports.time_increment=1 for daily trends.The smallest working request is:
GET /vXX.X/act_<AD_ACCOUNT_ID>/insights?level=campaign
&date_preset=last_7d
&fields=campaign_name,impressions,clicks,spend
&access_token=<ACCESS_TOKEN>That request can support campaign dashboards, scheduled exports, performance alerts, and Meta Ads data warehouses.