# Changelog of Google Ads Transparency, Bing Ads Library – Advertiser Check (`perceptr0n/google-ads-transparency-scraper`) Actor

- **URL**: https://apify.com/perceptr0n/google-ads-transparency-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/perceptr0n/google-ads-transparency-scraper.md

## Changelog

### 0.4 — 18 October 2026

After the platform test of 18 October 2026: a company name is also confirmed
when the ads pointing to the suggested domain come from a verified advertiser
that carries the name but was not among Google's suggestions (douglas.de,
viessmann.de and trumpf.com had stayed `name_only`). An advertiser without the
name is still never proof.

A change report that is aborted – by you, or by Apify at the run's maximum
cost – keeps the state of every company it checked and charged; the other
companies keep their saved state, and the next run compares with that instead
of starting a new baseline.

README and field text say which country's domain a name is confirmed on: with
`region` set, that country's domain is tried first.

Two opt-in options for company checks; without them every run behaves and
looks exactly as in 0.3.

- **Change report** (`list_id`): give a company list a stable ID and run it on
  a schedule. The first run saves every company as the starting point
  (`changeStatus: baseline`); later runs of the same list and region return
  only companies that changed: started or stopped advertising on Google or
  Microsoft (an ad shown in the last 30 days), or a new advertiser account.
  Unchanged companies are charged like any check and left out of the dataset;
  their evidence is in the record `UNCHANGED`. Companies that could not be
  checked are `not_compared` and keep their saved state. State: key-value
  store `google-ads-transparency-monitor`, one record per list and region.
  A restarted run (server move) neither checks nor charges a company twice.
  At most 2,000 companies per run and list.
- **Names to domains** (`resolve_names`): a company name is first resolved to a
  domain that Google confirms — a verified advertiser whose name matches runs
  the ads pointing to it — and then checked as that domain, so Microsoft
  accounts are proven by landing pages. `matchedOn` (`domain`,
  `confirmed_domain`, `name_only`) and `domainResolution` say how each company
  was matched; an unconfirmed domain is never used.

Robustness (night check 15 October 2026, no change to columns or prices):

- Answers that change shape (a number where a name was, a list as the ad
  format, impossible dates) no longer stop an ad export or make a company
  `unavailable`; an advertiser list that cannot be read is never reported as
  "not advertising". One search that fails unexpectedly gets its `query` row
  and goes to `REMAINING`; the export goes on.
- Text from the services is stored without control characters or direction
  overrides; image and landing-page addresses only as `http(s)` (otherwise
  empty).
- Paging that repeats itself stops; answers larger than 20 MB are not read.
- A saved list state or monitoring memory with parts of a foreign shape no
  longer ends the run: the unusable parts are dropped.
- Microsoft refusing every request (HTTP 403/429): the notes say "refused",
  Microsoft is given up after two such requests, and the status message names
  the next step (`platforms: ["google"]`).
- The company's own website (read only for its brand name) is fetched from
  public addresses only, on every redirect and at every connection.

Input and messages for AI agents (15 October 2026, no change to columns,
prices or run status):

- Fields spelled differently (`maxAds`, `Domains`) are read as the schema's
  fields; fields this actor does not have are named in the status message.
- Without domains, company_names and advertiser_ids the example companies run
  as before, but the message starts with "Example companies only" and names
  the ignored fields.
- Several domains or advertiser IDs in one entry ("a.de, b.de") are split
  into one entry each. A company name that is really a list or a website and
  matches no advertiser gets `invalid_input` (not charged) instead of a
  charged "not advertising".
- Ad export: an advertiser ID of a platform that is not selected and a domain
  without a DNS record get an `invalid_input` row instead of a silent
  "0 ads exported".
- When Google gives only the lower bound of its count, `googleAdCountMax` is
  empty and `googleAdCount` reads "10,000+" (before: "10,000–100").
