Skip to content

feat(webapp): add SSR cross-links for tag and source pages#5685

Merged
nimrodkra merged 5 commits intomainfrom
seo/pr3-cross-linking
Mar 9, 2026
Merged

feat(webapp): add SSR cross-links for tag and source pages#5685
nimrodkra merged 5 commits intomainfrom
seo/pr3-cross-linking

Conversation

@nimrodkra
Copy link
Member

@nimrodkra nimrodkra commented Mar 9, 2026

Summary

  • add server-rendered hidden links for recommended tags on tag detail pages
  • prefetch related tags and top source posts in source getStaticProps
  • render source related-tag and top-post sr-only links in SSR HTML for crawler discoverability

Why this matters

These SSR links create crawl paths that search engines can discover without relying on client-side rendering. That directly addresses orphaned tag/source surfaces and should improve indexation depth over time.

Test plan

  • pnpm --filter webapp lint
  • pnpm --filter webapp build (fails locally due DNS lookup for api.local.fylla.dev during prerender in this environment)

Made with Cursor

Preview domain

https://seo-pr3-cross-linking.preview.app.daily.dev

Expose related tag and top post links in server-rendered HTML so crawlers can discover tag and source-adjacent pages without relying on client-side fetches.

Made-with: Cursor
@vercel
Copy link

vercel bot commented Mar 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Mar 9, 2026 2:59pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Mar 9, 2026 2:59pm

Request Review

@nimrodkra
Copy link
Member Author

@claude please rview this pr

@claude
Copy link
Contributor

claude bot commented Mar 9, 2026

Claude finished @nimrodkra's task in 1m 43s —— View job


PR Review: feat(webapp): add SSR cross-links for tag and source pages

  • Gather context and read changed files
  • Analyze code for bugs, best practices, and issues
  • Post review feedback

Overall: The approach is sound — prefetching cross-link data in getStaticProps and rendering them as sr-only HTML gives crawlers something to follow without affecting the visual layout. A few issues worth addressing below.


Issues

1. Heavy query used for source top posts [sources/[source].tsx:345-351]

SOURCE_FEED_QUERY is a full feed query that fetches the entire FeedPostConnection fragment (includes contentHtml, pinnedAt, author/source info, engagement counts, etc.). Only id, title, and slug are needed for the cross-links.

The tag page uses the much lighter TAG_TOP_POSTS_QUERY which only fetches those three fields. A parallel query should exist (or be added) for source top posts. Using the full feed query here wastes bandwidth on every ISR revalidation and increases latency.

Fix this →

2. ranking: 'TIME' doesn't give top posts [sources/[source].tsx:349]

The query uses ranking: 'TIME' which returns most recent posts, not top/most popular ones. For SEO cross-links, popular posts (like how TAG_TOP_POSTS_QUERY uses ranking: POPULARITY) are better candidates since they're more likely to have been indexed and carry PageRank.

// current - fetches most recent, not top posts
ranking: 'TIME',

// should be
ranking: 'POPULARITY',

3. Duplicate type definitions [sources/[source].tsx:73-85]

SourceTopPost and SourceTopPostsData are structurally identical to TagTopPost and TagTopPostsData in tags/[tag].tsx. Per the CLAUDE.md guidelines on avoiding code duplication, these should be extracted to a shared location.

4. sr-only links placed inside <PageInfoHeader> (accessibility concern) [sources/[source].tsx:208-232]

Hiding links inside an otherwise visible header component can confuse assistive technologies — screen readers will read these links as part of the header content. While sr-only links for crawlability are an accepted SEO technique, they're typically placed at the end of the page or in a dedicated landmark, not inside a header. Consider moving them to the bottom of FeedPageLayoutComponent before </FeedPageLayoutComponent>.

5. Aggressive revalidation with added latency [sources/[source].tsx:373]

revalidate: 60 (1 min) now triggers 3 API calls in parallel. The tag page uses revalidate: 3600 (1 hour). Cross-link data doesn't change frequently enough to justify a 1-minute ISR cycle with 3 network calls. Consider aligning with the tag page's 3600 or at minimum 600.


Minor Notes

  • SourceRelatedTags hydration pattern (lines 88-111) — Passing initialTags for SSR hydration and using it as the fallback while the client query loads is clean. Nice improvement.
  • Error handling.catch(() => null) on both parallel fetches is correct; failures don't block the page render.
  • Tag page change is minimal — The tags/[tag].tsx diff is simply adding the sr-only recommended-tags block, which is clean and consistent with the existing topPosts sr-only block pattern above it.
    | Branch

Use a lightweight source top-posts query with popularity ranking, reuse shared top-post types across tag and source pages, move hidden crawl links out of the header, and relax source page ISR to hourly revalidation.

Made-with: Cursor
Resolve PR 5685 merge conflicts by keeping both the main-branch source SEO/JSON-LD updates and the PR's SSR cross-linking/top-post prefetch changes.

Made-with: Cursor
Replace stale TagTopPost reference with shared TopPost type so the webapp build passes after the cross-linking merge resolution.

Made-with: Cursor
@nimrodkra nimrodkra merged commit e9a209d into main Mar 9, 2026
11 checks passed
@nimrodkra nimrodkra deleted the seo/pr3-cross-linking branch March 9, 2026 15:00
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.

1 participant