Skip to content

feat(seo): add visible wallet evaluation methodology on find-wallet#18025

Merged
wackerow merged 8 commits into
ethereum:devfrom
konopkja:fix/find-wallet-methodology-seo
Apr 30, 2026
Merged

feat(seo): add visible wallet evaluation methodology on find-wallet#18025
wackerow merged 8 commits into
ethereum:devfrom
konopkja:fix/find-wallet-methodology-seo

Conversation

@konopkja
Copy link
Copy Markdown
Contributor

@konopkja konopkja commented Apr 23, 2026

Summary

Adds a visible "How we evaluate wallets" section at the bottom of /wallets/find-wallet/ so Google, AI crawlers, and readers can see the editorial methodology ethereum.org already applies to the wallet directory.

Motivation

/wallets/find-wallet/ is a YMYL (Your Money Your Life) finance page with ~35–40k monthly visits. The methodology behind the listing (8 must-have criteria, 6-month re-verification, core-team UX review) exists at /contributing/adding-wallets/ but was completely absent from the wallet-finder page itself. Google's December 2025 core update specifically rewards YMYL comparison pages that surface evaluation methodology, attribution, and verification dates — this PR addresses that gap.

Note: this does not fix issue #17717 (ssr: false hides the wallet table from bots). That's a separate, larger fix. This PR ensures that even while the product table remains client-rendered, the editorial trust signals are in the server HTML.

What's visible by default

  • H2 "How we evaluate wallets"
  • One-paragraph intro describing who reviews listings and what the criteria cover
  • Link to the full listing criteria at /contributing/adding-wallets/
  • Attribution: "Curated by the ethereum.org editorial team."
  • "Most recent listing update: {date}" — computed server-side as the max last_updated across wallet-data.ts

What's inside the collapsible panel

  • The 8 must-have criteria (security, 6+ month track record, active maintenance, accurate info, contact, EIP-1559, reviewable UX, Ethereum-focused) — condensed plain-language versions of the official criteria in /contributing/adding-wallets/
  • 6-month re-submission and removal policy
  • Short explanation of what the page's filter toggles represent
  • Existing (previously orphaned) footnote-1 / footnote-2 translation keys used as the final disclaimer

Why a custom CollapsibleCard instead of the existing ExpandableCard

This was the key decision and I want to flag it clearly.

The existing ExpandableCard (used by NetworkMaturity on /layer-2/networks/) wraps Radix AccordionPrimitive.Content without forceMount. By default Radix unmounts the content element when the accordion is closed — the markup disappears from the DOM entirely. I verified this against production:

curl -sL "https://ethereum.org/layer-2/networks/" | grep -i "network maturity"
# returns nothing — the collapsed content is absent from initial HTML

That means Googlebot, GPTBot, ClaudeBot, and PerplexityBot receive none of the collapsed content. For an E-E-A-T fix where the entire goal is to surface methodology to crawlers, reusing that component would actively defeat the PR's purpose.

This PR ships a small, focused CollapsibleCard component that:

  1. Always renders the content in the DOM (visible to crawlers regardless of collapsed state), toggling only the hidden attribute via React state
  2. Avoids Radix's forceMount entirely — I tried it first and the height-based animation keyframes race with the hidden attribute on initial mount, causing the panel to flash open on page load
  3. Retains accessibility: button uses aria-expanded and aria-controls, panel uses hidden (which the accessibility tree respects)
  4. No JS outside the component itself — zero shared-state risk

Verified via curl against the dev build that all collapsed content (every criterion bullet, the verification paragraph, the filter explanation, and disclaimers) is present in the initial server HTML.

Follow-up worth considering: ExpandableCard / NetworkMaturity likely have the same SEO hole. A separate PR could add forceMount + proper height transitions there.

Test plan

  • Visit /wallets/find-wallet/ — scroll to bottom, confirm the methodology section renders
  • Click "See listing criteria and policies" — confirm the card expands cleanly with no flicker
  • Click again — confirm it collapses
  • View source (or curl -sL) — confirm every criterion, verification paragraph, filter paragraph, and disclaimer is present in the HTML even when the card is collapsed
  • Confirm the "Most recent listing update" date matches the most recent last_updated in wallet-data.ts
  • Confirm the existing wallet product table and filters still work as before (nothing on the new section touches the client-rendered table)

Files changed

  • app/[locale]/wallets/find-wallet/page.tsx — adds the section render + computes most recent last_updated
  • src/components/FindWalletProductTable/WalletListingMethodology.tsx — the server component for the section
  • src/components/FindWalletProductTable/CollapsibleCard.tsx — SEO-safe collapsible (new, scoped to this feature)
  • src/intl/en/page-wallets-find-wallet.json — new translation keys (only the en locale in this PR; Crowdin will pick up the rest)

Preview link

https://deploy-preview-18025.ethereum.it/wallets/find-wallet

Related issue

Surfaces listing criteria, attribution, verification policy, and most
recent listing update directly on /wallets/find-wallet/ so Google and
AI crawlers receive the E-E-A-T signals this page has been lacking.

