AnswerLine Start free

Google Search

Google Search ads

The ads Google shows for a query, with block position, copy, destination and shopping-card prices.

`ads` returns text ads and sponsored shopping cards with their block, position and copy. Use it to catch bidding on your brand terms and to measure which advertisers hold the slots across a keyword set.

Returned in result

Field
ads

Request

curl -X POST "https://api.answerline.dev/v1/monitor/google" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"project management software","country":"US","include":{"aioverview":{"markdown":true}}}'

What Google ads are on the results page

Google search ads are the paid placements marked “Sponsored”: text ads above and below the organic results, and product-style cards in carousels at the top of the page or in the right-hand column. They show who is paying to be seen for a query, with what message, and at what price.

result.ads returns every ad on the fetched pages with its block, position, copy and destination. It is used to catch competitors or affiliates bidding on your brand terms, to measure which domains hold ad slots across a keyword set and how often they take the top block, to follow the headlines, sitelinks and shopping prices competitors run, and to score commercial intent, since keywords that attract many ads are ones advertisers value.

Field reference

result.ads[]

Field Type Meaning
position number 1-indexed position within the ad block on its page.
blockPosition top, bottom, middle or rhs Where the ad appeared. top/bottom are text-ad blocks, middle covers direct or in-content ads, rhs is the right-hand-side sponsored-products carousel.
type RESULT or SHOPPING_CARD Plain text ad or shopping-style sponsored card.
title string Ad title.
url string Destination URL. For SHOPPING_CARD items this is a Google aclk? redirect URL.
page number Results page where the ad was found.
displayedUrl string URL as displayed in the ad.
domain string Advertiser’s domain.
description string For RESULT, the ad copy. For SHOPPING_CARD, category-specific subtitle fragments joined with ·, for example condition and city.
category string Carousel header for shopping-card ads, such as Sponsored products, Sponsored vehicles or Sponsored hotels. Omitted for text ads.
price object Shopping-card price: value (number, nullable), currency (string, nullable), raw (string, nullable, the visible text verbatim).
oldPrice object Original price on cards with sale or MSRP messaging. Same shape as price.
store string Merchant or dealer on a shopping-card ad.
imageUrl string Hero image for shopping-card ads. Omitted when no product image is available.
sitelinks[] array Sitelinks under the ad, each with url, title and description (strings).

value and currency are set only when the displayed price is an unambiguous number and currency symbol; raw always carries what Google showed, so an installment label is not mistaken for a zero price.

Annotated excerpt

Values are illustrative; names and types follow the POST /v1/monitor/google result schema.

{
  "result": {
    "ads": [
      {
        "position": 1,                  // first ad in the top block of page 1
        "blockPosition": "top",
        "type": "RESULT",
        "title": "Accounting Software for Freelancers | Try LedgerLite Free",
        "url": "https://www.ledgerlite.example/freelancers",
        "page": 1,
        "displayedUrl": "www.ledgerlite.example/freelancers",
        "domain": "ledgerlite.example",
        "description": "Send invoices, track expenses and file quarterly taxes...",
        "sitelinks": [
          { "url": "https://www.ledgerlite.example/pricing", "title": "Pricing", "description": "Plans from one user" }
        ]
      },
      {
        "position": 1,                  // numbering restarts in each block
        "blockPosition": "rhs",
        "type": "SHOPPING_CARD",
        "title": "Example Label Printer LP-200",
        "url": "https://www.google.com/aclk?...",   // Google redirect for shopping cards
        "page": 1,
        "category": "Sponsored products",
        "price": { "value": 129.99, "currency": "$", "raw": "$129.99" },
        "oldPrice": { "value": 159.99, "currency": "$", "raw": "$159.99" },
        "store": "Example Supplies"
      }
    ]
  }
}

Cost

No include flag is needed. Ads come with every Google Search request at the base price: $0.00103 for one page, and +$0.00071 per extra page when pages is above 1. Start with page 1 and add pages only if you need ads served on deeper result pages.

If you also want ads placed inside the AI Overview, add include.aioverview (+$0.00071) and read result.aioverview.ads; see the AI Overview guide.

Example: advertiser share and brand-term conquesting

The script checks a keyword set, including your own brand terms, and reports each advertiser’s share of text-ad slots, how often it holds the first top slot, and which other advertisers bid on the brand terms.

