Google Ads Scraper: Ad Copy & Click-Through Links avatar

Google Ads Scraper: Ad Copy & Click-Through Links

Pricing

$19.99/month + usage

Go to Apify Store
Google Ads Scraper: Ad Copy & Click-Through Links

Google Ads Scraper: Ad Copy & Click-Through Links

Google Ads Scraper: Ad Copy & Click-Through Links extracts SERP ad data—headlines, descriptions, URLs, sitelinks & advertiser domains—for any keyword. 🚀 Perfect for PPC research, competitor monitoring & ad copy insights. 📊 Export CSV/JSON, schedule runs & automate reports.

Pricing

$19.99/month + usage

Rating

0.0

(0)

Developer

ScrapeMesh

ScrapeMesh

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

1

Monthly active users

4 days ago

Last modified

Share

📝 Google Ads Scraper: Ad Copy & Click-Through Links

A Google Ads Transparency scraper that goes one step past the plain creative list: for every listed ad it opens the ad's own preview document — the content.js render file every ad already carries as previewUrl — and reads out the headline, description, long headline and call-to-action button text, the click-through link the ad sends people to (with its display URL and click tracker), and, when the preview says so, the app, video or shopping product the ad is promoting.

Give it a Google Ads Transparency profile URL or an advertiser ID. No login, no API key, no cookies, no browser — one extra plain GET per ad, logged out, against a page Google already serves.


🔑 What it collects

CapabilityDetail
📰 Ad copyHeadline, description, long headline and call-to-action, read from the ad's own rendered preview
🎯 Click-through linkThe exact destination_url the ad sends people to, plus its short display_url and the raw googleadservices.com/pagead/aclk click tracker
🛍️ Promoted productApp-install ads: app name, store id, store, developer, category, blurb. Shopping ads: product item ids and ad-group id. Video ads: the YouTube video id, url, duration and thumbnail
✂️ Ad-copy filterKeep only ads whose preview actually gave up a headline or a link — Google renders text/search ads as flat pictures with none
🔗 Destination filterKeep only ads whose click-through link contains a domain, store or campaign-parameter string you name
🧱 Everything the base collectsAd Library URL, advertiser id/name, creative id, regions, first/last shown, format, preview URL, region statistics — unchanged

📥 Input

FieldTypeDefaultWhat it does
startUrlsarray of strings, requiredprefilledGoogle Ads Transparency profile URLs or AR… advertiser IDs
maxItemsinteger 1-1000010Max ad creatives to collect per advertiser. Counts rows that pass the filters below, not just listed creatives
proxyConfigurationobjectdirectProxy settings for the listing request
openAdPreviewsbooleantrueOpen each ad's own preview and read its copy and click-through link. One extra request per ad with a preview
onlyAdsWithAdCopybooleantrueKeep only ads whose preview gave up a headline or a link. Off = keep every ad, with nulls where Google published nothing
destinationDomainFilterarray of strings[]Keep only ads whose click-through link contains one of these strings (shop.example.com, play.google.com, utm_source=). Empty = keep everything
includePromotedProductbooleantrueAlso return the app / video / shopping-product record when the preview carries one

Example input

{
"startUrls": ["https://adstransparency.google.com/advertiser/AR04619580580634296321"],
"maxItems": 20,
"openAdPreviews": true,
"onlyAdsWithAdCopy": true,
"destinationDomainFilter": ["play.google.com"],
"includePromotedProduct": true,
"proxyConfiguration": { "useApifyProxy": false }
}

📤 Output

One row per ad creative. Every base field is reproduced unchanged, in base order, base shape and base value — including the base's own known quirks (see Limits below). Every added field is present on every row for a stable shape, null (or [] for the array fields) when Google's preview didn't carry it.

{
"adLibraryUrl": "https://adstransparency.google.com/advertiser/AR04619580580634296321/creative/CR02562382857502720001",
"advertiserId": "AR04619580580634296321",
"advertiserName": "Pokemon Co., Ltd.",
"creativeId": "CR02562382857502720001",
"creativeRegions": ["Region 137"],
"firstShown": "2026-04-01",
"format": "VIDEO",
"lastShown": "2026-08-15T06:46:35.069986Z",
"previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?...",
"regionStats": [
{ "regionCode": "137", "regionName": "Region 137", "firstShown": "2026-04-01",
"lastShown": "2026-08-15", "impressions": { "lowerBound": 0, "upperBound": 1000 } }
],
"adHeadline": null,
"adDescription": null,
"adLongHeadline": null,
"adCallToAction": "INSTALL",
"destinationUrl": "https://play.google.com/store/apps/details?id=jp.pokemon.pokemonsleep",
"displayUrl": "play.google.com/store",
"finalUrl": null,
"clickTrackerUrl": "https://www.googleadservices.com/pagead/aclk?sa=L&ai=C5w5Q...",
"hasAdCopy": true,
"promotedApp": {
"appName": "Pokémon Sleep", "shortAppName": "Pokémon Sleep",
"appId": "jp.pokemon.pokemonsleep", "appStore": "2", "appStoreName": "Google Play",
"developer": "The Pokémon Company", "appCategory": "GAME_SIMULATION",
"shortDescription": "Track your sleep with a smart device to discover adorable Pokémon sleep styles!"
},
"adVideoId": "G6qzzxZou2U",
"adVideoUrl": "https://www.youtube.com/watch?v=G6qzzxZou2U",
"adVideoDuration": null,
"adVideoThumbnail": null,
"shoppingItemIds": [],
"adGroupId": null,
"googleCreativeId": "802897023323",
"obfuscatedCustomerId": "5664803232",
"adWidth": 320,
"adHeight": 568,
"creativeTypeCode": 46
}
FieldTypeMeaning
adLibraryUrlregionStatsUnchanged base fields — see Limits for the base's own known quirks, preserved here
adHeadline / adDescription / adLongHeadlinestring | nullAd copy read from the preview. Present only when the preview's template carries these keys (measured ~24% / ~45% of all creatives)
adCallToActionstring | nullButton text, e.g. INSTALL
destinationUrlstring | nullThe click-through link, un-escaped, verified to start with http(s)://
displayUrlstring | nullThe short URL Google shows on the ad itself
finalUrlstring | nullA second landing-link field Google's preview carries. Measured empty in 100% of observations — a nullable fallback, never a promise
clickTrackerUrlstring | nullThe googleadservices.com/pagead/aclk?… tracker Google serves, returned as the string it is. Never followed — no second request, no landing page fetched
hasAdCopybooleantrue when a headline or a click-through link was read. Convenience only — not the point of the row
promotedAppobject | nullApp-install record when the preview is one. null for every other ad, or when includePromotedProduct is off
adVideoId / adVideoUrl / adVideoDuration / adVideoThumbnailThe YouTube video a video ad plays. adVideoDuration is Google's own m:ss string, never converted to seconds
shoppingItemIdsarrayShopping-ad product item ids, from the preview URL's own query string
adGroupId / googleCreativeId / obfuscatedCustomerIdstring | nullGoogle Ads account plumbing ids, read from the preview URL's query string — zero extra requests, present even when openAdPreviews is off
adWidth / adHeight / creativeTypeCodenumber | nullThe preview's own rendered dimensions and Google's internal creative-type code

