SERP overlay implementation handoff
Compare the designs, then use the design specifications and technical fixes below to implement the changes.
Legacy version
3.13.5Explore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.
Original styling; result number outside the bar.
Final Design
Implementation targetExplore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.
Implementation target.
Current version
Package 4.1.2Explore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.
Current styling reference.
Current → Final Design
Light-mode presentation changes only; preserve existing data, settings, loading/error behavior, metric and utility links, and tracking.
| Area | Current · 4.1.2 | Final Design · specification |
|---|---|---|
| Typography | 13px controls; 14px position. | 12px Inter (Arial / sans-serif fallback) throughout. Labels 400; values and #3 600. Control line height 20px; #3 22px. Tabular, lining numerals. |
| Strip | Padding 2px 7px; square corners; margins 4px 0 6px. | Width 100%; padding 4px 7px; radius 3px; no outer margin, border or shadow. #3 stays outside the wrapping flow, with a 7px gap. |
| Control spacing | 8px padding; 6px internal gap. | Padding 1px 0; internal gap 4px; radius 3px; min-height 24px. Metric text baseline-aligned; icons vertically centered. |
| Wrapping | Controls wrap independently. | Flow gap 0px vertically / 9px horizontally. Keep PIN, whois and source together with 10px gaps. Labels and values do not wrap internally. Height follows content: 32px for one row, 56px for two; more rows allowed. |
| Labels and order | Short labels without colons. | Keep order: #3 → Rank: → Traffic: → Costs: → L: → LD: → LRD: → PIN: → whois → source. PIN remains non-clickable. |
| Icons | Existing Semrush, Pinterest and utility icons. | Six Semrush icons plus Pinterest: 16 × 16px. Utility icons: 12 × 12px. Keep icon identities; no extra standalone logo. |
| Colors | Existing gray strip and controls. | Strip #F0F1F2; values #181E15; labels and Semrush/Pinterest icons #60636B; utilities #5C6269; #3 #696D76; interactive green #11AA88. |
| Hover and focus | Metric icon and label highlight. | Linked metric: highlight only the value; label and provider icon stay gray. Value focus outline: 2px green, 2px offset, 1px radius. Whois/Source: highlight icon and label; focus outline 2px #7137AD, 2px offset. No filled hover background. |
| Transitions | Existing control transitions. | Color / background-color: 120ms; disable for reduced motion. No entry animation or moving metrics. |
| New behavior | No Analyze link; definitions hidden in the SERP specimen. | Add Analyze and definitions as specified below. |
Known issue: approved interaction colors have unresolved contrast concerns; this is not an accessibility sign-off.
Analyze CTA
- Fit: measure rendered widths after fonts load; recheck on resize, item-size and content changes, including selected parameters. Use the 9px flow gaps; the utility group counts as one item. No fixed viewport breakpoint.
- Position: absolute, 7px from the right edge, vertically centered. Never reserve space or push metrics onto another row.
- Appearance: text and external-link icon #C190FF; 12px Inter / 20px line height / weight 600; padding 2px 4px; minimum height 24px; 6px gap to a 12px icon. Underline on hover, no filled button. Focus outline: 2px #7137AD with 2px offset.
- Keyboard: hidden means
visibility:hidden, no pointer events,aria-hidden="true"andtabindex="-1"; restore interaction when shown. If it disappears while focused, move focus to a nearby visible control (production safeguard; not implemented in the prototype). - Destination: Domain Overview for the analyzed domain, using the existing URL helper. Open in a new tab with
noopener noreferrer.
Tracking
Use the existing tracking helper with the new Analyze mapping:
utm_source=seoquake
utm_medium=toolbar
utm_campaign=serp_domain_overview
utm_content=serp_cta_analyze
ref=174537735
Definitions and tooltips
Reuse the existing Quick View / full-report copy verbatim:
| Label | Title | Definition |
|---|---|---|
| Rank: | Semrush Rank | A Semrush visibility ranking for the analyzed domain. |
| Traffic: | SE Traffic | Estimated US organic traffic for this domain from Semrush data. |
| Costs: | Traffic Cost | Estimated paid-search equivalent value of this domain's organic traffic. |
| L: | URL Backlinks | Links from other websites pointing to this URL. |
| LD: | Subdomain Backlinks | Total backlinks pointing to tracked subdomains for the analyzed domain. |
| LRD: | Root Domain Backlinks | Total backlinks pointing to the root domain. |
| PIN: | Pinterest Pin Count | Estimated Pinterest pin count for the linked URL. |
| whois | Whois | Ownership lookup helper for the linked domain. |
| source | Page Source | View the page source for the linked URL. |
- Show one tooltip at a time on hover or keyboard focus. PIN retains its hover definition without becoming a link or tab stop.
- Keep open while the trigger or tooltip is hovered, or the trigger is focused; allow 150ms before dismissal after leaving. Escape dismisses immediately.
- Use
role="tooltip"and a uniquearia-describedby; remove native titles. Position outside the strip’s flow so tooltips do not affect wrapping or Analyze visibility.
Tooltip positioning and visual specs
Fixed position, 6px below the trigger or above if needed; clamp to an 8px viewport inset. Max-width 280px, capped at viewport width minus 16px. Padding 10px 12px; radius 6px; white background; 1px #DADDDE border; #181E15 text; 12px / 18px Inter. Title weight 600 with 3px bottom gap. Shadow: 0 3px 12px #0002.
Highlight the value
- On hover and keyboard focus, highlight only the linked metric’s value with its existing theme-specific interaction color; keep the label and provider icon gray. Preserve the visible focus indicator.
- Whois / Source still highlight their icon and label together. Non-link counts and loading states keep their existing behavior.
- Scope shared-component changes to SEObar; leave SERP, Quick View and Full Report unaffected.
Everything else stays unchanged: layout, typography, spacing, hit areas, icons, tooltips, settings, destinations and seobar_* tracking. No Analyze CTA or dark-mode redesign for SEObar.
Technical fixes
Two correctness fixes, separate from the design changes above. Causes verified against the supplied 4.1.2 package and the freshly fetched SERP branch on 11 September 2026 (51b50b5). Recommendations below are implementation guidance, not an implemented or release-tested patch.
1. Destination URL
Required outcome: identify each result by its actual destination, never by an address reconstructed from Google’s displayed breadcrumb.
Confirmed problem: resolveResultUrl() prefers extractCiteUrl() over the title link. Tests with the supplied code collapse distinct /a and /b pages into one domain, or invent /Products/Widget instead of the real /products/detail?id=42 destination.
Implementation guidance
- Use the title anchor already selected by
findHeadingLink(). Parse its non-emptyhrefagainst the document base URL. Remove breadcrumb reconstruction from URL identity; do not fall back to it when a link is missing or invalid. - Unwrap only recognized Google-hosted redirects. For supported
/urllinks, extract a validqorurldestination and validate it again. Do not unwrap a third-party site merely because its path is/url. Keep existing ad and result-eligibility exclusions. - Accept only a resolved, eligible HTTP(S) destination. If a redirect form cannot be resolved safely, skip that URL-dependent overlay/export row; do not send Google’s redirect URL to the metric service. Add a captured fixture before supporting another redirect form such as
/goto. - Use the resolved URL consistently for result identity, CSV URLs and inputs to page-level metrics/report links. Keep domain-level metrics domain-scoped. Preserve the destination’s path and query; do not merge different pages by domain or displayed breadcrumb.
Follow the URL through the shared helpers. normalizeSemrushTarget() currently calls normalizeUrl(), which removes every query parameter. A resolver-only fix therefore does not preserve ?id=42 versus ?id=43 in page-level requests and report targets. Preserve query identity in the page-target path and test its callers, caches and generated requests. Do not globally change the shared normalizer without regression checks. This is an existing shared dependency, not established as a new SERP regression.
QA checklist
Run after implementation. These are checks to cover, not necessarily separate automated tests.
| Test | Required result |
|---|---|
| Different pages, same domain | Links to /a and /b remain distinct even when their displayed breadcrumbs show only the domain. |
| Misleading or absent breadcrumb | The real /products/detail?id=42 link wins over “Products › Widget”. For an otherwise eligible result, an absent cite does not prevent resolving its valid title-link destination. |
| Google redirect and ordinary /url page | Supported Google /url?q=… and /url?url=… links resolve correctly. An external site’s /url?q=… address remains that site’s URL. |
| Invalid or unresolved destination | Missing href, non-HTTP(S), excluded ads and unresolved Google redirects produce no guessed URL or metric request. |
| Meaningful query parameters | ?id=42 and ?id=43 remain distinct in results and CSV, and in page-level request/cache/report targets; domain metrics retain their existing scope. |
Source: URL resolution · detection and deduplication · metric target normalization · shared URL normalizer. Legacy 3.13.5 read the selected result link’s href directly; it did not reconstruct the breadcrumb.
2. Result numbering & exports
Required outcome: overlay positions and CSV rows must come from the same current, page-ordered list of eligible results.
Confirmed problem: added subtrees are scanned and numbered independently, then merged. In the supplied-code test, a fourth result becomes another #1; a whole-page scan gives #4. Removing an overlay’s metric snapshot does not remove its separate export row.
Implementation guidance
- After each relevant debounced mutation batch, run one complete detection pass for the current page and use the replacement path:
replaceSerpExportRows()plussyncSerpOverlays(). Do not merge independently numbered partial scans. - Number accepted, connected results in DOM order using the existing pagination offset. Preserve the current policy of one result per exact resolved URL, keeping its first accepted occurrence; this change does not introduce a new duplicate-card policy.
- Reconcile export membership, mounted overlays and metric snapshots together. Remove departed results and update retained positions. Preserve unchanged result state; do not clear/reload all metrics on every mutation. When a URL’s container or insertion anchor changes, reposition its existing host/root when possible. If remounting is necessary, retain or reuse loaded metric state for the unchanged URL; a connected host alone does not prove correct placement.
- Keep debouncing and the existing generation guards. Cover additions, removals, DOM moves and result-link
hrefchanges; the current observer watches child-list changes only. Filter SEOquake’s own DOM updates to avoid feedback loops. Invalidate obsolete async work on URL/lifecycle resets so old work cannot overwrite the current page. - Before Export reads the store, flush or run the current reconciliation and wait for it to finish. Capture rows, metric snapshots and search-query filename from the same current-page generation. Do not wait for every metric to load: retain existing
n/aversus zero behavior.
QA checklist
Run after implementation. These are checks to cover, not necessarily separate automated tests.
| Test | Required result |
|---|---|
| Append, insert, remove or reorder | Start with three results; append a fourth → #1–#4. Insert above or move/remove a result → positions and CSV follow the new DOM order, with no departed rows. |
| Container replacement or changed href | A retained URL’s overlay follows its current container/anchor. Changing a card’s URL removes the old identity and does not reuse the wrong page’s metrics. |
| Export immediately after a change | Click within the observer’s 400ms debounce window: exported URLs, positions and filename reflect the reconciled current page. |
| Pagination and exact duplicates | start=10 begins at #11. An exact duplicate resolved URL retains the first accepted occurrence; distinct same-domain paths remain separate. |
| Navigation, disable and delayed responses | Old settings/metric responses cannot restore departed results after navigation or teardown. Removing all results empties the list and CSV membership. |
| Stable results and repeated mutations | Position-only changes do not reset loaded metrics or trigger unnecessary refetches. SEOquake’s own updates cause no observer loop or duplicate overlay. |
Source: mutation orchestration · observer · result stores · overlay reconciliation · export action · CSV assembly. File links use the inspected revision; the async, placement and export-timing items are implementation safeguards, not additional reproduced live failures.
Verification boundary: isolated original-code tests reproduce the two causes. The acceptance cases above still require the implemented extension, including mixed Google results and coexistence with other extensions. This handoff is not release approval.