fix(seo): declare site icons for crawlers and ship favicon.ico - #11838
Merged
Merged
Conversation
Crawlers receive the bot HTML from api/routers/seo.py, whose head had no icon link, and the /favicon.ico fallback returned 404, so Google showed no icon for anyplot.ai. The bot template now mirrors the icon links of app/index.html, and app/public/ ships favicon.ico, apple-touch-icon.png and a square icon-512.png for Organization.logo. The favicon itself is now outlined from MonoLisa Bold by scripts/generate_favicon.py: an SVG favicon loads no webfonts, so the former <text> mark rendered in the system monospace. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Human confirmation of MonoLisa’s brand-use licensing is required before publishing the derived assets.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Adds crawler-visible site icons and updates structured metadata to use the new square logo.
Changes:
- Declares favicon and touch-icon links in browser and crawler HTML.
- Generates favicon assets from outlined branding.
- Documents and tests the SEO behavior.
| File | Description |
|---|---|
tests/unit/api/test_seo_helpers.py |
Tests crawler icon links. |
scripts/generate_favicon.py |
Generates SVG, PNG, and ICO assets. |
docs/reference/style-guide.md |
Documents the revised favicon mark. |
docs/reference/seo.md |
Documents site-icon behavior and assets. |
changelog.d/site-icons.md |
Records the SEO and favicon changes. |
app/public/favicon.svg |
Replaces font text with outlined paths. |
app/index.html |
Adds icon links and updates the organization logo. |
api/routers/seo.py |
Adds crawler icon links and updates structured data. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
api/routers/seo.py, whose<head>declared no icon, and Google's/favicon.icofallback returned 404. The bot template now carries the same three icon links asapp/index.html(absolute URLs), andapp/public/shipsfavicon.ico(16, 32, 48 px),apple-touch-icon.png(180 px) and a squareicon-512.png.Organization.logoinapp/index.htmlandseo.pypoints aticon-512.pnginstead of the 1200×630 banner.<text>mark always rendered in the viewer's system monospace.scripts/generate_favicon.pyoutlines theapmonogram from MonoLisa Bold into plain paths on an opaque paper ground (the transparent icon with dark ink vanished on dark result pages) and rasterizes the ICO and PNG siblings from that one SVG.Plan
scripts/generate_favicon.py: fontTools outlines atwght=700, resvg for the rasters, Pillow for the ICO. Run withuv run --with resvg-py python scripts/generate_favicon.py; outputs are committed.app/index.html,api/routers/seo.py: icon links andOrganization.logo.docs/reference/seo.md; the favicon row ofdocs/reference/style-guide.mdnow describes theapover square mark that is actually shipped (owner's choice over thea.preduction)..icoand.pngand wins over the bot proxy.Test plan
uv run ruff check .,ruff format --check .,mypy api core: cleanuv run pytest tests/unit tests/integration: 2023 passed, 1 skipped; newtest_has_site_icon_linkspins the three links in the bot HTMLyarn lint,yarn fm:check,yarn type-check,yarn test,yarn build: green;dist/contains the four icon files and the three linkscurl -A Googlebot https://anyplot.ai/ | grep 'rel="icon"'finds the links andhttps://anyplot.ai/favicon.icoanswers 200; then request re-indexing of the home page in Search Console (Google refreshes favicons over days to weeks)Not driven through
/verify-frontendor/verify-apiagainst a running stack; the change is static head markup plus files inapp/public/.Licensing note for
/audit-licenses: the new binaries contain only the outlines of two MonoLisa letters, no font data. The MonoLisa licence allows static images but asks for a special licence for "trademark, logo, brand" use, so a favicon is a borderline case the owner is aware of.