{"skill":{"slug":"google-ads","displayName":"Google Ads","summary":"Query, audit, and optimize Google Ads campaigns. Supports two modes: (1) API mode for bulk operations with google-ads Python SDK, (2) Browser automation mode for users without API access - just attach a browser tab to ads.google.com. Use when asked to check ad performance, pause campaigns/keywords, find wasted spend, audit conversion tracking, or optimize Google Ads accounts.","description":"---\nname: google-ads\ndescription: \"Query, audit, and optimize Google Ads campaigns. Supports two modes: (1) API mode for bulk operations with google-ads Python SDK, (2) Browser automation mode for users without API access - just attach a browser tab to ads.google.com. Use when asked to check ad performance, pause campaigns/keywords, find wasted spend, audit conversion tracking, or optimize Google Ads accounts.\"\nmetadata:\n  {\n    \"openclaw\":\n      {\n        \"emoji\": \"📊\",\n        \"requires\":\n          {\n            \"anyBins\": [\"python3\"],\n            \"config\": [\"~/.google-ads.yaml\"],\n          },\n      },\n  }\n---\n\n# Google Ads Skill\n\nManage Google Ads accounts via API or browser automation.\n\n## Mode Selection\n\n**Check which mode to use:**\n\n1. **API Mode** - If user has `google-ads.yaml` configured or `GOOGLE_ADS_*` env vars\n2. **Browser Mode** - If user says \"I don't have API access\" or just wants quick checks\n\n```bash\n# Check for API config\nls ~/.google-ads.yaml 2>/dev/null || ls google-ads.yaml 2>/dev/null\n```\n\nIf no config found, ask: \"Do you have Google Ads API credentials, or should I use browser automation?\"\n\n---\n\n## Browser Automation Mode (Universal)\n\n**Requirements:** User logged into ads.google.com in browser\n\n### Setup\n1. User opens ads.google.com and logs in\n2. User clicks Clawdbot Browser Relay toolbar icon (badge ON)\n3. Use `browser` tool with `profile=\"chrome\"`\n\n### Common Workflows\n\n#### Get Campaign Performance\n```\n1. Navigate to: ads.google.com/aw/campaigns\n2. Set date range (top right date picker)\n3. Snapshot the campaigns table\n4. Parse: Campaign, Status, Budget, Cost, Conversions, Cost/Conv\n```\n\n#### Find Zero-Conversion Keywords (Wasted Spend)\n```\n1. Navigate to: ads.google.com/aw/keywords\n2. Click \"Add filter\" → Conversions → Less than → 1\n3. Click \"Add filter\" → Cost → Greater than → [threshold, e.g., $500]\n4. Sort by Cost descending\n5. Snapshot table for analysis\n```\n\n#### Pause Keywords/Campaigns\n```\n1. Navigate to keywords or campaigns view\n2. Check boxes for items to pause\n3. Click \"Edit\" dropdown → \"Pause\"\n4. Confirm action\n```\n\n#### Download Reports\n```\n1. Navigate to desired view (campaigns, keywords, etc.)\n2. Click \"Download\" icon (top right of table)\n3. Select format (CSV recommended)\n4. File downloads to user's Downloads folder\n```\n\n**For detailed browser selectors:** See `references/browser-workflows.md`\n\n---\n\n## API Mode (Power Users)\n\n**Requirements:** Google Ads API developer token + OAuth credentials\n\n### Setup Check\n```bash\n# Verify google-ads SDK\npython -c \"from google.ads.googleads.client import GoogleAdsClient; print('OK')\"\n\n# Check config\ncat ~/.google-ads.yaml\n```\n\n### Common Operations\n\n#### Query Campaign Performance\n```python\nfrom google.ads.googleads.client import GoogleAdsClient\n\nclient = GoogleAdsClient.load_from_storage()\nga_service = client.get_service(\"GoogleAdsService\")\n\nquery = \"\"\"\n    SELECT campaign.name, campaign.status,\n           metrics.cost_micros, metrics.conversions,\n           metrics.cost_per_conversion\n    FROM campaign\n    WHERE segments.date DURING LAST_30_DAYS\n    ORDER BY metrics.cost_micros DESC\n\"\"\"\n\nresponse = ga_service.search(customer_id=CUSTOMER_ID, query=query)\n```\n\n#### Find Zero-Conversion Keywords\n```python\nquery = \"\"\"\n    SELECT ad_group_criterion.keyword.text,\n           campaign.name, metrics.cost_micros\n    FROM keyword_view\n    WHERE metrics.conversions = 0\n      AND metrics.cost_micros > 500000000\n      AND segments.date DURING LAST_90_DAYS\n    ORDER BY metrics.cost_micros DESC\n\"\"\"\n```\n\n#### Pause Keywords\n```python\noperations = []\nfor keyword_id in keywords_to_pause:\n    operation = client.get_type(\"AdGroupCriterionOperation\")\n    operation.update.resource_name = f\"customers/{customer_id}/adGroupCriteria/{ad_group_id}~{keyword_id}\"\n    operation.update.status = client.enums.AdGroupCriterionStatusEnum.PAUSED\n    operations.append(operation)\n\nservice.mutate_ad_group_criteria(customer_id=customer_id, operations=operations)\n```\n\n**For full API reference:** See `references/api-setup.md`\n\n---\n\n## Audit Checklist\n\nQuick health check for any Google Ads account:\n\n| Check | Browser Path | What to Look For |\n|-------|--------------|------------------|\n| Zero-conv keywords | Keywords → Filter: Conv<1, Cost>$500 | Wasted spend |\n| Empty ad groups | Ad Groups → Filter: Ads=0 | No creative running |\n| Policy violations | Campaigns → Status column | Yellow warning icons |\n| Optimization Score | Overview page (top right) | Below 70% = action needed |\n| Conversion tracking | Tools → Conversions | Inactive/no recent data |\n\n---\n\n## Output Formats\n\nWhen reporting findings, use tables:\n\n```markdown\n## Campaign Performance (Last 30 Days)\n| Campaign | Cost | Conv | CPA | Status |\n|----------|------|------|-----|--------|\n| Branded  | $5K  | 50   | $100| ✅ Good |\n| SDK Web  | $10K | 2    | $5K | ❌ Pause |\n\n## Recommended Actions\n1. **PAUSE**: SDK Web campaign ($5K CPA)\n2. **INCREASE**: Branded budget (strong performer)\n```\n\n---\n\n## Troubleshooting\n\n### Browser Mode Issues\n- **Can't see data**: Check user is on correct account (top right account selector)\n- **Slow loading**: Google Ads UI is heavy; wait for tables to fully load\n- **Session expired**: User needs to re-login to ads.google.com\n\n### API Mode Issues\n- **Authentication failed**: Refresh OAuth token, check `google-ads.yaml`\n- **Developer token rejected**: Ensure token is approved (not test mode)\n- **Customer ID error**: Use 10-digit ID without dashes\n","tags":{"latest":"1.1.0"},"stats":{"comments":0,"downloads":7318,"installsAllTime":31,"installsCurrent":30,"stars":14,"versions":5},"createdAt":1768839887563,"updatedAt":1779076443336},"latestVersion":{"version":"1.1.0","createdAt":1770969683223,"changelog":"Added structured openclaw metadata: google-ads.yaml config + python3 requirement","license":null},"metadata":{"setup":[{"key":"~/.google-ads.yaml","required":true}],"os":null,"systems":null},"owner":{"handle":"jdrhyne","userId":"s175stkgx5wmnsr24w9hqje36d84r4br","displayName":"Jonathan Rhyne","image":"https://avatars.githubusercontent.com/u/7828464?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1779915586802}}