WordPress teams often count GPTBot, ClaudeBot, PerplexityBot, Google-Extended, or other labels from a user-agent string and call it AI visibility. CloudFront logs can show requested pages, response codes, cache outcomes, bytes, timing, IPs, and referrers, but the same label can be spoofed and a successful fetch does not prove citation, ranking, or referral traffic.
Use this for publishers, ecommerce teams, agencies, SEO owners, security teams, and infrastructure analysts serving WordPress through CloudFront or another CDN with queryable access logs.
Quick answer
Query by user-agent family, date, URI, status, cache result, edge location, IP, request rate, bytes, and referrer. Normalize URLs before grouping, exclude static assets from content demand, verify published bot IP or reverse-DNS methods when available, and keep separate metrics for claimed agents, verified agents, successful content fetches, blocked requests, citations, referrals, and conversions.
What to check first
- Confirm CloudFront logging is enabled, fields match the Athena table, timestamps use UTC, partitions are current, retention is appropriate, sensitive query strings are protected, and analysts can reproduce the query window.
- Normalize host, path, trailing slash, percent encoding, query string, locale, pagination, feed, preview, canonical, and static-asset requests before measuring page demand.
- Group claimed AI agents by status, cache result, content type, path, IP, autonomous system, edge location, request interval, bytes, time taken, and suspicious user-agent variants.
- Verify crawler identity using the provider's supported network method where one exists, flag impossible request rates and spoofed labels, and keep unknown automation outside the verified bot total.
- Join successful canonical content fetches to robots policy, sitemap membership, indexability, server errors, referral sessions, assisted conversions, citations, and Search Console trends without implying causation.
Diagnostic table
Use this table to keep the work practical. It connects the symptom to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Validate logs and partitions | Confirm CloudFront logging is enabled, fields match the Athena table, timestamps use UTC, partitions are current, retention is appropriate, sensitive query strings are protected, and analysts can reproduce the query window. | The same query and partition window reproduce the reported totals. |
| Normalize content URLs | Normalize host, path, trailing slash, percent encoding, query string, locale, pagination, feed, preview, canonical, and static-asset requests before measuring page demand. | Canonical content, static assets, duplicate parameters, previews, feeds, and error paths are reported separately. |
| Segment claimed and verified agents | Group claimed AI agents by status, cache result, content type, path, IP, autonomous system, edge location, request interval, bytes, time taken, and suspicious user-agent variants. | Claimed, verified, spoofed, unknown, allowed, blocked, cached, and origin-served requests have distinct counts. |
| Measure status and cache behavior | Verify crawler identity using the provider's supported network method where one exists, flag impossible request rates and spoofed labels, and keep unknown automation outside the verified bot total. | The dashboard never labels a fetch as a citation, referral, lead, or conversion without corresponding evidence. |
Why this usually happens
- Any client can send a famous crawler name in its user-agent header.
- Static files and duplicate URL variants can dominate raw request counts.
- CloudFront status and cache fields can be misread when the distribution uses custom errors or multiple origins.
- Google reports AI feature traffic inside Web search, while third-party crawlers have different controls and reporting.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
SELECT
date, cs_user_agent, sc_status, x_edge_result_type,
regexp_replace(cs_uri_stem, '/+