📊 Measured coverage (live, 2026-08-15, Pokémon AR04619580580634296321)

MeasurementResult
Ads with a preview document at allmeasured 70/160 creatives (44%) across 4 advertisers — the rest are text/search ads rendered as flat images with nothing to read
Preview fetch success40/40 plain GETs returned HTTP 200
Previews carrying a headline22/40 fetched previews
Previews carrying a destination link18/40 fetched previews
Coverage swings hard by advertiserNike: 0/10 destination URLs. Pokémon: 11/12. HelloFresh: 4/4 previews with neither copy nor a link
onlyAdsWithAdCopy filter, livedefault run: 40 listed → 8 qualifying (headline or link present). onlyAdsWithAdCopy:false: same 40 listed, 4 pass / 11 fail, all 15 kept
destinationDomainFilter filter, live["play.google.com"] against the same advertiser: 5/5 returned rows contain play.google.com in destinationUrl
includePromotedProduct:false, livepromotedApp, adVideoId, shoppingItemIds all forced to null/[] while adCallToAction/destinationUrl stay populated

⚠️ Limits — please read

  • Only roughly a quarter of all creatives carry readable copy. Google renders text and search ads as flat pictures with no headline string and no link at all. onlyAdsWithAdCopy defaults to true because of this — turn it off to see every ad, including the blanks.
  • Coverage is not a promise. It swings from 0% to over 90% by advertiser, measured live (see table above).
  • finalUrl has never been observed with a value. It is present in the preview but always empty; it exists only as a nullable fallback for destinationUrl, never as a claim of its own.
  • One extra request per ad that has a preview. openAdPreviews:false returns exactly the base's behaviour — no preview fetch, no ad copy, no click-through link.
  • Preview links are signed and expire. They are fetched in the same run they are listed in; a failed or expired fetch returns nulls for that row rather than retrying forever.
  • maxItems counts qualifying rows, not listed creatives. With onlyAdsWithAdCopy on, the run pages further to find enough readable ads, up to an internal safety cap of 5 extra pages / 200 listed creatives per advertiser.
  • Nothing is downloaded, decoded pixel-by-pixel or guessed. Every field is a string or number Google's own preview document serves. There is no OCR, no score, no ranking, no spend estimate and no comparison with a previous run.
  • Base quirks are preserved, not fixed (this variant's job is ad copy, not a repair): creativeRegions / regionStats[].regionCode carry the base's Region <N>-style placeholders (the base misreads a days-shown counter as a region id), regionStats[].impressions is a constant {0, 1000} on every region, and format reads "UNKNOWN" on text ads. See the base contract for the full list.
  • Everything here is logged out. No cookie, no login, no API key, against pages Google publishes for public inspection.

💳 Pricing

Pay per event: one creative_result event per ad creative written to the dataset. Rows dropped by onlyAdsWithAdCopy or destinationDomainFilter are never pushed and never charged.


❓ FAQ

Do I need a Google account, cookie or API key? No. The whole run is logged-out.

Why is adHeadline null on some rows even though hasAdCopy is true? hasAdCopy is true when either a headline OR a destination link was read. A row can carry a link with no headline, or a headline with no link — see the measured coverage table.

Can I get the advertiser's landing page contents? No. destinationUrl is returned as a string; the page behind it is never fetched.

Does this follow the click tracker redirect? No. clickTrackerUrl is returned exactly as Google serves it — following it would be a second live request per ad and would leave Google's own site.

What can I export? The dataset exports to JSON, CSV, Excel, XML and JSONL from the Apify console or the API.


This actor reads only the public, logged-out Google Ads Transparency Center and the ad's own public preview document, both of which Google serves for ad-transparency inspection. It collects no personal data, uses no credentials and bypasses no access control. Respect Google's terms and the law of your jurisdiction when using the data.


Keywords: Google Ads scraper · Google Ads Transparency Center · ad copy scraper · ad creative text · click-through link · destination URL extractor · landing page link · call-to-action scraper · competitor ad research · advertiser ID lookup · app install ad scraper · YouTube ad scraper · shopping ad scraper · ad headline extractor · promoted app data · export JSON CSV Excel · no login required