Run everything you never had time to implement. Define your process once, and keep it running with Qore.

All reports
Amazon Ads Console
Advertising Performance

Amazon Sponsored Products Ad Group Report

The Sponsored Products ad group report gives you one row per ad group per day — impressions, clicks, cost and the purchases, units and sales Amazon attributed back, at 1, 7, 14 and 30-day windows. Sponsored Products has no ad group report type of its own, so this is the campaign report asked for at the ad group grain, and the swap costs you every campaign column except the bidding strategy.

Known upstream as
spCampaigns
One row is
One row per ad group
Refreshed
Daily
Columns
37
Marketplaces
All marketplaces
History
Amazon documents 95 days of data retention for the `spCampaigns` report type this grain comes from, and a maximum date range of 31 days per report request, so a longer history has to be accumulated by pulling repeatedly. The requested startDate and endDate are stamped onto the file as real data dates. Neither figure has been confirmed against files at the ad group grouping.
Latency
Amazon publishes initial impression and click data for sponsored ads within 12 hours and initial conversion data within 24 hours, and a requested report can take up to three hours to generate on top of that. Nothing is settled when it first lands — clicks keep moving for a few days under traffic validation, Amazon suggests waiting five days for a settled click figure, and conversion data is restated for up to 60 days back. This report's own attribution columns run to 30 days, so a recent row keeps changing after it first appears.
Requires
Amazon Ads API access

What this report contains

One row per ad group per day, for Sponsored Products. ad_group_id plus date is unique on every row. The left-hand side is what the ad group spent — impressions, clicks, cost — and the right-hand side is what Amazon attributed back to it: purchases, units and sales, each at 1, 7, 14 and 30-day windows, and each repeated again for the advertised SKU alone. That is how a report about ad groups reaches 37 columns.

The thing to understand first is where this report comes from. Sponsored Products has no ad group report type of its own. Sponsored Brands and Sponsored Display do; Sponsored Products does not. This file is the campaign report — spCampaigns — asked for with groupBy: ["adGroup"], which swaps the campaign's identity columns for the ad group's own. The column set is genuinely different, confirmed against real files: the nine campaign identity and budget columns the campaign report carries are not available here, and ad_group_id, ad_group_name and ad_status take their place.

The one campaign attribute that survives is campaign_bidding_strategy, which describes the campaign the ad group sits in. campaignId and campaignName are not returned at this grain, so a row cannot be attributed to its campaign from this file alone — that is a property of Amazon's grouping, not a missing request. The mapping lives in the ad group export (POST /adGroups/exports), whose model carries campaignId next to adGroupId for Sponsored Products; Amazon's own advice is to pull metadata as an export and merge it into the report.

The attribution windows nest rather than add: purchases_30d includes purchases_7d, and the _same_sku_ columns are subsets of their unqualified partners. Amazon's column reference defines each of these as conversions "within N days of an ad click", and each same-SKU column as the same event counted only "where the purchased SKU was the same as the SKU advertised".

How to get it

Through the Amazon Ads API v3, you POST to /reporting/reports with reportTypeId: spCampaigns, adProduct: SPONSORED_PRODUCTS, groupBy: ["adGroup"] and timeUnit: DAILY, naming every column you want. The groupBy value is the whole difference between this report and the campaign report — same report type, different grain, different column set. Amazon returns a report ID; poll it until the status is COMPLETED and download the gzipped JSON from the URL it hands back. The startDate and endDate you request are real data dates: the file covers exactly that window, one file per pull rather than one per day.

The trap is asking for campaign columns. The v3 API returns exactly the columns you requested and nothing else, so a missing column is your request, not Amazon's schema — but at the ad group grouping the campaign* identity and budget columns are simply not on offer, and a pipeline that converts this file against the campaign report's column set gets those columns all-null and drops ad_group_id, ad_group_name and ad_status as unrecognised, with nothing raising.

There is no ad-group report to download in the console either. Amazon's ad group report reference states that Sponsored Products has no separate ad group report and sends you to the campaign report's adGroup grouping, and its current help article on downloadable sponsored ads reports lists every report type the console offers for Sponsored Products, Sponsored Brands and Display without an ad group report among them. Take any console path lightly in any case: Amazon has announced it is sunsetting the console's Sponsored Ads reports section by 31 December 2026 in favour of unified reporting. The API request above is the route that outlasts that.

Sample rows