- Stop messages name the cause and one next step: a temporary block or
  failure is "not your input"; the cost limit asks for a new run with a
  higher maximum; HTTP 400 from Microsoft says a new run will not help.
- A maximum cost per run that the last company or ad uses up exactly is not
  reported as reached; the run ends with its normal message. Messages put the
  next step first, say that a run with only the companies under `REMAINING`
  does not charge the finished ones again, and no longer tell to run the same
  input again for companies Microsoft rejected (HTTP 400).
- The Docker build installs the tested package versions (`constraints.txt`).

### 0.3 — 12 October 2026

- **A status in every row** (Row Standard v1): `status` and `reason`, per
  platform `googleStatus` / `microsoftStatus`, `…MatchedOn`, `…Coverage`,
  evidence (`googleSampleAd`, `microsoftSourceUrl`), `schemaVersion`. Only
  `checked_advertising` and `checked_not_advertising` are charged.
- **`isAdvertising` is never "false" without a check**: when a platform
  refuses or fails, it stays empty and the row is `partial` or `unavailable`.
- **Every input gets a row** — also after a platform gave up, at the cost
  limit, for duplicates (`duplicateOf`) and for unusable lines
  (`invalid_input`: no DNS record, IP address, unknown ending, profile pages,
  sites on shared website builders). One bad line no longer stops the run.
- **Google's refusals** ("unusual traffic", HTTP 302 to /sorry): slower pace
  (one request every 2 s), every request pauses 1, 2, 3 and 4 minutes, then
  the run continues more slowly; after 10 minutes the rest is `unavailable`,
  not charged, and listed under `REMAINING`. `RUN_STATS` records the refusals.
- **Microsoft errors are never "no ads"**: HTTP 404, 400 and answers without a
  list now mean `unavailable`. "No ads" on either platform is only reported
  after a known advertiser was found in the same library.
- **Company names**: whole words only ("Ford" no longer matches "Oxford");
  one company is counted, other matching advertisers and other countries'
  accounts are listed with their own counts, never added.
- **Domains**: subdomains are checked on their registrable domain
  (Public Suffix List), internationalised domains (`bücher.de`) work.
- Google: how many of the 100 most recent ads come from the main advertiser
  (`googleMainAdvertiserAdsInSample`); umlaut domains match their advertisers
  (`mueller.de` → Müller).
- Export: a refused search is a `query` row with its status, not "0 ads";
  `ad-details` is charged only when details came back; monitoring no longer
  loses ads at `max_ads` or after a refusal.
- Microsoft-only checks outside the EU/EEA stop with a clear message instead
  of charging unchecked rows.

### 0.2 — 6 October 2026

- **Microsoft Ad Library (Bing)** next to Google: every company row now shows
  whether the company advertises on Google, on Bing, or both.
- Every Microsoft advertiser account is proven by the landing pages of its own
  ads — name lookalikes are listed separately and never counted.
- Google's verified legal name is used to find the Microsoft account when the
  domain has no searchable brand word (e.g. dm.de).
- Bing ad export with headline, description, landing page, images and product
  price; with details on: first and last day shown, reach range, share of
  impressions per country, targeting types and who paid.
- Monitoring (`only_new_ads`) on both platforms.
- New input `platforms` (default: both). Microsoft advertiser IDs are accepted
  in `advertiser_ids`.
- Company columns are now prefixed per platform (`googleAdCount`,
  `microsoftAdCount`, …) with a summary across platforms (`isAdvertising`,
  `advertisingOn`, `activeLast30Days`). Ads have `platform` and `adId`.
- If a platform stops answering, the affected companies are marked and not
  charged; after three in a row the run stops cleanly and lists the companies
  still to do under `REMAINING` in its key-value store.
- Runs that Apify moves to another server no longer deliver or charge anything
  twice.
- Company names with umlauts work on Microsoft ("Parfümerie Douglas").

### 0.1 — 5 October 2026

- First release: Google Ads Transparency Center — company checks, ad export,
  monitoring of new ads.
