AutomationFlowsMarketing & Ads › Fetch Full Google Ads Account Audit Data as Merged JSON

Fetch Full Google Ads Account Audit Data as Merged JSON

BySobek @maagic on n8n.io

Runs manually to pull read-only Google Ads reporting for one account: campaign, ad group, keyword, ad and search-term performance over a chosen date range, plus a current-state snapshot of negative keywords, ad group targeting and campaign assets. Returns everything as one…

Event trigger★★★★☆ complexity18 nodesHTTP Request
Marketing & Ads Trigger: Event Nodes: 18 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #16310 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "2RcO8eSL2bfsn9OLQmdrA",
  "name": "Google Ads Campaign Performance Audit",
  "tags": [],
  "nodes": [
    {
      "id": "8220c553-5f0a-43f3-8c05-6d789ac62bb7",
      "name": "overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        -320
      ],
      "parameters": {
        "width": 904,
        "height": 336,
        "content": "## \ud83d\udcca Google Ads Campaign Performance Audit\n\nPulls a complete **read-only** audit of one Google Ads account and merges everything into a single JSON payload: campaigns, ad groups, keywords, search terms, ads, negative keywords, audience segments and extensions/assets.\n\n### How it works\n1. **Setup & trigger** - the `.env` node holds your token, customer ID, date range and API version. A short `Wait` paces the calls.\n2. **Pull reports** - 8 parallel HTTP requests query the Google Ads `searchStream` API (`v23` tested).\n3. **Merge & output** - `Merge All Outputs` returns one keyed JSON object with all eight report sets.\n\n### Requirements\n- Google Ads **OAuth2** credential with access to the target customer ID\n- A Google Ads **developer token**\n\n\ud83d\udc49 Fill in the **Setup** note (bottom-left) before running."
      },
      "typeVersion": 1
    },
    {
      "id": "216b4127-6eef-487e-b917-92f5cc829a21",
      "name": "sec_setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        48
      ],
      "parameters": {
        "color": 4,
        "width": 480,
        "height": 320,
        "content": "## 1 \u00b7 Setup & trigger"
      },
      "typeVersion": 1
    },
    {
      "id": "1efa5317-ce8a-43a6-bfbc-16a84e198ca4",
      "name": "sec_pull",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        48
      ],
      "parameters": {
        "color": 5,
        "width": 896,
        "height": 544,
        "content": "## 2 \u00b7 Pull Google Ads reports (parallel)"
      },
      "typeVersion": 1
    },
    {
      "id": "55da01fd-522e-4153-86c9-0587ccec01b7",
      "name": "sec_merge",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1936,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 320,
        "content": "## 3 \u00b7 Merge & output"
      },
      "typeVersion": 1
    },
    {
      "id": "24e6d456-12bf-4c8e-9e1d-78384cba79bc",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        560,
        176
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "3f42e845-7dad-42ae-a099-9c8d7c1f9488",
      "name": "Merge All Outputs",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        400
      ],
      "parameters": {
        "jsCode": "\nconst nodeNames = [\n  '1. Campaigns',\n  '2. Ad Groups', \n  '3. Keywords',\n  '4. Search Terms',\n  '5. Ads',\n  '6. Negative Keywords',\n  '7. Audience Segments',\n  '8. Extensions & Assets'\n];\n\nconst output = {};\n\nfor (const name of nodeNames) {\n  try {\n    const items = $(''+name).all();\n    const key = name.replace(/^\\d+\\.\\s*/, '').toLowerCase().replace(/[^a-z0-9]+/g, '_');\n    output[key] = items.map(i => i.json);\n  } catch(e) {\n    output[name] = { error: e.message };\n  }\n}\n\nreturn [{ json: output }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a10f8631-5f4b-4dd7-9616-0a604c26a761",
      "name": "1. Campaigns",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1072,
        176
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ query: \"SELECT campaign.id, campaign.name, campaign.status, campaign.advertising_channel_type, campaign.bidding_strategy_type, campaign.target_cpa.target_cpa_micros, campaign.target_roas.target_roas, campaign.maximize_conversions.target_cpa_micros, campaign.maximize_conversion_value.target_roas, campaign.serving_status, campaign.optimization_score, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.conversions_value, metrics.ctr, metrics.average_cpc, metrics.search_impression_share, metrics.search_budget_lost_impression_share, metrics.search_rank_lost_impression_share FROM campaign WHERE segments.date BETWEEN '\" + $('.env').item.json.DATE_FROM + \"' AND '\" + $('.env').item.json.DATE_TO + \"' AND campaign.status != 'REMOVED'\" }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "0201b16e-9e9b-4bcd-b70f-9371c0e68d88",
      "name": "2. Ad Groups",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1296,
        176
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ query: \"SELECT campaign.id, campaign.name, ad_group.id, ad_group.name, ad_group.status, ad_group.type, ad_group.cpc_bid_micros, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.ctr, metrics.average_cpc FROM ad_group WHERE segments.date BETWEEN '\" + $('.env').item.json.DATE_FROM + \"' AND '\" + $('.env').item.json.DATE_TO + \"' AND campaign.status != 'REMOVED' AND ad_group.status != 'REMOVED'\" }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "fd26688b-856e-4229-9d9c-a50a0bdfd2f7",
      "name": "3. Keywords",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1520,
        176
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ query: \"SELECT campaign.name, ad_group.name, ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.status, ad_group_criterion.quality_info.quality_score, ad_group_criterion.quality_info.creative_quality_score, ad_group_criterion.quality_info.post_click_quality_score, ad_group_criterion.quality_info.search_predicted_ctr, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.average_cpc FROM keyword_view WHERE segments.date BETWEEN '\" + $('.env').item.json.DATE_FROM + \"' AND '\" + $('.env').item.json.DATE_TO + \"' AND campaign.status != 'REMOVED' AND ad_group.status != 'REMOVED' AND ad_group_criterion.status != 'REMOVED'\" }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "ce590088-ce2c-4bbc-b78a-be2c1b836e77",
      "name": "4. Search Terms",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1744,
        176
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ query: \"SELECT campaign.name, ad_group.name, search_term_view.search_term, search_term_view.status, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.ctr, metrics.average_cpc FROM search_term_view WHERE segments.date BETWEEN '\" + $('.env').item.json.DATE_FROM + \"' AND '\" + $('.env').item.json.DATE_TO + \"' AND campaign.status != 'REMOVED' ORDER BY metrics.cost_micros DESC LIMIT 300\" }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "641ed055-3614-48c5-b2f2-65684238d414",
      "name": "5. Ads",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1072,
        400
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ query: \"SELECT campaign.name, ad_group.name, ad_group_ad.ad.id, ad_group_ad.ad.type, ad_group_ad.status, ad_group_ad.ad.responsive_search_ad.headlines, ad_group_ad.ad.responsive_search_ad.descriptions, ad_group_ad.ad.final_urls, ad_group_ad.policy_summary.approval_status, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.ctr, metrics.average_cpc FROM ad_group_ad WHERE segments.date BETWEEN '\" + $('.env').item.json.DATE_FROM + \"' AND '\" + $('.env').item.json.DATE_TO + \"' AND campaign.status != 'REMOVED' AND ad_group_ad.status != 'REMOVED'\" }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "aa959b9a-1a84-4792-8d7a-148f651e78b2",
      "name": "6. Negative Keywords",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1296,
        400
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "{ \"query\": \"SELECT campaign.name, campaign_criterion.keyword.text, campaign_criterion.keyword.match_type, campaign_criterion.negative FROM campaign_criterion WHERE campaign_criterion.negative = TRUE AND campaign.status != 'REMOVED'\" }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "ae3347f6-23c6-46ac-84a7-27b44d7b6dd5",
      "name": "7. Audience Segments",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1520,
        400
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "{ \"query\": \"SELECT campaign.name, ad_group.name, ad_group_criterion.type, ad_group_criterion.bid_modifier, ad_group_criterion.status FROM ad_group_criterion WHERE campaign.status != 'REMOVED' AND ad_group_criterion.status != 'REMOVED'\" }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "1a0d082a-6a11-4b50-9c2a-371ebffb1785",
      "name": "8. Extensions & Assets",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1744,
        400
      ],
      "parameters": {
        "url": "=https://googleads.googleapis.com/{{ $('.env').item.json.api_version }}/customers/{{$('.env').item.json.account}}/googleAds:searchStream",
        "method": "POST",
        "options": {},
        "jsonBody": "{ \"query\": \"SELECT campaign.name, campaign.id, campaign.status, asset.type, asset.name, asset.call_asset.phone_number, asset.callout_asset.callout_text, asset.sitelink_asset.link_text FROM campaign_asset WHERE campaign.status != 'REMOVED'\" }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token",
              "value": "={{$('.env').item.json.GOOGLE_ADS_DEVELOPER_TOKEN}}"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {
        "googleAdsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "781419b1-329d-4794-9e7f-507c81624d92",
      "name": ".env",
      "type": "n8n-nodes-base.set",
      "position": [
        704,
        176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3966502b-d96a-4caf-a610-d0b6ffe109a5",
              "name": "GOOGLE_ADS_DEVELOPER_TOKEN",
              "type": "string",
              "value": ""
            },
            {
              "id": "083267bb-e5d4-4742-9196-d6f8eab298a1",
              "name": "account",
              "type": "string",
              "value": ""
            },
            {
              "id": "fa24102d-a160-4e04-84fb-7a2c9dd6b771",
              "name": "DATE_FROM",
              "type": "string",
              "value": "=2026-04-16"
            },
            {
              "id": "f0c3bce2-9043-46c5-a177-b7ca441015b9",
              "name": "DATE_TO",
              "type": "string",
              "value": "=2026-06-12"
            },
            {
              "id": "3d33ac17-b55d-44ec-b454-78b399b3cd85",
              "name": "api_version",
              "type": "string",
              "value": "v23"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7d0d3c6b-d53a-4ad9-aa44-ed2910c45845",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        848,
        176
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "5671a3bd-93d9-45e6-87c5-e91a956af8c1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        640
      ],
      "parameters": {
        "color": 6,
        "width": 480,
        "height": 288,
        "content": "### Google Ads - Account Audit\n#### Setup - open `.env` and fill in before running\n`GOOGLE_ADS_DEVELOPER_TOKEN`\n\u2192 Google Ads Manager \u2192 Tools \u2192 API Centre \u2192 View token\n`GOOGLE_ADS_CUSTOMER_ID`\n\u2192 Sub-account ID, no dashes (e.g. 3996289339)\n`DATE_FROM` / `DATE_TO`\n\u2192 See date examples\n`api_version` \n\u2192 enter latest Google API version - `v23` tested"
      },
      "typeVersion": 1
    },
    {
      "id": "379a373a-e80c-4801-93cb-0de2b489602b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        640
      ],
      "parameters": {
        "color": 6,
        "width": 1168,
        "height": 288,
        "content": "### Date examples\n**Fixed:** `2026-05-01` / `2026-05-31`\n**Last month:** `{{ DateTime.now().minus({months:1}).startOf('month').toFormat('yyyy-MM-dd') }}` / `{{ DateTime.now().minus({months:1}).endOf('month').toFormat('yyyy-MM-dd') }}`\n**Last week:** `{{ DateTime.now().minus({weeks: 1}).startOf('week').toFormat('yyyy-MM-dd') }}` / `{{ DateTime.now().minus({weeks: 1}).endOf('week').toFormat('yyyy-MM-dd') }}`\n**Last 30 days:** `{{ DateTime.now().minus({days:30}).toFormat('yyyy-MM-dd') }}` / `{{ DateTime.now().minus({days:1}).toFormat('yyyy-MM-dd') }}`\n### Credentials\nConnect Google Ads OAuth2 credential to any HTTP node on import. Account must have access to the customer ID (`GOOGLE_ADS_CUSTOMER_ID`).\n### Output\n**Merge All Outputs** node returns single JSON with keys: `campaigns` `ad_groups` `keywords` `search_terms` `ads` `negative_keywords` `audience_segments` `extensions_assets`"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "6fdff922-7748-45df-888b-e1c06a15bd55",
  "connections": {
    ".env": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "1. Campaigns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Ads": {
      "main": [
        [
          {
            "node": "6. Negative Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Keywords": {
      "main": [
        [
          {
            "node": "4. Search Terms",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Campaigns": {
      "main": [
        [
          {
            "node": "2. Ad Groups",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Ad Groups": {
      "main": [
        [
          {
            "node": "3. Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. Search Terms": {
      "main": [
        [
          {
            "node": "5. Ads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Negative Keywords": {
      "main": [
        [
          {
            "node": "7. Audience Segments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. Audience Segments": {
      "main": [
        [
          {
            "node": "8. Extensions & Assets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Extensions & Assets": {
      "main": [
        [
          {
            "node": "Merge All Outputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": ".env",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Runs manually to pull read-only Google Ads reporting for one account: campaign, ad group, keyword, ad and search-term performance over a chosen date range, plus a current-state snapshot of negative keywords, ad group targeting and campaign assets. Returns everything as one…

Source: https://n8n.io/workflows/16310/ — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Marketing & Ads

This n8n workflow automates the process of finding ecommerce seller leads, enriching them with product and business details, discovering company websites, and extracting contact information such as em

Google Sheets, N8N Nodes Mrscraper, HTTP Request
Marketing & Ads

This template is for B2B sales teams, SDRs, growth marketers, and founders who maintain a spreadsheet of prospects and need verified contact details -- emails and mobile numbers -- without manual rese

Google Sheets, HTTP Request
Marketing & Ads

This workflow finds local businesses from Google Maps and automatically enriches them with emails, social profiles, AI summaries, and personalized outreach messages — all saved to Google Sheets. Searc

HTTP Request, Google Sheets
Marketing & Ads

This workflow leverages n8n to perform automated Google Maps API queries and manage data efficiently in Google Sheets. It's designed to extract specific location data based on a given list of ZIP code

Execute Workflow Trigger, Stop And Error, HTTP Request +1
Marketing & Ads

This workflow reads LinkedIn profile URLs from Google Sheets, enriches each lead using PhantomBuster profile and company scrapers, finds a work email via Hunter.io with a Dropcontact fallback, writes

Google Sheets, HTTP Request, PhantomBuster +2