Skip to content

feat(analytics): split og:image tracking by who fetched the image - #10475

Merged
MarkusNeusinger merged 3 commits into
mainfrom
feat/split-og-image-tracking-by-audience
Aug 18, 2026
Merged

feat(analytics): split og:image tracking by who fetched the image#10475
MarkusNeusinger merged 3 commits into
mainfrom
feat/split-og-image-tracking-by-audience

Conversation

@MarkusNeusinger

Copy link
Copy Markdown
Owner

The change

Fetcher Recorded on Extra props
Twitter, Facebook, Slack, WhatsApp, … anyplot.ai (unchanged)
Googlebot, Claude, ChatGPT, Perplexity, … bots.anyplot.ai assistant, kind

Why now, and not before

A preview fetch means a human shared a link — a product signal that belongs with the human numbers. A crawler fetching the same image is not a share.

That distinction was academic until this release. api.anyplot.ai/robots.txt was a blanket Disallow: / until #10472, so crawlers were never permitted to fetch /og/ at all: every og_image_view came from a link preview, and recording them all on the main site was correct.

Opening /og/ changes it. Crawler fetches of 3,913 preview images arrive in volume, and on the main site they would drown the sharing signal and inflate visitor counts — on the very site whose bot inflation an audit already had to remove once (2026-07-08, High #7, ~40% overcount).

Implementation

The split reuses detect_ai_agent rather than inventing a second classification rule. If it recognises the agent, the fetch is machine-side; machine-side events carry the same assistant and kind props as bot_fetch, so both events slice identically on the bot dashboard. Anything it does not recognise is treated as a share.

Verification

  • pytest tests/unit — 1638 passed, 7 new: four preview agents asserted to stay on the main site without assistant props, and three crawler classes (search / user-directed / training) asserted to land on the bot site with the right pair
  • ruff check + ruff format --check — clean

Dashboard follow-up

Machine-side og_image_view events carry the main site's image properties too, so page, platform, spec, language, library and the filter_* family need registering on bots.anyplot.ai as well — noted in docs/reference/plausible.md. Without registration the events land but cannot be broken down.

🤖 Generated with Claude Code

A social or messenger preview means a human shared a link. That is a
product signal and belongs with the human numbers, so those events stay
on anyplot.ai. A search or AI crawler fetching the same image is not a
share.

The distinction only starts mattering now. robots.txt on api.anyplot.ai
was a blanket Disallow until #10472, so crawlers were never allowed to
fetch /og/ at all — every og_image_view came from a link preview, and
recording them all on the main site was right. Opening /og/ changes that:
crawler fetches of 3,913 preview images would arrive in volume, drown the
sharing signal, and inflate visitor counts on the site whose bot
inflation audit 2026-07-08 already had to remove once.

The split reuses detect_ai_agent rather than inventing a second rule: if
it recognises the agent the fetch is machine-side and goes to
bots.anyplot.ai, carrying the same assistant and kind props as bot_fetch
so both events slice alike. Anything it does not recognise — Twitter,
Facebook, Slack, WhatsApp — is a share and stays put.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 18, 2026 19:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines server-side Plausible analytics so og_image_view events are recorded on different Plausible sites depending on who fetched the preview image: social/messenger link previews stay on anyplot.ai, while recognized AI/search crawlers are routed to bots.anyplot.ai with assistant/kind properties (reusing detect_ai_agent). This keeps human sharing signals from being diluted now that /og/ is crawlable.

Changes:

  • Route og_image_view to BOT_DOMAIN when detect_ai_agent() recognizes the user agent; include assistant and kind props for machine-side events.
  • Add unit tests asserting the domain/props split for representative share-preview bots vs crawlers.
  • Document the new split (and required Plausible property registration) and add a changelog entry.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
api/analytics.py Splits og_image_view tracking between DOMAIN and BOT_DOMAIN using detect_ai_agent, adding assistant/kind props for machine-side fetches.
tests/unit/api/test_analytics.py Adds async unit tests validating the new audience split and ensuring share-preview user agents remain on the main site without bot props.
docs/reference/plausible.md Documents og_image_view audience split and notes additional property registration needed on bots.anyplot.ai.
CHANGELOG.md Adds an [Unreleased] entry describing the new split behavior and rationale.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

MarkusNeusinger and others added 2 commits August 18, 2026 21:16
…racking-by-audience

# Conflicts:
#	CHANGELOG.md
Same convention fix as #10474, applied to this entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 18, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@MarkusNeusinger
MarkusNeusinger merged commit 4709bb5 into main Aug 18, 2026
8 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the feat/split-og-image-tracking-by-audience branch August 18, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants