AutomationFlowsData & Sheets › Daily Google Ads Performance to Notion and Google Sheets

Daily Google Ads Performance to Notion and Google Sheets

ByAziz dev @azizdev on n8n.io

This workflow automates the daily reporting of Google Ads campaign performance. It pulls click and conversion data from the Google Ads API, merges both datasets, and stores the results into Notion databases and Google Sheets.

Cron / scheduled trigger★★★★☆ complexity19 nodesHTTP RequestNotionGoogle Sheets
Data & Sheets Trigger: Cron / scheduled Nodes: 19 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "5ff5e3a4-baf5-4cbf-a75d-6d36a82a4e56",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        760
      ],
      "parameters": {
        "color": 3,
        "width": 640,
        "height": 720,
        "content": "\n#### 2. G-Ads Query Conversion\n\n**Purpose**: Fetches bottom-of-funnel metrics (results and ROI).\n\n**Query:**\n\n```sql\nSELECT\n  campaign.id,\n  campaign.name,\n  metrics.conversions,\n  segments.conversion_action_name,\n  segments.date\nFROM campaign\nWHERE segments.date = '{{$json.yesterday}}'\n```\n\n**Returns:**\n\n* `metrics.conversions`: Number of conversions (e.g. purchase, lead)\n* `segments.conversion_action_name`: Type of conversion action\n* `segments.date`: The reporting date\n\n**Use case**: Track campaign outcomes and effectiveness.\n\n---\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4e646849-8389-4ee5-95d1-f1d50437c623",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -100,
        760
      ],
      "parameters": {
        "color": 3,
        "width": 640,
        "height": 740,
        "content": "### Google Ads Click vs Conversion (HTTP POST)\n\n***\nThis workflow includes two HTTP Request nodes that send POST requests to the Google Ads API via the `googleAds:search` endpoint. Both use GAQL to query yesterday's campaign data, but each focuses on different metrics.\n***\n\n---\n\n#### 1. G-Ads Query Click\n\n**Purpose**: Fetches top-of-funnel metrics (traffic and cost).\n\n**Query:**\n```sql\nSELECT\n  campaign.id,\n  campaign.name,\n  metrics.impressions,\n  metrics.clicks,\n  metrics.cost_micros,\n  segments.date\nFROM campaign\nWHERE segments.date = '{{$json.yesterday}}'\n````\n\n**Returns:**\n\n* `metrics.impressions`: Number of times ads were shown\n* `metrics.clicks`: Number of ad clicks\n* `metrics.cost_micros`: Ad cost in micros (\u00f7 1,000,000)\n* `segments.date`: The reporting date\n\n**Use case**: Monitor ad visibility, engagement, and spending.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "33ddcd1d-f6f7-437c-b920-f8b3e17ffa3b",
      "name": "G-Ads Query Click",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        380,
        400
      ],
      "parameters": {
        "url": "https://googleads.googleapis.com/v20/customers/{{YOUR_CUSTOMER_ID}}/googleAds:search",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ \n  {\n    query: `SELECT \n      campaign.id, \n      campaign.name, \n      metrics.impressions, \n      metrics.clicks, \n      metrics.cost_micros, \n      segments.date \n    FROM campaign \n    WHERE segments.date = '${$json.yesterday}'`\n  }\n}}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "login-customer-id"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {},
      "typeVersion": 4.2
    },
    {
      "id": "58d2857b-fbe7-4906-9878-985a99426f29",
      "name": "G-Ads Query Conversion",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        380,
        600
      ],
      "parameters": {
        "url": "https://googleads.googleapis.com/v20/customers/{{YOUR_CUSTOMER_ID}}/googleAds:search",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ \n  {\n    query: `SELECT \n      campaign.id,\n      campaign.name,\n      metrics.conversions,\n      segments.conversion_action_name,\n      segments.date \n    FROM campaign \n    WHERE segments.date = '${$json.yesterday}'`\n  }\n}}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "developer-token"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "login-customer-id"
            }
          ]
        },
        "nodeCredentialType": "googleAdsOAuth2Api"
      },
      "credentials": {},
      "typeVersion": 4.2
    },
    {
      "id": "a6009cf3-afc3-4539-b58f-d8e3138564d5",
      "name": "Notion1",
      "type": "n8n-nodes-base.notion",
      "onError": "continueRegularOutput",
      "position": [
        1200,
        400
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Campaign Name|title",
              "title": "={{ $json.campaign.name }}"
            },
            {
              "key": "Campaign ID|number",
              "numberValue": "={{ parseInt($json.campaign.id) }}"
            },
            {
              "key": "Impressions|number",
              "numberValue": "={{ parseInt($json.metrics.impressions)}}"
            },
            {
              "key": "Clicks|number",
              "numberValue": "={{ parseInt($json.metrics.clicks) }}"
            },
            {
              "key": "Cost|number",
              "numberValue": "={{ Math.floor($json.metrics.costMicros / 1000000) }}"
            },
            {
              "key": "Conversion Type|rich_text",
              "textContent": "={{ $json.segments.conversionActionName || \"N/A\" }}"
            },
            {
              "key": "Conversions|number",
              "numberValue": "={{ Math.round(Number($json.metrics.conversions || 0) * 100) / 100 }}"
            },
            {
              "key": "Date|date",
              "date": "={{ $json.segments.date }}"
            }
          ]
        }
      },
      "credentials": {},
      "typeVersion": 2.2
    },
    {
      "id": "049a0fc6-bf5b-4c82-96c7-da45563d1017",
      "name": "Notion2",
      "type": "n8n-nodes-base.notion",
      "onError": "continueRegularOutput",
      "position": [
        1460,
        760
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Tanggal|date",
              "date": "={{ $json.date }}"
            },
            {
              "key": "Total Impressions|number",
              "numberValue": "={{ $json.total_impressions }}"
            },
            {
              "key": "Total Clicks|number",
              "numberValue": "={{ $json.total_clicks }}"
            },
            {
              "key": "Total Conversions|number",
              "numberValue": "={{ $json.total_conversions }}"
            },
            {
              "key": "Total Cost|number",
              "numberValue": "={{ $json.total_cost }}"
            },
            {
              "key": "Conversion Types|rich_text",
              "textContent": "={{ $json.conversion_types }}"
            }
          ]
        }
      },
      "credentials": {},
      "typeVersion": 2.2
    },
    {
      "id": "9e331b5a-2162-404c-9918-50b1f8a0c14b",
      "name": "Google Sheets10",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        600
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": ""
        }
      },
      "credentials": {},
      "typeVersion": 4.5
    },
    {
      "id": "59bd6861-0ceb-42a1-a85d-0d239dc607d5",
      "name": "Split Click2",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        660,
        400
      ],
      "parameters": {
        "jsCode": "return items[0].json.results.map(r => ({ json: r }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "154beaed-97e3-42eb-8c36-34487cda7e0c",
      "name": "Split Conversion2",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        660,
        600
      ],
      "parameters": {
        "jsCode": "return items[0].json.results.map(r => ({ json: r }));"
      },
      "typeVersion": 2
    },
    {
      "id": "7a981181-0a99-4446-bcc4-042b7b7e9dbe",
      "name": "Merge2",
      "type": "n8n-nodes-base.merge",
      "position": [
        900,
        500
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "advanced": true,
        "joinMode": "enrichInput1",
        "mergeByFields": {
          "values": [
            {
              "field1": "campaign.id",
              "field2": "campaign.id"
            },
            {
              "field1": "segments.date",
              "field2": "segments.date"
            }
          ]
        }
      },
      "typeVersion": 3.1
    },
    {
      "id": "29a7436f-61e9-42f7-bdfe-7a4b50f45d36",
      "name": "Daily Recap2",
      "type": "n8n-nodes-base.code",
      "position": [
        1200,
        860
      ],
      "parameters": {
        "jsCode": "let totalClicks = 0;\nlet totalImpressions = 0;\nlet totalCost = 0;\nlet totalConversions = 0;\nlet conversionTypes = new Set();\nlet date = null;\n\nfor (const item of items) {\n  const d = item.json;\n\n  totalClicks += parseInt(d.metrics?.clicks || 0);\n  totalImpressions += parseInt(d.metrics?.impressions || 0);\n  totalCost += parseInt(d.metrics?.costMicros || 0) / 1_000_000;\n  totalConversions += parseFloat(d.metrics?.conversions || 0);\n\n  const convType = d.segments?.conversionActionName;\n  if (convType) conversionTypes.add(convType);\n\n  date = d.segments?.date || date;\n}\n\nreturn [\n  {\n    json: {\n      date,\n      total_clicks: totalClicks,\n      total_impressions: totalImpressions,\n      total_cost: Number(totalCost.toFixed(2)),\n      total_conversions: Number(totalConversions.toFixed(2)),\n      conversion_types: Array.from(conversionTypes).join(', ') || 'N/A'\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "2708ffda-f942-4e55-990d-baeac0f1d8f3",
      "name": "Google Sheets11",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1480,
        960
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": ""
        }
      },
      "credentials": {},
      "typeVersion": 4.5
    },
    {
      "id": "3be681d5-6941-443d-8485-2603107190f4",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1760,
        600
      ],
      "parameters": {
        "color": 4,
        "width": 640,
        "height": 460,
        "content": "\n## Output Summary\n\n**Notion Databases:**\n- `Google Ads Campaign Tracker`: stores individual campaign metrics\n- `Google Ads Daily Summary`: stores daily totals and conversion types\n\n**Google Sheets Tabs:**\n- `Campaign Daily Report`: per-campaign data\n- `Summary Report`: aggregated daily performance"
      },
      "typeVersion": 1
    },
    {
      "id": "9be455f9-4fe9-4bdd-882f-4ec4ec212f36",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        0
      ],
      "parameters": {
        "color": 3,
        "width": 640,
        "height": 460,
        "content": "\n\n### 3. Notion Database Setup\nCreate two databases in Notion:\n- **Google Ads Campaign Tracker**\n  - Fields: `Campaign Name`, `Campaign ID`, `Impressions`, `Clicks`, `Cost`, `Conversion Type`, `Conversions`, `Date`\n- **Google Ads Daily Summary**\n  - Fields: `Date`, `Total Impressions`, `Total Clicks`, `Total Conversions`, `Total Cost`, `Conversion Types`\n- Share both databases with your Notion integration\n\n### 4. Google Sheets Setup\n- Create a spreadsheet with two tabs:\n  - `Campaign Daily Report` \u2192 for campaign-level rows\n  - `Summary Report` \u2192 for daily aggregated metrics\n- Match all column headers to the workflow fields\n- Connect your Google account to n8n using **Google Sheets OAuth2**\n\n---"
      },
      "typeVersion": 1
    },
    {
      "id": "b5865a91-1a2e-43d2-869d-6b321a94abea",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -100
      ],
      "parameters": {
        "color": 3,
        "width": 640,
        "height": 480,
        "content": "---\n\n## Setup Steps\n\n### 1. Schedule the Workflow\n- The workflow is triggered using a `Schedule Trigger` node\n- Set the schedule to run **every day at 08:00 AM**\n- Connect it to the `Set Yesterday Date` node\n\n### 2. Google Ads API Access\n- Create a Google Ads developer account and obtain a **developer token**\n- Set up OAuth2 credentials with Google Ads scope\n- In n8n, configure the **Google Ads OAuth2 API** credential\n- Ensure HTTP request headers include:\n  - `developer-token`\n  - `login-customer-id`\n  - `Content-Type: application/json`\n- To retrieve data, make a `POST` request to:\nhttps://googleads.googleapis.com/v20/customers/{customerId}/googleAds:search\nReplace `{customerId}` with the client account ID (not the MCC ID)"
      },
      "typeVersion": 1
    },
    {
      "id": "9aeaf3f7-798f-4ca9-b7e1-6ffad5ead9d1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -780,
        620
      ],
      "parameters": {
        "width": 640,
        "height": 800,
        "content": "## How It Works\n\n1. **Scheduled Trigger at 08:00 AM**  \n   The workflow begins with a `Schedule Trigger` node that runs once per day at 08:00.\n\n2. **Set Yesterday\u2019s Date**  \n   The `Set` node defines a variable for the target date (yesterday), which is used in the API queries.\n\n3. **Query Google Ads API \u2013 Clicks & Cost**  \n   The first HTTP request pulls campaign-level metrics:\n   - `campaign.id`, `campaign.name`  \n   - `metrics.clicks`, `metrics.impressions`, `metrics.cost_micros`\n\n4. **Query Google Ads API \u2013 Conversions**  \n   The second HTTP request pulls conversion-related data:\n   - `metrics.conversions`, `segments.conversion_action_name`\n\n5. **Split and Merge**  \n   Both responses are split into individual campaign rows and merged using:\n   - `campaign.id`  \n   - `segments.date`  \n\n6. **Store Campaign-Level Data**  \n   - Stored in Notion database: **\"Google Ads Campaign Tracker\"**  \n   - Appended to Google Sheets tab: **\"Campaign Daily Report\"**\n\n7. **Generate Daily Summary**  \n   A code node calculates daily totals across all campaigns:\n   - Total impressions, clicks, conversions, cost\n   - Unique conversion types  \n   The summary is stored in:\n   - Notion database: **\"Google Ads Daily Summary\"**  \n   - Google Sheets tab: **\"Summary Report\"**\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c0b96c74-15f6-4cea-8727-e1a9c5c0a9d1",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        500
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "be1b4d73-99b2-4fe6-a1a3-34df0eada594",
      "name": "Set Yesterday Date2",
      "type": "n8n-nodes-base.set",
      "position": [
        180,
        500
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bfc7fb43-2b0f-4f44-a239-b35583c4d114",
              "name": "=yesterday",
              "type": "string",
              "value": "={{ $now.minus({ days: 1 }).toFormat('yyyy-MM-dd') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "79d493b6-2e71-45e7-8c05-a6f20e8b9b55",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -780,
        120
      ],
      "parameters": {
        "width": 640,
        "height": 460,
        "content": "## Description\n\n\nThis workflow automates the daily reporting of Google Ads campaign performance. It pulls click and conversion data from the Google Ads API, merges both datasets, and stores the results into Notion databases and Google Sheets.\n\nIt includes a campaign-level log and a daily performance summary. The workflow is triggered automatically every day at **08:00 AM**, helping marketing teams maintain a consistent and centralized reporting system without manual effort.\n\n---\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Merge2": {
      "main": [
        [
          {
            "node": "Google Sheets10",
            "type": "main",
            "index": 0
          },
          {
            "node": "Daily Recap2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Recap2": {
      "main": [
        [
          {
            "node": "Notion2",
            "type": "main",
            "index": 0
          },
          {
            "node": "Google Sheets11",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Click2": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Yesterday Date2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G-Ads Query Click": {
      "main": [
        [
          {
            "node": "Split Click2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Conversion2": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Set Yesterday Date2": {
      "main": [
        [
          {
            "node": "G-Ads Query Conversion",
            "type": "main",
            "index": 0
          },
          {
            "node": "G-Ads Query Click",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G-Ads Query Conversion": {
      "main": [
        [
          {
            "node": "Split Conversion2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow automates the daily reporting of Google Ads campaign performance. It pulls click and conversion data from the Google Ads API, merges both datasets, and stores the results into Notion databases and Google Sheets.

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

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

Daily Business Report Generator. Uses googleSheets, httpRequest, slack, gmail. Scheduled trigger; 17 nodes.

Google Sheets, HTTP Request, Slack +3
Data & Sheets

Revenue operations teams, SaaS growth managers, and sales directors who need automated weekly insights from their Stripe payment data. Perfect for small to medium businesses tracking subscription reve

HTTP Request, Google Sheets, Google Gemini Chat +4
Data & Sheets

This workflow automates video distribution to 9 social platforms simultaneously using Blotato's API. It includes both a scheduled publisher (checks Google Sheets for videos marked "Ready") and a subwo

Google Sheets, HTTP Request, Form Trigger +2
Data & Sheets

YogiAI. Uses googleSheets, googleSheetsTool, httpRequest, stopAndError. Scheduled trigger; 61 nodes.

Google Sheets, Google Sheets Tool, HTTP Request +1
Data & Sheets

This workflow monitors Google Calendar for events indicating that a customer will visit the company today or the next day, retrieves the required details, and sends reminder notifications to the relev

Google Calendar, Google Sheets, HTTP Request +1