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).
- 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.
- 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").
- First release: Google Ads Transparency Center — company checks, ad export,
monitoring of new ads.