Tutorial

How to Monitor Competitor Ad Copy from SERP Data

Track competitor Google Ads headlines and descriptions programmatically using the Scavio API. Monitor ad copy changes over time for competitive intelligence.

Google Ads copy reveals your competitors' messaging strategy, value propositions, and promotional offers. Monitoring how ad copy changes over time helps you stay ahead of competitor positioning and identify new campaigns early. The Scavio API includes paid ad results in its SERP response, containing the headline, description, display URL, and advertiser name. This tutorial builds a script that tracks ad copy for a set of keywords, saves snapshots to JSON, and diffs changes between runs.

Prerequisites

  • Python 3.8 or higher
  • requests library installed
  • A Scavio API key
  • A list of keywords where competitors run ads

Walkthrough

Step 1: Fetch SERP results including ads

Query Google through Scavio. The response includes an ads array with headline, description, and display_url for each paid result.

Python
import requests

def get_ads(keyword: str) -> list[dict]:
    r = requests.post(
        "https://api.scavio.dev/api/v1/search",
        headers={"x-api-key": API_KEY},
        json={"query": keyword, "country_code": "us"}
    )
    r.raise_for_status()
    return r.json().get("ads", [])

Step 2: Extract ad copy details

Parse each ad for headline, description, display URL, and the advertiser domain.

Python
def parse_ad(ad: dict) -> dict:
    return {
        "headline": ad.get("title", ""),
        "description": ad.get("description", ""),
        "display_url": ad.get("displayed_link", ""),
        "link": ad.get("link", ""),
    }

Step 3: Save ad snapshot to JSON

Store each run as a timestamped snapshot so you can diff ad copy between runs.

Python
import json
from datetime import datetime

def save_snapshot(keyword: str, ads: list[dict]) -> None:
    snapshot = {
        "keyword": keyword,
        "timestamp": datetime.now().isoformat(),
        "ads": [parse_ad(a) for a in ads]
    }
    filename = f"ads_{keyword.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d')}.json"
    with open(filename, "w") as f:
        json.dump(snapshot, f, indent=2)

Step 4: Diff ad copy between two snapshots

Compare two snapshot files to detect new ads, removed ads, and changed copy.

Python
def diff_snapshots(old_file: str, new_file: str) -> dict:
    with open(old_file) as f:
        old = {a["link"]: a for a in json.load(f)["ads"]}
    with open(new_file) as f:
        new = {a["link"]: a for a in json.load(f)["ads"]}
    return {
        "new_ads": [new[k] for k in new if k not in old],
        "removed_ads": [old[k] for k in old if k not in new],
        "changed": [new[k] for k in new if k in old and new[k] != old[k]],
    }

Python Example

Python
import os
import json
import requests
from datetime import datetime

API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
KEYWORDS = ["crm software", "project management tool", "email marketing platform"]

def get_ads(keyword: str) -> list[dict]:
    r = requests.post(ENDPOINT, headers={"x-api-key": API_KEY},
                      json={"query": keyword, "country_code": "us"})
    r.raise_for_status()
    return r.json().get("ads", [])

def monitor():
    for kw in KEYWORDS:
        ads = get_ads(kw)
        print(f"\n{kw}: {len(ads)} ads")
        for ad in ads:
            print(f"  {ad.get('title', 'N/A')}")
            print(f"  {ad.get('description', '')[:80]}")
        snapshot = {"keyword": kw, "ts": datetime.now().isoformat(), "ads": ads}
        with open(f"ads_{kw.replace(' ', '_')}.json", "w") as f:
            json.dump(snapshot, f, indent=2)

if __name__ == "__main__":
    monitor()

JavaScript Example

JavaScript
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";
const fs = require("fs");

async function getAds(keyword) {
  const res = await fetch(ENDPOINT, {
    method: "POST",
    headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ query: keyword, country_code: "us" })
  });
  const data = await res.json();
  return data.ads || [];
}

async function main() {
  const keywords = ["crm software", "project management tool"];
  for (const kw of keywords) {
    const ads = await getAds(kw);
    console.log(`\n${kw}: ${ads.length} ads`);
    ads.forEach(a => console.log(`  ${a.title}`));
    fs.writeFileSync(`ads_${kw.replace(/ /g, "_")}.json`, JSON.stringify({ keyword: kw, ads }, null, 2));
  }
}
main().catch(console.error);

Expected Output

JSON
crm software: 4 ads
  Salesforce CRM - The #1 CRM Platform
  Start your free trial today. Trusted by 150,000+ businesses worldwide.
  HubSpot CRM - Free Forever CRM
  Get started with a CRM that scales. No credit card required.

project management tool: 3 ads
  Monday.com - Work Management Platform
  Manage projects, workflows, and tasks in one place.

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.8 or higher. requests library installed. A Scavio API key. A list of keywords where competitors run ads. A Scavio API key gives you 500 free credits per month.

Yes. The free tier includes 500 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Track competitor Google Ads headlines and descriptions programmatically using the Scavio API. Monitor ad copy changes over time for competitive intelligence.