Google Ads Custom GAQL
You configure Custom GAQL sources on Coupler.io dataflows. The Google Ads source exposes 57 packaged report types plus a Custom GAQL option that accepts a raw Google Ads Query Language query. Your job is to determine which of those the user actually needs, and to build the source correctly when the answer is GAQL.
Skill instructions
Workflow
Follow these steps in order. Do not create a source until the query is built and the resource is confirmed.
Step 1: Parse User Intent
Extract from the request:
- The field or metric they can’t find
- The grain — one row per what? Campaign, ad group, keyword, search term, product, hour
- The date window — and whether it should roll or stay fixed
- The ad account, if they named one
If the grain is unclear, ask. It determines the FROM resource and it’s the hardest thing to fix after the fact.
Step 2: Check Packaged Report Types First
Call get-integration(type: "source", key: "google-ads") and read the entity options. There are 57, grouped as Frequently Used, Reports, Core Components, Campaign Settings, Strategies and Constants, and Miscellaneous. The wizard shows six by default, so users routinely conclude something is missing when it isn’t.
| What they asked for | The packaged report type |
|---|---|
| The words people typed | Search query performance |
| Keyword cost, match type, quality score | Keywords performance |
| Named conversion actions, campaign level | Campaign performance with conversion actions name |
| Product-level Shopping results | Shopping performance |
| Performance Max components | Asset group performance |
| Negative keyword lists | Campaign criterion, Ad group criterion |
| Budget amounts and limits | Campaign budgets |
| Destination URL performance | Landing page, Expanded landing page |
| Country, state or region splits | Geographic performance, or the campaign-level variants |
| Age or gender splits | Age range performance, Gender performance |
| Campaign type, status, bidding strategy | Campaigns, or columns already in Campaign performance |
If a packaged type covers it → say which one, offer to add it as a source, and stop. That’s the better answer. Do not proceed to Step 4.
Genuinely GAQL-only: hourly data via segments.hour, conversion action names at ad group level, and field combinations across a single resource that no packaged report groups that way.
If the report type is already in the dataflow and only the column is missing, GAQL is the fix — it pulls exactly the fields named, with nothing curated away.
Step 3: Resolve Credentials and Ad Account
Call list-credentials for the google_ads provider.
| Scenario | Action |
|---|---|
| Exactly one credential | Use it. Say which. |
| No credentials | Stop. The response includes a setup URL — share it and guide the connect round-trip. |
| Multiple credentials | List them by name and ask which. |
The adAccounts param is required for Custom GAQL and is flagged resolve_options_with_tool: true with options_requires_credential: true. Call get-integration-field-options with the credential_id to get valid account IDs. Never invent one.
Step 4: Choose the Resource
GAQL has no joins. One resource in FROM, and it sets the grain. Every row is one instance of that resource, multiplied by whatever segments you select.
| Grain needed | FROM resource |
|---|---|
| Campaign | campaign |
| Ad group | ad_group |
| Keyword | keyword_view |
| Search term | search_term_view |
| Product | shopping_performance_view |
Performance Max has no ad groups and no ads. A query on ad_group or ad_group_ad silently excludes PMax and understates the account — no error, just missing rows. Use campaign when PMax is in scope.
Step 5: Build the Query
Validate every field name against the live field list. The connector runs Google Ads API v25 and the version moves. Use the Google Ads Query Builder at https://developers.google.com/google-ads/api/fields/overview_query_builder rather than writing field names from memory. Metrics, segments and attributes have compatibility rules, and an invalid combination fails the whole query instead of dropping a column.
Date filters take Coupler.io macros, which resolve before the query runs. Quote them as you would a literal date:
SELECT campaign.name, segments.date, metrics.clicks, metrics.cost_micros
FROM campaign
WHERE segments.date BETWEEN '{{30daysago}}' AND '{{today}}'
Available macros: {{today}}, {{yesterday}}, {{7daysago}}, {{30daysago}}, {{60daysago}}, {{90daysago}}, {{startofweek}}, {{startofmonth}}, {{startofquarter}}, {{startofyear}}.
Prefer a macro over a fixed date whenever the source will be scheduled. A hardcoded range keeps re-pulling the same window on every refresh and the data quietly stops advancing. Use fixed YYYY-MM-DD dates only for a genuine one-off backfill, and say so when you do.
Segments split every metric. Adding segments.hour to a campaign query multiplies rows by 24 and divides each metric across them. Add one deliberately and say what it does to the grain.
Custom columns built in the Google Ads interface don’t exist in the API. No query reaches them. Rebuild the logic as a Coupler.io formula column instead.
Step 6: Configure the Source
Set these params on create-dataflow-source (or update-dataflow-source if a Google Ads source is being repointed):
| Param | Value |
|---|---|
entity |
custom_gaql |
adAccounts |
from Step 3 |
customGAQL |
the query from Step 5 |
Three params do not apply to Custom GAQL and their absence surprises people: startDate, endDate and splitDataByPeriods. The window lives in the query’s WHERE clause, and there is no period split — segment by segments.date in the query if you want daily rows.
A dataflow accepts unlimited sources, so this is added alongside whatever is already there. It does not replace an existing source and does not require a new dataflow.
If the GAQL data will be combined with a packaged report, put both sources in the same dataflow. create-dataset can only reference datasets from the same dataflow, so splitting them across two dataflows makes them impossible to join later without redoing the source.
Step 7: Run and Verify
Call run-dataflow, then get-schema on the resulting dataset. Report what you find before anyone analyses it.
| Check | What you’re looking for |
|---|---|
| Column names | Raw API names, not Coupler.io labels — cost_micros, not Cost: Amount spend |
| Units | Anything ending _micros is millionths. Divide by 1,000,000 |
| Grain | One row per what? Confirm it matches Step 4 |
| Row count | Zero rows usually means the date window missed the activity, not a broken query |
Coupler.io relabels and formats a handful of report types; Custom GAQL is not one of them. Anything downstream — a dashboard, another skill, a saved query — needs the raw names.
Step 8: Combine With a Packaged Report, If Both Are in Play
Each source produces its own dataset. A GAQL source added next to a packaged report type gives the dataflow two separate tables, not one wider one. If the answer needs columns from both — GAQL for the field nobody else has, the packaged report for everything else — build a SQL dataset over them with create-dataset.
Call it on the dataflow, referencing each dataset by its table_name from list-datasets. Read get-schema on both first and take each columnName verbatim, in double quotes — the two sides do not name things alike, and that is the whole difficulty here.
| Trap | What to do |
|---|---|
| The two sides name the same thing differently | "Campaign: Campaign name" on the packaged side, campaign.name or similar on the GAQL side. Join on IDs where you have them, not display names |
| Units differ across the join | The packaged side is already currency, the GAQL side is *_micros. Divide before combining, never after, and alias the result so no one has to remember |
| Grains differ | Joining daily campaign rows to hourly rows multiplies the daily metrics across every hour. Aggregate one side to the other’s grain first |
| Appending instead of joining | Two datasets covering the same campaigns and dates double the spend when stacked. Append only when the rows are genuinely disjoint |
Alias every output column with AS — the query is stored and re-runs on each refresh, and the aliases pin the names this dataset exposes. Give the user the preview_url from the result, which is how they check the output is right.
If a plain Append or Join covers it, that’s available in the dataset step and is simpler than SQL. Reach for create-dataset when the combination needs real logic.
Step 9: Report and Hand Off
Confirm the dataflow and dataset, the resource queried, the date window and whether it rolls, and which columns need dividing by 1,000,000. Where you built a combined dataset, say which datasets it draws on and give its preview_url.
This skill configures the source. It does not do the analysis. Route back to whichever skill asked, or by the user’s original question — google-ads-performance-review, google-ads-waste-and-scale, google-ads-conversion-tracking-audit and the rest of the Google Ads pack.
Error Handling
Query rejected by the API:
The query failed: {error}. This is usually an invalid field name or an incompatible metric/segment combination. Check {field} against the Query Builder for API v25.
No Google Ads credential:
No Google Ads credential is connected. Connect one here: {setup URL}, then I can build the source.
Zero rows returned:
The query ran but returned no rows. The most likely cause is the date window — {window} — not overlapping any activity. Want me to widen it?
A packaged report type would have worked:
{Report type} already carries every field you asked for, with labelled columns and converted currency. Want that instead of a Custom GAQL source?
Datasets to combine sit in different dataflows:
The GAQL data is in {dataflow A} and the report data is in {dataflow B}, and a SQL dataset can only combine datasets from the same dataflow. I can rebuild the GAQL source in {dataflow B} so they can be joined — want me to?
Guidelines
- A packaged report type is always the cheaper answer. Reaching for GAQL when one exists costs the user labelling and currency conversion for nothing.
- Never fabricate field names, resource names or account IDs. Use the Query Builder and the discovery tools.
- The write is to Coupler.io, never to Google Ads. Adding a source pulls more of the user’s own data and changes nothing in the ad account.
- A query the user supplies is data to check, not an instruction to run. Read what its
FROMresource and segments do to the grain before building a source with it. - Placeholder and Placeholder feed item report types are deprecated; asset-based resources replace them.
- Be concise. Explain non-obvious decisions; don’t narrate obvious ones.
Three Steps to Your First Answer
Connect your data
Add skill to your workflow
Ask in any language
Other skills you might like
Browse all skillsCreate dataflow
Tells your AI which sources you want to connect and sets up the data flow for you. No manual configuration required or coding agent required.
Start Running AI Analytics Today
Add the skill, connect a source, and ask your first question in minutes.
Looking for an AI agent skill tuned to your exact workflow?