Skip to content

The field your Google Ads audit is reading is the wrong one

GOOGLE ADS
The field your Google Ads audit is reading is the wrong one
Conner Crowe

Quick Take

If you are auditing what a Google Ads account bids toward, do not read conversion_action.primary_for_goal. It is a legacy field. An account can report primary_for_goal: true on actions that are not biddable at all, which makes a correctly configured account look broken. I know because I did exactly this on my own account in August and produced a wrong finding: I flagged two Google Business Profile local actions as poisoning the bidding signal when the goal layer had already excluded them. The setting that governs what Smart Bidding optimizes toward is the conversion-goal layer, and it has two levels that have to be read together.

What the legacy field is doing

primary_for_goal is a per-conversion-action boolean, and it reads like the answer to “does this count.” It used to be closer to that. The account structure moved on and the field stayed, so what you are reading now is a flag that no longer expresses the thing you want to know.

The specific failure is that it cannot express a campaign-level override. A conversion goal can be biddable at the account level and switched off for one campaign, and no per-action boolean can represent that, because the state does not live on the action.

The two levels that do decide

Read both of these. Neither one alone is the answer.

SELECT customer_conversion_goal.category,
       customer_conversion_goal.origin,
       customer_conversion_goal.biddable
FROM customer_conversion_goal
SELECT campaign.name,
       campaign_conversion_goal.category,
       campaign_conversion_goal.origin,
       campaign_conversion_goal.biddable
FROM campaign_conversion_goal
WHERE campaign.id = <id>

The first gives you the account default. The second gives you what a specific campaign actually does, including where it departs from that default. Resource names come back as CATEGORY~ORIGIN, so you will see values like GET_DIRECTIONS~GOOGLE_HOSTED and SUBMIT_LEAD_FORM~WEBSITE. Origin matters as much as category, because the same category arriving from a Google-hosted surface and from your website are different rows with different settings.

The gotcha that will invert your reading

biddable is omitted from the response when it is false. The API drops false and zero values rather than returning them, so a row with no biddable key means not biddable.

If you parse this assuming a missing key is an error or a null to skip, you will either crash or, worse, silently treat non-biddable goals as unknown and drop them from your analysis. Read it as .get('biddable', False) and move on. This is the same omission behavior that bites elsewhere in the Google Ads API, and it is the single most common reason a script’s picture of an account disagrees with the interface.

What still deserves a flag

Getting the layer right does not mean the account is fine. It means you now have to check something harder, and primary_for_goal was never going to tell you this either.

A goal can be correctly biddable while the conversion action underneath it fires on the wrong event. On my own account, BOOK_APPOINTMENT~WEBSITE is biddable, which is right. The action feeding it is “Call booked (Calendly),” which sounds right. It fires on a GTM trigger called book_call_click, which is the scheduling modal opening. Not a booking. Somebody who opened the modal and closed it counts the same as somebody who put a meeting on my calendar.

Under Manual CPC that is a reporting annoyance. Under Smart Bidding it is a direction, and the system will go find more people who open modals.

So the audit step is: for every biddable goal, open the GTM trigger behind the conversion action and confirm the event is the outcome, not the intent to start it. Names lie. book_call_click is honest about what it is if you read it, and the conversion action’s display name is what hides it.

What to do with this

Three passes, in order.

Pull customer_conversion_goal and write down which categories are biddable. Then pull campaign_conversion_goal for every enabled campaign and note where it diverges, because those overrides are usually deliberate and occasionally forgotten. Then, for each biddable goal, trace the action to its trigger and decide whether that trigger is a completed outcome.

If the third pass turns up a soft trigger on a biddable goal, that is your finding, and it is a real one. It is also the finding I would have missed entirely if I had kept reading the legacy field, because the legacy field had me looking at two harmless local actions instead.

What I am not claiming

I am not claiming primary_for_goal is meaningless everywhere. It still exists, older tooling still reads it, and in accounts that never diverged from account-level defaults it will often agree with the goal layer. The claim is that it is not a reliable basis for an audit conclusion, and agreement in the simple case is not evidence in the complicated one.

I am also not claiming this is the whole measurement picture. It tells you what bidding is aimed at. Whether the thing it is aimed at is being counted correctly is a separate question, and the architecture I work through for that is the Tracking Stack. If you want the numbers behind how far apart platforms land on the same event, that is in the Ecommerce Tracking Accuracy Benchmark.

Want a review like this on your account?

Want this kind of review
on your account?

Thirty minutes on the phone. Same person on the call as on the work. Walk out with a clear set of next steps.