Closes ethereum#17720
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 23, 2026

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit df5068b
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/69f3690d73b5ab0008d4e4f7
😎 Deploy Preview https://deploy-preview-18025.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 71 (🟢 up 17 from production)
Accessibility: 93 (no change from production)
Best Practices: 100 (no change from production)
SEO: 98 (🔴 down 1 from production)
PWA: 59 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added content 🖋️ This involves copy additions or edits translation 🌍 This is related to our Translation Program labels Apr 23, 2026
myelinated-wackerow and others added 5 commits April 28, 2026 21:15
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
- CollapsibleCard and WalletListingMethodology replaced with usage of ExpandableCard inside new reusable/generalized ListingMethodology component
- Removes strings dedicated to component-listing-methodology.json namespace from page-wallets-find-wallet.json

Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@github-actions github-actions Bot added the tooling 🔧 Changes related to tooling of the project label Apr 29, 2026
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@myelinated-wackerow
Copy link
Copy Markdown
Collaborator

Refactor review

The first commit on this branch explicitly flagged this as worth doing later:

Follow-up worth considering: ExpandableCard / NetworkMaturity likely have the same SEO hole. A separate PR could add forceMount + proper height transitions there.

This refactor takes that follow-up rather than landing the bespoke CollapsibleCard, since ExpandableCard already had the right shape — only forceMount plumbing and a closed-state CSS workaround were missing.

Original PR vs this refactor

Concern Original PR This refactor Verdict
Methodology text in initial HTML ✅ via bespoke hidden attribute toggle ✅ via forceMount + [[data-state=closed]_&]:hidden Equivalent SEO
Methodology text in post-hydration DOM ✅ never unmounted ✅ never unmounted Equivalent
Component reuse ❌ added a new bespoke CollapsibleCard ✅ reuses ExpandableCard, generalizes ListingMethodology Better
Open/close animation ❌ no animation, snap toggle ✅ Radix accordion-up / -down slide Better
Matomo tracking on expand ❌ none ✅ inherits trackCustomEvent from ExpandableCard Better
ARIA on the trigger ✅ manual aria-expanded / aria-controls / useId ✅ Radix manages everything Equivalent
Translation key cleanup Added 7 generic UI keys to a page-specific namespace Moved generic labels to component-listing-methodology.json Better (reusable)
Attribution semantics <p><strong>...</strong></p> <p><strong>...</strong></p> Equivalent (<strong> preserved for E-E-A-T signal)
Other ExpandableCard consumers (NetworkMaturity, MdComponents → staking, gas, layer-2, roadmap, etc.) n/a forceMount defaults to undefined, conditional class doesn't apply No regression

On the "forceMount causes flash" concern from the original PR

I tried it first and the height-based animation keyframes race with the hidden attribute on initial mount, causing the panel to flash open on page load

That happens when forceMount is set without visually hiding the closed-state content — Radix's accordion-up / -down keyframes return the element to its default (auto) height after the animation finishes, so a closed-but-mounted panel sits at full height after first paint. The fix is [[data-state=closed]_&]:hidden [[data-state=closed]_&]:h-0 on the inner div: display: none at server-render time means there's nothing to animate on initial mount → no flash. Verified with both pnpm dev and pnpm build && pnpm start.

SEO parity verified

curl -sL on the local build returns, in the body HTML (not just the RSC Flight payload or next-intl messages JSON):

  • ✅ "How we evaluate wallets" heading
  • ✅ All 8 must-have criteria as real <li> elements
  • ✅ Verification-policy paragraph
  • ✅ Filter-explanation paragraph
  • ✅ Both footnotes
  • ✅ Attribution + last-update date

Post-hydration check (DevTools → Elements) shows the same content in real divs before the trigger is clicked.

Anchor ID change

Section ID is now id="listing-methodology" (was id="how-we-evaluate-wallets"). The component is generic now, and the URL stem (/wallets/find-wallet/) already disambiguates the topic. Anyone landing on #listing-methodology from a future reuse of the component (e.g. /dapps/find-app/) gets the right behavior without per-page renaming. No inbound links to the previous fragment since the section is new in this PR.

Latent footgun for future consumers

id="listing-methodology" and id="methodology-heading" (used by aria-labelledby) are static. Two instances on one page would produce duplicate IDs. Not a problem today; worth a useId() swap on the heading and a prop-overridable section ID if the component ever fans out. Leaving as-is — YAGNI.


Net: same SEO outcome as the original CollapsibleCard approach, fewer files, more reuse, smoother UX, free analytics. NetworkMaturity and any other future ExpandableCard consumer gains the same SEO escape hatch without code changes.

Review by Claude Opus 4.7

@wackerow wackerow added the feature ✨ This is enhancing something existing or creating something new label Apr 29, 2026
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@wackerow wackerow merged commit bd4fc9a into ethereum:dev Apr 30, 2026
9 of 10 checks passed
@wackerow wackerow mentioned this pull request May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content 🖋️ This involves copy additions or edits feature ✨ This is enhancing something existing or creating something new tooling 🔧 Changes related to tooling of the project translation 🌍 This is related to our Translation Program

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(seo): Surface wallet evaluation methodology on /wallets/find-wallet/ for E-E-A-T signals

3 participants