# Google Ads Creative Text & OCR (Transparency Center) (`steadyfetch/google-ads-creative-text-scraper`) Actor

Charged only when ad content is extracted — video and unreadable creatives are free rows. What competitor Google ads actually SAY: headline, body, CTA and all visible text from Ads Transparency Center creatives, image ads read by OCR. By advertiser or domain. No start fee.

- **URL**: https://apify.com/steadyfetch/google-ads-creative-text-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** AI, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 ad creative contents

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Ads Creative Text & OCR — what competitor ads actually say

Every Google Ads Transparency scraper returns the same thing: metadata rows — IDs, dates, formats — and stops. The Transparency Center renders every ad as a **screenshot image**, so the actual creative content (headline, body, CTA) never appears in their output. This actor reads it.

**Advertiser or domain in → structured ad copy out:**

```json
{
  "advertiserName": "HelloFresh",
  "format": "TEXT",
  "headline": "Dinner just levelled up - Weeknights, upgraded",
  "body": "Not sure what's for dinner? Get farm-fresh ingredients and easy recipes delivered.",
  "cta": "Get Offer",
  "displayUrl": "www.hellofresh.ca/",
  "rawText": "HelloFresh www.hellofresh.ca/ Dinner just levelled up …",
  "status": "extracted",
  "firstShown": 20260214,
  "lastShown": 20260818
}
```

### Output

One JSON row per creative. `status: "extracted"` rows carry the ad copy and are the only rows charged; everything else ships free with a `statusReason` saying why. Real rows from the live example run below (long text trimmed with … for the page):

| status | statusReason | advertiserName | format | headline | body | cta | displayUrl | firstShown | lastShown |
|---|---|---|---|---|---|---|---|---|---|
| `extracted` | *null* | HelloFresh SE | TEXT | Schmeckt Deiner ganzen Familie | Weniger Einkaufsstress: Plane flexibel, wähle Rezepte und koche frisch zu Hause. | *null* | www.hellofresh.de/ | 20260820 | 20260826 |
| `not_extracted` | `no_screenshot` | HelloFresh SE | IMAGE | *null* | | *null* | *null* | 20260819 | 20260826 |
| `not_extracted` | `video_metadata_only` | HelloFresh SE | VIDEO | *null* | | *null* | *null* | 20260604 | 20260826 |
| `extracted` | *null* | HelloFresh SE | IMAGE | HelloFresh is Hiring in Poland | Bring your flavour to HelloFresh — fresh roles now open in Poland! | Apply Now | careers.hellofresh.com | 20260402 | 20260826 |

The last row is an **image ad**: headline, body and CTA read straight off the rendered creative by OCR — the rows other Transparency Center scrapers leave blank. The two middle rows are free.

