# Google Ads Transparency Scraper ($0.90/1K) (`silentsuperpower/google-ads-transparency-scraper`) Actor

Pull every Google ad a competitor runs (Search, YouTube, Shopping, Maps, Play) from the Google Ads Transparency Center, by brand name, domain, or advertiser ID. Only $0.90 per 1,000 ads ($0.72 on Gold). Fast, no browser.

- **URL**: https://apify.com/silentsuperpower/google-ads-transparency-scraper.md
- **Developed by:** [Silent Superpower](https://apify.com/silentsuperpower) (community)
- **Stats:** 4 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.72 / 1,000 ads

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Google Ads Transparency Scraper do?

It pulls every Google ad a company runs, straight from the public [Google Ads Transparency Center](https://adstransparency.google.com/). Give it a **brand name**, a **website domain**, an **advertiser ID**, or an Ads Transparency **link**, and you get a clean spreadsheet of that advertiser's Search, YouTube, Shopping, Maps, and Play ads, with ad images, formats, first/last shown dates, and how many days each ad has been running.

It also works as a **lead generation tool** (one row per advertiser, with an approximate ad count) and as an **ad alert feed** (schedule it and get only the ads that are new since the last run).

It talks to the Transparency Center directly instead of driving a browser, so it's **fast and cheap**: a few seconds and a fraction of a cent for hundreds of ads.

### Why scrape Google Ads Transparency?

- **Competitor research:** see every ad your competitors are running right now and how long they've kept each one live. Ads that run for months are the ones that make money.
- **Creative inspiration:** build a swipe file of text, image, and video ads for any niche.
- **Agency prospecting:** find brands that advertise on Google in a country and pitch them with their own ads in hand. Advertisers mode gives you the company list directly.
- **Brand protection:** spot advertisers bidding on your brand or domain.
- **Market monitoring:** schedule a daily run in monitor mode and get only the ads that launched since yesterday.

### How to use it

1. Enter one or more targets. Any of these work, in any mix:
   - a brand name: `Patagonia`
   - a domain: `nike.com`
   - an advertiser ID: `AR16735076323512287233`
   - an `adstransparency.google.com` advertiser page, domain search page, or single creative page
2. Pick **Ads** or **Advertisers** under *What to return*.
3. Optionally filter by **country**, **format** (text/image/video), **platforms** (Search, YouTube, Shopping, Maps, Play, pick as many as you like), or **date range**.
4. Click **Start** and download the results as JSON, CSV, Excel, or HTML, or pull them through the API.

### Input

| Field | What it does |
|---|---|
| `queries` | Names, domains, advertiser IDs, or Transparency Center URLs, one per line. |
| `domains` | Domains only, for when they come from another system. |
| `advertiserIds` | Advertiser IDs (`AR...`), the most exact target. |
| `startUrls` | Transparency Center links: an advertiser page, a domain search page, or a **creative page** (`.../advertiser/AR.../creative/CR...`), which fetches just that ad with its details. A link to a `.txt` or `.csv` file also works here. |
| `urlsFromFile` | A pasted list (one per line) or one link to a public `.txt` or `.csv` file. For a CSV the first column is used and a header row is skipped. Google Sheets that need a login are not supported: publish the sheet as CSV and paste that link. |
| `resultType` | `ads` (default) or `advertisers`. |
| `maxAdsPerQuery` | Ads per query (default 100). In monitor mode this limits the *new* ads returned. Tested up to 10,000 per query (5,000 on two different advertisers and 10,000 on one, all delivered in full); larger values run but are not covered by our reliability tests. |
| `maxAdvertisersPerQuery` | Advertisers mode: advertisers per query (default 10, max 50). |
| `advertisersPerName` | Ads mode: for a name query, how many matching advertiser accounts to scrape (default 1). |
| `region` | Only ads shown in this country. Also ranks name matches toward advertisers registered there. |
| `format` | `ALL`, `TEXT`, `IMAGE`, or `VIDEO`. |
| `platforms` | Multi-select: `SEARCH`, `YOUTUBE`, `SHOPPING`, `MAPS`, `PLAY`. Empty means all. The old single `platform` value still works. |
| `dateFrom` / `dateTo` | Only ads shown in this date range (`YYYY-MM-DD`). |
| `includeDetails` | Adds regions and variations to every ad (one extra charge per ad). |
| `includeAdCopy` | Adds the ad text: `headline`, `longHeadline`, `description`, `callToAction`, `displayUrl`, `destinationUrl`, `businessName`, plus `adCopyStatus`. Turns details on too, so each ad is charged the details event (no extra event). See "Output: ad copy". |
| `detailConcurrency` | Detail lookups run in parallel (default 4, max 10) while Apify Proxy is carrying the run; on a direct connection they run one at a time to avoid blocks. |
| `includeRawData` | Adds Google's unprocessed creative record as `rawData` (and `rawDetails` when details are on). |
| `onlyNewAds` | Monitor mode, see below. |
| `monitorStoreName` | Name of the key-value store that holds monitor history (default `ads-transparency-monitor`). |
| `proxyConfiguration` | Optional. Apify Proxy switches on by itself when Google rate-limits a run. |

Switching from another Ads Transparency scraper? `maxAdsPerSearch`, `adFormat`, `startDate`, and `endDate` are accepted as aliases for `maxAdsPerQuery`, `format`, `dateFrom`, and `dateTo`. They are not shown in the input form (use the API, a Task or the JSON editor), and when one is present it wins over the form field. The run log says which aliases were used.

```json
{
    "queries": ["nike.com", "Patagonia"],
    "region": "US",
    "platforms": ["SEARCH", "YOUTUBE"],
    "maxAdsPerQuery": 200,
    "includeDetails": false
}
```

### Monitor mode: only new ads

Turn on **Only new ads** and schedule the Actor (hourly, daily, weekly). It remembers the creative IDs each query has already returned, in a named key-value store, and returns only ads it has not shown you before.

- The **first run** returns every ad it finds (up to your limit) and seeds the history. Every run after that returns only new ads.
- Each query has its own history, so `nike.com` and `Nike` never mix.
- History is saved as the run goes, so a run that is aborted or stopped by its cost limit does not lose it. An ad is remembered only after it was actually saved, so ads cut off by `maxAdsPerQuery` or the cost limit show up next time.
- **Ads skipped as already seen are never charged.**
- Google does not promise newest-first order, so a monitor run looks through at most the larger of 5,000 ads or twice `maxAdsPerQuery` per target. For huge advertisers, add a **Shown on or after** date to keep runs short.
- Use a different `monitorStoreName` for each separate monitor, or to start fresh.

### Output: ads

```json
{
    "query": "nike.com",
    "advertiserId": "AR16735076323512287233",
    "advertiserName": "Nike, Inc.",
    "creativeId": "CR14561993098470096897",
    "format": "TEXT",
    "adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR14561993098470096897",
    "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/11975201839024397116",
    "previewUrl": null,
    "imageSize": "348x505",
    "firstShown": "2026-06-05T07:00:00.000Z",
    "lastShown": "2026-09-24T18:30:53.000Z",
    "shownForDays": 111,
    "isRunningNow": true,
    "daysSinceLastShown": 0,
    "scrapedAt": "2026-09-24T19:02:11.000Z"
}
```

With **Include regions and variations** switched on, each ad also gets:

```json
{
    "regions": [{ "countryCode": "US", "geoTargetId": 2840, "lastShown": "2026-09-24" }],
    "variations": [{ "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/..." }]
}
```

- `shownForDays` is the number of whole days from `firstShown` to `lastShown` (0 if both are on the same day, `null` when either is missing). Long-running ads are the ones that make money.
- `isRunningNow` is `true` when the ad was last shown within 48 hours of `scrapedAt`, and `daysSinceLastShown` counts the whole days from `lastShown` to `scrapedAt`. Use them to separate live ads from old ones.
- `imageUrl` is a static image of the ad (text ads are archived by Google as screenshots).
- `previewUrl` is Google's interactive preview script, used for responsive display and video ads.
- A creative page link returns the same fields, except `firstShown` and `shownForDays`, which are `null` because Google does not include a first-shown time for single-creative lookups.
- If a detail lookup keeps failing for an ad, the ad is still saved with a `detailsError` field and you are not charged for details on it.

### Output: ad copy

Switch on **Include ad copy** to get the words of each ad, not only its picture and dates. For every ad the scraper reads the preview Google serves and fills:

```json
{
    "headline": "Stop chasing data. Start closing deals.",
    "longHeadline": "Everything your team needs to grow. Get started free with HubSpot Smart CRM.",
    "description": "Track every contact, call, and deal in one place so nothing slips through the cracks.",
    "callToAction": "Sign up",
    "displayUrl": "hubspot.com",
    "destinationUrl": "https://www.hubspot.com/crm/e010a",
    "businessName": null,
    "adCopyStatus": "ok"
}
```

- Turning it on also fetches the ad details, so each ad is charged the **Ad details** event. No other event is added.
- A field is `null` when Google gives none. **Nothing is guessed, and no pictures are read (no OCR).**
- `adCopyStatus` says why: `ok` (copy found), `image-only` (Google archived the ad as a picture only, so there is no text to read), `no-text` (a preview was read but holds no copy the scraper understands), or `unavailable` (the preview could not be fetched; the ad is still saved).
- What we measured on build 0.1.11 (50 ads per run): video ads 50 of 50 with headline, long headline, description, call to action and display URL. Nike text ads 32 of 50 with copy: 26 with headline, description and display URL, and 6 dynamic search ads where Google writes the headline and URL at serving time, so only the description and business name are returned (a placeholder is never copied into a field); 17 more were screenshots only. HubSpot's mixed ads 10 of 50 (all 8 video ads, 2 of 40 text ads, the rest screenshots only). Adidas image ads in Germany 4 of 50 (38 screenshots only, 8 previews with no copy fields). So video and display ads usually carry copy, and text ads vary a lot by advertiser. Where there is only a screenshot, use `imageUrl`.
- The run summary (`OUTPUT.adCopy`) counts how many ads had copy, per status and per format.
- `destinationUrl` is the plain landing page. Google's click-tracking links are never returned or opened.

### Output: advertisers

Set *What to return* to **Advertisers** to get one row per matched advertiser instead of every ad. A name finds all matching advertiser accounts, a domain finds the advertisers running ads that point to it.

```json
{
    "query": "nike.com",
    "advertiserId": "AR18378488041124659201",
    "name": "Nike Retail BV",
    "country": null,
    "approxAdCount": 75000,
    "adCountMin": 70000,
    "adCountMax": 80000,
    "transparencyUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201",
    "scrapedAt": "2026-10-10T15:09:01.945Z"
}
```

- `approxAdCount` is Google's own estimate; `adCountMin` and `adCountMax` are the range Google reports. With country, format, platform, or date filters on, the counts are for ads matching those filters, and advertisers with no matching ads are left out.
- `country` is the advertiser's registered country when Google returns it (name searches), otherwise `null`.
- An advertiser appears once per run, even if several queries find it.

### How much does it cost?

You pay only for results, per event. The price per 1,000 depends on your Apify plan:

| Event | Free and Bronze | Silver | Gold and above |
|---|---|---|---|
| Ad scraped | $0.90 per 1,000 | $0.81 per 1,000 | $0.72 per 1,000 |
| Ad details (optional, per ad that returned details) | $0.44 per 1,000 | $0.35 per 1,000 | $0.08 per 1,000 |
| Advertiser row (advertisers mode) | $2.69 per 1,000 | $2.69 per 1,000 | $2.69 per 1,000 |
| Run start | $0.00005 | $0.00005 | $0.00005 |

Scraping 500 of a competitor's ads on the Free plan costs about **$0.45**. Ads skipped by monitor mode, ads Google returns without an ID, and details Google refused are never charged. If a query fails, you are charged only for the rows that were saved. Set a maximum cost per run in the run options and the scraper stops cleanly when it is reached.

At the start of every run the log shows the price on your plan, the worst-case size of the run, and every limit that can end a query early.

### Limits and what the run tells you

Nothing here depends on your Apify plan. The limits are:

- **Max ads per query** (default 100). Tested up to 10,000 per query: a 10,000-ad run finished in about 18 minutes for about $0.08 of platform usage, and 5,000-ad runs took 10 to 12 minutes. Larger values run but are not covered by our tests. A run that long needs a run timeout above 20 minutes (the Actor's own default is 1 hour).
- A name query tries at most the first 5 matching advertiser accounts and stops after **Advertisers per name** of them have ads.
- Monitor mode pages through at most the larger of 5,000 ads or twice **Max ads per query** for each query.
- In Advertisers mode, a domain query takes its advertisers from the first 200 ads of that domain.
- With details on, a query stops after 3 refused detail requests in a row; its ads are saved without details.
- With ad copy on, a run turns ad copy off after 10 ads in a row whose preview could not be fetched; the ads are still saved.

The first log lines list these for your input, and the run's status message and the `OUTPUT` record say when one of them ended a query.

**Reliability.** If Google blocks or drops a request, the scraper waits, takes a fresh IP, and retries. A query that still fails is retried once more on a fresh proxy session, resuming where it stopped, so nothing is saved or charged twice. Then the run ends honestly:

- Everything worked: the status message starts with "Done:". If the only limit hit is your own **Max ads per query**, it reads "Done: 100 ads saved (your limit of 100 per query)", and "Questions?" with the Issues link.
- Some queries did not finish: the run succeeds with the rows that were saved, and the status message starts with **"PARTIAL:"**, names the queries, and points to the Issues tab. You are charged only for saved rows.
- Nothing could be saved: the run fails and no results are charged (only Apify's small run start fee applies).

The `OUTPUT` record in the run's key-value store has the details: a line per query with its status, rows saved, attempts and error, the limits that were reached, and the billable events counted.

### Tips

- Big brands run thousands of ads. Use **Max ads per query** plus the **country** and **date** filters to keep runs focused.
- Brand names can match several advertiser accounts (brands often have one per country). Raise **Advertisers per name** to scrape more than the best match, or use the domain or advertiser ID for an exact target.
- Searching by **domain** returns ads from every advertiser that points to that site, including resellers and affiliates.
- For a prospect list, run Advertisers mode first, then feed the `advertiserId` values you care about back in as **Advertiser IDs** to pull their ads.

### FAQ

**Is scraping the Ads Transparency Center legal?**
The Transparency Center is a public site Google built so anyone can see who is advertising. This scraper collects only that public ad data and no personal information. Check that your own use complies with the laws and terms that apply to you.

**Does it need a proxy?**
No. If Google rate-limits a run, the scraper switches to Apify Proxy automatically (datacenter first, then residential), and replaces any proxy IP that stops answering.

**Why is the ad copy empty for some text ads?**
Google keeps some text ads only as a screenshot (`adCopyStatus` is `image-only`). The text is then not available as text anywhere in the Transparency Center, and this scraper does not guess it or read it from the picture. The screenshot link is in `imageUrl`.

**Something broke or you need a field?**
Open an issue on the Issues tab with the input you used. Turn on **Include raw data** to see everything Google returns for an ad.

# Actor input Schema

## `queries` (type: `array`):

One per line. Accepts an advertiser name (e.g. <code>Nike</code>), an advertiser ID (<code>AR16735076323512287233</code>), a website domain (<code>nike.com</code>), or any adstransparency.google.com advertiser, domain or creative URL. A creative URL (<code>.../advertiser/AR.../creative/CR...</code>) fetches just that ad, with details.

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

Optional. Website domains to search, one per line (e.g. <code>nike.com</code>). Same as putting them in the first list; handy when your domains come from another system.

## `advertiserIds` (type: `array`):

Optional. Advertiser IDs to scrape directly, one per line (<code>AR</code> followed by digits). The most exact way to target one advertiser.

## `startUrls` (type: `array`):

Optional. adstransparency.google.com links: an advertiser page, a domain search page, or a single creative page (<code>.../advertiser/AR.../creative/CR...</code>, which fetches just that ad with details). You can also add a link to a .txt or .csv file with one query per line.

## `urlsFromFile` (type: `string`):

Optional. Paste a list of names, domains, IDs or URLs (one per line), or paste one link to a public .txt or .csv file. For a CSV the first column is used and a header row is skipped. Private files and Google Sheets that need a login are not supported; publish the sheet as CSV and paste that link.

## `resultType` (type: `string`):

Ads returns every ad creative. Advertisers returns one summary row per matched advertiser with its country, approximate ad count and Transparency Center link, which is the fast way to build a list of companies that advertise on Google.

## `maxAdsPerQuery` (type: `integer`):

Stop after this many ads for each query (default 100). Big brands run tens of thousands of ads. With "Only new ads" on, this limits the new ads returned. Tested up to 10,000 ads per query (a 10,000-ad run takes about 18 minutes); larger values run but are not covered by our reliability tests. The run log and status message say when this limit ended a query.

## `maxAdvertisersPerQuery` (type: `integer`):

Advertisers mode only. How many matching advertisers to return for each query (default 10). A brand name often matches several advertiser accounts (one per country or subsidiary). For a domain query, advertisers are collected from the first 200 ads of that domain.

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

Only ads shown in this country.

## `format` (type: `string`):

Only ads in this format. Text ads are Google Search ads, archived by Google as screenshots.

## `platforms` (type: `array`):

Only ads shown on these Google platforms. Leave empty for all platforms.

## `dateFrom` (type: `string`):

YYYY-MM-DD

## `dateTo` (type: `string`):

YYYY-MM-DD

## `includeDetails` (type: `boolean`):

Adds the countries each ad ran in (with the last date shown there) and every creative variation. Costs one extra event per ad, only for ads where details were returned. A query stops after 3 refused detail requests in a row; its ads are then saved without details and without the details charge. Runs in parallel while Apify Proxy is carrying the run.

## `includeAdCopy` (type: `boolean`):

Reads the ad text Google serves with each ad: headline, long headline, description, call to action, display URL, destination URL and business name. It also fetches the ad details, so each ad is charged the details event (no other event is added). Video and display ads usually carry copy; a text ad that Google archived only as a picture has none, so its copy fields stay empty and adCopyStatus says "image-only". Nothing is guessed and no pictures are read. Ads only; ignored in advertisers mode.

## `detailConcurrency` (type: `integer`):

How many ad detail lookups run in parallel. Only used while a proxy is active (Apify Proxy switches on by itself if Google rate-limits the run); on a direct connection details are fetched one at a time to avoid blocks.

## `includeRawData` (type: `boolean`):

Adds Google's unprocessed creative array as <code>rawData</code> on every ad (and <code>rawDetails</code> when details are on). Useful if you need a field this Actor does not parse yet.

## `onlyNewAds` (type: `boolean`):

Remembers the ad IDs each query has already returned and gives you only new ones, so a scheduled run is an alert feed. The first run saves every ad it finds and seeds the history. Ads skipped as already seen are never charged. Google does not promise newest-first order, so each query looks through at most the larger of 5,000 ads or twice "Max ads per query"; add a "Shown on or after" date to keep runs short.

## `monitorStoreName` (type: `string`):

Name of the key-value store that holds the history for monitor mode (letters, digits and hyphens, 3 to 63 characters). Each query keeps its own record. Use a different name to keep separate monitors apart.

## `advertisersPerName` (type: `integer`):

When a query is a name, how many matching advertiser accounts to scrape (brands often have one per country). Only the first 5 matching accounts are tried, and the run stops looking once this many have ads.

## `proxyConfiguration` (type: `object`):

Not needed normally. Apify Proxy switches on automatically if Google rate-limits the run (datacenter first, then residential). A proxy you choose here is used for every request, retried on a fresh IP when it fails, and never changed.

## Actor input object example

```json
{
  "queries": [
    "nike.com"
  ],
  "resultType": "ads",
  "maxAdsPerQuery": 50,
  "maxAdvertisersPerQuery": 10,
  "region": "ANY",
  "format": "ALL",
  "includeDetails": false,
  "includeAdCopy": false,
  "detailConcurrency": 4,
  "includeRawData": false,
  "onlyNewAds": false,
  "monitorStoreName": "ads-transparency-monitor",
  "advertisersPerName": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per ad creative with images, format and first/last shown dates; or one row per advertiser in advertisers mode.

## `summary` (type: `string`):

The OUTPUT record: how the run ended (ok, partial, failed or stopped), the final status message, a count and error for every target, the limits that were reached, and the billable events counted.

# 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 = {
    "queries": [
        "nike.com"
    ],
    "maxAdsPerQuery": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("silentsuperpower/google-ads-transparency-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 = {
    "queries": ["nike.com"],
    "maxAdsPerQuery": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("silentsuperpower/google-ads-transparency-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 '{
  "queries": [
    "nike.com"
  ],
  "maxAdsPerQuery": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call silentsuperpower/google-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,silentsuperpower/google-ads-transparency-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/Kag2CtmJ8b5jwXfIP/builds/ZitFccgrPRyWvEvmr/openapi.json
