# Changelog of SiteVerdict — Consent Mode v2 & Tracking Auditor (`siteverdict/siteverdict-tracking-consent-auditor`) Actor

- **URL**: https://apify.com/siteverdict/siteverdict-tracking-consent-auditor/changelog.md
- **Full Actor documentation**: https://apify.com/siteverdict/siteverdict-tracking-consent-auditor.md

## Changelog

### 2.0.4 (2026-10-16) — Proxy input security

- **Security: proxy input.** Only the proxy settings the input form offers are accepted: Apify Proxy, or custom proxy URLs starting with `http://` or `https://`. Other proxy options (for example `tieredProxyUrls`) and SOCKS proxies are refused before anything is loaded, with a clear message; nothing is charged. Previously a proxy given as `tieredProxyUrls` skipped the private-network check.
- **Security: https proxies.** A custom `https://` proxy is now connected to over TLS (certificate checked, default port 443), so your proxy password is never sent in clear text.
- Only Apify's own proxy host is trusted without a check (was: any `*.apify.com` name). Redirects followed by the built-in HTTP client no longer carry credentials to another site.
- No change to outputs or pricing.

### 2.0.3 (2026-10-16) — Private-network (SSRF) protection

- Start URLs, redirects, meta refreshes, script navigations, sub-resources and alert webhooks are checked against private, loopback, link-local, cloud-metadata and internal destinations in every IP encoding; names are resolved once and the checked address is the one connected to (local DNS-pinned checking proxy for Chromium; request interception when a customer proxy is used; custom proxy URLs must be public hosts).
- Refused start URLs are skipped and never charged (`refused: private-network protection; not charged`); a site that redirects to a private address gets a `blocked` row (not charged). The summary reports `sitesRefused` and `privateRequestsBlocked`.
- A custom proxy is connected to at the address that was checked, so its name cannot be switched to a private address mid-run.
- No change to scoring, output fields or pricing.

### 2.0.0 (2026-10-11) - accuracy + evidence release

**Accuracy (false-positive fixes found on a 25-site UK/EU benchmark):**

- **Reject/Accept read-back.** After every click the Actor reads the consent state the CMP actually stored, from these sources:
  - OneTrust (group names, so custom IDs work), Cookiebot, CookieYes, Didomi, Usercentrics, Osano, TrustArc, iubenda, Complianz and Transcend;
  - IAB TCF strings and the Google CMP;
  - GOV.UK / NHS-style JSON cookies;
  - the Google Consent Mode state.
- **Confidence on every finding.** Each finding now carries `confidence`, derived from the read-back:
  - "after Reject" findings are `high` only when the rejection is confirmed;
  - if the consent tool recorded the opposite of the click, the finding becomes a "check manually" item;
  - `confidence: low` findings are never scored.
- **Wrong-click guards.**
  - Never clicks "MORE OPTIONS" as Reject (Quantcast/InMobi) or "Accept only essential" as Accept.
  - Ignores accordion headers in preference centres, e.g. "Strictly Necessary Cookies".
  - The banner context must be a banner-sized container, not the whole page.
- **Late banners.** The Actor waits up to `bannerWaitSecs` (default 6 s) before concluding there is no banner, so lazy CMPs no longer cause false "tracking without a banner" results.
- **Closed shadow DOM banners** (for example Transcend) are found and clicked through the Chrome DevTools protocol.
- **Consent-or-pay** is detected when a "Pay to remove ads" / "Subscribe" option sits next to Accept in the banner.
- **Bot-protection and access-denied pages** are reported as `status: "blocked"`. They are not scored and not charged. Previously they could show a misleading clean score.
- **What counts as data sent.** Library downloads alone no longer count; this covers session-replay scripts, Bing UET `.js`, DotMetrics `door.js` and GPT dictionaries. These are not data sent:
  - Microsoft UET `asc=D` pings;
  - Google `npa=1` / `ltd=1` "limited ads" requests, which now get their own low-severity finding;
  - beacons already in flight within 400 ms of the click.
- **Cookie classifier.** Generic names (uid, UID, SM, MR, sb, CLID, bcookie…) are only matched on the vendor's own domain. Google `AEC` / `SOCS` / `CONSENT` are treated as necessary. YouTube `YSC` is treated as functional.
- **GA4 duplicate `page_view`** is now counted per page **and** per consent phase, because a cookieless ping followed by a consented hit is not a duplicate.
- **Severity of transient errors.** Broken-tag findings come only from real script downloads, and 5xx responses are treated as transient (low). One-off network failures are low severity.

**New features:**

- **Google Consent Mode v2 checklist** with pass/fail per check:
  - v2 parameters;
  - default set before the first hit (from `gcd` letters);
  - `dataLayer` order;
  - default denied;
  - Reject keeps denied;
  - Accept grants;
  - Accept grants `ad_user_data` and `ad_personalization`.
- **Evidence pack** (`evidencePack`, on by default):
  - a client-ready HTML + PDF report, with white-label agency/client name;
  - screenshots before any choice, after Reject and after Accept;
  - a timestamped, redacted request log (CSV + JSON) with each request's offset from the click;
  - CMP-specific fix steps.
- **Monitoring mode:** snapshots in a named key-value store, a diff against the last run (new trackers before consent or after Reject, new/resolved issues, CMP or Consent Mode change), and an `onlyChanged` output option.
- **Alerts** to Slack or any HTTPS webhook, sent as one digest per run. Secret inputs, public HTTPS only.
- **AI fix plan** using the user's own Anthropic or OpenAI key (off by default). It drafts exact CMP/GTM changes, a Consent Mode snippet and cookie-policy wording, and sends only the audit summary.
- **New CMPs:** Google CMP (Privacy & messaging), Transcend. Quantcast is updated to InMobi Choice. Selectors are updated for Usercentrics v3, Termly, TrustArc, CookieYes and iubenda.
- **New pay-per-event events:** `evidence-pack`, `ai-fix-generated`, `alert-sent`. All are charged only when delivered.
- **Tests:** 50 unit tests, plus 32 browser tests that run the real scenario engine against synthetic banners for 12 CMPs plus edge cases (second layer, consent-or-pay, late banner, closed shadow DOM).

### 1.0.0 (2026-10-11)

First public release.

- **Three-scenario audit** in real Chrome: no interaction, Reject and Accept all. Reject also works through the second layer (settings, then reject or save).
- **Cookie banner detection** for 20+ consent platforms, plus custom banners matched by button text in about 10 languages. Consent-or-pay banners are recognised and not clicked.
- **Tag inventory** for 50+ vendors, including GTM, GA4, Google Ads, Floodlight, Meta, TikTok, LinkedIn, Microsoft UET, Hotjar and Clarity.
- **Google Consent Mode v2** decoding of `gcs` and `gcd`, with default, after-reject and after-accept state, v1 vs v2, and basic vs advanced.
- **Findings with severity, a plain-English fix and evidence:**
  - tags before consent and after reject
  - tracking cookies
  - broken tag libraries (4xx/5xx)
  - duplicate libraries and duplicate GA4 `page_view`s
  - missing `page_view`
  - legacy Universal Analytics
  - multiple GA4 properties or GTM containers
  - IAB TCF detection
- **Outputs:**
  - scores and grade
  - a first-visit screenshot
  - an HTML report (`REPORT`)
  - a JSON summary (`SUMMARY`)
  - an optional redacted raw capture
- **Pay-per-event charging:** `site-audited`, `quick-scan` and `extra-page-audited`. Respects the run's maximum total charge.