Illustrative values, not data from a real account. Shown to give the shape of the file.

datead_group_namead_statuscampaign_bidding_strategyimpressionsclicksclick_through_ratecostpurchases_7dsales_7d
2026-09-14Exact Match - Core TermsENABLEDoptimizeForSales305004581.502366.40411639.59
2026-09-14Auto - Close MatchENABLEDlegacy842009261.100648.20521456.00
2026-09-14Competitor ASINsPAUSEDmanual124001180.952106.207244.93
2026-09-14Broad - DiscoveryENABLEDruleBased6800610.89745.75259.98
2026-09-14Launch - Long TailENABLEDoptimizeForSales000.0000.00

Field reference

ColumnTypeDescription
datedateThe advertising day the row's metrics are attributed to, as ISO YYYY-MM-DD with no time component. It is what the requested window filters by and the column to partition on.
ad_group_idstringAmazon's numeric ad group identifier, 13 to 15 digits, carried as a string because it is the only join key this file has and a numeric type would silently drop a leading zero.
ad_group_namestringThe ad group's name, advertiser-authored free text. Join on ad_group_id, not on this.
ad_statusstringThe ad group's status label — ENABLED, with PAUSED and ARCHIVED expected in an account that has any. Real at this grain even though the campaign columns are not.
campaign_bidding_strategystringThe bidding strategy of the campaign the ad group sits in, and the only campaign attribute this grain exposes. Observed values are legacy, manual, ruleBased and optimizeForSales.
impressionsint64Times an ad from this ad group was displayed.
clicksint64Clicks on those ads. The billable event for Sponsored Products.
click_through_ratefloat64Clicks divided by impressions, as a percentage rather than a 0-1 fraction. Null on a row with no impressions. Recompute from the counts when aggregating instead of averaging the column.
costdecimalWhat the clicks cost. Equal to spend on every row observed; both are carried because both are in Amazon's vocabulary.
spenddecimalAmazon's other name for cost. Carried so a consumer reading either finds it, but nobody should expect the two to differ.
cost_per_clickdecimalAverage cost per click for the row. Looks like a rate but is money — it multiplies back into cost — so recompute it from cost and clicks rather than averaging it.
purchases_1dint64Orders attributed to a click within 1 day.
purchases_7dint64Orders attributed within 7 days.
purchases_14dint64Orders attributed within 14 days.
purchases_30dint64Orders attributed within 30 days. The most generous window, and the slowest to settle.
purchases_same_sku_1dint64The subset of purchases_1d that were for the advertised SKU itself rather than another product bought after the click.
purchases_same_sku_7dint64Same-SKU subset of purchases_7d.
purchases_same_sku_14dint64Same-SKU subset of purchases_14d.
purchases_same_sku_30dint64Same-SKU subset of purchases_30d.
units_sold_clicks_1dint64Units sold from click-attributed orders within 1 day. Counts units, where purchases_1d counts orders.
units_sold_clicks_7dint64Units sold from click-attributed orders within 7 days.
units_sold_clicks_14dint64Units sold from click-attributed orders within 14 days.
units_sold_clicks_30dint64Units sold from click-attributed orders within 30 days.
units_sold_same_sku_1dint64Units of the advertised SKU specifically, within 1 day.
units_sold_same_sku_7dint64Units of the advertised SKU specifically, within 7 days.
units_sold_same_sku_14dint64Units of the advertised SKU specifically, within 14 days.
units_sold_same_sku_30dint64Units of the advertised SKU specifically, within 30 days.
sales_1ddecimalAttributed sales value within 1 day.
sales_7ddecimalAttributed sales value within 7 days. Divide cost by this for a 7-day ACOS.
sales_14ddecimalAttributed sales value within 14 days.
sales_30ddecimalAttributed sales value within 30 days.
attributed_sales_same_sku_1ddecimalThe portion of sales_1d from the advertised SKU itself. The gap between the two is other products bought after the click.
attributed_sales_same_sku_7ddecimalSame-SKU portion of sales_7d.
attributed_sales_same_sku_14ddecimalSame-SKU portion of sales_14d.
attributed_sales_same_sku_30ddecimalSame-SKU portion of sales_30d.
kindle_edition_normalized_pages_read_14dint64KENP pages read within 14 days, for KDP titles. Present on every row and zero for any account with no Kindle advertising.
kindle_edition_normalized_pages_royalties_14ddecimalRoyalties earned on those KENP pages. Money, and zero wherever the pages-read column is.