import os
import time
from collections import Counter
from datetime import date

import requests

API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
OWN_DOMAIN = "ledgerlite.example"
BRAND_TERMS = ["ledgerlite", "ledgerlite pricing"]
GENERIC_TERMS = ["accounting software for freelancers", "invoice app for contractors", "self employed tax software"]
DAY = date.today().isoformat()


def run_tasks(tasks):
    resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
    resp.raise_for_status()
    pending = {item["task"]["id"]: tasks[item["index"]] for item in resp.json()["results"] if item["success"]}
    done = []
    while pending:
        time.sleep(10)
        for task_id in list(pending):
            body = requests.get(f"{API}/v1/async/task/{task_id}", headers=HEADERS, timeout=30).json()
            if body["task"]["status"] in ("COMPLETED", "FAILED"):
                task = pending.pop(task_id)
                if body["task"]["status"] == "COMPLETED":
                    done.append((task["payload"]["query"], body["response"]["result"]))
    return done


keywords = BRAND_TERMS + GENERIC_TERMS
tasks = [
    {"taskType": "GOOGLE", "payload": {"query": kw, "country": "US"}, "idempotencyKey": f"ads-{i}-{DAY}"}
    for i, kw in enumerate(keywords)
]

slots, top_first = Counter(), Counter()
conquesting = {}
with_ads = 0
for keyword, result in run_tasks(tasks):
    text_ads = [ad for ad in result["ads"] if ad.get("type") == "RESULT" and ad.get("domain")]
    with_ads += bool(text_ads)
    for ad in text_ads:
        slots[ad["domain"]] += 1
        if ad.get("blockPosition") == "top" and ad.get("position") == 1:
            top_first[ad["domain"]] += 1
    if keyword in BRAND_TERMS:
        rivals = sorted({ad["domain"] for ad in text_ads} - {OWN_DOMAIN})
        conquesting[keyword] = rivals

total = sum(slots.values()) or 1
print(f"keywords with text ads: {with_ads}/{len(keywords)}")
for domain, count in slots.most_common(10):
    print(f"{domain:28} slot share {count / total:5.1%}   first top slot on {top_first[domain]} keywords")
for keyword, rivals in conquesting.items():
    print(f"brand term '{keyword}': {', '.join(rivals) or 'no competitor ads'}")

To track shopping ads instead, filter on type == "SHOPPING_CARD" and group by store; compare price.value only when it is not null, and keep price.raw for display.

Pitfalls

The advertisers shown for a query differ by time of day and location, so one check per keyword per day misses advertisers that appear only some of the time. For conquesting alerts, sample the same brand terms several times a day and alert on repeated sightings.

position restarts in every block and on every page. Identify a slot by (page, blockPosition, position).

Text ads and shopping cards carry different fields: domain and ad copy for RESULT; store, price and a Google redirect url for SHOPPING_CARD. Keep them in separate share metrics.

price.value and price.currency are null when the displayed price is not a plain amount, for example on installment offers. Read raw before treating a price as zero or missing.

Advertisers target cities and devices, so set location (or uule) and device to check the ads a given searcher sees.

Ads Google places inside the AI Overview are not in the top-level array; they appear in aioverview.ads when you request the overview.

Questions

Which Google ads does the API return?

ads contains text ads (type RESULT) from the top, middle and bottom blocks and shopping-style sponsored cards (type SHOPPING_CARD) from the right-hand-side and top-of-page carousels, each with its block position, page and copy.

Do Google ads cost extra?

No. ads comes with every Google Search request at the base price: $0.00103 for one page, plus $0.00071 for each extra page you request.

How is ad position numbered?

position is 1-indexed within the ad block on its page, so the first top ad and the first bottom ad both have position 1. Combine page, blockPosition and position to identify a slot.

Are ads inside the AI Overview included in ads?

No. Ads Google places inside the AI Overview are returned in result.aioverview.ads, which requires include.aioverview. The top-level ads array covers the results page blocks.

Why does a shopping card ad have a Google URL instead of the retailer's?

For SHOPPING_CARD ads the url is Google's aclk redirect URL. Use store for the merchant name and price for the offer.

More Google Search data

All Google Search fields · API reference