Track Competitor Google Ads at Scale With a SERP API
If you run paid search, you already know the feeling: a competitor quietly launches a new offer, your CTR dips, and you find out three weeks later when the monthly report lands. By then they've had a month of head start.
There's a faster way. Every Google Ads listing is public — it's right there on the results page. A SERP API lets you read that ads block for every keyword that matters to you, on a schedule, and turn it into a daily change-log of who's bidding, what they're saying, and who just showed up. No guesswork, no waiting for a monthly export.
This guide shows the data, the build, and the way to read it. It pairs naturally with SERP-API keyword research on the organic side.
What the ads block gives you
For any query, the SERP API returns an ads object split into top and bottom placements. Each ad carries the advertiser's headline, display URL, and copy — exactly what a searcher sees. Watch it across your keyword set and you can answer questions a keyword planner only estimates:
- Which competitors bid on each of your money keywords, and how aggressively (top vs bottom)?
- What promotions and angles are they testing in their copy right now?
- Has a new advertiser entered a keyword you own?
- Did an incumbent suddenly stop bidding — an opening for you?
Is this allowed?
You're reading ads Google publishes to everyone on a public results page — the same listings any searcher sees. Google even runs its own Ads Transparency Center for this kind of visibility. You're not touching anyone's account or private data. (For the broader picture on collecting public search data responsibly, see legal and ethical search data collection.)
Step 1: Pull the ads block
import os, requests
KEY = os.environ["SERPENT_API_KEY"]
def ads_for(query, country="us"):
r = requests.get("https://apiserpent.com/api/search",
params={"q": query, "country": country},
headers={"X-API-Key": KEY}, timeout=90)
r.raise_for_status()
ads = r.json().get("results", {}).get("ads", {})
out = []
for slot in ("top", "bottom"):
for ad in ads.get(slot, []):
out.append({
"slot": slot,
"advertiser": ad.get("displayedUrl", ""),
"title": ad.get("title", ""),
"copy": ad.get("snippet", ""),
"url": ad.get("url", ""),
})
return out
Run it across your whole keyword list. The Google SERP API returns the live ads block as clean JSON for any keyword and country. 100 free quick-search calls on signup. See pricing →
Step 2: Diff against yesterday
The real value is in change. Store each day's snapshot, then compare advertisers and copy to flag what moved:
import json, os
def load(path):
return json.load(open(path)) if os.path.exists(path) else {}
def diff(today, yesterday):
events = []
for kw, ads in today.items():
now = {a["advertiser"] for a in ads}
was = {a["advertiser"] for a in yesterday.get(kw, [])}
for new in now - was:
events.append(f"NEW advertiser '{new}' on '{kw}'")
for gone in was - now:
events.append(f"DROPPED '{gone}' from '{kw}'")
# copy changes for advertisers present both days
prev_copy = {a["advertiser"]: a["copy"] for a in yesterday.get(kw, [])}
for a in ads:
old = prev_copy.get(a["advertiser"])
if old and old != a["copy"]:
events.append(f"COPY change by '{a['advertiser']}' on '{kw}'")
return events
The full change-log script
import os, json, requests
from datetime import date
KEY = os.environ["SERPENT_API_KEY"]
KEYWORDS = ["crm software", "best crm for startups", "sales pipeline tool"]
def ads_for(q, country="us"):
r = requests.get("https://apiserpent.com/api/search",
params={"q": q, "country": country},
headers={"X-API-Key": KEY}, timeout=90)
r.raise_for_status()
ads = r.json().get("results", {}).get("ads", {})
return [{"advertiser": a.get("displayedUrl",""),
"title": a.get("title",""),
"copy": a.get("snippet",""),
"slot": slot}
for slot in ("top","bottom") for a in ads.get(slot, [])]
def main():
today = {kw: ads_for(kw) for kw in KEYWORDS}
yfile = "ads_prev.json"
prev = json.load(open(yfile)) if os.path.exists(yfile) else {}
print(f"=== Ad change-log {date.today()} ===")
any_change = False
for kw in KEYWORDS:
now = {a["advertiser"] for a in today[kw]}
was = {a["advertiser"] for a in prev.get(kw, [])}
for n in now - was:
print(f" + NEW {n:28} on '{kw}'"); any_change = True
for g in was - now:
print(f" - LEFT {g:28} on '{kw}'"); any_change = True
if not any_change:
print(" no advertiser changes since last run")
json.dump(today, open(yfile, "w"), indent=2)
print(f"\nSnapshot saved. {sum(len(v) for v in today.values())} ads captured.")
if __name__ == "__main__":
main()
Five ways to use the data
1. Catch new entrants instantly. A "NEW advertiser" alert on your core keyword is your earliest warning that someone is moving into your space — days, not weeks.
2. Reverse-engineer winning angles. When a competitor keeps a piece of copy live for weeks, it's probably working. Their persistence is free A/B-test data for your own headlines.
3. Spot promo cycles. Track when rivals launch discounts and seasonal offers, and you can plan your counter-offer before, not after.
4. Find abandoned keywords. A "LEFT" event means a competitor stopped bidding — potentially cheaper clicks for you on a keyword that just got less crowded.
5. Brief leadership with facts. "Three new advertisers entered our top keyword this month, here's their copy" is a far stronger report than "competition feels tougher." Combine it with organic intelligence from SERP-API lead generation for the full picture.
FAQ
Can a SERP API show competitor Google Ads?
Yes — it returns the live ads block (top and bottom) with each ad's headline, display URL, and copy. Run your keyword list on a schedule to see who's bidding and what they say.
Is monitoring competitor ads allowed?
You're reading ads Google publishes publicly on the results page — the same thing any searcher sees, and the same data Google surfaces in its Ads Transparency Center. No accounts or private data are involved.
How is this different from keyword planners?
Planners estimate. A SERP API shows the actual ads running now, with live copy and landing pages, so you detect day-to-day change instead of working from monthly averages.
How often should I check?
Daily in competitive niches, weekly in slower ones. Storing snapshots lets you build a change-log of entries, exits, and copy rewrites.
Watch Your Competitors' Paid Search
The Google SERP API returns the live ads block for any keyword and country as clean JSON. Build your competitor change-log today.
Get Your Free API KeyExplore: Google SERP API · AI Rank API · Playground · Docs