Use cases

Ad group ACOS without the campaign average hiding it. ACOS is cost divided by sales_7d (or whichever window you standardise on). A campaign at a comfortable 20% ACOS routinely contains one ad group at 8% and another at 60%; this is the report that separates them.

Finding ad groups that spend and never convert. Filter for rows where cost is positive and purchases_30d is zero over a run of dates — the 30-day window is the most generous, so an ad group that is still at zero there is not waiting on attribution.

Separating same-SKU sales from everything else. The gap between sales_7d and attributed_sales_same_sku_7d is revenue from products other than the one advertised. An ad group whose same-SKU ACOS looks poor but whose total ACOS is healthy is doing a job; judging it on the advertised SKU alone would have you pause it.

Comparing bidding strategies across ad groups. campaign_bidding_strategy is on every row, so cost_per_click and ACOS can be grouped by legacy, manual, ruleBased and optimizeForSales without a join.

Building a daily ad group time series. date is a clean ISO day and (ad_group_id, date) is unique, so the file loads straight into a partitioned table. Join on ad_group_id, never on ad_group_name, which is free text the advertiser can edit.

Limitations and gotchas

No campaign on the row. campaignId and campaignName are not returned at this grouping. If a dashboard needs ad groups rolled up to campaigns, this file cannot do it alone; you need a second source that maps ad_group_id to its campaign. The documented one is the ad group export, which carries campaignId for every ad group. What will not work is joining this file to the campaign report: grouped by campaign, that report has no ad_group_id on it to join against. Amazon's other route is to ask for groupBy: ["campaign", "adGroup"] in one request, which returns both ids on the row — but that is a different pull from this one, not a join onto it.

Attribution windows nest — never add them. sales_30d contains sales_14d contains sales_7d contains sales_1d. Summing them counts the same orders up to four times over.

cost and spend are the same number. Equal on every row observed, at this grain as at the campaign grain. Adding them doubles your spend.

Recent days keep changing. The 30-day window means a click today can still attribute a purchase a month from now, so any snapshot of the last month disagrees with the same days re-pulled later. That is attribution settling, not a bug.

Don't average the rate columns. click_through_rate is a percentage computed per row and null where there were no impressions; cost_per_click looks like a rate but is money. Recompute both from clicks, impressions and cost when aggregating.

The raw JSON types wander. In the gzipped JSON Amazon returns, cost, spend and every sales* column arrive as an integer on some rows and a float on others, seller by seller. Anyone inferring types from the file will get one pull as int and the next as double; pin the schema.

Numeric IDs are not numbers. ad_group_id is a 13 to 15 digit JSON number. Read it as a string, or a leading zero disappears silently and the only join key in the file is corrupted.

Sponsored Brands and Sponsored Display are separate reports. Each has its own ad group report type. This one is Sponsored Products only, and the columns do not line up across the three.

KENP is invisible to ACOS. For KDP advertisers, kindle_edition_normalized_pages_royalties_14d is revenue no sales_* column includes. For everyone else both Kindle columns are zero on every row — present, not retired.

FAQ

Why doesn't the ad group report have a campaign ID?

Because Sponsored Products has no ad group report of its own. This is the campaign report grouped by ad group, and Amazon's grouping replaces the campaign identity columns with the ad group's rather than adding to them. Only the campaign's bidding strategy survives.

Is this the same as the campaign report?

Same report type and the same request apart from groupBy, but a genuinely different column set. The campaign report carries campaign identity and budget columns; this one carries ad group id, name and status instead. The performance and attribution columns are the same.

Which attribution window should I use?

Whichever you use consistently. The four windows nest, so 30-day figures are always at least the 7-day ones; pick one, label it, and do not add them together.

Why do cost and spend match exactly?

They are two names for the same measure in Amazon's vocabulary. Both are carried so that a consumer reading either finds it, but they are not independent numbers.

Why is click_through_rate empty on some rows?

It is null wherever the ad group had no impressions that day, because there is nothing to divide by. It is also a percentage, not a fraction: 1.5 means 1.5 percent.

Can I get ad group data for Sponsored Brands or Sponsored Display from this report?

No. Those ad products have their own ad group report types with their own columns. This report is Sponsored Products only.

Sources

