Reporting · Exports
My Google Ads export doubled an account. The file was fine.
A Google Ads export carries more rows than your account has campaigns. Every filter you leave applied adds a total row, and one of them leaves the campaign column holding a dash instead of a name. Filter on that one column and you sum an account total as if it were a campaign.
The export is the deliverable, whatever the dashboard says
Before the mechanics, the reason this is worth an afternoon. For most people running paid media, the CSV is not a step on the way to the report. It is the report.
Five operators said it in two subreddits on the same day, without anyone asking:
“The person you built it for still wants the numbers in a spreadsheet anyway.”
u/Exact_Entertainer600, r/analytics, 1 August 2026. Recorded in our own ICP voice bank.
Those five are not saying they have no tool. They have one, and the number lands in a sheet regardless. So whatever the export gets wrong travels straight into the deck, the invoice and the decision.
And getting the file out is not a solved problem either:
“I am trying to download change history over long periods and the report fails for unknown reasons, and it is not even a big file. I do not think our MCC supports pulling change history.”
u/annmariedsc, r/PPC, 27 August 2026, thread 1w041ya. Paraphrased from the original post, which had no replies after 12 hours.
Nobody answered. That is the state of the art on this subject.
What actually happened, with the numbers
On 25 August 2026 I ran our reconciliation check against a real client export for the first time. It is a small script. Its only job is to add up the campaign rows and compare that total against the number the interface shows.
The reconciliation came out at exactly twice the real figure. On the export segmented by conversion action, exactly four times. The account’s biggest conversion action read 5,547.9 conversions where the truth was 1,387.0.
The file was correct. My filter was not.
A Google Ads export does not bring one total row. It brings several, one per level, and each one puts its marker in the column that belongs to its own level. Here is the census from that export, which had 53 campaigns and six total rows.
| Row | Where it puts its marker | What the Campaign column holds | Caught by a filter on Campaign alone? |
|---|---|---|---|
Total: Account |
Campaign status |
Empty | Yes. An empty campaign name is easy to drop |
Total: Search, Total: Display, Total: Performance Max |
Campaign status |
Empty | Yes, for the same reason. Three rows, one per campaign type present |
Total: Filtered campaigns |
Campaign status |
" --", a space and two hyphens |
No, and this is the whole problem. It is not empty and it does not contain the word Total |
The filter I had was the obvious one. Keep rows where the campaign name is present and does not contain Total. It drops five of the six. The sixth is an account total with a dash for a name, and it gets summed as campaign number 54.
Two things follow, and the second one is the useful one.
- The dash is a marker for an empty cell, not a value. Google Ads writes
--where a cell does not apply. Read as text, it turns an aggregate into a named entity. - An exact multiple is a signature. A business problem does not produce a clean 2x. A total row summed twice does. If your reconciliation comes out round and wrong, look at the filter before you look at the data.
Three checks before you trust an export
None of these needs a tool. All three are things I now do before reading a single number, because each one has cost me time.
1. Reconcile the file against the screen
Sum the cost column of the rows you kept. Compare it against the total the interface shows for the same period and the same filter. They should match to the cent.
Reconciling the file against the screen catches everything else on this page, and it takes a minute. It is also the check most reports skip, because the file opens and looks plausible.
2. Test five columns for the total marker, not one
A row is a total if any of these starts with Total:: campaign status, campaign, conversion action, ad group, ad group status. Checking one column is how the filtered row survives.
The rule, anchored. The colon is not decoration
Anchor the pattern with the colon. An unanchored ^Total on a search terms export took out 31 legitimate Dutch terms starting with totale, including totale knieprothese. In that account it moved 1.55 EUR out of 15,544 and changed nothing. In a Dutch or German account it will not always be harmless.
3. Know which columns stop repeating under a segment
Segment a campaign report by conversion action and the shape changes. Each campaign becomes several rows, and cost is written once. Every other row for that campaign shows zero cost.
So for cost you take the maximum per campaign. For conversions and conversion value you sum, because those really do belong to each row.
I had this half right for months, and the half I had wrong was written down as if it were a rule. Our own document said use the maximum, not the sum, with no qualifier. Measured on a three campaign fixture, taking the maximum of conversions returns 2,500 where the truth is 2,878, and of value 85,340 where the truth is 93,900.
One sentence, one missing word, and every segmented audit understates conversions. A rule with no qualifier is where the next bug lives.
One more thing that is not a check but costs the same afternoon: All conv. and All conv. value are not in the default column set. Conversions counts only the actions included in your account goals. If a client counts bookings as a secondary action, the default export hides them.
Three ways to get the data out, and what each one is for
The route changes which of the three checks you still need. It does not remove them.
| Route | What you get | Where it breaks | Best for |
|---|---|---|---|
| Download from the interface | Exactly the view on screen, filters and segments included | Total rows travel with it. Manual, one account at a time. Large search terms files get unwieldy, so filter to cost above zero first | A one off question you will not ask again. Fastest route to an answer, worst route to a habit |
| Scheduled report by email | The same file, on a timetable, without anyone remembering | Still a view, so it still carries totals. The definition drifts silently if someone edits the report | A recurring request from the same person. Worth setting up the day you answer it twice |
| The API, with a query | Rows you asked for, with no total rows in them | Rows where every selected metric is zero are not returned, so an empty day arrives as an absence. Change events reach back 30 days only | Anything that has to be compared over time. The only route where you control the shape |
Note what the third row buys and what it costs. The API removes the problem this page is about, and hands you the opposite one: rows that are missing rather than rows that should not be there. We wrote that up separately in Google Ads missing data.
And one habit that saves a wasted afternoon: pull change history month by month. In our runs, asking for a long period returns a file that looks complete and is not.
The objections this gets
We pull through the API, so none of this applies
Half right. The API does not hand you total rows, so the specific bug on this page cannot happen to you. The segmentation behaviour is the same, though, and so is the need to reconcile. A query can also be wrong in ways a CSV cannot, because nobody eyeballs it.
Our reporting tool handles all of that
Maybe. The question to ask it is which rows it dropped and on what rule. If the answer is not in its documentation, you have moved the filter somewhere you cannot read it. That is worse than a filter you wrote badly yourself.
This is an edge case
The filtered total row appears whenever a filter is applied in the interface, which for most people is most of the time. You get it by looking at enabled campaigns only. That is not an edge, it is the default workflow.
Our numbers have always matched
Then you have the check already, and this page costs you nothing. If nobody has actually added the file up against the screen, you do not know that they match. You know that nobody has looked.
What this cost, and what I still do not know
The uncomfortable part first, because it is the part worth copying.
That reconciliation check was not new. It had a self test, I had watched it fail on purpose, and I had written it down as tested. Then it met a real client file and returned a number twice the truth.
The fixture did not contain a filtered total row, because I did not know one existed. A fixture is written by the same head that wrote the check, so it inherits the same blind spots. A self test proves your check can go red. It does not prove your check can read the world.
- What I would do differently. Run the reconciliation against one real file before writing any analysis on top of the parser. First contact with a real export is part of the testing, not part of the usage.
- What it cost. An afternoon, and the credibility of a check I had already signed off. It failed loudly rather than quietly, which is the cheap direction. A false alarm still sends you to fix data that was fine.
- What I still do not know. Whether the dash marker and the total row names are identical across every account language and currency. We have measured this on Google Ads accounts in English and Dutch. That is not a census.
- Where this does not reach. Meta exports have a different shape and we have not run the same count on them. Assuming the rule carries over would be exactly the mistake described above.
Questions people actually ask
How do I export Google Ads data?
Open the view you want, set the date range and any segment, then use the download control and pick CSV. The file contains exactly what is on screen, filters included. For something you will need again, build it in the report editor and schedule it by email instead. For anything compared over time, query the API so you control the shape of the rows.
Why does my Google Ads export not match the interface total?
The usual cause is a total row counted as a campaign. An export carries one total row per level, and the one produced by an applied filter leaves the campaign column holding a dash rather than a name. A filter that only drops empty or Total named rows lets it through. If the gap is an exact multiple such as two or four times, that is the signature.
What does the double dash mean in a Google Ads export?
The double dash marks a cell that does not apply to that row, and it is not a value. Google Ads writes it where a column has no meaning at that level. Treating it as text is what turns an aggregate row into an entity with a name, which is how a whole account total gets summed as one more campaign.
How many total rows does a Google Ads export have?
The count depends on what is in the account and on what is filtered. In one real export of 53 campaigns there were six: one for the account, one for each campaign type present, and one for the filtered set. Rather than counting them, test five columns for a value starting with Total followed by a colon.
Why is cost zero on most rows of a segmented export?
Because cost is not repeated when a campaign is split into several rows by a segment such as conversion action. It is written once and the other rows show zero. Take the maximum per campaign for cost. Sum conversions and conversion value, because unlike cost they do belong to each individual row.
Can Google Ads export data automatically?
Yes, in two ways. A scheduled report from the report editor arrives by email on a timetable and needs no one to remember it. A query against the API gives you the same data with no total rows in it. Prefer it whenever the output feeds anything other than a human reading a sheet.
Last updated:
Related reading
- Google Ads missing data. The opposite failure in the same file: rows that are absent rather than rows that should not be there.
- Google Ads change history. The one export with its own window and its own limits, and what it will never tell you.
- Reading Google and Meta together. Which columns survive being added across two platforms, and which never do.
- Marketing report template. What to do with the file once you trust it.
The short version
Add the file up against the screen before you read a number off it. Test five columns for the total marker, not one. Know which columns stop repeating under a segment.
An export is a copy of a view, not a copy of your account. The difference is a handful of rows, and they are the largest ones in the file.
If you would rather see what your team should look at first on a real account, the Paid Media Capacity Check is being built for that.