Circle Separator5 mins read

Facebook Ads Insights API How to

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.

At a Glance

RequirementValue
APIMeta Marketing API Insights API
Endpoint/{ad-account-id}/insights
Ad account formatact_<AD_ACCOUNT_ID>
AuthenticationMeta access token with access to the ad account
Reporting levelsaccount, campaign, adset, ad
Common metricsimpressions, reach, clicks, spend, ctr, cpm, cpc, actions
Large reportsUse 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.

Create an Access Token with Ad Account Access

You need:

  1. A Meta developer app.
  2. A Meta user or system user access token.
  3. Access to the relevant ad account.
  4. The appropriate advertising permission, normally ads_read for read-only reporting.
  5. The ad account ID, formatted as 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.

Make Your First Facebook Ads Insights API Request

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.

Choose the Correct Reporting Level

The level parameter controls the report's granularity.

LevelUse it to answer
accountHow did the entire ad account perform?
campaignWhich campaigns generated the results?
adsetWhich audiences, budgets, or placements performed best?
adWhich 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.

Select Useful Insights API Fields

The fields parameter controls which metrics and identifiers the API returns.

Core Delivery and Cost Metrics

impressions
reach
frequency
spend
cpm

Click and Traffic Metrics

clicks
ctr
cpc
outbound_clicks
outbound_clicks_ctr
inline_link_clicks
website_ctr

Conversion Metrics

actions
action_values
conversions
conversion_values
cost_per_action_type
purchase_roas
website_purchase_roas

Identity Fields

account_id
account_name
campaign_id
campaign_name
adset_id
adset_name
ad_id
ad_name
date_start
date_stop

A campaign report might use:

campaign_id,
campaign_name,
impressions,
reach,
clicks,
spend,
actions,
action_values,
purchase_roas,
date_start,
date_stop

The official Meta Python SDK includes these fields on the AdsInsights object, including identifiers, delivery metrics, actions, conversions, spend, and ROAS fields.

Use a Fixed Date Range for Reliable Reporting

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_year

Use one date strategy per request. time_range works well for dashboards and scheduled pipelines because each request continues to represent the same reporting period.

Split Results by Day with time_increment

To 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.

Add Breakdowns Such as Placement, Age, or Country

Breakdowns divide the report into dimensions such as:

age
gender
country
device_platform
impression_device
publisher_platform
platform_position
region

Example:

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.

Retrieve Data with Python

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.

Handle Pagination

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.

Use Asynchronous Reports for Large Queries

An asynchronous Insights report can help when a query covers:

  • Many ad accounts.
  • A long date range.
  • Ad-level data.
  • Multiple breakdowns.
  • Many requested fields.
  • A large historical export.

The workflow is:

  1. Send a POST request to the ad account's /insights edge.
  2. Receive a report_run_id.
  3. Poll the report-run object until processing finishes.
  4. Request /{report_run_id}/insights.
  5. Paginate through the returned data.

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.

Common Errors and Fixes

OAuth or Permission Errors

Check that:

  • The token has the required advertising permission.
  • The user or system user can access the ad account.
  • The ad account ID is correct.
  • The token belongs to the Meta app making the request.

Empty data Responses

Check whether:

  • The date range contains delivered ads.
  • The selected ad account is correct.
  • The requested level matches the available entities.
  • Campaigns, ad sets, or ads were active during the selected dates.
  • A breakdown or filter is excluding the results.

Invalid Field or Breakdown Errors

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.

Timeouts

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.

Missing Conversions or Revenue

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:

  1. Start with a campaign-level synchronous request.
  2. Use a fixed time_range for scheduled reports.
  3. Request only the fields required by the dashboard.
  4. Add time_increment=1 for daily trends.
  5. Add one breakdown at a time.
  6. Follow pagination links.
  7. Switch to asynchronous reports when the query becomes large.
  8. Store the raw API response before transforming metrics.
  9. Record the API version, account ID, date range, and request parameters with each import.

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.

Next Read