Every researched claim on this page, and the Amazon or Walmart page it came from.

  • marketplaces — advertising.amazon.com/faq — 'In what regions will the updated API be available? The reporting updates are available worldwide (NA, EU, FE) wherever you can run sponsored ads.'
  • history_window — advertising.amazon.com/campaign — the configurations table for `spCampaigns` gives Maximum date range 31 days and Data retention 95 days.
  • history_window — advertising.amazon.com/faq — version 3 offers 'Date ranges up to 31 days' and a 'Longer historical reporting window of up to 95 days (versus 60 days for version 2 reports)'.
  • latency — advertising.amazon.com/overview — 'Initial impression and click data from sponsored ads campaigns is available using the API within 12 hours', Amazon recommends 'waiting at least 5 days for the most accurate click data', and conversion data 'is subject to change for up to 60 days back from the current date'.
  • latency — advertising.amazon.com/faq — 'Initial conversion data is available within 24 hours' and 'Report generation can take as long as three hours.'
  • how-to-get-it — advertising.amazon.com/ad-group — 'For Sponsored Products, there is not a separate ad group report. You can get ad group-level data using the ad group groupBy in a campaign report.'
  • how-to-get-it — advertising.amazon.com/campaign — under `spCampaigns`, Group by `adGroup` adds only adGroupName, adGroupId and adStatus; campaignId and campaignName are listed only under Group by `campaign`.
  • how-to-get-it (console) — advertising.amazon.com/advertising-console — Amazon's console-versus-API comparison maps the console's Sponsored Products Campaign report to the API campaign or ad group report and says 'The API also provides an adGroups report with the same data broken out by ad group.'
  • overview / limitations (ad group to campaign) — advertising.amazon.com/ad-groups — the ad group export model carries `campaignId`, 'The unique identifier of the campaign the ad group belongs to', beside `adGroupId`, and the ad product mapping table marks both available for Sponsored Products.
  • overview / limitations (ad group to campaign) — advertising.amazon.com/get-started — Amazon's own sample request uses groupBy ["campaign","adGroup"] with campaignId and adGroupId in the column list, and the reporting FAQ recommends retrieving metadata by export and merging it into the report.
  • fields (attribution windows) — advertising.amazon.com/columns — purchases30d is 'Number of attributed conversion events occurring within 30 days of an ad click' and purchasesSameSku30d the same 'where the purchased SKU was the same as the SKU advertised'.
  • marketplaces — advertising.amazon.com/api-overview — the API endpoints table names the three regional hosts (NA, EU, FE) and the 22 marketplaces behind them, which is the scope the version 3 reporting FAQ's "worldwide … wherever you can run sponsored ads" covers. Nothing in the `spCampaigns` reference narrows it further, so `all` is Amazon's own answer rather than an absence of restrictions.
  • history_window (conflict resolved) — advertising.amazon.com/campaign — re-read 2026-09-28. The configurations table gives `spCampaigns` a maximum date range of 31 days and data retention of 95 days; the 60- and 65-day retentions in the same table belong to `sbCampaigns` and `sdCampaigns`. The sibling campaign report page now states the same figures and cites the same distinction, so the two pages no longer disagree.
  • how-to-get-it (console) — advertising.amazon.com/GBYSPTSLR337JMLH — Amazon's current "Downloadable reports in sponsored ads" help article lists every report type the console offers for Sponsored Products, Sponsored Brands and Display. No ad group report appears in it for any of the three.
  • how-to-get-it (console sunset) — advertising.amazon.com/streamline-campaign-analysis-with-unified-reporting — Amazon's 8 June 2026 launch announcement for unified reporting: "we're sunsetting Sponsored Ads reports (Measurement and reporting > Sponsored Ads reports) and Amazon DSP reports (Measurement and reporting > Amazon DSP reports) by December 31, 2026."
  • limitations (why not to join the campaign report) — advertising.amazon.com/campaign — joining `ad_group_id` against the campaign report to recover the campaign is a recommendation that cannot hold. Amazon's reference adds `adGroupId` under Group by `adGroup` only, and a campaign-grouped file carries no ad group column to join against. The page follows the ad group export and the two-value `groupBy` instead.
  • limitations (two-value groupBy) — advertising.amazon.com/get-started — Amazon's tutorial request uses `"groupBy":["campaign","adGroup"]` with `campaignId` and `adGroupId` in the column list, and the sample response rows carry both.