![Google Ads creative text output table — status, format, headline, body copy, CTA and display URL, including an image ad read by OCR](https://raw.githubusercontent.com/steadyfetch/n8n-templates/master/assets/google-ads-creative-text-scraper-output-table.png)

**[Browse the full live example dataset →](https://api.apify.com/v2/datasets/RiIoulo9o5Ct175YE/items?clean=true\&format=json)** — real output from a verified run, including the free uncharged rows.

Every row also carries `charged` — `true` only on rows that were actually billed, so you can reconcile the dataset against your invoice — plus `advertiser`, `advertiserId`, `creativeId`, `rawText` (all visible text, verbatim) and `screenshotUrl`. Non-extracted rows use `statusReason` — `video_metadata_only`, `all_video`, `no_screenshot`, `screenshot_unavailable` (the archive no longer serves it), `screenshot_fetch_failed` (temporary — re-run to retry), `ocr_no_text_found`, `ocr_unreliable` (a garbled read is never billed), `ocr_service_unavailable` (our text-reading service was unavailable — that is on us, not you; every remaining creative and target still gets its own free row saying so, and the run stops cleanly), `no_creatives_found`, `advertiser_not_found`, `domain_not_listed`, `unsupported_region` — and none of them are charged. Rows a fresh run can genuinely recover (source weather, screenshot-host blips, an outage on our side) additionally carry `retryable: true`, so you can filter exactly what a re-run would fix.

### For AI agents & LLMs — copy this block

```
Actor:   steadyfetch/google-ads-creative-text-scraper  (Apify Store)
Does:    Google Ads Transparency Center creatives -> what the ad actually SAYS:
         headline, body, CTA, display URL and all visible text. Image/display ads
         are read by a vision model (OCR). One JSON row per creative. No Google login.
Run:     POST https://api.apify.com/v2/acts/steadyfetch~google-ads-creative-text-scraper/run-sync-get-dataset-items?token=APIFY_TOKEN
Input    (advertisers and/or domains — at least one):
  {
    "advertisers": ["HelloFresh", "AR17410177287600472065"],  // names or AR… advertiser IDs
    "domains": ["factormeals.com"],                           // every advertiser verified for it
    "formats": ["TEXT", "IMAGE", "VIDEO"],                    // optional, this is the default
    "region": "US",                                           // optional, default US
    "maxCreativesPerAdvertiser": 50                           // optional, default 30
  }
Output   one row per creative: status, charged, statusReason, advertiser, advertiserName,
         advertiserId, creativeId, format, headline, body, cta, displayUrl, rawText,
         screenshotUrl, firstShown, lastShown
Pricing  pay per event, platform usage INCLUDED, no start fee:
  ad-creative-content   $0.015 -> $0.004 per extracted creative (falls with your Apify plan tier)
  Charged only on extraction — video creatives, missing screenshots and unreadable
  creatives ship as free rows.
  Cap any run with maxTotalChargeUsd (minimum $0.05). Empty input runs a free 2-row demo.
MCP:     reachable through Apify's MCP server; ask for "what Nike's Google ads say".
```

### What you get

- **TEXT and IMAGE creatives read by a vision model** — headline, body text, CTA, display URL, and all visible text verbatim. Image/display ads included: the format most tools skip entirely.
- **Video creatives listed free** — advertiser, dates, format, creative ID as metadata rows. No video is downloaded and nothing is charged for them.
- **Search by advertiser name, AR… advertiser ID, or domain** (a domain spans every advertiser verified for it). Region-aware — the same brand runs different ads per country.
- **Charged only when content is extracted.** A creative whose screenshot is missing, expired, or unreadable is delivered free with an honest per-row reason (`screenshot_unavailable`, `ocr_no_text_found`, …) — never a charged empty row.

### Who uses this

- **Competitive ad research:** pull a competitor's live headlines and offers as text you can diff, count, and track over time.
- **Ad copywriting / creative teams:** mine what the market's ads say before writing yours — real inputs for ad-generation workflows.
- **Agencies:** monitor client categories across regions without screenshotting by hand.

### How much does it cost?

**1 result = one creative's extracted content** (all fields above from one ad). No start fee, no subscription. Pricing is **all-inclusive** — platform usage is included in the event price, no separate usage line.

| What you run | Results | Cost |
|---|---|---|
| One competitor, 30 newest creatives | ~24 extracted | ~$0.36 |
| 10 competitors, 50 creatives each | ~400 extracted | ~$6.00 |
| Track one brand's ads weekly | ~100/mo | ~$1.50/mo |

Video creatives, misses, and unreadable screenshots are always $0. You stay in control with **Maximum cost per run** — the run stops cleanly at your cap and tells you what's left. Apify's free plan ($5 monthly credit) is enough to evaluate seriously.

**Tip — search by `domains` for full coverage.** A brand name matches exactly **one** verified advertiser entity, and big brands often run ads under several (plus their agencies). A domain search finds **every** advertiser verified for that domain, so `domains: ["brand.com"]` regularly surfaces creatives — and whole advertiser accounts — that a name search misses. The counts in the table above assume the advertiser you hit actually runs text/image ads; if a name search comes back thin, try the domain.

### Honest scope (read before big runs)

- **v1 extracts TEXT and IMAGE creatives.** Video creatives ship metadata only (free rows) — no video content is fetched. An advertiser whose ads are **all video** gets those free rows plus one free row pointing you to the [video-transcript companion](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) — never an empty dataset.
- **Region matters.** An advertiser can show thousands of ads in one country and zero in another. Default is US; set `region` for others.
- Some rich/HTML creatives have no public screenshot; those rows arrive free with `no_screenshot`.
- The Transparency Center shows what Google publishes — typically ads served in roughly the last 30 days.

### Input

```json
{
  "advertisers": ["HelloFresh", "AR17410177287600472065"],
  "domains": ["factormeals.com"],
  "formats": ["TEXT", "IMAGE", "VIDEO"],
  "region": "US",
  "maxCreativesPerAdvertiser": 50
}
```

Run with no input at all and you get a tiny free demo (2 real creatives, nothing charged).

### Use it via API and MCP

```bash
curl "https://api.apify.com/v2/acts/steadyfetch~google-ads-creative-text-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"advertisers":["Nike"],"region":"US","maxCreativesPerAdvertiser":25}'
```

Works out of the box from any MCP client (Claude, Cursor, …) via Apify's MCP server — ask for "what do Nike's Google ads say right now" and point it at this actor.

### FAQ

**Why doesn't my usual Transparency scraper return the ad text?** Because the Transparency Center serves ads as rendered screenshots — the text isn't in the page data. Reading it requires per-ad OCR, which row-priced scrapers don't do. That's the exact job this actor exists for.

**What if an advertiser has no ads in my region?** You get a free row saying `no_creatives_found` with guidance to try another region — not a charged empty result.

**Can it read every ad?** No — and it won't pretend to. Creatives without a public screenshot or whose text can't be read reliably are delivered free with the reason on the row. You pay only for extracted content.

**Is this an official Google product?** No. This is an independent actor from steadyfetch — unofficial, and not affiliated with, endorsed by, or sponsored by Google LLC. "Google" and "Google Ads" are trademarks of their respective owners, used here only to name the public Ads Transparency Center surface this actor reads.

### Steadyfetch ad-intelligence suite

One actor per ad surface, one job each, the same contract everywhere: **all-inclusive pay-per-event,
no start fee, charged only on delivery** — and the same row shape, so a workflow built for one platform
ports to the next.

**Ad creatives → transcripts & on-creative text**

| Ad surface | Actor | Free n8n template |
|---|---|---|
| Facebook & Instagram Ad Library | [Facebook Ad Library Transcript Scraper — Video & Image Ad Text](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) | [Facebook ad transcripts →](https://github.com/steadyfetch/n8n-templates#facebook-ad-transcripts--scrape-competitor-ads--hooks-ctas--transcripts) · [Competitor ad teardown →](https://github.com/steadyfetch/n8n-templates#competitor-ad-teardown--one-competitor-pagekeyword--hooks-ctas--transcripts-one-row-per-ad) |
| Google Ads Transparency Center | [Google Ads Video Transcripts & Hooks (Ads Transparency Center)](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) | [Google Ads video transcripts →](https://github.com/steadyfetch/n8n-templates#google-ads-video-transcripts--one-advertiserdomain--hooks--transcripts) |
| TikTok Creative Center Top Ads | [TikTok Ad Transcripts & Hooks (Creative Center Top Ads)](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) | [TikTok Top Ads transcripts →](https://github.com/steadyfetch/n8n-templates#tiktok-top-ads-transcripts--creative-center-industryregion--hooks--transcripts) |
| LinkedIn Ad Library | [LinkedIn Ads Transcript Scraper — Video Hooks & CTAs](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper) | [LinkedIn Ad Library transcripts →](https://github.com/steadyfetch/n8n-templates#linkedin-ad-library-transcripts--one-advertiser--hooks--transcripts) |
| Instagram Reels (organic posts) | [Instagram Reels to Text · @handle](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) | [Instagram Reel transcripts →](https://github.com/steadyfetch/n8n-templates#instagram-reel-transcripts--scrape-a-profiles-reels--hooks--transcripts) |

**Ad creatives → text (image & text ads, read by OCR)**

| Ad surface | Actor |
|---|---|
| **Google Ads Transparency Center** | **this actor** |

All templates in one place: **[github.com/steadyfetch/n8n-templates](https://github.com/steadyfetch/n8n-templates)** — free, no community nodes needed.

**The rest of the steadyfetch shelf** — same contract everywhere: all-inclusive pay per event,
no start fee, charged only on delivery.

| Family | Actors |
|---|---|
| **Ad creative intelligence** | [Facebook](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) · [Google Ads video](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) · [TikTok](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) · [LinkedIn](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper) · [Google Ads text & OCR](https://apify.com/steadyfetch/google-ads-creative-text-scraper) |
| Trends & keywords | [Google Trends](https://apify.com/steadyfetch/google-trends-scraper) · [Trends Now](https://apify.com/steadyfetch/google-trends-now-scraper) · [Breakout keywords](https://apify.com/steadyfetch/breakout-keywords-scraper) · [Autocomplete keywords](https://apify.com/steadyfetch/google-keyword-suggest-scraper) · [Keyword volume & CPC](https://apify.com/steadyfetch/keyword-search-volume-scraper) · [Social trends](https://apify.com/steadyfetch/social-trends-scraper) |
| YouTube transcripts | [YouTube videos](https://apify.com/steadyfetch/youtube-transcript-scraper) · [YouTube channels](https://apify.com/steadyfetch/youtube-channel-transcripts) |
| Instagram | [Reel transcripts](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) · [Profile posts](https://apify.com/steadyfetch/instagram-profile-posts) |
| Jobs | [Indeed](https://apify.com/steadyfetch/indeed-jobs-scraper) · [Career sites by domain](https://apify.com/steadyfetch/company-jobs-by-domain) · [Glassdoor](https://apify.com/steadyfetch/glassdoor-jobs-scraper) · [Multi-board](https://apify.com/steadyfetch/multi-job-board-scraper) · Google Jobs |
| Amazon | [Products](https://apify.com/steadyfetch/amazon-product-scraper) · [Search](https://apify.com/steadyfetch/amazon-search-scraper) · Bestsellers · Sellers |
| Any media file | [Speech to Text · any link or file](https://apify.com/steadyfetch/media-transcriber) |

Unlinked names are publishing shortly on the same account — search **steadyfetch** on Apify Store.

### Feedback & support

Found an issue? Open it on the **Issues tab** — we respond within one business day. Feature requests welcome.

# Actor input Schema

## `advertisers` (type: `array`):

Brand names (resolved via Transparency Center search) or exact AR… advertiser IDs. Up to 20.

## `domains` (type: `array`):

Website domains (like amazon.com) — spans every advertiser verified for that domain. Up to 10.

## `formats` (type: `array`):

Which creative formats to process. TEXT and IMAGE creatives get their text extracted; VIDEO creatives are listed with metadata for free (no video is downloaded, nothing charged).

## `region` (type: `string`):

2-letter country code the ads were shown in (US, GB, DE, …). Regions differ a lot — an advertiser can be empty in one country and huge in another. A code we do not support falls back to US and says so in a free row, so you always know which market you got.

## `maxCreativesPerAdvertiser` (type: `integer`):

Cap per target (1–500).

## Actor input object example

```json
{
  "advertisers": [
    "HelloFresh"
  ],
  "formats": [
    "TEXT",
    "IMAGE",
    "VIDEO"
  ],
  "region": "US",
  "maxCreativesPerAdvertiser": 30
}
```

# Actor output Schema

## `creatives` (type: `string`):

One row per creative: headline, body, CTA, display URL, all visible text, and a status (extracted / video\_metadata\_only / screenshot\_unavailable / …). Only 'extracted' rows are charged.

## `errors` (type: `string`):

Present only when screenshots or text extraction failed after retries: creative ID and reason.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "advertisers": [
        "HelloFresh"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/google-ads-creative-text-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "advertisers": ["HelloFresh"] }

# Run the Actor and wait for it to finish
run = client.actor("steadyfetch/google-ads-creative-text-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "advertisers": [
    "HelloFresh"
  ]
}' |
apify call steadyfetch/google-ads-creative-text-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyfetch/google-ads-creative-text-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ARtq7Ov4A1eUlT6Qj/builds/wkPfA62hY6zyQxAH3/openapi.json
