Implementation handoff
Download handoff

SEOquake implementation handoff

Open work first, then the approved design reference, completed fixes and earlier builds.

Current status · Updated November 6, 2026

4.3.2 released · 4.3.3 follow-ups

4.3.2 is live. Chrome-6 closes the CTA, Links tooltip and SEObar exclusion cards. AI source panel width is reopened for the hotel layout.

29 completed · 1 open

Open work 1

One layout correction remains for 4.3.3. Completed implementations and their references are below.

Engineering handoff · November 6, 2026

AI source panel width

Keep Analyze sources aligned with the AI answer column Reopened · 4.3.3

Medium priority · Layout gap in chrome-6 · User screenshots confirmed

Hotel query · panel spans the wider layout
Hotel query · panel spans the wider layout. User capture from chrome-6.
Same query · answer text stays narrower
Same query · answer text stays narrower. User capture from chrome-6.
SEO checker · aligned comparison
SEO checker · aligned comparison. User capture from chrome-6.

November 6 captures. Click any image to view full size.

Issue: On “NYX Hotel London Holborn”, Analyze sources stretches across the wider layout instead of matching the narrower AI answer text. “seo checker” aligns correctly, so the earlier width fix does not cover every Google layout.

Fix:

  • In src/utils/serp/google/ai/detect.ts, tighten the column selection returned by detectAiOverview. The packaged selector climbs ancestors until source-card containment stops it; it can select a wider wrapper. Use the visible answer column as the sizing reference and validate the hotel layout’s actual DOM before choosing the correction.
  • In src/utils/serp/google/ai/controller.ts, size and align the panel host to that column’s outer edges. Keep the scoped ResizeObserver, update only changed dimensions and reconnect after Google replaces the column. Do not hard-code 652px or size from the hotel block or right-hand source cards.
  • Keep src/components/serp/AiSources.tsx within the host width. Preserve list height/scrolling, open state, metric wrapping, source links and CSV export. When the column is unavailable, use a viewport-bounded fallback rather than treating a broad wrapper as a verified answer column.

The selector is unchanged from chrome-4. Controlled 652px/500px layouts still pass; the hotel page’s exact selected DOM element has not been inspected live.

Engineering checks
  • Reproduce the hotel query and compare panel edges with the answer text column. Keep “seo checker” and the existing two-column fixture as passing controls; cover layouts with and without visible right-hand source cards.
  • Resize/zoom, expand the answer, toggle Google navigation and change queries. Preserve alignment and open state without duplicate panels, horizontal overflow or repeated layout jumps.
  • Check long URLs, connected metric rows, Analyze and CSV export. Keep light/dark appearance and the separate source-card metric strips unchanged.
Earlier specification and limited-width verification

The earlier closure is superseded by the hotel-layout evidence above. Preserve the passing checks as regression coverage.

Verified November 6 · chrome-4: The panel matches the answer column’s left edge and width at 652px and 500px, retaining its open state after resizing.

Approved design, specification and engineering checks

Low priority · Layout consistency · Implementation not yet verified

Current · Analyze sources list: 758px
Inspector shows the SEOquake AI sources list at 758 pixels wide, extending beyond the answer text column.
Reference · Google AI Overview text column: 652px
Inspector shows the Google AI Overview text column at 652 pixels wide, separate from the right-hand source cards.

Issue: The expanded Analyze sources panel extends beyond Google’s AI Overview text column. In this capture, our list is 758px wide while the answer column is 652px, leaving their right edges misaligned.

Fix:

  • In src/components/serp/AiSources.tsx, replace the independent max-w-190 sizing on #sq-ai-source-panel with sizing tied to the visible answer text column. Align the panel’s outer left and right edges with that column; do not include Google’s right-hand source cards or hard-code 652px.
  • Use the panel host in src/utils/serp/google/ai/controller.ts and the structure identified by detectAiOverview in ai/detect.ts to establish the correct layout reference. The current next.root.before(panel.host) placement does not guarantee a shared column width. Prefer layout inheritance where possible; otherwise measure the text column and apply its width and alignment to the host. Validate the reference across layouts rather than relying on one generated Google class.
  • If measurement is needed, use a scoped ResizeObserver, update only when dimensions change, and reconnect when Google replaces the answer container. Clean it up through the controller’s removal/disposal path; avoid polling, scroll-time full-page scans or remounting the panel just to resize it. If the column is temporarily unavailable, retain a viewport-bounded fallback until a valid reference returns.
  • Keep the existing list height, vertical scrolling, open/closed state, source links, metrics, Analyze and CSV export. Let header controls and metric rows wrap within the narrower panel without clipping or horizontal overflow. Leave AiSourceCard strips in Google’s source cards unchanged.

Code references were checked in the local source checkout; confirm their current equivalents in the implementation branch. Captured dimensions are evidence, not fixed layout targets. This changes the expanded source panel only; Analyze sources stays attached to the AI Overview.

Engineering checks
  • Compare the panel’s outer edges with the answer text column on layouts with and without right-hand source cards. Test signed-in and Incognito results, light and dark appearance, and AI Overviews before or between organic results.
  • Resize and zoom, expand/collapse Google’s answer, and open/close its left navigation. Keep the width aligned without overlap, horizontal scrolling, repeated layout jumps or duplicate hosts.
  • Change queries and let Google replace the answer. Reattach sizing to the new column, preserve the panel’s existing lifecycle behavior and remove stale observers.
  • Check long titles, URLs and full connected metric rows. Header controls, Analyze links and CSV export remain usable; source-card strips, scrolling and collapse controls remain unchanged.

Completed designs 6

Implemented. See each item’s verification and remaining checks. Still the source of truth for any change to these surfaces.

SERP sidebar

Collapsible sidebar tab

Implemented · 4.2.2

Adds a collapse option to the SERP sidebar. The arrow collapses the panel to a small logo tab, and the logo opens it again. The choice is remembered. The panel is 4px wider so the arrow fits.

States

Design spec

Logic

Terms: Panel = the full sidebar. Tab = the collapsed sidebar.

  1. Arrow: collapses the panel to the tab and saves serp.panelCollapsed: true. It stays collapsed on later searches and reloads. Add panelCollapsed to the SERP settings type, defaults (false) and normalizer: the normalizer only keeps known keys, so without it the choice is silently dropped. Reset to default sets it back to false.
  2. Logo click: opens the panel in the same spot and saves serp.panelCollapsed: false.
  3. Overlay off: if serp.panelCollapsed is true, show the off tab. Its checkbox uses serp.enabled, the same setting as the panel checkbox. Ticking it turns the overlay on. The logo does nothing while the overlay is off.

Accessibility: name the icon-only controls the same way the Parameters button is named today (aria-label and title): tab “Open SEOquake panel”, arrow “Collapse SEOquake panel”, off-tab checkbox “SEOquake”. When a control disappears on collapse, reopen or re-enable, move keyboard focus to the control that replaces it: the tab, the collapse arrow or the colored logo.

Reuse: the SEObar already has this pattern in src/components/seobar/layout/SeobarLogoTab.tsx: a logo button that toggles the bar between expanded and collapsed, with aria-expanded and the same app-icon.svg. Start from it.

Final Design

Implemented · 4.2.0
Apple
https://www.apple.com › iphone

Explore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.

Sep 15: Result position moved into the strip as #3, before Rank; 12px semibold.

SERP implementation

Previous build → Final Design

Implemented · 4.2.0

Approved design reference. Current package and validation evidence are summarized above.

Light-mode changes below only. Preserve data, loading/error behavior, existing settings, links and tracking except the additions specified here.

AreaCurrent · 4.1.2Update
Typography13px controls.12px Inter (Arial / sans-serif fallback); labels 400 / values 600; 20px line height; tabular, lining numerals.
Strip2px 7px padding; square corners; 4px / 6px outer margins.4px 7px padding; 3px radius; no outer margin, border or shadow. Fill the result column; height follows content. 652px is the preview width, not a production fixed width.
Result numberInside the metric strip, at 14px.Keep inside the SEOquake strip, first before Rank, as #3. Use 12px / 20px Inter, weight 600, muted #60636B; non-interactive, no tooltip or tab stop. Accessible label: Search result position 3. Do not insert a number beside Google’s title. Preserve numbering and visibility settings; this changes placement, not calculation.
Control spacing8px padding; 6px internal gap.1px 0 padding; 4px internal gap; 24px minimum height; 3px radius. Metric text baseline-aligned; icons centered.
Flow spacingControls wrap independently.9px horizontal / 0px vertical gap. PIN, whois and source wrap independently. Never split a label/value. Reference heights: 32px for one row, 56px for two; allow more rows.
Labels and orderShort labels without colons.#position → Rank: → Traffic: → Costs: → L: → LD: → LRD: → PIN: → whois → source. PIN stays non-clickable. Analyze uses spare space on the last row.
Icon sizingExisting provider and utility icons.Six Semrush icons + Pinterest: 16 × 16px. Whois/Source: 12 × 12px. Keep icon identities; no additional standalone logo.
ColorsExisting gray strip and controls; #11AA88 interaction accent.Values #181E15; labels and Semrush/Pinterest icons #60636B; utilities #5C6269. Interactive green #00785F. Keep strip #F0F1F2.
Hover / focusMetric label and icon highlight.Highlight the linked value only; label/icon stay gray. Value focus: 2px green outline, 2px offset, 1px radius. Whois/Source highlight together; focus outline 2px #7137AD, offset 2px. No filled hover background.
Transitions150ms control transitions in the supplied package reference.120ms color/background-color transitions; disable for reduced motion. No entry animation or moving metrics.
New behaviorNo Analyze link; definitions hidden in the SERP specimen.Add Analyze, tooltips and the Show tooltips preference, as specified below.

Analyze CTA

Show only when the last row has room for Analyze + 16px clearance.
Live example · Five Semrush metrics selected; LRD, PIN, Whois and Source switched off by the user. Illustrative selection, not default settings.

Sep 15: Analyze text and icon changed to #5C5DC4. Example includes #3 and five selected Semrush metrics so the CTA remains visible; default settings are unchanged.

  • Fit: after fonts load, measure the last row’s remaining width from its rightmost item to the flow’s right edge, accounting for the result number, selected controls and existing gaps. Recheck on resize, item-size, content or selection changes; no fixed viewport breakpoint.
  • Placement: 7px from the right edge, centered on the last existing row—not the panel. Never disable, hide, reorder or displace selected metrics, reserve space, add a row or increase height to fit Analyze; otherwise hide it.
  • Style: text/icon #5C5DC4; 12px / 20px Inter, weight 600; padding 2px 4px; minimum height 24px; 12px external-link icon with 6px gap. Underline on hover, no fill; focus outline 2px #7137AD, offset 2px.
  • Keyboard: hidden means invisible, non-interactive, excluded from tab order and assistive technology. Restore these when shown. If it disappears while focused, return focus to the nearest preceding visible focusable control, or the strip.
  • Link: Domain Overview for the analyzed domain, using the existing helper; new tab with noopener noreferrer.

Tooltips

  • One at a time on hover or keyboard focus. Keep open while the trigger or tooltip is hovered, or the trigger is focused; dismiss 150ms after leaving, or immediately on Escape. PIN stays hover-only, not a link or tab stop.
  • Fixed position, 6px below the trigger; flip above when needed. Keep an 8px viewport inset; never affect wrapping or Analyze visibility. Use role="tooltip" and a unique aria-describedby; remove native titles.
Actual-size reference · Traffic tooltip shown
Traffic:1.62B
SE TrafficEstimated US organic traffic for this domain from Semrush data.

12px / 16px Inter; title weight 600, 2px bottom gap. White background, #181E15 text, 1px #DADDDE border; 8px 10px padding; 4px radius; max-width 280px, capped to viewport minus 16px. Shadow: 0 2px 6px #00000014.

Exact tooltip copy

Reuse the existing Quick View / Full Report definitions:

LabelTitleDefinition
Rank:Semrush RankA Semrush visibility ranking for the analyzed domain.
Traffic:SE TrafficEstimated US organic traffic for this domain from Semrush data.
Costs:Traffic CostEstimated paid-search equivalent value of this domain's organic traffic.
L:URL BacklinksLinks from other websites pointing to this URL.
LD:Subdomain BacklinksTotal backlinks pointing to tracked subdomains for the analyzed domain.
LRD:Root Domain BacklinksTotal backlinks pointing to the root domain.
PIN:Pinterest Pin CountEstimated Pinterest pin count for the linked URL.
whoisWhoisOwnership lookup helper for the linked domain.
sourcePage SourceView the page source for the linked URL.

SERP Overlay preferences

Add Appearance → Show tooltips, enabled by default. Save independently of the SEObar setting; control both standard and connected SERP tooltips, on hover and focus.

Implemented in 4.2.3: Appearance → Theme adds Match Google (default), Light and Dark. See the dark SERP Overlay ticket for the settings and theme rules.

Default selection · Implemented in 4.2.0: Enable SE Traffic by default for SERP Overlay. Keep Traffic Cost and other defaults unchanged; preserve users’ explicitly saved selections. Included in the tested core overlay update.

Implementation: SE Traffic shares the existing Rank API request; enabling it should not require an additional request.

#00785F meets normal-text contrast on these light surfaces. Analyze #5C5DC4 has 4.86:1 contrast on #F0F1F2. This is not a full accessibility sign-off.

SEObar implementation

Highlight the value

Implemented · 4.2.0

Retained implementation reference for SEObar styling and metric defaults.

  • On hover/focus, highlight only the linked metric’s value; keep its label and provider icon gray. Whois/Source still highlight icon and label together. Preserve visible focus indicators, non-link counts and loading behavior.
  • Use #00785F on light backgrounds, including white menus in dark mode. Keep #18F0BF on dark backgrounds. Apply to green interactive text, control icons and green value-focus outlines.
  • Scope component changes to SEObar; use the SERP specs for SERP. Leave Quick View, Full Report, brand fills and status colors unchanged; do not replace the global green palette.

Otherwise preserve layout, typography, spacing, hit areas, icons, tooltips, settings, links and seobar_* tracking. No Analyze CTA or dark-mode redesign for SEObar.

Semrush connection

Connected SERP overlay

Implemented · Tested

Included in 4.2.0 chrome-4. Semrush connection and connected metrics passed user testing on September 17.

Legacy comparison, Final Design and design specifications.

Legacy version

Apple
https://www.apple.com

Introducing the iPhone Duo. Plus new iPhone 18 Pro, Apple Watch Series 12, Apple Watch Ultra 4, and AirPods 5.

Final Design

Apple
https://www.apple.com

Introducing the iPhone Duo. Plus new iPhone 18 Pro, Apple Watch Series 12, Apple Watch Ultra 4, and AirPods 5.

Connected SERP overlay — design specs

Add the connected Semrush row above the Final Design. These specs cover the new row and connected tooltip differences; the standard SERP specs apply to the lower strip and result number.

AreaSpecification
LayoutAbove the standard strip in the same full-width panel; no gap, outer border or shadow between rows. Width follows the result column; 652px is the preview reference. Keep the result number first in the lower metric strip, before Rank, following the standard specs.
Order and wrappingAS: → Visits: → Pages/Visit: → Avg. Visit: → Bounce rate:. Wrap whole metrics, keeping icon, label, value and score bar together. Never truncate or hide values. Lower-strip order follows the standard specs.
Typography12px Inter (Arial / sans-serif fallback); 20px line height; labels 400, values 600; tabular, lining numerals. Match the lower strip.
Spacing4px 7px row padding; 12px between metrics; 3px internal gap. Controls: no padding, 20px minimum height. Reference heights: 28px top row; 84px total with the two-line lower strip. Height follows content; do not hardcode.
Surfaces and colorsTop row #E9EBED; lower strip #F0F1F2. Top corners 3px; preserve 3px bottom corners. Labels/provider icon #60636B; values #181E15.
Authority Score16 × 16px Semrush icon before AS:. After the value: 32 × 4px score bar, 2px radius, 2px extra left margin; replace orange with #5C5DC4. Preserve score-to-fill behavior; 100 shows a full bar. No icons on the other four metrics.
Hover and focusInteractive values and value-focus outlines #00785F; Whois/Source highlight icon and label together. Labels, provider icons and purple score bar stay unchanged; no filled hover background. Connected controls: 2px #7137AD focus outline, 2px offset. Same light-surface accent as standard SERP/SEObar; leave global brand/status colors unchanged.
Tooltip behaviorOne across both rows; show after 180ms hover or immediately on focus. Top-row tooltips: 8px above the whole panel when space permits; lower strip: 8px below. Flip outside the panel to fit; keep 8px viewport inset. No layout impact. Dismiss on Escape; the preview also dismisses on pointer exit, blur, scroll or resize.
Tooltip appearanceWhite background; 1px #D8DADD border; 4px radius; 8px 10px padding; max-width 260px. Text #181E15, 12px / 16px Inter; bold title with 2px bottom gap. Shadow: 0 2px 6px #00000014. Preserve approved copy; wrap naturally without forced breaks or clipping.

Exact connected tooltip copy

LabelTitleDefinition
AS:Authority ScoreSemrush’s domain reputation score.
Visits:Monthly VisitsEstimated monthly visits from Semrush Traffic Analytics.
Pages/Visit:Pages per VisitAverage number of pages viewed during each visit.
Avg. Visit:Avg. Visit DurationAverage time visitors spend on the site per visit.
Bounce rate:Bounce RatePercentage of visits that end after one page view.

Traffic definitions reuse Full Report copy; Authority Score uses the approved short Semrush adaptation. Example values are screenshot samples, not live data.

Implementation: reuse existing Semrush connection behavior, data sources, formatting, links, tracking and settings. Flag missing capability before implementation.

SERP sidebar

Parameters and search locale

Implemented · Tested

Included in 4.2.0 chrome-4. Quick Parameters autosave, Set locale and Reset passed user testing on September 17.

Current controls · shown at 120px
Parameters + Locale
Locale

SERP sidebar — design specs

AreaSpecification
Layout120px wide, expanded or collapsed; keep the left edge fixed. Replace Settings with Parameters; keep Export CSV and Locale below it. Both previews show the proposed width; the current sidebar is 110px.
TypographyInter: existing controls and Locale heading 13px; field labels 11px / 16px; selected values 12px / 18px. Keep the existing gray surface and control styling.
FieldsStack Country / region and Language. Use 8px side insets; fields fill the available width, 32px high, with 2px horizontal padding, 4px corners and 12px bottom spacing. White fill; 1px #DADDDE border.
ButtonsStack Set locale and Reset, full width, with a 6px gap. 12px / 18px semibold text; 30px minimum height; pill corners. Set locale: #2969FF with white text, hover #2154CC. Reset: blue text, #709BFF outline; hover #EBF1FF fill and #2969FF outline.
Parameters menu192px flyout beside Parameters; 12px padding, 13px labels, 16px checkboxes, 8px label gap and 28px rows. Both group headings have a 4px gap before their first option. Match current SERP settings: Core metrics, then Other parameters, preserving names and order. No visibility count or Save button. SE Traffic defaults on; keep Traffic Cost and other defaults unchanged and preserve explicitly saved selections. This default change is part of the September 16 core overlay target.
Expand and focusLocale toggles the fields and buttons without changing sidebar width. Keep visible keyboard focus: 2px #7137AD outline, 2px offset. Preserve the existing SEOquake enable control.

Parameters behavior: Apply and save checkbox changes automatically in the quick Parameters menu; keep selections synchronized with SERP settings and show feedback if saving fails. More settings opens the full SERP settings page. If straightforward to implement safely without delaying sidebar delivery, extend autosave across all Full Report settings, including validation and save-error feedback. Otherwise, retain their existing Save behavior and flag the broader change for a later iteration. The mock-up is preview-only and does not persist extension preferences.

Locale behavior: Match legacy native country and language menus: None option, Main and Other groups. Open menus may extend beyond the sidebar without changing its width; appearance follows the browser/OS. Use legacy as the behavior reference, not the mock-up’s popup rendering. None means no country/language override; Reset clears both overrides. Keep explicit Set locale and Reset actions; changing a selection alone does not apply it.

Implementation: Reuse current SERP parameter definitions and settings, referencing legacy quick-selection autosave and Locale behavior. Refer to the bundled country/language lists and existing Set locale, Reset and saved-preference handling. Flag missing capability before implementation.

Completed 65

Implemented. See each item’s verification and remaining checks. The original diagnosis and fix are kept as history.

Engineering handoff · November 6, 2026

SEObar built-in exclusions

Stop built-in exclusions matching unrelated websites Completed implementation · 4.3.3

Verified November 6 · chrome-6: 46 packaged-function checks pass for hostname boundaries, unrelated-site examples, intended exclusions, path/query restrictions and user settings. Semrush remains excluded. These are function checks, not real-site browser tests.

Approved copy, references and engineering checks

Historical implementation request. The verification above is the current status.

Medium priority · Matching flaw confirmed in chrome-4 · Targeted correction

Issue: Built-in URL patterns can hide SEObar on unrelated sites: the Bing rule matches climbing.com and benjaminfranklinplumbing.com, while the Semrush rule matches example.com/?next=semrush.com/. These are unintended exclusions, even when the user has enabled the bar.

Fix:

  • In src/utils/seobar/urlFilters.ts, review all 16 DEFAULT_EXCLUDES rules and their use through DEFAULT_EXCLUDE_EXPRESSIONS in isSeobarAllowedOnUrl. Match the intended hostname and supported subdomains with explicit boundaries; domain mentions in a path, query or user info must not qualify.
  • Prefer parsed URL.hostname for host checks, with explicit path/query predicates where the original rule requires them. Preserve intended host coverage and restrictions such as search paths; do not turn path-specific exclusions into blanket domain blocks.
  • Keep Semrush excluded, including the homepage, app and checkout. Preserve user-entered settings.matches and settings.excludes regex behavior, HTTPS settings and existing enable/pause controls. This ticket changes built-in rules, not saved user rules.

Confirmed by evaluating the packaged rule patterns, not by a new live-browser test. This is separate from the completed “For this domain” rule fix. If the full correction cannot be verified in time for 4.3.3, carry it into the next patch rather than ship a partial rule rewrite.

Engineering checks
  • With SEObar enabled and no user exclusions, verify climbing.com, benjaminfranklinplumbing.com and example.com/?next=semrush.com/ are allowed. Use rotorooter.com as an unaffected control.
  • For every built-in rule, cover intended hosts/subdomains and deceptive suffixes such as bing.com.example.com. Check domain mentions in paths, queries and user info, plus hostname case, ports and trailing-dot normalization.
  • Confirm real Bing, Semrush and other intentionally excluded destinations retain the intended behavior. Check the existing path/query restrictions explicitly.
  • Verify manual regex include/exclude rules, disabled/paused behavior and HTTPS preferences. No changes to the separate user-created domain-exclusion feature.
Package verification · November 6, 2026

4.3.3 chrome-4 closeouts

Four chrome-4 closeouts remain complete. The AI panel-width card is reopened above for an additional layout.

Evidence: outputs/package-qa-4.3.3-chrome-4-2026-11-06/report.md. No new memory benchmark; the earlier SERP disappear/reappear observation remains unresolved.

Engineering handoff · November 5, 2026

Technical fixes

Keep SEOquake clear of Google’s left navigation Completed implementation · 4.3.3

Verified November 6 · chrome-4: Visible rail measurements, adaptive placement, compact controls above the first organic result, Escape/focus and preserved collapse preferences pass controlled checks. The saved Google layout also passes at two window widths.

Approved design, specification and engineering checks

Medium priority · Not included in 4.3.3-chrome-3 · Required before this release’s submission

November 5 · Incognito: SEOquake’s collapsed logo overlaps Google’s left navigation. Capture reference, not the proposed placement.
Google results for seo checker in Incognito, with SEOquake’s collapsed logo overlapping the left navigation controls.

Captured layout: The saved HTML/CSS defines a 64px fixed rail and a separate 261px navigation panel with open/close controls. These dimensions describe this capture only; measure the visible bounds at runtime instead of hard-coding either width.

Issue: Google sometimes places navigation in the left rail occupied by SEOquake’s sidebar. Our collapsed logo or expanded controls can cover Google’s controls.

Fix:

  • Extend the host positioning in syncSerpControlPanel / applyPanelPosition in src/utils/serp/syncControlPanel.ts. Measure the visible Google rail and available space before the results. Keep the familiar left placement when it fits; offset past the rail with a small gap when needed. Check the expanded panel and its flyouts, not just the collapsed logo. In this capture, aim-lhs-panel-container, role="navigation" and the Open sidebar / Close sidebar controls provide inspection clues. Validate visibility and geometry; do not rely solely on generated class names or English labels.
  • If the expanded controls will not fit, render a compact SEOquake button immediately above the first organic result on the current page. Reuse the organic classification around detectOrganicResults in google/base/detect.ts, but do not wait for a redirect destination or metric strip to resolve before locating that result. Exclude ads; do not anchor to the AI Overview or its separate Analyze sources control.
  • Reuse SerpControlPanel.tsx controls in a dismissible panel opened by the compact button. Keep Parameters, Export CSV, Keyword data, Locale and enable controls available. Fit the panel within the viewport, preserve theme and keyboard focus, and support Escape/outside dismissal with focus returned appropriately.
  • Keep layout mode separate from the saved settings.panelCollapsed preference and patchSerpSettings. Temporary collision handling must not overwrite the user’s choice. Reuse one panel host; do not create duplicate controls or change sides as the user scrolls.
  • Recompute placement on window resize and relevant Google rail/result-layout changes. Integrate with the batched lifecycle around watchSerpMutations in google/base/observe.ts; ignore our own changes and remove added listeners/observers through unmountSerpControlPanel. Avoid constant polling or full-page scans on scroll.

Scope: Positioning and access to the existing controls only. Preserve metric strips, numbering, Analyze sources, saved settings and tracking. No added permissions or automatic switch to a right-hand sidebar. If no organic result is available yet, do not attach the fallback to an ad or AI module; wait for an eligible anchor without obstructing Google.

Local debugging evidence: /Users/babepig/Downloads/seo checker - Google Search.html and its seo checker - Google Search_files/ folder. Keep the raw saved page and assets local; they may contain page/session metadata and are not bundled with this handoff.

References were checked in the local source checkout; confirm their current equivalents in the implementation branch. The older sidebar design remains the control-style reference; this ticket supersedes its fixed-left placement rule. Engineering may choose another layout implementation that meets these outcomes.

Engineering checks
  • Test Google with and without the left rail, signed in and Incognito. Collapsed and expanded SEOquake controls must leave Google’s controls accessible.
  • Open and close Google’s own navigation with SEOquake collapsed, expanded and in fallback mode. Recompute when the visible panel changes, including its transition; both interfaces remain accessible without duplicate controls or an overwritten collapse preference.
  • Resize and zoom until the expanded sidebar no longer fits. Verify the compact button is above the first organic result, including later result pages, ads before results and AI Overviews before or between results. Do not duplicate Analyze sources.
  • Open the fallback with mouse and keyboard. Exercise Parameters/flyouts, CSV, Keyword data, Locale and enable controls; check light/dark appearance, focus, Escape and outside dismissal.
  • Change queries, navigate Back/Forward and let Google replace results or its rail. Keep one valid host/anchor and no stale or overlapping controls. An unresolved first-result redirect must not shift placement to the second result.
  • Restore room for the sidebar and reopen the page. Retain the saved collapse choice. Verify placement does not jump between sides during scrolling and that observers/listeners are cleaned up.
  • Retain the chrome-3 redirect recovery, numbering, correct Analyze destinations and Links revisions. Run a focused live smoke review before submission; follow up separately if the unresolved disappear/reappear observation recurs.
Product handoff · November 5, 2026

Semrush panel trial banner

Replace the connected MCP banner with a free-trial CTA Completed implementation · 4.3.3

Verified November 6 · chrome-4: Approved connected-report copy and report_free_trial / semrush_connected_cta tracking pass. The disconnected branch and Quick View MCP tip are preserved.

Approved design, specification and engineering checks

Medium priority · Approved copy and destination · Implementation not yet verified

Issue: Full Report’s connected Semrush panel currently promotes MCP. Replace that banner’s copy and link with the approved free-trial offer, while retaining MCP in Quick View’s connected tips.

Approved copy:

  • Headline: See What’s Behind These Numbers
  • Body: Get AI visibility, keyword, backlink, and competitor data for any site, all in Semrush One.
  • Button: Try Free for 7 Days

Fix:

  • In src/components/report/panels/SemrushPanel.tsx, update only the connected branch’s MCP Cta title, text and link. Reuse src/components/shared/Cta.tsx unchanged so the banner keeps its existing position, styling and responsive behavior. Leave the disconnected branch unchanged.
  • Set the button destination to https://www.semrush.com/semrush-free-trial/. Pass destination: 'free_trial', placement: 'cta', panel: 'semrush' and connectionState: 'connected' through the shared Link tracking. With the report surface, withSemrushTrackingParams must produce report_free_trial / semrush_connected_cta; do not use the popup campaign.
  • Reuse the 'free_trial' addition to SemrushDestination in src/utils/semrush/utm.ts from the Quick View trial-link ticket. Add it once if absent; preserve the builder’s source, medium and referral values.
  • Keep the connected semrush tip in src/utils/popup-tips/messages.ts unchanged: “Explore Semrush MCP”, its MCP destination, eligibility, rotation and tracking. Do not remove 'mcp' from the tracking types or change other banner/tip placements.

Tagged destination: https://www.semrush.com/semrush-free-trial/?utm_source=seoquake&utm_medium=toolbar&utm_campaign=report_free_trial&utm_content=semrush_connected_cta&ref=174537735

Scope: Full Report → Semrush, connected users only. Copy and outbound link replacement; no new banner, OAuth flow, account-plan targeting or permissions. Preserve the existing new-tab behavior. Trial eligibility remains determined by Semrush’s landing page.

Code references were checked in the local checkout; confirm their equivalents in the implementation branch. The Semrush One wording above is approved for this banner; it does not change the separate free-account connection copy.

Engineering checks
  • With SEOquake connected, open Full Report → Semrush. Confirm the exact approved headline, body and button replace the MCP banner in the same location, with readable wrapping and keyboard access.
  • Click the button. Verify a new tab opens the trial page with utm_source=seoquake, utm_medium=toolbar, utm_campaign=report_free_trial, utm_content=semrush_connected_cta and ref=174537735. The original report stays open.
  • Disconnect and reopen the Semrush panel. Its existing disconnected content is unchanged. Reconnect and confirm the new trial banner returns.
  • In connected Quick View → Semrush, verify “Explore Semrush MCP” remains available in the existing tip rotation with its original link and tracking. Confirm the separate unsupported-page trial link still uses popup_free_trial / empty_cta.
Design handoff · November 5, 2026

SERP metric tooltips

Use one short description in metric tooltips Completed implementation · 4.3.3

Verified November 6 · chrome-4: All 14 approved descriptions match. The rendered Rank tooltip has no heading and dismisses with Escape; accessible metric names and retry behavior are retained.

Approved design, specification and engineering checks

Low priority · Approved copy · Implementation not yet verified

Issue: SERP metric tooltips repeat the metric name in a bold heading above the description. The extra line makes them larger and covers more of the search results.

Fix:

  • Update SERP_PARAMETER_TOOLTIPS in src/utils/parameters/meta.ts with the approved descriptions below. In src/components/shared/parameters/ParameterByKey.tsx, stop passing serpTooltip.title as the visible tooltipTitle for the SERP variant. Retain the metric’s full name for accessible identification.
  • In src/components/serp/overlay/SerpConnectedMetrics.tsx, update the five connected-metric descriptions and omit the visible title from InfoTooltipBubble. Keep one description with the existing body typography and content-sized height; do not leave an empty heading or its spacing.
  • Apply the same copy through the shared organic-result and expanded Analyze sources metric components. Keep existing tooltip availability in AiSources.tsx; do not enable tooltips on compact source cards where they are currently disabled.
  • Preserve light/dark appearance, placement, hover delay, keyboard focus, Escape dismissal and accessible descriptions. Keep the existing “Couldn’t load. Click to retry.” error override and retry action unchanged. Scope this to SERP metric tooltips; do not remove headings globally from the shared tooltip component or alter Quick View, Full Report, SEObar or sidebar-control tooltips.

Approved copy: The first column identifies the current heading; remove it from the visible tooltip. Show only the new description. Current strings were matched in 4.3.3-chrome-3.

Metric / current headingCurrent descriptionNew tooltip
Semrush RankA Semrush visibility ranking for the analyzed domain.Semrush’s visibility ranking for this domain.
SE TrafficEstimated US organic traffic for this domain from Semrush data.Estimated US organic traffic for this domain.
Traffic CostEstimated paid-search equivalent value of this domain's organic traffic.Estimated cost of buying this domain’s organic traffic through search ads.
URL BacklinksLinks from other websites pointing to this URL.Links from other websites pointing to this URL.
Subdomain BacklinksTotal backlinks pointing to tracked subdomains for the analyzed domain.Backlinks to this domain’s tracked subdomains.
Root Domain BacklinksTotal backlinks pointing to the root domain.Total backlinks to this root domain.
Pinterest Pin CountEstimated Pinterest pin count for the linked URL.Estimated Pinterest pins for this URL.
WhoisOwnership lookup helper for the linked domain.Look up this domain’s registration details.
Page SourceView the page source for the linked URL.View this page’s source code.
Authority ScoreSemrush’s domain reputation score.Semrush’s domain reputation score.
Monthly VisitsEstimated monthly visits from Semrush Traffic Analytics.Estimated monthly visits to this site.
Pages per VisitAverage number of pages viewed during each visit.Average pages viewed per visit.
Avg. Visit DurationAverage time visitors spend on the site per visit.Average time spent on this site per visit.
Bounce RatePercentage of visits that end after one page view.Percentage of visits with only one page view.

Code references were checked in the local checkout; confirm the current implementation-branch equivalents. Keep metric definitions, values, destinations and tracking unchanged.

Engineering checks
  • Hover and keyboard-focus standard and connected metrics on organic results and in expanded Analyze sources. Show the exact new description without a bold heading or blank heading space.
  • Enable optional parameters, including Pinterest, Whois and Page Source. Verify their copy and actions. Keep disconnected locks and failed-request retry behavior intact.
  • Check Light, Dark and Match Google appearance. Text remains readable, the tooltip fits the viewport and does not obscure or intercept neighboring controls. Escape and moving focus away dismiss it correctly.
  • Confirm the Show tooltips setting still works, compact AI source cards retain their existing tooltip availability, and other SEOquake surfaces are unchanged.
Product handoff · November 5, 2026

Quick View Audit banner

Add a dismissible site-audit trial banner Completed implementation · 4.3.3

Verified November 6 · chrome-4: Approved copy and tracking, both connection states, Show tips gating and independent persisted seven-day dismissal pass. Reopening preserves dismissal; expiry restores eligibility without changing tip dismissals.

Approved design, specification and engineering checks

Medium priority · Approved copy and mockup · Connected and disconnected users

Approved mockup · Banner below the passed section, inside the Audit scroll area. Click to view full size.
Quick View Audit with a purple site-audit trial banner below the passed row, a top-right close button, and the separate tip bar below.

Issue: Quick View’s Audit tab ends after the page checks, often leaving unused space. Add a clear next step for users who want to audit the whole site.

Approved copy:

  • Headline: You Checked One Page. Now Audit the Whole Site.
  • Body: Scan your site for 140+ SEO and AI search issues, and see what to fix first.
  • Button: Try Free for 7 Days

Fix:

  • In src/components/popup/panels/AuditPanel.tsx, place the banner after the passed section, outside its Collapsible, in the existing scroll flow. When there are no passed checks, keep it below the remaining audit content. Do not pin it above the tip bar or limit eligibility to pages with few issues; expanding passed checks moves the banner below that content.
  • Reuse the purple treatment from src/components/shared/Cta.tsx, adapting the content/button stack to the popup mockup without changing existing Full Report banners. Reuse close.svg and the close-control treatment from shared/layout/TipBar.tsx in the top-right corner, with an accessible label such as “Dismiss site audit offer” and room for the headline to wrap.
  • Gate visibility on settings.general.showTips from useAppSettings and a separate persisted banner dismissal. Wait for settings and dismissal storage to load before showing it, so a dismissed banner does not flash. Apply the same rule to connected and disconnected users; do not infer paid-plan or trial eligibility from connection status.
  • Follow the #imports storage pattern in src/utils/popup-tips/storage.ts, but use a dedicated banner key, for example local:popup.auditTrialDismissedAt. On X, hide immediately and persist the dismissal time for 7 * 24 * 60 * 60 * 1000 milliseconds. The dismissal applies across pages and popup reopenings in that browser profile. After expiry, show it on the next eligible Audit view; no background polling is needed. Clean up any storage subscriptions and handle write failures without treating an unsaved dismissal as persisted.
  • Keep the banner key independent of local:popup.tipDismissals, dismissPopupTip and tip rotation. Closing the banner must not dismiss the tip bar; closing the tip bar must not dismiss this banner. Turning Show tips off hides both, but does not erase or restart the banner’s seven-day clock.
  • Use the shared Link with href="https://www.semrush.com/lp/website-audit-1/" and destination: 'site_audit', placement: 'cta', panel: 'audit'. The popup surface produces popup_site_audit / audit_cta through withSemrushTrackingParams in src/utils/semrush/utm.ts. Omit connection-state suffixes and qualifiers; site_audit already exists in the destination type.
  • Remove only the Audit tip with ctaText: 'Open Site Audit' from src/utils/popup-tips/messages.ts. Keep the other Audit tips, including the internal “View audit report” action, and leave Full Report Site Audit CTAs unchanged. Verify rotation still handles the reduced list. The old tip used audit_tip, while this banner uses audit_cta; removing it prevents future campaign-level mixing, but historical popup_site_audit totals still include prior tip traffic.

Tagged destination: https://www.semrush.com/lp/website-audit-1/?utm_source=seoquake&utm_medium=toolbar&utm_campaign=popup_site_audit&utm_content=audit_cta&ref=174537735

Scope: One banner in Quick View → Audit only, not other tabs, Full Report or unsupported-page states. Reuse existing storage permissions and outbound new-tab behavior. Clicking the CTA does not start the dismissal clock; X does. Trial eligibility remains with Semrush’s landing page.

Code references were checked in the local checkout; confirm current implementation-branch equivalents. Copy and destination are user-approved; the offer’s live eligibility and “140+” claim were not independently verified in this handoff edit.

Engineering checks
  • Check connected/disconnected Audit views with zero, few and many issues, including no passed checks. Confirm the exact copy, compact purple styling and top-right X. Expand passed checks and scroll: the banner follows the content and never covers the list or tip bar.
  • Dismiss the banner, switch pages/tabs, reopen Quick View and restart the browser. It stays hidden in that profile. With a controlled clock or saved test timestamp, verify it remains hidden just before seven days and returns on the next eligible Audit view at or after expiry. Do not wait a real week or poll in the background.
  • Dismiss the tip bar and banner independently. Toggle Show tips off/on while each is dismissed and after expiry; neither dismissal resets or hides the other. Exercise initial storage loading and a failed save without a dismissed-banner flash or unhandled error.
  • Activate CTA and X with keyboard. Verify focus remains usable after dismissal. CTA opens a new tab with the exact approved tags, with audit_cta for both connection states, and leaves the current report intact.
  • Confirm “Open Site Audit” no longer enters Audit’s tip rotation, the remaining tips still rotate, and the Quick View MCP tip, other trial CTAs and Full Report banners are unchanged. Compare attribution using campaign plus content and release date, not campaign totals alone.
Package verification · November 5, 2026

4.3.2 and 4.3.3 verified fixes

Implementation closeouts. Submission, publication and final release smoke checks are separate.

Google redirect metric recovery Completed implementation

Verified November 5: 4.3.2-chrome-3 resolves the tested delayed HTTP 200 continuation and respects bounded waits, validation and credential omission. Beatus’s Incognito smoke review passed recovery, pagination and correct Analyze destinations. Submitted November 5 at 10:30 a.m. EST; Beatus subsequently confirmed approval, the Store-installed smoke pass and 100% rollout at 2:20 p.m. EST that day. The correction is also merged and fixture-tested in 4.3.3-chrome-3. The separate disappear/reappear observation remains unresolved. Evidence: outputs/package-qa-4.3.2-chrome-3-2026-11-05/report.md and Beatus’s live review.

Unresolved observation · metrics disappear and reappear

Unresolved observation: Beatus saw metric strips disappear together and reappear seconds later in 4.3.2-chrome-3. The cause is not established. Preserve this for targeted reproduction; the redirect fix and later smoke pass do not prove it resolved. Progressive loading alone is a separate behavior.

Original requirements, visuals and engineering checks

Historical November 4 review below. The closeout above supersedes its former open status; original evidence and mockups are preserved.

Medium–high priority · Partially implemented · Live review November 4 · 4.3.2-chrome-2

Completed: Position numbers render independently of destination lookup. All eight organic results were numbered in live review. Bounded retries are running; controlled checks also passed delayed recovery, changed links and navigation.

Issue: Five of eight organic results still had no metric strip. Refreshing changed which results displayed metrics but did not clear the issue. The background capture recorded five Google /goto URLs returning HTTP 200 on all three attempts. The inspected response was HTML without a Location header; the resolver accepts only validated redirect destinations and discards the response body.

Investigation and fix direction:

Engineering discretion: Use these points as a starting point. Investigate other causes or approaches if the evidence supports them. The required outcome is reliable metric strips for the correct result URLs, while preserving working position numbers, security safeguards and performance.

  • In redirectsBackground.ts, capture and inspect a failing HTTP 200 response before it is discarded. Establish whether it provides a valid exact destination or whether the result contains another reliable source for that URL.
  • Recover and validate the exact destination before loading its metric strip. The implementation approach remains unverified; do not assume every HTML response contains a usable URL or prescribe a parser before inspecting it.
  • Preserve the independent numbering and bounded retry/backoff behavior in resolveOpaqueGoogleRedirect. More retries alone will not resolve the repeated HTTP 200 case.
  • Keep the result-identity and href-change handling in detectResults/syncOverlays. Retain known-good metrics only for the same result; never attach another page’s metrics.
  • Retain credential omission, manual redirect handling and batched observation. Do not visit every result automatically or guess exact destinations from abbreviated display URLs.

Still to establish: The HTML body was unavailable in DevTools because the resolver cancels or aborts it. We have confirmed the response mismatch, but not whether the body contains a destination, an interstitial or another response. Verify the chosen correction on real Incognito results before closing this ticket.

Files: src/utils/serp/google/redirectsClient.ts, redirectsBackground.ts, google/base/detect.ts, google/base/observe.ts, google/base/positionNumber.ts and src/utils/serp/syncOverlays.ts. Confirm the current source equivalents; change source, not generated bundles.

Live evidence · November 4 · 4.3.2-chrome-2

All eight positions appeared. Metric strips were present for Backlinko, Yoast and Chrome Web Store, and missing for Seobility, SEOptimer, Semrush, Rank Math and DebugBear. After one refresh, a changed result set still had five missing strips. The network capture included 15 HTTP 200 responses across five lookup URLs, with three attempts per URL.

Incognito Google results with positions 1 through 8 present, but metric strips missing for five results.
November 4 · seo checker · numbering works, metric recovery remains incomplete. Open image for full size.

The initial page was inspected before opening worker DevTools. The refreshed load was captured with DevTools open, which keeps the worker awake. No product code or settings were changed.

Original diagnosis and user screenshots · November 3

In 4.3.0 and 4.3.1, a failed destination lookup was cached without expiry or automatic retry, hiding both the number and metrics. Controlled tests confirmed that flaw. The 4.3.2 candidate corrects numbering and retry behavior; the remaining live response case is described above.

The first capture shows positions 5, 8 and 9; the later capture shows 1, 4, 7 and 8. Numbers and entire metric strips change together. These are full-page references; sponsored results are expected to remain unnumbered.

Initial Incognito Google search with missing organic position numbers and metric strips.
Initial capture · seo checker
Later Incognito capture with Seobility numbered but several other organic overlays still missing.
Later capture · different organic results enhanced
Engineering checks
  • Test direct links and real Incognito /goto links with ads and AI modules between organic results. Every eligible organic result keeps its correct number.
  • Cover delayed success, temporary failure followed by success and permanent failure. Verify bounded requests, recovery without a full reload and no fabricated destination or metrics.
  • Add the captured HTTP 200 HTML case, including the same response on all three attempts. Verify the destination is recovered from validated evidence when available; an unsupported or invalid response must not produce guessed metrics.
  • Repeat real Incognito searches and refreshes, including seo checker. Confirm consistent strips across eligible results with resolvable destinations and investigate any remaining omissions before acceptance. A controlled redirect fixture alone does not close this ticket.
  • Change a result link in place, trigger repeated rescans and test Back navigation. Numbers remain stable; overlays recover on the correct result and never show stale metrics from another page.
  • Confirm normal-profile rendering, SERP export ordering and existing performance behavior remain intact.

Acceptance: Keep the passed position-number behavior. Resolve the observed live missing-strip case using verified exact destinations, with consistent rendering after refresh and no stale or fabricated metrics. Unsupported responses remain safely unresolved. Do not close the ticket while the reproduced live omissions remain unexplained.

Evidence: Current live findings: outputs/serp-overlay-live-followup-2026-11-04/evidence.json. Earlier controlled package checks: outputs/package-qa-4.3.2-2026-11-03/report.md. Original investigation: outputs/serp-position-investigation-2026-11-03/report.md, static-findings.md and redirect-cache-results.json. These are workspace evidence references, not public downloads.

Completed implementation · Confirmed November 4, 2026

4.3.2 · Reviews and feedback

Release closeout · November 3, 2026

Completed in 4.3.1

19 implementation cards closed from package checks and live review, including the final light-tooltip correction. Beatus confirmed the Store upgrade smoke test and 100% rollout setting on November 2. Historical requirements and engineering checks are preserved inside each card; the new redirect-recovery issue is tracked separately above.

Use light tooltips in Quick View and Full Report Completed · 4.3.1

Closed November 3, 2026 · Final package and live review passed

Completed: Quick View and Full Report retain light tooltips under either system appearance. SEObar and SERP Overlay retain their own theme behavior. The final SEObar 3 package passed 12 browser scenario groups, followed by Beatus’s live smoke test. Original issue and implementation guidance follow as history.

Original requirements, visuals and engineering checks

Issue: Quick View and Full Report stay light, but their shared tooltip styles respond to the system’s dark preference. Tooltips can therefore use a dark background on the white report. SEObar and SERP Overlay already follow their own selected appearance.

Fix:

  • Resolve the shared Tooltip appearance from its owning surface. Keep Quick View and Full Report tooltips light under both system preferences, including tooltips rendered through a portal.
  • Reuse the existing light treatment: white background, dark heading/body text, light border and current shadow. Apply the same appearance to the arrow. Keep the approved copy, sizing, spacing and placement.
  • Preserve SEObar’s selected Light/Dark appearance and SERP Overlay’s Light/Dark/Match Google behavior. Avoid changing the global dark: selector or removing dark support from shared tooltips.
  • Keep hover, keyboard focus, Escape dismissal, accessible associations, interactive links and the current delegated tooltip lifecycle unchanged. This is a theme correction, not another tooltip implementation.

Scope: Quick View and Full Report tooltip appearance only. No report dark-mode feature, new preference or changes to metric-error styling.

Files: Shared tooltip renderer and the app’s surface/theme wiring. src/components/shared/Tooltip.tsx is the local source reference; confirm its current source equivalent. In the reviewed package, chunks/download-Bb8NZV5h.js contains renderer Ro and assets/download-D9G6iL8w.css applies tooltip dark: styles through prefers-color-scheme. Change source, not generated bundles.

Earlier appearance · October 28 references
Quick View stays light while the URL Backlinks tooltip has a dark background.
Quick View · current package, October 28
Full Report Page Info stays light while the SE Traffic tooltip has a dark background.
Full Report · current package, October 28
Engineering checks
  • With light and dark system preferences, inspect metric and information tooltips in Quick View and Full Report. Background, text, border and arrow must retain the existing light appearance.
  • Check SEObar in Light and Dark, and SERP Overlay in Light, Dark and Match Google. Explicit choices must work even when they differ from the system preference.
  • Verify hover, keyboard focus, Escape, placement and stacking. Interactive tooltip links must remain usable; no clipped popup tooltips, duplicated tooltips or lingering invisible overlays.

Acceptance: Tooltips follow the owning surface’s appearance. Quick View and Full Report stay light; the existing SEObar and SERP appearance controls retain their behavior.

SEObar memory across open tabs Completed · 4.3.1

Closed October 28, 2026 · Targeted memory optimization verified

Completed: Chrome 3 SEObar includes a smaller content UI, shared stylesheets with fallback/cleanup, delegated tooltip listeners and shared connection subscriptions. The targeted optimization produces a repeatable, modest memory reduction.

Previous measurement · October 27

Measured result: Across 30 controlled article tabs, Chrome 3 SEObar used 1,845.5 MiB of aggregate browser-process footprint versus 1,887.5 MiB for Chrome 3: a 42 MiB reduction. Paired savings were 38 and 46 MiB. Tab JavaScript heap fell from 73.03 to 65.91 MiB, about 9.75%, and median listeners fell from 245 to 190 per tab. The 10-tab comparison also improved.

October 28 comparison: At 30 tabs, Chrome 3 used 1,890.5 MiB of aggregate browser-process footprint, Chrome 3 SEObar 1,845 MiB and SEObar 2 1,849 MiB. Tab JavaScript heap was 72.75, 65.84 and 65.60 MiB respectively. SEObar 2 retains a 2.2% footprint and 9.8% heap reduction versus Chrome 3 before the optimization. All 12 captures passed validation.

Interpretation: There is no meaningful additional memory gain over the first optimized package. The paired footprint change reverses direction: 4 MiB lower, then 12 MiB higher. Both optimized builds retain a median 190 listeners per tab versus 245 in Chrome 3. These are controlled memory results, not a demonstrated page-speed improvement.

Completed interaction check: Package tests passed tooltip hover, keyboard focus and Escape after layout changes. Beatus’s October 28 live review also passed tooltip dismissal and the exposed Top/Bottom positions. The separate S-key typing fix is complete.

Closeout: The targeted optimization and interaction checks are complete. No further testing or memory work is requested for this card.

Future consideration: Revisit broader memory optimization only if slowdown complaints persist or engineering identifies a specific improvement worth measuring. Scope that work separately; this card does not require ongoing testing.

Measurement limits: The October 28 benchmark reran all three builds with two repetitions in reversed order, fresh Chrome for Testing profiles, 10 and 30 local article tabs, eight-second settling windows and post-GC heap readings on a Mac. Aggregate process footprint is not extension-only memory or exact unique physical RAM. These results do not establish Windows performance, connected-account memory use, a long-session leak or a dramatic page-speed gain.

Files: src/components/seobar/SeobarApp.tsx; src/components/seobar/layout/; src/components/seobar/parameters/; src/assets/styles/seobar.css; src/entrypoints/seobar.content.ts and shared content-UI style, tooltip and subscription helpers.

Engineering checks · regression reference
  • Retain the now-passed tooltip interaction checks as regression coverage: hover, keyboard focus, placement and Escape after layout changes.
  • Preserve the verified performance change, metrics, preferences, connection state, layouts and existing-tab controls alongside the completed hotkey correction.
  • For any later memory change, repeat matched enabled/off comparisons and inspect retained-object ownership. Do not use feature removal as evidence of an optimization.

Status: Completed. These checks are a reference for future changes, not outstanding work on this card.

Shared regression checks · preserve repeat-visit caching

Working as tested: All three sequences made four API requests on the first visit and zero on the immediate repeat. The three cached metric entries survived natural worker termination with their original fetch timestamps. The post-restart request count was not captured. This is a regression check, not another defect or a replacement for the audit-header cache fix.

  • Keep cold and repeat visits separate. With the same selected parameters and fresh session cache, verify that repeat visits reuse valid entries instead of restarting every metric request.
  • Allow the worker to stop naturally without DevTools keeping it alive. Revisit the page and confirm that valid entries survive without stale URL/account data. Check expiry and account-change behavior, including connected metrics.
  • Retest saved preferences, Semrush connection and metric/CSV completeness after each performance change. Compare the final candidate with the unchanged baseline.

S shortcut blocks typing in embedded text fields Completed · 4.3.1

Verified October 28: 48 focused package checks passed for native, nested, open and closed shadow editors, shortcut guards and horizontal/vertical layouts. Beatus’s October 28 live review confirmed intact typing, S toggling outside text fields and logo expansion. The composition guard was tested synthetically; no physical OS IME test is claimed.

Original requirements and engineering checks

Historical specification. The verified closeout above supersedes its open status.

High priority · Confirmed in 4.3.0, Chrome 3 and Chrome 3 SEObar

Issue: With SEObar’s “Minimize to icon” setting enabled, typing S inside some embedded editors toggles the bar instead of entering the letter. useSeobarMinimize checks only event.target. For fields inside shadow DOM, that target is the outer component rather than the editable field, so the handler calls preventDefault() while the user is typing.

Fix:

  • Update isEditableTarget and the handleKeyDown guard to consider event.composedPath() and the active editing context, including editable ancestors and supported textbox/editor controls. Skip the shortcut whenever focus is in a text-entry control.
  • Handle closed shadow components conservatively. Their internal fields are not exposed in the event path, so composedPath() alone is insufficient. When the editing state cannot be established, allow the key through rather than suppressing the typed character.
  • Ignore composition and already-handled events, and review repeated keydown events and physical KeyS matching so other keyboard layouts do not lose text. Preserve existing modifier exclusions and click-to-expand behavior.

Scope: The existing SEObar shortcut handler in horizontal and vertical layouts. Protect typing without requiring users to discover a setting or workaround. Do not redesign SEObar or add a new shortcut preference as part of this fix.

Files: src/hooks/useSeobarMinimize.ts, including isEditableTarget, handleKeyDown and its document capture listener. Source path is a reference; matching logic was independently verified in both supplied Chrome 3 packages.

Engineering checks · typing and shortcut behavior
  • With “Minimize to icon” enabled, type as and uppercase S in ordinary inputs, textareas and contenteditable editors, plus each equivalent inside open and closed shadow DOM. Text must arrive intact and typing must not toggle the bar.
  • Check focused nested editor content, supported rich-editor/textbox controls, composition input, key repeats and non-Latin layouts. These are required regression cases, not claims that every one was already reproduced.
  • Confirm the intended shortcut still works in clearly nonediting page contexts. Preserve Ctrl/Meta/Alt combinations, click-to-expand, horizontal/vertical layouts, pause/resume and existing-tab settings changes.
  • Verify the packaged build. The prior controlled test passed all nine no-extension controls and all ordinary fields, while all 18 shadow-field checks across three packages lost S.

Acceptance: SEOquake never consumes text entry to activate the S shortcut. Ambiguous editor contexts must favor typing.

Evidence · package reproduction and uninstall feedback

October 27 controlled browser tests used actual unchanged packages and trusted key events: 36 valid editable-control checks across a no-extension baseline, 4.3.0 chrome-5, 4.3.1 chrome-3 and chrome-3-seobar. All six open/closed shadow input, textarea and contenteditable controls lost S in each package. Ordinary input, textarea and contenteditable controls worked.

The latest uninstall survey contains two explicit S-key complaints (October 12 on 4.2.2 and October 23 on 4.3.0), plus one nonspecific typing complaint (October 19 on 4.3.0). This is not four confirmed hotkey reports. The users’ websites are unknown, so the reproduction establishes a matching mechanism rather than proving every report’s cause.

Domain exclusions also hide SEObar on unrelated sites Completed · 4.3.1

Verified October 28: Newly generated rules escape the selected host and enforce its boundary. All 23 browser checks and 87 packaged-function checks passed. Beatus’s October 28 live review confirmed Backlinko stayed excluded across reload and another page while Wikipedia remained enabled.

Existing rules: Older saved expressions are preserved because generated and manual rules share the same list without provenance. An old broad rule can still overmatch; adding a new rule does not override it. Remove or edit the affected old rule before recreating the exclusion. This closes the new-rule correction, not an automatic migration.

Original requirements and engineering checks

Historical specification. The verified closeout above supersedes its open status.

Medium priority · Confirmed in Chrome 3 SEObar · Inherited from legacy 3.13.5

Issue: “For this domain” builds an exclusion by appending window.location.host to ^http(s)?://. The hostname’s dots are treated as regex wildcards, and the pattern has no host boundary. Excluding example.org therefore also hides SEObar on unrelated hosts such as examplexorg and example.org.other.test.

Working behavior: The exclusion saves and remains effective on the selected host through navigation, reload, a new tab and browser restart. This is a matching correction, not a fix for lost settings. Legacy 3.13.5 generated and evaluated the same pattern.

Fix:

  • Make buildDomainExcludePattern treat the selected host as literal text and enforce the end of the host. Escape regex metacharacters and use a proper boundary, or use an equivalent structured host comparison. Retain HTTP/HTTPS handling and the current explicit-port behavior.
  • Preserve the current host scope. Excluding example.org must not silently expand to www.example.org or other subdomains. Site-wide exclusions and changes to the control’s wording are separate product decisions.
  • Keep manually entered regex rules working through isSeobarAllowedOnUrl. Review how previously generated exclusions can be corrected safely; do not rewrite stored entries whose origin or intent cannot be established. Keep appendSeobarExcludePattern deduplication and existing settings persistence intact.

Existing rules: The current list stores generated and manual expressions together without a provenance marker. Robert should identify a safe treatment for old generated entries and state any remaining limitation. A matching-looking string alone is not proof that it was generated automatically.

Scope: SEObar’s “For this domain” action and its generated host-exclusion rules. No change to the Google SERP overlay, global pause, whitelist behavior, custom regex semantics or default visibility.

Files: src/utils/seobar/urlFilters.ts (buildDomainExcludePattern, appendSeobarExcludePattern, isSeobarAllowedOnUrl); src/components/seobar/layout/SeobarCloseDropdown.tsx. Confirm the source equivalents in the current implementation before editing; supplied-package matching logic was independently verified.

Engineering checks · exact host matching and persistence
  • Use the actual close menu on example.org. SEObar disappears there and stays absent on another path, after reload, in a new tab and after browser restart.
  • Confirm examplexorg, example.org.other.test and an unrelated control still display the bar after the exclusion. Verify they display it before the test as well.
  • Confirm www.example.org and sibling subdomains retain the current independent behavior. Check HTTP/HTTPS and a host with an explicit port without broadening the approved scope.
  • Keep intentional custom regex exclusions, whitelist entries and duplicate handling unchanged. Test the selected treatment of older generated rules alongside manually entered patterns; document ambiguous entries rather than silently rewriting them.

Acceptance: Newly generated rules exclude only the selected host under the existing scope. Unrelated hosts remain unaffected, custom regex rules keep their meaning, and handling of older entries is explicit.

Evidence · current package and legacy behavior

October 27 checks used the unchanged 4.3.1-chrome-3-seobar package in an isolated Chrome for Testing profile. Actual menu actions confirmed same-host persistence through browser restart and reproduced both unrelated-host false exclusions. Exact packaged-function checks confirmed the same matching behavior.

The legacy 3.13.5 package’s data/plugins.js builds the same pattern in handleExcludeClick and evaluates it with new RegExp(r, 'i') in checkMatch. This is inherited behavior, not a newly introduced rebuild regression. The uninstall respondent’s website is unknown; these findings do not prove the cause of that individual complaint.

Metric error text disappears on light reports Completed · 4.3.1

Verified October 28: The shared report error label stays dark and Retry stays blue under both system preferences. Package tests cover Pinterest, Backlinks and SE Traffic. Beatus’s October 28 live screenshots show a readable Pinterest error followed by successful Retry to a numeric zero. Request recovery remains complete.

Original requirements and engineering checks

Historical specification. The verified closeout above supersedes its open status.

UX-01 · Low priority · Styling correction only

Completed: Pinterest failures now show an error and remain eligible for Retry and Request all parameters. HTTP 429/500 and transport-failure recovery passed in both Chrome 3 packages. Genuine zero stays numeric; a successful empty response stays n/a. Previously completed Backlinks, domain and AI-source retry work remains complete.

Issue: With a dark system color preference, the white Full Report displays “Couldn’t load” in white. The shared error label uses text-gray-darker dark:text-white, so the system preference changes the text without changing the report surface. Retry remains visible and works. This is a presentation issue, not a recurrence of the Pinterest recovery bug.

Fix:

  • In the shared metric-error component used by the Links table, remove the OS-triggered dark:text-white from the light report label and dark:text-lavender from its Retry control. Keep text-gray-darker and text-blue so both remain readable on the white report under either system preference.
  • Scope the change to the light app/report error treatment. If the source component also serves a genuinely dark surface, use an explicit surface variant. Preserve the separate serp-ui.js error renderer and overlay theme styles; do not change the global dark-mode selector.
  • Keep role="status", Retry’s accessible name, keyboard focus and onRetry unchanged. Preserve the working Pinterest service/message handling, manual and bulk retry, and zero/empty formatting. No request or retry orchestration changes are needed.

Fix validation: Removing only those two classes in a temporary browser DOM override kept the label dark under both system preferences. Retry remained readable and recovered a real zero. This validates the color correction; the rebuilt source patch still needs the checks below.

Files: Shared metric failure renderer used by the Full Report Links table and metric cards. In 4.3.1-chrome-3-seobar/chunks/semrush-Ck9Hqxg5.js, it is li, exported as Q (formatted lines 3143–3156). Locate the source equivalent by Couldn’t load and its label/onRetry props; the older local checkout does not establish the new source filename. Do not patch generated bundles.

Engineering checks · error contrast and preserved recovery
  • Force a Pinterest failure in the white Links report under both light and dark system preferences. “Couldn’t load” must be readable and Retry must remain visible, keyboard-accessible and functional.
  • Check failed Backlinks and domain-metric cells that reuse the renderer. Confirm manual Retry and Request all parameters still recover failed cells without re-requesting successful cells.
  • Confirm the separate SERP and AI-source error treatment remains readable on light and dark overlay surfaces, including explicit appearance choices that differ from the system preference.
  • Keep genuine zero and successful no-data responses distinct from failures. This correction must not change response/cache behavior.

Acceptance: Error text is readable on the surface where it appears, and the verified retry behavior is preserved.

Previous requirements and verified retry work

October 26 requirements retained for traceability. The Chrome 3 completion and styling-only revision above supersede the former Pinterest failure report.

UX-01 · Low priority · Revision required for 4.3.1 chrome-2-perf

Completed: Backlinks and domain-metric errors, manual and bulk recovery, AI-source retry, independent metric-group state and CSV zero/n/a handling passed the focused package checks.

Issue: A failed Pinterest request still becomes {ok:true,count:null}. Links shows n/a without Retry, and Request all parameters skips that cell after recovery. Beatus reproduced this offline and online in the same report. This is a low-priority failure-path edge case.

Fix:

  • Preserve HTTP and network failures at the Pinterest service/message boundary instead of turning them into a successful empty response. Reuse the existing Links error state to show “Couldn’t load” with Retry.
  • Keep failed Pinterest cells eligible for Request all parameters. Skip successful and in-flight requests; retry only on user action.
  • Keep successful empty responses as n/a and genuine zero counts numeric. Preserve the completed retry behavior for other metric groups.

Scope: Pinterest failure handling and recovery only. This remaining edge case does not alone block 4.3.1.

Files: Pinterest service/message handler in background.js (reviewed functions Mt and Kt); src/components/report/panels/LinksPanel.tsx; src/components/report/panels/links/LinksTable.tsx. Use the source equivalents when implementing.

Original scope and completed work

Historical October 26 requirements. At that review, only Pinterest failure handling remained open; Chrome 3 subsequently completed it. The current revision above concerns error-text contrast only.

Issue: In Full Report → Links, a failed Backlinks, domain-metric or Pinterest request is stored as loaded, with an error that is never shown. The cell displays n/a, the same as a successful response with no data, and Load all skips it. AI Overview source cards follow the same pattern for public metrics: a failed request leaves n/a and the source is marked as requested, so it is not tried again until the page reloads. A temporary timeout or rate limit reads as “this site has no data”.

Fix:

  • In LinksPanel’s requestMetric, keep a failed request distinguishable from a successful empty one for all three metric groups. Today the catch paths set loaded: true with an error that nothing renders. Render the error state in the metric cell as “Couldn’t load” with a Retry control; keep n/a only for successful responses without data. Keep errors separate by metric group, so a Backlinks request cannot clear a Pinterest failure or vice versa.
  • Load all includes unrequested eligible cells and retries failed cells, while skipping successful and in-flight requests. A cell retries only on a user action (Retry or Load all); add no automatic retry loops.
  • For AI Overview sources, allow a user-initiated retry of failed public metric groups. In ai/metrics.ts, load() returns entry.loadPromise before checking entry.requested. An explicit retry must clear or replace that settled promise, reset the requested state as needed and replace a failed domainRequests entry for the origin. Preserve successful group data, shared in-flight deduplication and the current navigation/disposal guards. Match the existing connected-metric retry (retryConnected) in placement and behavior.
  • Keep connected-metric loading, retry controls and their copy unchanged.

Scope: Full Report Links metric cells and AI Overview public metrics, where the verification confirmed the pattern. Check SEObar, SERP result rows and Quick View Semrush metrics for the same error-to-n/a conversion; include them only if they share it, and list them in the change. A page or report reload already retries, because failures are not cached.

Files: src/components/report/panels/LinksPanel.tsx; src/components/report/panels/links/LinksTable.tsx; src/utils/serp/google/ai/metrics.ts; src/components/serp/AiSources.tsx.

Engineering checks · Pinterest recovery and regression coverage
  • For each Links metric group, simulate a timeout, HTTP 429 and 500 responses and going offline. The cell shows the error with Retry instead of n/a. After the service recovers, Retry fills the value. Load all includes unrequested eligible cells and failed cells, while skipping successful and in-flight requests.
  • Run Backlinks and Pinterest requests together with one failing and the other succeeding, then reverse the outcomes. Each cell retains its own result or error; starting or completing one group must not clear the other group’s failure.
  • A successful response without data still shows n/a and is not requested again by Load all. Real zero values stay numeric.
  • Fail public requests for one AI Overview source and wait for the original entry.loadPromise to settle. Retry issues a fresh request and restores failed values without replacing successful group data or duplicating active requests for sources on the same origin. Test a second failure followed by recovery. Connected retry controls behave as before.
  • Retry is a named button (for example “Retry Backlinks”), reachable by keyboard and visible in light and dark themes. Error text is announced without moving focus.
  • CSV exports must not write a number for a failed cell. Keep the current export value for missing data.

Acceptance: Verify on the rebuilt extension with controlled failures. Pinterest recovery was unimplemented at the October 26 review and passed in Chrome 3. Retain these functional checks as regression coverage; only the contrast correction remains open.

Remove the Keyword data tooltip Completed · 4.3.1

Verified: Chrome 3 and Chrome 3 SEObar show no Keyword data tooltip or browser title on hover/focus. The accessible description, query/country destination and tracking remain intact. The approved row and Opus’s reference mockups are preserved below.

Original requirements, visuals and engineering checks

Historical specification below. The closeout above supersedes its former open status.

CRO-07 · Low priority · Copy revision for 4.3.1

Completed: The Keyword data row, query/country destination and tracking are implemented. Package checks and live review passed.

Issue: The visible tooltip repeats the query already shown in Google. Remove it; keep the approved row and accessible description.

Fix:

  • Remove the visible tooltip from “Keyword data”, including any browser title tooltip. Keep its descriptive accessible name, current query and new-tab information.
  • Keep the existing label, icon, placement, destination, locale handling, tracking and keyboard focus unchanged.
Implemented design · reference

Visual: shipped 4.3.0 sidebar compared with the proposed row, for the query “what is seo”.

Current · 4.3.0 · light
Expanded SERP sidebar in light Google: SEOquake toggle, Parameters, Export CSV and Locale, beside result 1.
Proposed · light: Keyword data under Export CSV
The same sidebar with a Keyword data row and the Semrush icon under Export CSV, styled like the rows above it.
Current · 4.3.0 · dark (Match Google)
Expanded SERP sidebar in dark Google: SEOquake toggle, Parameters, Export CSV and Locale.
Proposed · dark (Match Google)
The dark sidebar with a Keyword data row and the Semrush icon under Export CSV.

Captured from the shipped 4.3.0 package on a local Google results page at 2x; live Google was not loaded. The proposed row is built from the Export CSV row’s own markup, so its spacing, color, hover and focus classes match. The icon is the Semrush mark already used on result metrics.

Implemented row requirements

Fix:

  • Add one row under Export CSV in the expanded sidebar, using ParameterControl’s stack layout: the Semrush icon and the label “Keyword data”. It is a link that opens in a new tab.
  • Link to https://www.semrush.com/analytics/keywordoverview/?q=<query>&db=<database>. Use the trimmed, URL-encoded Google query. Hide the row when the query is empty. Keep the destination current when Google changes the search query without a full reload.
  • Choose the database with resolveSemrushDatabaseCountry, using the applied settings.googleGl and current Google URL, as result rows and Analyze links do. Germany opens db=de; preserve the helper’s fallback for unset or unsupported countries. Do not treat the search phrase as a target domain or derive the database from the language. Preserve the existing Set locale navigation.
  • Track with the shared Link helper: surface serp, destination: 'keyword_overview', placement: 'cta', panel: 'serp' and qualifier research_keyword. The explicit panel is required because the sidebar has no current panel ID. That generates utm_campaign=serp_keyword_overview and utm_content=serp_cta_research_keyword with the standard source, medium and ref, a new campaign that can be measured on its own.

Revision · October 21: Remove the Keyword data tooltip. Repeating the search query adds clutter because it is already visible in Google’s search field. Keep the row label and screen-reader description; no replacement tooltip copy is needed.

Label: the sidebar leaves about 88px for a row label at 13px. “Keyword data” (84px) fits. “Research keyword” (113px) and “Keyword Overview” (115px) would truncate. Keep the implemented label.

Preserved behavior: Hiding the row for queries with operators such as site: or inurl: is a product choice, not an approved requirement. Keep the implemented original-query behavior; do not strip operators as part of the tooltip revision.

Scope: One placement, in the expanded sidebar only. The collapsed tab is unchanged, and the row hides with the other tools when the SEOquake overlay is unchecked. No result-row or AI Overview keyword links in this ticket; measure this campaign before adding more placements.

Files: src/components/serp/SerpControlPanel.tsx; src/components/shared/parameters/ParameterControl.tsx; src/utils/semrush/utm.ts; src/utils/semrush/databaseCountry.ts.

Engineering checks
  • Check single words, multi-word phrases, quotes, non-Latin scripts and very long queries. The URL is encoded and the label never truncates.
  • Select Germany and apply Set locale. After the existing Google navigation, the link uses db=de. Check unset and unsupported countries against the helper’s fallback, and confirm that a language-only change does not select a country database.
  • Change the Google search query without a full reload; the link and accessible name use the new query. Empty queries hide the row. Test operator queries against the confirmed behavior without silently rewriting them.
  • Check hover and keyboard focus in light and dark themes against the Parameters and Export CSV rows, including the sidebar’s mint focus ring in dark mode.
  • Hover and keyboard focus show no tooltip for Keyword data. The link still works by keyboard, keeps its visible focus ring and exposes the descriptive accessible name.
  • Verify the landing page for signed-out, free and paid accounts. Do not imply unlimited keyword data; flag any limit that contradicts the label.
  • Verify the final URL includes utm_campaign=serp_keyword_overview, utm_content=serp_cta_research_keyword, the encoded query, country database and standard source, medium and ref. Confirm the campaign appears in attribution reporting before judging the experiment. A click is not a registration.

Acceptance: Verify on the rebuilt extension with the real Keyword Overview journey. This ticket does not claim a measured conversion increase.

Audit results change after the background worker stops Completed · 4.3.1

Verified: Captured HTTP status and noindex survived natural worker shutdown in the reviewed package. Same-tab navigation and uncaptured-page/PDF checks passed.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: After Chrome stops the background worker, SEOquake can lose the page’s HTTP status and response headers. A captured 200 response becomes an error, and a page with X-Robots-Tag: noindex can appear indexable. The recorded chrome-5 test reproduced this after 30 seconds idle. The root cause also exists in 4.2.3.

Fix:

  • Register network and tab-cleanup listeners synchronously. Preserve enabled and paused behavior while settings initialize; do not collect while SEOquake is paused.
  • Keep the required network observations in session storage and restore them before answering report requests. Associate them with the correct tab and navigation. Clear closed-tab data and invalidate stale observations when the page changes.
  • Distinguish a response that was not observed from an observed response with no robots header. Missing capture must not become an HTTP failure, an indexable verdict or a healthy summary count. Apply the same distinction to the combined Noindex result and PDF output.

Copy to confirm: The label and explanation for an unobserved response still need review. The required behavior is settled: do not show a definitive pass or failure without captured evidence.

Files: src/entrypoints/background.ts; src/utils/page/messaging/registerBackgroundNetworkHandlers.ts; src/utils/page/messaging/pageNetworkHandlers.ts; src/utils/page/cache/; network-dependent analyzers in src/utils/page/analyzers/.

Engineering checks
  • Load a page returning 200 and X-Robots-Tag: noindex. Compare Quick View, Full Report and PDF before and after natural worker termination. Captured noindex remains blocked. Run without DevTools keeping the worker alive.
  • Navigate while the worker is stopped, and analyze a page already open before extension installation. Uncaptured data stays unknown rather than becoming a definitive pass or failure.
  • Navigate to a different URL in the same tab. The new document must not inherit old response headers. A captured 200 response without a robots header retains its normal result.
  • Check pause/resume, settings initialization, tab closure and session restoration. Keep saved preferences and existing report navigation intact.

Acceptance: Run these checks on the rebuilt extension. Verification identifies the existing defect; it does not establish that a fix has shipped.

Standard robots directives produce false warnings Completed · 4.3.1

Verified: Focused parser, report and PDF checks passed for permissive, restrictive and crawler-scoped directives.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: Common Yoast and Rank Math directives such as max-image-preview:large and max-snippet:-1 trigger warnings in Meta Robots and Noindex Tag. The shared parser also misses bot-scoped headers such as googlebot: noindex. These results misrepresent the page’s indexing directives.

Fix:

  • Evaluate directive values and bot scopes in both parsing paths. Permissive max-* values should not trigger restrictive-directive warnings; do not blanket-allow every value.
  • Preserve meaningful handling of noindex, none, restrictions and conflicts. A bot-scoped noindex must not produce an unqualified indexable result.
  • Keep Meta Robots, X-Robots-Tag and Noindex Tag consistent. Preserve agent scope rather than silently applying one bot’s directive to every crawler.

Files: src/utils/page/analyzers/metaRobots.ts; src/utils/page/helpers.ts; src/utils/page/analyzers/noindex.ts; src/utils/page/analyzers/xRobotsTag.ts.

Engineering checks
  • Test max-snippet:-1, max-video-preview:-1 and max-image-preview:large, separately and together. They must not produce restrictive-directive warnings.
  • Test restrictive values such as max-snippet:0, noindex, none, multiple meta/header values and conflicting follow directives. Retain the relevant restriction and scope.
  • Test googlebot: noindex alongside unscoped directives. Check all three related results, including the combined Noindex check. Missing network capture follows the unknown-state handling above.

Acceptance: Run these checks on the rebuilt extension. Verification identifies the existing defect; it does not establish that a fix has shipped.

Responsive pages fail when CSS cannot be inspected Completed · 4.3.1

Verified: Cross-origin CSS and fluid-layout fixtures returned neutral results; PDF and summary handling passed.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: The responsive-design check counts readable media rules. Cross-origin stylesheets are skipped, and a zero count produces a failure even when the viewport is valid. Responsive pages using CDN CSS, nested rules or fluid layouts without media queries can therefore fail this check.

Fix:

  • Track whether the relevant stylesheets could be inspected and traverse accessible nested rules where supported.
  • Do not infer a responsive-design failure from zero readable media rules. Cover unreadable CDN CSS and valid fluid layouts, not just the cross-origin exception.
  • Use an inconclusive result when the available evidence cannot establish responsiveness. Keep the separate viewport findings; a valid viewport alone does not prove a responsive layout.

Status and copy to confirm: The inconclusive label and explanation still need review. Do not substitute an automatic pass or keep a false failure while choosing the wording.

Files: src/utils/page/collectors/responsiveDesign.ts; src/utils/page/analyzers/responsiveDesign.ts.

Engineering checks
  • Compare fixtures using same-origin media rules, nested media rules, unreadable cross-origin CSS and a valid fluid layout without media queries.
  • The CDN and fluid-layout cases must not fail solely because the collector found no media rules. A valid viewport alone must not create a responsive-design pass.
  • Check invalid and missing viewport tags separately. Review the agreed inconclusive label in Quick View, Full Report, summary counts and PDF.

Acceptance: Run these checks on the rebuilt extension. Verification identifies the existing defect; it does not establish that a fix has shipped.

Page text can invalidate a valid Analytics setup Completed · 4.3.1

Verified: Valid GA4 plus unrelated body text remained valid. Malformed tracking configuration and body-only text stayed distinct.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: The Analytics collector scans the entire page HTML for tracking-like IDs. Ordinary text such as G-20 summit can be treated as an invalid ID and make a valid Analytics setup fail. A valid GA4 ID plus this body text reproduced the false result.

Fix:

  • Collect IDs from supported tracking scripts and configuration contexts. Do not treat arbitrary page copy as tracking configuration.
  • Preserve supported GA4, Universal Analytics and Tag Manager detection. A malformed ID in an actual tracking configuration must still be identified; unrelated text must not override a valid setup.

Files: src/utils/page/collectors/analytics.ts; src/utils/page/analyzers/googleAnalytics.ts.

Engineering checks
  • A valid GA4 setup plus G-20 summit in body text remains valid. The same body text without tracking code must not establish an Analytics installation.
  • Check supported GA4, Universal Analytics and Tag Manager configurations. A malformed ID in an actual tracking configuration remains actionable.
  • Confirm the same result appears in Quick View, Full Report and the Audit PDF. Do not change other audit checks or the 28-check total.

Acceptance: Run these checks on the rebuilt extension. Verification identifies the existing defect; it does not establish that a fix has shipped.

SEObar code loads when nothing will display Completed · 4.3.1

Verified: Off, paused and excluded fixtures avoided full UI work. Existing-tab enable/disable and pause/resume checks passed.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: Pages still load and compile the SEObar bundle when SEObar is off, SEOquake is paused or the page is excluded. The off and paused cases used about 6–7 ms of extension script work at normal CPU and 27 ms at 4×. The excluded-page check also used about 27 ms at 4×, with no visible bar.

Fix:

  • Keep the initial script small. Check the current settings and page eligibility before loading the SEObar UI, styles and other expensive dependencies.
  • Verify the packaged output actually keeps that UI separate. The existing dynamic import is inlined into the shipped bundle, so changing the source import alone is not enough.
  • Preserve settings changes, pause/resume and navigation in already-open tabs. If changing content-script registration, account for scripts already injected into those tabs.

Expected benefit: Less repeated processing where the bar will not appear. The measured script time is a target to reduce, not guaranteed page-load savings.

Files: src/entrypoints/seobar.content.ts; src/utils/seobar/visibility.ts; src/utils/seobar/urlFilters.ts; src/utils/seobar/watchPageUrl.ts; packaged content-scripts/seobar.js.

Engineering checks
  • Compare the shipped baseline and rebuilt package on enabled, SEObar-off, globally paused and excluded pages. Inspect loaded scripts as well as the visible UI. The full UI bundle must not load where it is not needed.
  • Enable and disable SEObar, pause and resume SEOquake, and change exclusions with tabs already open. Check normal navigation, history navigation and pages that update their URL without a reload. Avoid duplicate bars, listeners or timers.
  • Repeat the normal-CPU and 4× checks with the same pages, observation window and five runs per condition. Report the actual reduction; keep saved preferences and the existing default behavior.
  • Run the shared cache checks. Confirm that the normal enabled path still loads its metrics and report shortcuts.

Acceptance: Verify the built package and record before/after results. No implementation or measured savings are claimed yet.

Resource-heavy pages generate unnecessary background messages Completed · 4.3.1

Verified: The resource-heavy fixture recorded fewer worker message events while tested network evidence remained correct. This is reduced overhead, not elimination.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: Broad network listeners observe requests across tabs and resource types. On the 300-image test page, the worker received 2,505 messages with SEOquake enabled and 2,431 with SEObar off. Worker processing was 26.1 ms and 23.5 ms respectively. These are messages, not separate worker starts.

Fix:

  • Map each listener to the report evidence that needs it. Narrow request types, URLs and collection lifetime where that evidence can still be captured correctly. Restrict redirect tracing to the requests that need it.
  • Coordinate this with the 4.3.1 network-observation fix. Preserve synchronous listener registration, session restoration, tab/navigation ownership and unknown-state handling.
  • Retain original navigation status, response headers, redirects and required image evidence. A later fetch is not a substitute for the original response, especially on authenticated pages. Keep permission removal or optional-permission changes out of this fix.

Expected benefit: Less background work on pages with many requests. The exact reduction needs a candidate build; the independent run did not isolate each listener's cost.

Files: src/utils/network/redirectCapture.ts; src/utils/page/messaging/registerBackgroundNetworkHandlers.ts; src/utils/page/messaging/pageNetworkHandlers.ts; src/utils/page/cache/mainFrameNetworkCache.ts; src/utils/page/cache/imageResponseSizeCache.ts; src/entrypoints/background.ts.

Engineering checks
  • Compare the baseline and candidate on the article and 300-image fixtures, with SEOquake enabled, SEObar off and globally paused. Measure worker messages and processing separately from page-load time. Verify a repeatable reduction. Measure report-opening latency too, and confirm that deferred collection preserves responsiveness and complete audit evidence.
  • Run all network-observation acceptance cases, including natural worker termination, missing capture and a captured X-Robots-Tag: noindex response.
  • Test concurrent tabs, redirects, authenticated pages, navigation in the same tab and tab closure. Check image evidence, Quick View, Full Report and PDF results against the baseline.
  • Keep link checks on demand and preserve recognized logout/action-link filtering. Run the shared cache checks and verify paused behavior.

Acceptance: Confirm both the reduced work and unchanged audit evidence on the rebuilt extension. Performance gains must not turn missing evidence into a healthy result.

SERP Overlay adds processing on Google pages Completed · 4.3.1

Verified: The perf package reduced processing in controlled comparisons. Beatus’s connected live Google/AI review and both CSV exports passed. Windows and real-world timing gains are not established.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: The verified ten-result fixture added about 582 ms of page processing and 95 ms of blocking time at 4× CPU throttling. All ten overlays rendered in each extension run. The SERP bundle also loads on Google pages where there are no web results. These measurements describe browser processing, not the size of a rebuild or guaranteed page-load savings.

Fix: Investigate before choosing the rendering changes. Separate the small page-eligibility check from expensive results UI. Profile startup, overlay creation, repeated rendering and rescans to find the dominant costs. Propose a targeted change that keeps the existing design and functionality. The fixture confirms overhead; it does not establish the best rendering fix.

Coverage to complete: Test real Google results and AI Overview with Semrush connected and disconnected. Google served a verification challenge during the independent live check. Authentication succeeded, but the connected timing harness failed before recording measurements. Windows and lower-memory hardware remain untested.

Files: src/entrypoints/serp.content.tsx; src/utils/serp/syncOverlays.ts; src/utils/serp/google/match.ts; src/utils/semrush-connected/cache.ts; packaged content-scripts/serp.js.

Engineering checks
  • Profile the verified ten-result fixture and real results before changing the render path. Compare five baseline and candidate runs over the same observation window. Record processing, long tasks and time until usable metrics; do not treat shifted post-load work as eliminated work.
  • Check Google home, web results and other search modes. A /search* path alone does not identify web results. Preserve supported navigation into and out of results pages.
  • Verify all expected overlays, position numbers, inserted/removed results, AI source cards, light/dark appearance, tooltip layering and sidebar controls. Keep country/language and metric selections intact.
  • Test connected and disconnected metrics on cold and repeat visits. Confirm authenticated metric responses, not just the connection label. SERP and AI-source CSV exports must include all eligible results, including anything loaded lazily.
  • Run the shared cache checks. Repeat on a lower-powered Windows machine when available; keep that limitation explicit until tested.

Acceptance: First return the profile evidence and proposed change. Then demonstrate reduced work and passing functional checks on the rebuilt extension. A redesign or rebuild is not prescribed.

Connect Semrush directly and update the signup copy Completed · 4.3.1

Verified: Package checks and Beatus’s live authorization, automatic refresh and existing free-account metric checks passed. The bottom banner also passed live review; the earlier isolated result is superseded for closeout. The pending card was explained by an open OAuth tab. New-account registration was not separately tested.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: Connect Semrush opens Settings → Integrations before users can start connecting. The connection card asks whether they already have an account, while the signup prompt still promotes Semrush One. Remove the extra settings step and give new users a clear free-account option.

Fix:

  • Start the existing OAuth flow directly from connection CTAs in Quick View, Full Report and the first-result SERP teaser. Reuse startSemrushAuth() through the existing connection flow instead of the Settings navigation callbacks. Keep source-tab context for returning to the report. Keep Settings available for managing or disconnecting the account.
  • Require an explicit click. Preserve the random, single-use authorization state, its 10-minute expiry, callback validation, existing scopes and token handling. Do not hard-code a standalone authorization URL or expose credentials to the host webpage.
  • Keep the original page/report available. Prevent duplicate starts throughout authorization, handle cancellation and failure with a retry option, and refresh connection status and metrics after success. The existing useSemrushConnection hook’s busy state covers launch only; opening OAuth is not a completed connection.
  • Apply the approved copy below to the shared connection card in Quick View and Full Report. Replace the associated Semrush One signup promotion with the free-account link. Keep the existing layout and responsive behavior. The compact SERP teaser keeps its current copy for this ticket; only its Connect action changes.
  • For signup links, add signup to SemrushDestination and use destination: 'signup', placement: 'cta', panel: 'semrush' with the shared Link helper. Use /signup/; generate popup_signup or report_signup by surface, preserving the attribution fields below.
Current Backlinks Overview connection card with Already Have a Semrush Account headline, Connect Semrush button and Semrush One trial link.
Current design reference · Replace the connection-card copy and Semrush One signup prompt below. Click to open full size.

Approved copy:

  • Headline: See Authority Score, visits and engagement data
  • Body: Connect a free Semrush account to see these metrics.
  • Button: Connect Semrush
  • Line below: New to Semrush? Create a free account

Signup link and tracking: Use https://www.semrush.com/signup/. Add signup to the shared tracking destinations. Keep utm_source=seoquake, utm_medium=toolbar, utm_content=semrush_cta and ref=174537735. Use utm_campaign=popup_signup in Quick View and report_signup in Full Report. Remove the old semrush_one destination from these signup links so the helper does not overwrite the new campaign. Do not change unrelated promotions or add these signup UTMs to the OAuth URL.

Scope: Signup creates an account; Connect authorizes SEOquake to use it. Verify the new-account journey and available free-account metrics before shipping this copy. Do not imply unlimited data access. The approved first-result lock icons are covered by the separate teaser ticket, and the header status entry point by the status ticket.

Files: src/components/shared/semrush/LockCta.tsx; src/components/popup/panels/SemrushPanel.tsx; src/components/report/panels/SemrushPanel.tsx; src/components/serp/overlay/SerpConnectedMetrics.tsx; src/hooks/useSemrushConnection.ts; src/utils/semrush-auth/messaging/authHandlers.ts; src/utils/semrush-auth/oauthState.ts; src/utils/semrush/utm.ts.

Engineering checks
  • From Quick View Overview and Traffic Analytics, Full Report and the first-result SERP teaser, click Connect once. The normal Semrush authorization flow opens without requiring a second click in Settings. Verify any connection banner in the same surfaces uses the same behavior.
  • Test signed-in and signed-out accounts, cancellation, failed requests, retry and repeated clicks. The original page/report remains available. A successful connection refreshes the relevant UI and metrics without a manual reload.
  • Confirm invalid, expired and replayed authorization state and an unexpected callback origin are rejected. Preserve existing permissions, account-disconnect behavior and secure background token handling. A shortcut to the same flow is not a replacement for its security checks.
  • Verify both signup destinations and their final generated tracking parameters. Walk through new-account creation and returning to connect SEOquake. Confirm which Authority Score, visits and engagement data a free account can actually access; flag any mismatch with the approved copy before release.
  • Check the longer headline in Quick View and Full Report at their supported widths. Keep wrapping readable, button focus visible and loading/error states clear. Keep actual zero values unchanged. Disconnected placeholder changes are scoped to the teaser ticket.
  • Measure connection success and signup completion separately where supported. A CTA click is not a completed connection or registration. Confirm signup attribution with the analytics owner; do not infer conversion gains from click counts alone.

Acceptance: Verify the rebuilt package and the real authorization/signup journeys. No implementation, security certification or conversion lift is claimed by this handoff.

Show locks instead of disconnected teaser zeros Completed · 4.3.1

Verified: Five disconnected locks and the absent teaser gauge passed. Connected Authority Score 0, traffic n/a formatting and live exports remain unchanged.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: When Semrush is disconnected, the first organic result shows placeholder zeros for Authority Score, Visits, Pages/Visit, Avg. Visit and Bounce Rate. These are not measured values. They can make the result look like it has no authority or traffic instead of showing that an account connection is needed.

Visual: shipped 4.3.0 compared with the proposed locks, on result 1 with the top of result 2.

Current · 4.3.0 · light: placeholder zeros and an empty AS gauge
Disconnected SERP result 1 in light Google: AS 0 with an empty gauge, Visits 0, Pages/Visit 0, Avg. Visit 0, Bounce rate 0, and the Connect prompt. Result 2 shows only its standard row.
Proposed · light: five locks, no gauge; labels and Connect prompt unchanged
The same result 1 with a small lock after AS, Visits, Pages/Visit, Avg. Visit and Bounce rate, no gauge, and the unchanged Connect prompt. Result 2 is unchanged.
Current · 4.3.0 · dark (Match Google)
Disconnected SERP result 1 in dark Google with placeholder zeros and an empty AS gauge.
Proposed · dark (Match Google)
Disconnected SERP result 1 in dark Google with five locks, no gauge and the unchanged Connect prompt.
Connected · real API zeros: unchanged by this ticket
Connected SERP result 1 with the API returning zeros: AS 0 keeps its gauge, and Visits, Pages/Visit, Avg. Visit and Bounce rate show n/a.

Captured from the shipped 4.3.0 package on a local Google results page at 2x; live Google was not loaded. The proposed frames change only the five disconnected values: each becomes the repository’s lock.svg at 12px in the label colour, and the AS gauge is removed. Screen readers would hear “Authority Score: connect Semrush to view” instead of a zero.

Connected reference: an actual Authority Score of 0 keeps its numeric value and gauge. Zero traffic already displays n/a, because formatTrafficMetrics (src/utils/semrush-connected/trafficAnalytics.ts) treats visits of 0 or less as no data.

Fix:

  • Replace those five disconnected placeholder values with small lock icons. Keep the metric labels, order, existing strip styling and connection prompt. Show this teaser only on the first organic result, as it does today.
  • In ConnectedMetric, select locks only for status === 'disconnected'. Keep SerpOverlay’s first-result visibility rule. Do not use a zero-value or falsy-value check. Leave formatTrafficMetrics unchanged and preserve existing connected-value formatting: Authority Score 0 stays numeric with its gauge; zero or unavailable visits retain the traffic formatter’s n/a behavior.
  • Gate the Authority Score gauge with !disconnected && score != null so the teaser does not imply a measured score of zero. Keep the gauge and its normal behavior for actual connected scores, including 0.
  • Use lock.svg at 12px in the label colour, matching the mockups. Provide accessible text such as “Authority Score: connect Semrush to view” for each locked metric; do not announce a numeric zero. Preserve existing tooltip keyboard access and verify visibility in light and dark themes.
  • Keep the icons non-interactive. The existing Connect CTA remains the action, with direct OAuth covered by the connection-flow ticket. No extra sign-in controls or permission changes are needed.

Scope: Only the disconnected connected-metrics teaser on the first organic result. Leave the separate SE Traffic and other standard metrics unchanged. Preserve connected values, missing-data labels, loading indicators and retry behavior. Disconnected AI Overview cards currently omit Authority Score; do not add locks or change their layout as part of this ticket.

Files: src/components/serp/SerpOverlay.tsx; src/components/serp/overlay/SerpConnectedMetrics.tsx; src/assets/icons/lock.svg. Keep the change scoped where shared metric components are reused.

Engineering checks
  • While disconnected, confirm that result 1 shows five labeled locks, no placeholder zeros and no Authority Score gauge. Later organic results must not gain this teaser. Keep the Connect prompt visible.
  • While connected, test zero and nonzero API values for all five metrics. Authority Score 0 keeps its numeric value and normal gauge. With zero or unavailable visits, traffic and engagement fields retain the formatter’s n/a output. With positive visits, preserve the existing formatting of valid zero engagement values. Missing data must not become zero or a lock.
  • Check initial connection checking, loading, partial success, request errors and retry. Connect and disconnect without reloading the results page; the row must switch between its normal metric states and the locked teaser.
  • Check light and dark Google, narrow available widths and dynamic result insertion/removal. Keep labels readable and the first-result teaser attached to the correct result. Screen readers announce the connection requirement; decorative icons do not add keyboard stops.
  • Confirm that SE Traffic, standard result metrics, AI Overview cards and SERP/AI-source CSV exports are unchanged. Lock icons are presentation only, never metric or export values.
  • Verify that the existing Connect CTA still works. If the connection-flow ticket ships in the same package, run its cancellation, retry and successful-connection checks too.

Acceptance: Verify the rebuilt extension across disconnected and connected states. Disconnected placeholder zeros become locks; all connected-value formatting remains unchanged, including Authority Score 0 and the existing traffic n/a behavior. This ticket does not claim a measured conversion increase.

Disconnected status cannot start a connection Completed · 4.3.1

Verified: Beatus confirmed that the connected header control opens Integrations across the tested surfaces. Disconnected authorization also passed.

Original requirements and engineering checks

Reviewed 4.3.1 chrome-2-perf · Closed October 26, 2026

Issue: Quick View, Full Report and Settings show “Disconnected from Semrush” in the header, but the status is a static element (SemrushStatus.tsx). Users who notice it have to find a Connect button elsewhere. The status is the one connection cue that appears on every surface.

Fix:

  • Make the header status a button. While disconnected, it starts the direct OAuth flow from the connection-flow ticket, using the same handler and duplicate-start guard. While connected, it opens Settings → Integrations, the same destination as the Settings menu’s Manage Semrush connection row.
  • Keep the dot, label and header layout. The pause switch and Settings button keep their positions.
  • Show that it is interactive on the dark header: pointer cursor, mint #18F0BF text on hover and keyboard focus like the other header controls, and a visible focus ring. Add the tooltip “Connect your free Semrush account” while disconnected and “Manage Semrush connection” while connected.
  • Use the accessible names “Connect to Semrush” and “Manage Semrush connection”, matching the Settings menu. Where the label is hidden at narrow widths, keep the dot inside a padded button with the same accessible name. Match the other header controls’ hit area; do not make the 6px dot the entire click target.

Scope: The header status only. If the connection-flow ticket does not ship in the same package, the disconnected status opens Settings → Integrations instead, like today’s Connect paths. Add no UTMs to the OAuth URL.

Files: src/components/shared/layout/header/SemrushStatus.tsx; src/components/shared/layout/Header.tsx; src/hooks/useSemrushConnection.ts. Reference: src/components/shared/layout/header/SettingsButton.tsx.

Engineering checks
  • In Quick View, Full Report and Settings, click and keyboard-activate the status in both states. With the connection-flow ticket included, disconnected starts authorization once; connected opens Settings → Integrations.
  • If the connection-flow ticket ships separately, verify that the disconnected status opens Settings → Integrations and its existing Connect control still starts authorization. On the Settings surface, open Integrations within Settings.
  • Repeated clicks and Enter presses during authorization do not open a second authorization tab. Cancellation and failure leave the status usable. A successful connection updates the label and dot without a reload.
  • Check hover, focus and tooltip on the dark header and at narrow widths. Click the padding around the dot as well as the dot itself; the full button remains usable when the label is hidden. The status does not shift the pause switch or Settings button.
  • If analytics can record connection entry points, record this one separately from the connection cards. A click is not a completed connection.

Acceptance: Verify on the rebuilt extension with the real authorization journey. No conversion lift is claimed by this handoff.

Engineering handoff

Technical fixes

Implemented. See each item’s verification and remaining checks. The original diagnosis and guidance are kept as history.

Quick View report shortcuts and count fit Completed · 4.3.0

Shipped in 4.3.0: separate Internal/External counts, Words routing, the Full Report menu and the count-fit change. The Words hover/focus descriptions were accepted as unnecessary and are not open work. The combined-large-count limit remains accepted. Earlier screenshots and comparisons below are retained as references, not current defects.

Earlier follow-up requirements · superseded

Implemented in chrome-4: Internal/External occurrence counts and destinations, clickable Words in Page Info and Content, and the Full Report sections dropdown. Loaded-extension checks confirm the four tile routes, report reuse, menu coordination and focus restoration. The original navigation implementation is complete; the two follow-ups below remain.

Issue: Both Words tiles lack a hover/focus description of their Keyword Density destination. Page Info’s seven-column strip also truncates larger values: 10,028 displays as 10,0… at native popup size, while Content shows the full count.

Fix:

  • In PageSummary.tsx and ContentSummary.tsx, add buttonTooltip: 'Open Keyword Density' to the words item. Reuse BoxValue’s existing button tooltip; preserve the blue value, full-tile action and openReportFromPopup(reportSourceTabId, 'density') routing.
  • In PageSummary.tsx, replace grid-cols-7 with grid-cols-[repeat(7,minmax(max-content,1fr))] and change the strip’s valueClassName from block w-max max-w-[calc(100%+12px)] truncate text-left to block text-left. Columns share the available space until a label or value needs more room. Keep the 16px tile padding, typography, dividers and full-tile actions; Content’s five-column layout stays unchanged. Do not add ellipses or abbreviate counts.

Known limit: Combined large counts—for example, multiple four- or five-digit counts alongside six-digit Words—can exceed the available width. This limit is accepted for 4.3.0; no compact fallback is planned.

Files: src/components/popup/panels/page-info/PageSummary.tsx, src/components/popup/panels/content/ContentSummary.tsx. Reference: src/components/shared/box/BoxValue.tsx and src/utils/surface/navigation.ts.

Engineering checks
  • Words tooltip: both callers omit the packaged buttonTooltip string prop. Supply the same exact copy to both. Verify hover and keyboard focus, a resolving aria-describedby, existing tooltip placement/dismissal, and no added info icon or tab stop.
  • Count fit: Keep the change local to PageSummary.tsx; preserve shared BoxValue defaults, divide-x!, divide-gray-light, px-4 padding and 20px values. In the supplied extension, 10,028 needs 70px while its current button has 67px available. Confirm the new arbitrary grid class is generated in the rebuilt stylesheet.
  • Values: At the native 640 × 600px popup, check Words at 0, 4,204, 9,999, 10,028, 99,999, 100,000, 999,999 and 1,234,567, with the other counts held at the reference values. Also check Internal, External and Images counts in the thousands. Within the available width, require complete formatted values, accurate accessible names, no ellipsis or divider overlap, aligned left edges and unchanged data, formatting and scan behavior.
  • Combined counts and display settings: record where multiple large counts exceed the strip’s available width; this is the accepted limit above, not a guaranteed fit. Check the rebuilt native popup at 125% and 150% zoom, with a larger Chrome minimum font size, and on Windows. A 589px mock strip only simulates reduced width; it does not verify Windows or browser zoom. Keep Content’s existing layout and routing intact.
  • Routing regression: click and keyboard-activate Words in Page Info and Content; both open Keyword Density for the same source tab and reuse the existing report. Preserve Internal/External count parity and targets, Images/H1–H4 actions, menu coordination, focus restoration and empty-state behavior.
  • Settings: keep the Full Report list separator-free; use the Settings follow-up for its two group separators and 8px header gap. No shared dropdown or permission changes are needed.

Evidence: routing and count clipping were checked in the exact supplied chrome-4 extension using controlled page data. Complete native count captures below show the stored number is correct. Earlier fixture-only and retained inactive-panel measurements are not the basis for this finding.

Count clipping screenshots

Page Info · 10,028 truncated at native size
Loaded chrome-4 Page Info with a Words value of 10,028 clipped to an ellipsis.
Content · the same 10,028 count fits
Loaded chrome-4 Content with the full Words value 10,028 visible.

Controlled page data, exact supplied package, native 640px viewport. No live Semrush scan.

Proposed count fit · 5, 6 and 7 digits

Current / Proposed design references. Only Words changes; the other counts stay fixed. Each view uses a native 640 × 600px frame, scaled to fit. These previews do not verify the rebuilt extension.

5 digits · 10,028 words

Current · chrome-4 · Open at full size
Proposed · Open at full size

6 digits · 123,456 words

Current · chrome-4 · Open at full size
Proposed · Open at full size

7 digits · 1,234,567 words

Current · chrome-4 · Open at full size
Proposed · Open at full size

Open the count-fit comparison and implementation notes

Interactive previews

Earlier Before / Proposed references. Try the implemented link counts, Words routing and Full Report menu; proposed Settings shows the remaining grouping and 8px-position fixes. Actions are simulated; nothing is saved. The proposed header includes the Pause controls.

Counts strip

Full Report sections

Open the interactive comparison · Full 640 × 600 previews, scaled to fit.

Screenshots
Internal / External counts and clickable Words · Opus’s proposal
Current and proposed Quick View comparison: Internal / External counts and clickable Words.
Full Report sections dropdown · Opus’s proposal
Current and proposed Quick View comparison: Full Report sections dropdown.
Legacy 3.13.5 navigation reference
Legacy popup tabs for Page Info, Diagnosis, Internal and External link counts, Density and Compare URLs.
Earlier implementation · Content · Words had no action
Quick View Content tab showing H1–H4 counts and an unlinked Words value of 1,844 above Heading Structure and Keyword Density.

Original proposal screenshots retained for reference; the interactive previews above show the latest Settings grouping. Renderings are design references, not proof of implementation.

Original implementation requirements · reference

Earlier requirements retained as history. The remaining Fix and Engineering checks above define the current work.

Issue: Quick View combines Internal and External links into one count, Words has no action in Page Info or Content, and Compare has no direct shortcut. Legacy users previously reached these reports from the popup’s top navigation.

Fix:

  • In PageSummary.tsx, replace links with Internal and External. Use pageData.links.filter(link => link.internal).length and pageData.links.filter(link => !link.internal).length so counts match the report’s total occurrences. Route them through openReportFromPopup(reportSourceTabId, 'links', 'internal') and the corresponding 'external' call.
  • In PageSummary.tsx and ContentSummary.tsx, add button: { onClick: () => openReportFromPopup(reportSourceTabId, 'density') } to words, reusing BoxValue’s blue value and full-tile action. Use grid-cols-7 in Page Info; keep Content’s grid-cols-5. Preserve Images and H1–H4 destinations.
  • In NavButton.tsx, add a separate chevron beside View Full Report, gated to isPopup. Reuse Dropdown with panelTitle="Full Report", its existing aria-haspopup="dialog" / role="dialog" semantics, and ordinary navigation buttons. Use REPORT_PANEL_IDS in order with the report’s icons; each row calls openReportFromPopup(reportSourceTabId, panelId). Keep rows label-only and separator-free; omit divide-y / divide-gray-light from the report list.
  • Preserve the label’s getReportTargetFromPopupTab(currentPanelId) routing and Header’s !isEmptyState visibility condition. Coordinate dropdown state through open / onOpenChange so Settings and Full Report cannot remain open together. Move focus into the dropdown on opening and return it to the chevron on Escape or Close; keep the shared dropdown’s other callers unchanged.

Files: src/components/popup/panels/page-info/PageSummary.tsx, src/components/popup/panels/content/ContentSummary.tsx, src/components/shared/layout/header/NavButton.tsx, Header.tsx, SettingsButton.tsx and src/components/shared/Dropdown.tsx. Reference: src/utils/surface/navigation.ts.

Engineering checks

Package grounding: the chrome-3 PageSummary uses links.length, six columns and a noninteractive Words value. LinksPanel already accepts internal / external section targets on initial load and through its section watcher. Its Total sums occurrences; Unique counts grouped URLs. The shared Dropdown already supports controlled open / onOpenChange, outside-click dismissal and Escape, but does not supply initial-focus movement or focus restoration.

  • Counts: reuse the collected internal flag; do not reclassify URLs or count deduplicated rows. Internal + External must equal the old Links count and each report tab’s Total, including duplicate URLs. Check zero links, all-internal, all-external and mixed pages. Use existing formatting and data-loading behavior; no extra scan, API request or permission is needed.
  • Destinations: Internal opens ('links', 'internal'), External opens ('links', 'external'), and Words in both Page Info and Content opens ('density'). Images keeps ('audit', 'images'); Page Info’s H1–H3 and Content’s H1–H4 keep ('audit', 'heading-structure'). Retain reportSourceTabId and existing report-tab reuse. Check a new report and an existing report on either Links subtab, plus multiple source pages/windows.
  • Words consistency: verify both PageSummary.tsx and ContentSummary.tsx use words.total, the same openReportFromPopup(reportSourceTabId, 'density') action and BoxValue button behavior. In both tabs, the full tile is clickable, the value is blue, Enter/Space activates it, keyboard focus is visible and the hover/focus description names Keyword Density. Test zero and large word counts, then a new and reused Full Report. Reuse collected data; no new scan, request or permission.
  • Main label: preserve the existing handler. Quick View Audit opens Audit; Schema opens Audit’s schema section; Semrush opens Semrush; Page Info and Content use the existing default. Do not replace this with an always-Page-Info callback. Dropdown rows target page-info, audit, density, links, compare and semrush.
  • Layout: rebuild and verify grid-cols-7 is generated; it is absent from chrome-3’s current stylesheet. Keep Page Info’s seven columns and Content’s existing five columns (H1, H2, H3, H4, Words). Keep the 640px popup, current tile fonts, padding, dividers and hit areas. Check large formatted counts, zoom and no clipped labels/values. Keep short visible labels Internal / External, full accessible names with counts, and a hover/focus description for Words’ Keyword Density destination.
  • Dropdown: Header owns one active-menu state, passed to the report trigger and Settings through controlled props. The existing props coordinate visibility only; implement focus behavior as an opt-in for this popup flow. Keep the trigger’s accessible name Full Report sections, correct aria-expanded/aria-controls, a labelled nonmodal dialog and ordinary buttons. Do not add menu/menuitem roles without implementing the corresponding keyboard model.
  • Separators: Full Report has no row dividers. Remove list divider utilities rather than masking them with .sqs-row { border: 0 }. Settings uses the Pause ticket’s three groups, with separators only after Enable SEOquake and the display toggles. Check both menus, connected/disconnected labels and paused Settings; any wrapper change must preserve descendant click handlers, row height and focus styling.
  • Keyboard: Enter/Space opens the dialog and focuses its first destination. Tab/Shift+Tab reach every destination and Close with a visible indicator. Escape and Close restore focus to the report chevron; outside-click dismissal preserves focus on the clicked control. Choosing a destination uses the existing report-opening flow. Opening Settings closes the report dialog and vice versa.
  • Scope and Pause: gate the new control to popup; retain empty/paused/unsupported visibility and valid source-tab handling. Test connected and disconnected Semrush headers alongside the Pause switch, including pausing while a dropdown is open. Keep the header, menu and notice within the popup; preserve the existing Full Report/Settings header behavior and other Dropdown callers.
  • Permissions: reuse current collected data and report messaging. No new Chrome extension permissions or permission prompts are required.

Design reference: copied from Opus’s October 13 chrome-2 renderings with frozen page data (123 Internal + 11 External = 134). Chrome-3’s completed fixes are tracked separately.

Verification boundary: the bundled routing and shared components support this approach. The interactive copies demonstrate the design with simulated actions; rebuilt-extension routing, keyboard and state checks are required before closing the ticket.

Quick View pause and Settings layout Completed · 4.3.0

Shipped in 4.3.0: Pause/Resume, Settings grouping and the 8px header gap. The current What’s New spacing is accepted; no padding revert is planned. Earlier screenshots and previews below are retained as references, not current defects.

Earlier follow-up requirements · superseded

Implemented in chrome-4: Header switch, Settings Enable checkbox, shared Pause/Resume state, pending guard, confirmed-state reconciliation and persistent retry feedback. Tested loaded-extension flows cover successful and failed saves, retry, repeated activations, preserved display-toggle values and loading failure. Settings spacing and What’s New dismissal work; only the design follow-ups below remain.

Issue: Settings still separates Preferences, Semrush connection and About with individual lines. Its panel starts 16px below the header, while Full Report starts 8px below it.

Fix:

  • In SettingsButton.tsx, wrap the popup’s Preferences, Semrush connection and About SEOquake in one navigation group. Keep divide-y on the three-group container only: Enable SEOquake; Show SEObar / Show SERP Overlay; navigation. Keep the outer border and exactly two group separators.
  • Set the popup Settings panel to an 8px gap below the header, matching Full Report. Replace its scoped mt-4 panel override with mt-2, and verify the final geometry. Keep horizontal alignment, 16px padding, the 12px title gap and 34px navigation rows.

Files: src/components/shared/layout/header/SettingsButton.tsx. Reference: src/components/shared/Dropdown.tsx. Gate spacing changes to popup Settings; preserve Full Report/Settings surfaces and other dropdown callers.

Engineering checks
  • Groups: the packaged divide-y list has five direct children, producing four separators. Group the three navigation links as one child without inner divide-y; retain the outer card border and two group lines. Preserve 34px row heights, full-row checkbox targets, descendant click handlers and hover/focus styles.
  • Position: at native 640px, the measured header bottom is 48px; Settings starts at 64px, Full Report at 56px. Settings must also start at 56px. Measure the final effective gap after wrapper and panel margins; do not add another 8px to an existing wrapper offset.
  • States: check connected/disconnected Semrush labels, enabled/paused Settings, and menus with/without What’s New. The top gap stays 8px and the panel stays below the header and within the popup. It overlays the tabs and page content as designed. Preserve the 9px What’s New top padding, 24px column gap, release scrolling and Got it keeping Settings open at single-column width.
  • Behavior: Tab/Shift+Tab, Escape/Close, navigation actions, menu mutual exclusion and focus restoration must keep working. Verify Pause/Resume and saved SEObar/SERP choices after regrouping. Preserve existing shared enabled/pending/error handling; no new storage, permissions or page requests.
  • Scope: the 8px position is the newly approved design change. Apply it to popup Settings only; preserve the Full Report menu and every other Dropdown caller, including Add/Hide Parameters.

Release validation: live Google/account states, all Full Report failure paths, restart/upgrade persistence and assistive-technology announcements remain separate release checks. The review found no additional demonstrated Pause save defect.

Current chrome-4 screenshots
Settings · extra navigation lines and 16px gap
Chrome-4 Quick View Settings with individual navigation separators and the lower panel position.
Full Report · accepted separator-free list and 8px gap
Chrome-4 Full Report sections dropdown positioned closer to the header.

Earlier native Before / Proposed references. Pause controls are implemented in chrome-4; proposed Settings now shows the remaining two group separators and 8px header gap. Controls are simulated and do not change extension preferences.

Quick View header
Earlier implementation referenceOpen at full size
ProposedOpen at full size

Settings open

Earlier implementation referenceOpen at full size
ProposedOpen at full size

Settings open, with What’s New after an update

Earlier implementation referenceOpen at full size
ProposedOpen at full size
Paused
Earlier implementation referenceOpen at full size
ProposedOpen at full size
Legacy 3.13.5 reference

Supplied screenshots of the legacy popup: the green on/off switch beside Settings, and Enable SEOquake at the top of its settings menu.

Header switch
Legacy SEOquake 3.13.5 popup with a green on/off switch next to the Settings icon
Settings menu
Legacy SEOquake 3.13.5 settings menu with Enable SEOquake at the top
Original implementation requirements · reference

Earlier requirements retained as history. The remaining Fix and Engineering checks above define the current work.

Issue: Pausing requires opening Settings → Preferences → General. Quick View’s Settings menu only offers separate SEObar and SERP Overlay controls, making the global pause setting harder to find.

Fix:

  • Add a popup-only switch between the Semrush status and Settings, with a 36 × 32px hit area. Use mint #18F0BF with a dark #181E15 knob when enabled, and grey #60636B with a white knob when paused. Keep the accessible name Enable SEOquake, update aria-checked, and show Pause SEOquake or Resume SEOquake on hover and focus.
  • Add Enable SEOquake as the first Settings checkbox, in its own group above the two display toggles. Make each checkbox’s full row clickable. Use 16px panel padding, 12px below the title and 34px navigation rows. In SettingsButton.tsx, group Preferences, Semrush connection and About SEOquake in one wrapper; use divide-y between groups only. Keep these changes local to this menu.
  • Give What’s New a plain wrapper with 9px top padding and a 24px gap from the menu box. Align its heading with the first menu row and use the approved 4.3.0 copy. Preserve scrolling; Got it dismisses the notes while keeping Settings open at its single-column width.
  • Share enabled, pending and error state across the switch, Settings checkbox and existing Resume button. Save only general.enabled, keep the controls synchronized and prevent stale reads from restoring an older state. Disable pause controls during loading or saving; keep them disabled if loading fails.
  • On a failed save, restore the confirmed state and show “Couldn’t pause SEOquake.” or “Couldn’t resume SEOquake.” with Try again below the header. Keep the notice visible across normal and paused states. Apply failure reconciliation to Full Report’s existing Pause/Resume too.
  • Keep the existing paused screen and Settings access. Preserve saved SEObar/SERP choices, disabling their controls during saving and while paused. Keep native navigation, Settings positioning and empty-state behavior; shift the Semrush status 48px left. Full Report and Settings headers stay unchanged.
Engineering checks

Supporting evidence: Quick View’s Settings → Preferences opens Settings → General → Pause SEOquake, which is also available from Full Report. In the uninstall survey (1,301 answers, September 28 to October 13), “I couldn’t find how to turn it off” is the most chosen follow-up for “got in the way”: 61 of 138 answers. Legacy 3.x had an on/off switch in the popup header and an Enable SEOquake option in its settings menu.

Implementation requirements

  • Add a switch to the Quick View header, between the Semrush status and Settings, with a 36 × 32px hit area aligned to the Settings button. On uses a mint #18F0BF track with a #181E15 knob; paused uses a #60636B track with a white knob. Expose it as role="switch" with the constant accessible name Enable SEOquake and aria-checked reflecting the enabled state. Show Pause SEOquake or Resume SEOquake on hover and focus, using InfoTooltipBubble with the button ref; the default Tooltip renders its own info icon and cannot wrap the switch. Use the mint focus ring.
  • Add Enable SEOquake as the first row of the Quick View Settings menu, in its own group above Show SEObar and Show SERP Overlay. Reuse the existing checkbox. Keep three direct groups under the menu’s divide-y container: Enable SEOquake; Show SEObar / Show SERP Overlay; Preferences / Semrush connection / About SEOquake. The navigation wrapper has no divide-y; keep the outer border and separators between groups only.
  • Tighten the Settings menu to the 4.3 rhythm: 16px panel padding on every side (was 24px top and bottom), 12px below the Settings title (was 20px) and 34px menu rows (8px top and bottom, was 16px). Apply these to the Settings menu only; the shared dropdown panel keeps its spacing elsewhere, including Add/Hide Parameters.
  • Make each checkbox row the click target. Move the row spacing into the label, so Enable SEOquake, Show SEObar and Show SERP Overlay are clickable across the full row (30 to 33px tall, was 17px).
  • When What’s New shows, replace its inner Box with a plain wrapper: no border or background, no inherited Box padding, 9px top padding and 24px from the menu box, with WHAT’S NEW aligned to the first menu row. Keep the existing release-list scrolling and empty-state height limits. Use the approved 4.3.0 What’s New copy. Got it keeps today’s behavior: What’s New disappears and the menu stays open at its single-column width.
  • Use one popup controller for enabled, pending and error state, shared by the header switch, Settings row and paused-screen Resume. Save only general.enabled through saveEnabled / saveSeoquakeEnabled. The popup controls share the same displayed state; Full Report and other open surfaces synchronize when storage commits. The existing hook updates optimistically without rollback; add failure reconciliation with confirmed storage and prevent older refreshes from overwriting a newer accepted action. Guard the enabled-status watcher in usePageData too, so an older read cannot restore the wrong normal/paused body; preserve existing page-loading behavior.
  • Render the switch while settings load, disabled with loading feedback. Keep it disabled if settings fail to load. Guard all three popup pause entry points while a save is pending; repeated activations during that save are ignored, so the final state is the last accepted action. Show pending feedback and disable the SEObar/SERP toggles during the pause transition.
  • Catch failed Pause and Resume saves, including the existing paused-screen Resume. Restore the confirmed enabled state and show a persistent Notice below the header, outside the dropdown and normal/paused content. Use “Couldn’t pause SEOquake.” or “Couldn’t resume SEOquake.” with an actionable Try again control that retries the failed action once saving is available. Keep the notice through popup state changes; show no success notice. Apply failure reconciliation to both Full Report paths: Settings → General via saveEnabled, and paused-screen Resume via usePageData / saveSeoquakeEnabled.
  • Pausing shows the existing paused Quick View: “SEOquake is paused” with Resume SEOquake. Keep Show SEObar and Show SERP Overlay at their saved values but disabled while paused, so resuming restores the previous setup.
  • Gate the new switch to surface === 'popup' in the shared Header and render it independently of isEmptyState. Keep the native left navigation and Settings button in place; the Semrush status shifts 48px left to make room. The paused and unsupported states keep their existing hidden View Full Report behavior. Settings remains usable while paused. Full Report and Settings headers do not change.

Package evidence: in the supplied 4.3.0 package, the Quick View header has the Semrush status and Settings only. The Settings menu lists Show SEObar, Show SERP Overlay, Preferences, Connect to Semrush (Manage Semrush connection when connected) and About SEOquake. Pausing from Full Report → Settings → General shows “SEOquake is now paused.” and the paused Quick View. The comparisons reuse that rendered markup; they are appearance references, not a rebuilt extension.

Verification

  • Pause and resume through the header switch, Enable SEOquake row, Quick View’s paused-screen Resume, Full Report → Settings → General and Full Report’s paused-screen Resume. All popup controls share state; other surfaces agree after the write commits. Verify persisted state after reopening Quick View, page reload and browser restart.
  • Pausing stops the same surfaces as the existing global pause, in every open tab. Resume restores the saved SEObar and SERP Overlay choices. Settings remains openable while paused, with Enable SEOquake unchecked and the saved surface toggles disabled.
  • Force settings loading, a load failure and a slow save. The switch stays visible; saving is unavailable until settings load successfully. All popup pause controls are guarded during a pending write. Rapid activations cannot enqueue conflicting actions; the last accepted action wins.
  • Force failed Pause/Resume saves from each popup entry point and Full Report → Settings → General, plus a failed Resume from Full Report’s paused screen. The displayed state reconciles with confirmed storage. The popup error notice stays visible outside the menu and changing page content; Try again retries the failed action. Delay older settings and page-status refreshes while accepting a newer action; verify neither the controls nor the normal/paused body can revert to stale state.
  • Keyboard: Tab reaches the switch before Settings; Space and Enter activate it once. A screen reader announces Enable SEOquake with the changing on/off state. Check loading/pending feedback, the mint focus ring and the Pause/Resume tooltip on hover and focus.
  • At 640px, check connected/disconnected status, Settings with and without What’s New, paused and unsupported states. Nothing wraps or overlaps. View Full Report stays hidden in empty states. Full Report and Settings headers are unchanged.
  • Measure the revised menu height at 640px with and without What’s New; confirm it fits the popup. Keep navigation rows at 34px when removing their borders. Verify exactly two group separators, no lines between the three navigation links, and unchanged hover/focus, Tab order and link actions in connected/disconnected and enabled/paused states. Every checkbox label is a full-row target. Got it removes What’s New and leaves the menu open at its single-column width. Check longer or multiple unseen releases with the existing scroll limits. Rebuild and verify the scoped spacing utilities; Add/Hide Parameters and other dropdowns are unchanged.

Files: src/components/popup/PopupApp.tsx (shared popup pause controller and persistent error notice), src/components/shared/layout/Header.tsx (popup-only switch), a new src/components/shared/layout/header/PauseSwitch.tsx, src/components/shared/layout/header/SettingsButton.tsx (shared pause handler, menu row and scoped spacing), src/components/shared/form/Checkbox.tsx (optional label className), src/hooks/useAppSettings.ts (save reconciliation and stale-refresh protection), src/components/shared/PageAnalysisState.tsx (Resume busy state), src/hooks/usePageData.ts (caught Resume handling and enabled-status refresh ordering) and src/components/settings/panels/GeneralPanel.tsx (verify reconciled Full Report Pause/Resume). References: src/utils/settings/storage.ts, src/utils/settings/messaging/handlers.ts, src/components/shared/Notice.tsx, src/components/shared/Tooltip.tsx (InfoTooltipBubble) and src/components/shared/layout/header/ReleaseNotePanel.tsx. Reuse the existing preference and pause consumers.

SERP script loads on every website Implemented · 4.2.1 chrome-3

Verified Sep 24: Robert’s ai branch scopes the SERP script with includeGlobs. On a regular site it no longer loads: 105 ms script time and 3.2 MB JavaScript heap at 4x CPU, the same as 4.1.1.

Issue: 4.2.0 loads the SERP Overlay script and styles (serp.js, serp.css) on every website, next to content.js and seobar.js. That is about 1.6 MB per page, against 0.4 MB in 4.1.1. The SERP code only acts on Google, but Chrome reads and prepares it on every page before that check runs. The 4.2.1 build from the ai branch still loads it everywhere, and the AI Overview panel makes it heavier:

BuildLoaded on every website
4.1.1408 KB
4.2.0, live1,646 KB
4.2.1, ai branch package chrome-21,952 KB

Measured on 10 regular websites with the CPU slowed 4×, close to a budget laptop:

BuildScript time per pageJavaScript heap per page
4.1.199 ms3.1 MB
4.2.0 as shipped188 ms5.2 MB
4.2.0 with this fix105 ms3.2 MB

Fix: Load the SERP content script only on Google. In src/entrypoints/serp.content.tsx, add include globs. WXT then writes a separate manifest entry for the SERP files:

export default defineContentScript({
  matches: ['<all_urls>'],
  includeGlobs: ['*://www.google.*/*', '*://google.*/*'],
  cssInjectionMode: 'manifest',
  runAt: 'document_idle',
  ...
  • Match patterns can’t use a wildcard for the domain ending, so *.google.* is invalid in matches. Include globs allow it, which covers Google’s country domains.
  • Cover all Google pages, not only /search, so the script is already present when results load without a full page navigation from the homepage.
  • Keep the runtime Google check. The globs decide where Chrome loads the script; the code decides where it acts. See the Google host check below.
  • No permission change. Host access stays on all sites for SEObar and the popup, and Chrome only prompts users when an update adds access.

Verified on a hand-edited copy of the chrome-3 manifest: the SERP script no longer loads on regular sites. It still loads on google.com, google.co.in, google.de and the Google homepage, and the sidebar appears on results pages. Confirm the WXT build emits the same shape: an <all_urls> entry with content.js and seobar.js, and a second entry with serp.js, serp.css and include_globs.

Retest on the 4.2.1 build: the overlay and the AI Overview panel on google.com, a country domain and incognito; after Set locale; after searching from the Google homepage; SEObar on regular sites and still off Google. Download the check script. It reports which SEOquake scripts load on each test address and the script time per page.

No uninstall feedback Implemented · 4.2.1 chrome-3

Verified Sep 24: setUninstallURL points at the Google Form in chrome-3. Code verified; the manual remove-and-check test is still to run.

Issue: Weekday uninstalls rose from 1,061 before launch to 1,635 on September 14–15 and 1,951 on September 21. Neither legacy nor v4 sets an uninstall page, so there is no direct way to learn why.

Fix: Set an uninstall page when the background service worker starts. Chrome opens it in a new tab after someone removes SEOquake. It needs no permission, and the URL can be up to 1,023 characters. The form is live, and the version field fills in from the URL:

const UNINSTALL_FORM_URL =
  'https://docs.google.com/forms/d/e/1FAIpQLScp-KrstuXiG74yLkPZx4j5yAprdDdXoh3cqrPCq3YoItNGBA/viewform?usp=pp_url';
const VERSION_FIELD = 'entry.566287330';

browser.runtime.setUninstallURL(
  `${UNINSTALL_FORM_URL}&${VERSION_FIELD}=${encodeURIComponent(browser.runtime.getManifest().version)}`
);
  • Pass only the version, nothing that identifies the user. Open the form with 4.2.0 filled in.
  • Verified September 22: the form opens without sign-in, and the version field shows the value from the URL.
  • Form content, for reference: one required question, “Why did you remove SEOquake?”, with seven reasons in shuffled order plus Other. Then an optional “Anything else we should know?” and the version field. No email is collected.
  • Mention the uninstall page in the privacy policy.

Retest: in a test profile, remove SEOquake. Chrome should open the form in a new tab with the installed version filled in. Delete the test response afterward.

AI Overview panel adds a duplicate stylesheet Implemented · 4.2.1 chrome-3

Verified Sep 24: One stylesheet copy in the AI panel. serp.js is 944 KB, down from 1,384 KB.

Issue: On the ai branch, src/utils/serp/google/ai/controller.ts imports serp-ai.css?inline, and that file imports all of Tailwind. The SERP script now carries a third full copy of the stylesheet, about 215 KB. Until the SERP script scope fix ships, that copy loads on every website.

Fix: Style the AI panel with the stylesheet the overlay already carries. Both existing copies in the 4.2.1 package include every utility class the panel uses. From serp-ai.css, keep only the rules the shared stylesheet lacks: the :host block and the .ai-compact-tight padding rule. Drop its Tailwind and base imports.

Retest: serp.js shrinks by about 215 KB. The Analyze sources button, the panel and the strips on source cards look identical to the chrome-2 package, in light and dark mode and in a narrow window.

Analyze always opens the US database Implemented · 4.2.1 chrome-4

Verified Sep 24: commit 9c2927a adds databaseCountry.ts and follows the country order below. The SERP Analyze button, the Rank, Traffic and Costs links, the AI Overview panel and Quick View pass the country. All original retest cases passed against the committed code, and the chrome-4 build has no hard-coded db=us left.

Issue: src/utils/semrush/overviewLinks.ts hard-codes db=us (line 9), so every caller opens Domain Overview on the US database, even when Locale is set to another country. Reported by a user: a .nl domain that barely ranks in the US opened an empty-looking report until they switched countries manually. Legacy never set db on these links; v4 added the US hard-code. Callers:

  • SerpAnalyzeCta.tsx: the Analyze CTA in the SERP strip, also used on AI Overview source cards.
  • metricLinks.ts: the Rank, Traffic and Costs links.
  • SemrushOverview.tsx: Quick View.

Fix:

  1. Add an optional country argument, domainAnalyticsOverviewUrl(input, country?), and set db from it.
  2. Resolve the country in this order, first match wins:
    1. The saved SERP Locale country, the one Set locale applies as gl.
    2. The gl parameter on the current Google URL.
    3. The Google country domain: google.nl is nl, google.co.uk is uk. google.com gives no signal.
    4. The result domain’s country ending: .nl is nl, .co.uk is uk. Generic endings like .com give no signal.
    5. us.
  3. Map Google and ISO codes to Semrush database codes. Most match in lowercase; the United Kingdom is uk in Semrush, gb in Google.
  4. If Semrush has no database for the country, fall back to us.
  5. Pass the resolved country from the SERP strip, the AI panel and the metric links. Quick View can use step d only.

Out of scope: the Rank, Traffic and Costs values in the strip come from seoquake.publicapi.semrush.com/info.php, which has no country parameter. They stay US figures, and the Traffic tooltip already says US. Only the links change.

Why it matters: Analyze is the top SERP Overlay source of Semrush visitors, and India and Pakistan are the biggest audiences. Local sites analyzed on the US database show thin data at the moment we ask people to register. Compare the serp_domain_overview visit-to-registration rate in Stork before and after.

A number formatter slows every page load Implemented · 4.2.2 chrome-4

Verified Sep 30: chrome-4 creates the integer formatter on first use and reuses it. Extracted checks passed in all four bundled consumers, with unchanged output for eight values each. Fresh page-timing checks remain part of final QA.

Original issue: the earlier 4.2.2 candidate creates its integer formatter (new Intl.NumberFormat) when src/utils/format.ts loads, instead of the first time a number is formatted. The SEObar script runs on every website, so every page pays for it. On local test pages with the CPU slowed 4×, 4.2.2 used about 20 to 30 ms more script time per page than 4.2.1, on regular sites and on Google results. On a normal CPU that is roughly 5 ms per page (an estimate).

Fix: create the formatter on first use.

let integerFormatter: Intl.NumberFormat | undefined;
export const formatInteger = (num: number): string =>
  (integerFormatter ??= new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 })).format(num);

Applied to a copy of the 4.2.2 build, this brought regular pages back to 4.2.1’s range in two independent test sessions and reduced the difference on Google results. formatInteger is the formatter’s only consumer, and output is unchanged.

Verify: the formatter isn’t created at load, and integers format the same (12,345). Regular-site script time matches 4.2.1 on the same test pages, with the builds measured in both orders. Report any remaining difference on Google results.

Files: src/utils/format.ts.

4.2.2 What’s New needs clearer copy Implemented · 4.2.2 chrome-5

Verified Sep 30 · chrome-5: the package contains all four approved lines, including the sign-out fix. In the installed Quick View Settings popup, all four lines, View all updates and Got it were visible. Text wraps within the column without being cut off.

Original issue: the popup’s What’s New shows each [+] and [*] line from the 4.2.2 block in CHANGELOG. The earlier candidate said “audit heading detection” for a SERP fix, claimed unmeasured audit performance gains and buried Analyze opening the exact page under “Analyze/Semrush links”. Its fifth line was cut off.

Implemented copy:

================================
Change Notes for SEOquake 4.2.2
================================

Date: 9/30/2026

SEOquake 4.2.2 gives you more control over the SERP Overlay and sharper Semrush links.

[+] Collapse the SERP sidebar to a small tab.
[+] Analyze opens the exact page in Semrush.
[+] Settings now save as you change them.
[*] Fixed a bug where SEOquake could sign you out of your site.

The popup shows the three [+] lines and the [*] line; the parser skips the summary line and section headers. The security fix is implemented in the same package; its remaining controlled browser checks stay part of final release QA. Update the date if the build ships later.

Verify: all four lines are fully visible in the popup, with no text cut off.

Files: CHANGELOG.

Sidebar tab and arrow show the browser’s focus ring Implemented · 4.2.2 chrome-4

Verified Sep 30: both buttons use the 2px green #00785F focus style in chrome-4, and the style is present in the bundled CSS. Replacement-control focus logic is also present. Keyboard Tab and Enter verification remains part of final QA.

Original issue: the collapsed logo tab and the collapse arrow in SerpControlPanel.tsx had no focus styles, so keyboard focus showed Chrome’s default ring instead of the 2px #00785F outline in the sidebar spec. Mouse users never see it.

Fix: give both buttons the focus classes the AI Overview panel already uses (AiSources.tsx): focus-visible:rounded-[3px] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-dark. green-dark is #00785F.

Verify: with the keyboard, Tab to the collapse arrow and press Enter. The logo tab takes focus with the green outline. Press Enter again, and the arrow takes focus with the same outline.

Files: src/components/serp/SerpControlPanel.tsx.

Quick View Settings has a SERP Overlay switch Implemented · 4.2.3 candidate

Implemented in the 4.2.3 candidate. Show SERP Overlay now sits directly below Show SEObar. Package checks passed for saving, sync, rapid changes, preserved preferences and failed-save retry. Installed-browser smoke checks remain.

Browser checks and files

Original issue: turning off the overlay required opening Preferences or using the Google sidebar. The new control uses the same checkbox style and existing serp.enabled preference.

Verify: it toggles the overlay, stays synced and saved, and leaves other preferences unchanged.

  • Reuse serp.enabled. Keep saved metrics, AI-source and sidebar-collapse choices. Disable the control while settings are loading or unreadable; don’t show a failed save as saved.
  • Check off/on against an open Google results page without reloading, then reopen Quick View and restart Chrome. Changes from the sidebar or full Settings must agree. Rapid SEObar and SERP Overlay changes must both persist.
  • Check keyboard access, a failed save and popup fit with and without What’s New.

Files: src/components/shared/layout/header/SettingsButton.tsx, src/hooks/useAppSettings.ts and the existing settings save/watch flow.

Readable result position numbers Implemented · 4.2.3

Implemented: 4.2.3 places numbers beside the title as 3., with inherited typography, legacy float wrapping and the existing preference. Numbers follow Google’s background independently of the selected overlay theme. Package checks covered counting, offsets, dynamic cleanup and CSV positions; the user’s October 12 captures show readable numbers on light and dark Google, including positions 11–15 on the next results page.

Release status: shipped in 4.2.3, with rollout set to 100% on October 12, 2026, at 1:58 PM EDT. The earlier diagnosis and comparison below are retained as history.

Earlier October 7 candidateNumber stays dark on dark Google
Apple
https://www.apple.com › iphone

1.iPhone

Designed for Apple Intelligence. Discover iPhone Duo, iPhone 18 Pro, iPhone Air, iPhone 17, and iPhone 17e.
Implemented number stylingOnly the number color and cursor change
Apple
https://www.apple.com › iphone

1.iPhone

Designed for Apple Intelligence. Discover iPhone Duo, iPhone 18 Pro, iPhone Air, iPhone 17, and iPhone 17e.

Historical comparison of the October 7 candidate and accepted number styling, using that candidate’s selected metrics, fonts and title → overlay → snippet order. Metrics are October 7 snapshots; these are rendered references, not October 12 runtime captures. Scroll narrow previews to keep the reference width.

Earlier extension screenshots · October 7
Apple result
Actual candidate with an unreadable dark position number beside the Apple iPhone title
Wikipedia result
Actual candidate with an unreadable dark position number beside the Wikipedia iPhone title

Fix: use #181E15 on light pages and readable light text on dark pages, based on Google’s actual page theme. Keep the title’s font family, size, line height, 0.3em gap and float wrapping. The clickable number should use the title link’s pointer cursor.

Verification and files

Verify: check the number on light and dark Google pages, then toggle numbers off/on; check short and wrapped titles, the next results page and results added or removed dynamically. The number matches the title’s typography and first-line baseline; wrapped lines can use the full title width below it. Numbers agree with the existing result positions and CSV, without duplicates or counting ads/AI source cards. Clicking either the title or number opens the same result; mouse and keyboard navigation stay usable. Check that the screen reader’s link name remains clear. Test on the identified rebuilt extension; this comparison is a mockup.

Files: src/components/serp/overlay/SerpStandardMetrics.tsx, the SERP host mount/update/cleanup flow and Google title placement in src/utils/serp/google/insert.ts. Reuse showPositionNumbers and the existing result position data.

Dark SERP Overlay and theme settings Implemented · 4.2.3

Implemented: 4.2.3 uses SEObar’s dark palette for organic strips, connected metrics, AI source cards and the Analyze sources panel. Full Report → Settings → SERP Overlay → Appearance offers Match Google, Light and Dark. Package review and the user’s October 12 smoke evidence confirmed the dark surfaces and readable result numbers. The sidebar still needs its own application of this shared theme.

Release status: shipped in 4.2.3, with rollout set to 100% on October 12, 2026, at 1:58 PM EDT. The accepted specification and earlier comparison remain below.

Fix:

  • Keep the current layout and spacing. In dark mode, use #2A3028 for the connected top row and #181E15 for the standard strip and AI cards, with a thin, subtle divider between organic rows. Keep white values and icons, muted labels #A8A9AD, green #18F0BF for hover and keyboard focus, and light lavender #C190FF for Analyze and purple accents.
  • In Full Report → Settings → SERP Overlay → Appearance, add Theme above Show tooltips, using the existing Appearance choice style: Match Google (default), Light, Dark. Save automatically and independently of SEObar. Existing users without a saved choice start on Match Google; Reset restores it.
  • Match Google follows Google’s actual page theme and updates when it changes. Light and Dark override the overlay’s appearance. Keep the existing light palette. Position numbers always follow Google’s background, independently of the overlay choice, so they remain readable.
  • Apply the same colors to organic strips, connected metrics, AI source cards and the Analyze sources panel, including their tooltips and controls. Keep values, links, preferences, exports and counting intact.

Related: result position numbers are implemented in the same 4.2.3 package and follow Google’s background independently of the overlay choice.

Earlier October 7 candidateOrganic result
Apple
https://www.apple.com › iphone

1.iPhone

Designed for Apple Intelligence. Discover iPhone Duo, iPhone 18 Pro, iPhone Air, iPhone 17, and iPhone 17e.
Implemented appearanceSame organic layout and metrics
Apple
https://www.apple.com › iphone

1.iPhone

Designed for Apple Intelligence. Discover iPhone Duo, iPhone 18 Pro, iPhone Air, iPhone 17, and iPhone 17e.
Earlier October 7 candidateAI source cards
  • Apple
    Apple unveils iPhone Duo
    iPhone Duo will be available in 28 other countries and regions beginning Friday, October 30. The iPhone Duo Case will be available...
  • Forbes
    Apple iPhone Duo Release Timeline: New Date Enters The Schedule
    Pre-Orders: Apple.com (Friday, Oct. 16, 5 a.m. PT / 8 a.m. ET / 1 p.m. BST); Colors (Night Sky, Star White). Review Units & Event:
  • Tom's Guide
    Planning to buy the iPhone Duo? Here's how to get one on launch day
    How To By Kaycee Hill Last updated 10 hours ago The ultimate playbook for scoring an iPhone Duo on day one (Image credit: Tom's Gu...
  • AppleInsider
    'Get Ready' to pre-order the iPhone Duo starting October 12
    You can "Get Ready" to pre-order the iPhone Duo starting October 12. Apple will let customers set up their iPhone Duo pre-order st...
  • Wikipedia
    iPhone Duo - Wikipedia
    Apple CEO John Ternus unveiled the iPhone Duo on September 9, 2026. It is scheduled for release on October 23, 2026, in about 70 c...
Show allShow less
Implemented appearanceSame Google cards and metrics
  • Apple
    Apple unveils iPhone Duo
    iPhone Duo will be available in 28 other countries and regions beginning Friday, October 30. The iPhone Duo Case will be available...
  • Forbes
    Apple iPhone Duo Release Timeline: New Date Enters The Schedule
    Pre-Orders: Apple.com (Friday, Oct. 16, 5 a.m. PT / 8 a.m. ET / 1 p.m. BST); Colors (Night Sky, Star White). Review Units & Event:
  • Tom's Guide
    Planning to buy the iPhone Duo? Here's how to get one on launch day
    How To By Kaycee Hill Last updated 10 hours ago The ultimate playbook for scoring an iPhone Duo on day one (Image credit: Tom's Gu...
  • AppleInsider
    'Get Ready' to pre-order the iPhone Duo starting October 12
    You can "Get Ready" to pre-order the iPhone Duo starting October 12. Apple will let customers set up their iPhone Duo pre-order st...
  • Wikipedia
    iPhone Duo - Wikipedia
    Apple CEO John Ternus unveiled the iPhone Duo on September 9, 2026. It is scheduled for release on October 23, 2026, in about 70 c...
Show allShow less

Historical reference using the October 7 candidate’s rendered markup, Inter fonts and icons, with Google’s source-card structure, favicons and thumbnails. The accepted treatment changes colors only. Overlay theme previews the implemented setting; it does not save extension preferences. Metrics are October 7 snapshots; these are rendered references, not October 12 runtime captures. Scroll narrow previews to keep the reference width.

Actual extension screenshots

October 7 captures. These are the original images; the comparisons above keep their layout and selected metrics.

Organic result · Apple
Actual SEOquake candidate on a dark Google Apple iPhone result, with a two-row metrics strip above the snippet
AI Overview sources · Apple and Forbes
Actual Google AI source cards with AS, Traffic, L and Analyze on one row
Engineering checks

Verify: on light and dark Google pages, test Match Google and both overrides, including a page theme that differs from the computer’s setting. Change Google’s theme without reloading. Confirm numbers remain readable with the opposite overlay theme. Check wrapped titles, connected/disconnected metrics, AI cards, the source panel, tooltips, hover and keyboard focus. Reopen Settings and restart the browser to confirm the saved choice; check the default, Reset and existing autosave failure/retry behavior. SEObar settings, values, destinations and exports remain intact.

Files: reuse SEObar’s existing theme colors in the SERP styles and shared metric components, with the top-row shade specified above. Add the SERP Appearance choice through the existing settings control, preferences defaults/normalization and autosave flow. Apply Google theme detection and the saved override at the SERP host, including its separate shadow roots. Keep title-number contrast tied to Google’s background and preserve its accepted placement and lifecycle.

Report parameters don’t save until you click Save Implemented · 4.3.0 chrome-3

Verified October 13, 2026: Report choices update and save immediately; Save is removed. Package checks cover retry, scoped Reset, stale updates and Compare loading states. Supplied-package review and Beatus’s live review passed for this ticket. Original requirements and references below are retained as history; release QA is tracked separately.

Issue: Add/hide parameters in Full Report’s Links and Compare still requires Save. Closing the menu can leave ticks that don’t match the displayed metrics, and reloading loses those changes. Saving Internal can also discard unsaved External ticks. Settings already saves automatically; these report menus should work the same way.

Fix:

  • Update visible metrics and save each tick immediately in Internal Links, External Links and Compare. Remove Save. Closing, reopening and reloading must keep the ticks and displayed metrics in agreement, including changes made from Settings → Parameters.
  • Reuse useSettingsAutosave for parameters.internal_links, parameters.external_links and parameters.compare: write changes in order, keep edits when a save fails and offer Try again. An older settings refresh must not overwrite a newer edit. No success notice.
  • Keep Reset to default and its confirmation. The hook’s current Reset clears its whole pending patch; scope it to the current section and prevent its earlier saves from restoring old values. Preserve pending or failed edits in the other Links tab.
  • In Compare, show Run Compare to load in a newly enabled metric’s row only when its data was never requested. Track the domain, backlinks and Pinterest request groups for each result. Preserve already fetched values and keep failed or unavailable results distinct. The next comparison loads enabled metrics; ticking a parameter does not start a request.

Files: src/components/report/panels/LinksPanel.tsx, src/components/report/panels/ComparePanel.tsx, src/utils/compare/buildRows.ts, src/components/shared/ParameterVisibilityDropdown.tsx and src/hooks/useSettingsAutosave.ts.

Engineering checks

Package evidence: the draft/applied split and cross-tab reset are present in the supplied 4.2.3 and 4.3.0 packages. The proposed autosave fix still needs rebuilt-package checks.

  • Toggle several parameters quickly, close the menu, switch tabs and reload. The final choice stays applied and stored. A change made from Settings agrees with the report menus.
  • Force a save failure, keep editing and retry. Reset Internal while External has a pending or failed edit, then reverse the tabs. Only the reset section returns to defaults; stale writes and refreshes cannot undo either section’s latest choice.
  • Run Compare, then enable a metric whose request group was not attempted. Its row shows the load hint until the next run. Also enable a metric from a group already fetched: retain its value. Failed requests and unavailable results must keep their existing states rather than showing the never-requested hint.

Tooltip icons overlap the Links toolbar and Parameters menu Implemented · 4.3.0 chrome-3

Verified October 13, 2026: Metric cards have the isolation root; tooltip bubbles still render through their portal and existing card actions are preserved. Supplied-package review and Beatus’s live review passed for this ticket. Original requirements and references below are retained as history; release QA is tracked separately.

Issue: Links overview tooltip icons can appear over Add/hide parameters and the toolbar when it sticks. BoxValue raises every tooltip anchor with relative z-10, including the noninteractive Links tiles. The tile has no stacking context, so its icons compete with the toolbar instead of staying inside the tile.

Fix:

  • Add isolate to the BoxValue root: group relative isolate flex flex-col. Rebuild so the stylesheet includes this utility. The icon and extra content keep their existing stacking order inside each tile.
  • Keep the shared tooltip bubble portaled outside the tile. Preserve hover and keyboard behavior, and preserve the full-tile action only on tiles that already have an enabled link or button. Links overview tiles remain noninteractive.

Files: src/components/shared/box/BoxValue.tsx.

Screenshots
4.3.0 package capture · October 7 build
Current 4.3.0 Links Parameters menu with overview tooltip icons visible over the menu.
Proposed isolate fix · test capture
The same Links Parameters menu with isolate applied; overview tooltip icons stay behind the menu.
4.3.0 package capture · October 7 build
Current 4.3.0 sticky Links toolbar with overview tooltip icons visible over its controls.
Proposed isolate fix · test capture
The same sticky Links toolbar with isolate applied; overview tooltip icons stay behind its controls.

Historical comparisons from the October 8 design review. The supplied 4.3.0 chrome-2 package still has the same stacking mechanism, checked October 12. The proposed capture demonstrates the fix; it does not show a shipped implementation. Click a screenshot to open the original full size.

Engineering checks

Package evidence: the latest supplied 4.3.0 chrome-2 package has the unisolated tile root and raised tooltip anchors. Controlled rendering confirms that isolation contains the icon stacking. The shared tooltip bubble is portaled outside the tile.

  • In Internal and External Links, open Add/hide parameters with the toolbar in its normal and stuck positions. No overview icon paints over the menu or toolbar; each toolbar control still receives clicks.
  • Verify tile tooltip hover, then check shared interactive tiles with mouse and keyboard. Existing actions, focus outlines and tooltip behavior remain usable; the fix does not turn Links tiles into actions.
  • Confirm the rebuilt stylesheet includes isolation: isolate and the root computes to isolation: isolate. Check Quick View and Full Report wherever BoxValue is shared.

Info icons sit low beside metric-card labels Implemented · 4.3.0 chrome-3

Verified October 13, 2026: Metric-card info SVGs lift by 2px in Quick View and Full Report, preserving label sizes, wrapping, 14 × 14px anchors and the 4px gap. This closes the original metric-card scope. Supplied-package review and Beatus’s live review passed for this ticket. Original requirements and references below are retained as history; release QA is tracked separately.

Issue: Info icons look slightly lower than labels such as Unique Visitors, SE Traffic and Total words in Quick View and Full Report. The shared BoxValue label uses an inline tooltip with align-middle; section headings already center their label and icon with flex layout.

Fix:

  • In BoxValue.tsx, add [&>svg]:-translate-y-[2px] to the tooltip's existing anchorClass, alongside relative z-10 and the caller's classes. Lift only the info SVG by 2px; leave the tooltip anchor and label in their current positions.
  • Keep the existing inline whitespace-nowrap last-word wrapper and earlier words outside it. Labels still wrap naturally, while their last word and info icon stay together on the final line, including Semrush Rank.
  • Keep Inter labels at 13px in Full Report and 12px in Quick View, with the existing weight and line height. Keep the tooltip anchor and SVG at 14 × 14px and the existing 4px left gap. Do not resize the icon or change section-heading alignment.
  • Preserve the tooltip's relative z-10 anchor, portal, hover and existing focus behavior, plus card actions and focus outlines. Apply this alongside Tooltip stacking; preserve that ticket's isolate root. Keep the alignment change local to BoxValue rather than changing every Tooltip instance.

Files: src/components/shared/box/BoxValue.tsx. Reference: src/components/shared/Tooltip.tsx and src/components/shared/SectionHeading.tsx.

Native alignment previews

Complete Quick View and Full Report screens rendered by the actual 4.3.0 chrome-2 package, using frozen local reference data. Switch between Current and the recommended 2px SVG lift on the same screens. The package supplies the headers, tabs, native grids, fonts, icons, spacing and wrapping; only the card info-icon alignment changes.

Open Quick View and Full Report previews. Quick View renders at 640 × 600 and Full Report at 1280 × 900. Fit scales the whole screen uniformly; Actual size preserves 1:1 rendering with scrolling. The Full Report selector includes Domain Metrics, Traffic Analytics and Keyword Density.

The native-screen comparison verifies a 2px upward SVG movement, unchanged 14 × 14px anchor hitboxes, and identical label, card and section-heading geometry. The lift improves the optical alignment; it does not change section-heading icons. These previews do not access live extension settings, website probes or Semrush account data. Rebuilt-extension checks remain required.

Screenshots
Full Report · Traffic Analytics
Monthly Visits, Unique Visitors and Bounce Rate card labels with info icons sitting slightly low.
Full Report · Keyword Overview
Total words card label with its info icon sitting slightly low.
Full Report · Domain Metrics and Backlinks
SE Traffic, Traffic Cost, Total Backlinks and Referring Domains labels, including the wrapped Semrush Rank label.
Quick View · Page Info
Small Semrush metric-card labels with low info icons; the section-heading icon provides an alignment reference.

User-supplied October 12 captures of the observed appearance, retained unchanged. They are references for the issue, not examples of an implemented fix; the screenshots do not display the installed version. Click any image to open the original full size.

Engineering checks

Package evidence: the supplied 4.3.0 chrome-2 package contains the same BoxValue inline last-word wrapper and Tooltip anchor classes. Its stylesheet declares text-13 as 13px, text-12 as 12px and --spacing: 4px, making size-3.5 14px. The SVG's intrinsic 16px dimensions are overridden by size-full. Reviewed source: origin/4.3.0 at ce65ab66263f51431a453e8fa126dbedd9e446ff.

  • Rebuild and inspect Quick View's Semrush cards, Full Report's Domain Metrics, Backlinks Overview and Traffic Analytics, and Keyword Overview's Total words. Icons should visually align with the adjacent label text, with no downward drift.
  • Check ordinary desktop width, narrow cards and browser zoom. Use both short labels and labels that wrap to two lines. The icon remains with the final word; the text keeps its normal wrapping and does not overlap the value, clip or force card overflow.
  • Verify computed label font sizes remain 12px / 13px, tooltip and SVG boxes remain 14 × 14px, and the left margin remains 4px. Confirm the generated stylesheet includes [&>svg]:-translate-y-[2px]; the SVG moves up exactly 2 CSS pixels while the anchor and inline last-word wrapper retain their current geometry.
  • Hover the info icons and activate existing card links/buttons with mouse and keyboard. Tooltips, destinations and focus outlines still work. Section headings retain their current alignment; the separate isolation fix still keeps icons behind the Links toolbar and Parameters menu.

Local visual evidence: same-document comparisons of native Quick View, Domain Metrics (including wrapped labels), Backlinks Overview, Traffic Analytics and Keyword Overview confirm the SVG-only lift improves alignment without moving labels, values, cards or headings. The flex alternative reduced Quick View's line-box height by 0.125px and was dropped.

Verification boundary: these are package-rendered previews with frozen fixtures. The proposed SVG-only change still needs visual and interaction checks in the rebuilt extension.

Technical Snapshot order differs between Quick View and Full Report Implemented · 4.3.0 chrome-3

Verified October 13, 2026: Both surfaces use Canonical → Robots.txt → Schema.org Markup → URL, retaining the compact Quick View treatment. Supplied-package review and Beatus’s live review passed for this ticket. Original requirements and references below are retained as history; release QA is tracked separately.

Issue: Quick View uses the revised Technical Snapshot order, but Full Report still uses its earlier order. Both surfaces should follow the approved design: Canonical → Robots.txt → Schema.org Markup → URL.

Fix:

  • Use the existing POPUP_KEYS order on both surfaces: canonical, robotsTxt, schemaOrg, url. Remove the report-only SNAPSHOT_KEYS list and conditional list choice so there is one shared order.
  • Preserve popup compact rows, popup-only Schema result shortening and LINK_ONLY_KEYS for Canonical and Robots.txt. Keep the existing positional divider rules and responsive report grid.

Files: src/components/shared/info/TechnicalSnapshot.tsx.

Screenshots
4.3.0 package capture · October 7 build
Current 4.3.0 Full Report Technical Snapshot using URL, Canonical, Schema.org Markup and Robots.txt order.
Revised mockup · approved order
Revised Full Report Technical Snapshot using Canonical, Robots.txt, Schema.org Markup and URL order.

Historical comparison from the October 8 design review. The supplied 4.3.0 chrome-2 package still uses two lists, checked October 12. The revised mockup shows the intended order, not a shipped fix. Click a screenshot to open the original full size.

Engineering checks

Package evidence: the latest supplied 4.3.0 chrome-2 package chooses between POPUP_KEYS and SNAPSHOT_KEYS. Using one order matches the accepted design correction.

  • Quick View and Full Report read Canonical, Robots.txt, Schema.org Markup, URL. At the report’s two-column width, Canonical and Robots.txt occupy the first row, with Schema.org Markup and URL below.
  • Check compact Quick View, the two-column report and a narrow single-column report. Dividers appear once at each shared edge; values, links and shortened popup Schema text keep their existing behavior.

4.3.0 What’s New copy Implemented · 4.3.0 chrome-3

Verified October 13, 2026: Both approved lines and their [+] / [*] prefixes are present. The release panel retains View all updates and Got it. Supplied-package review and Beatus’s live review passed for this ticket. Original requirements and references below are retained as history; release QA is tracked separately.

Issue: the current popup lists all five right-click destinations. Its design-refresh line needs a clearer user benefit.

Fix: replace the two marked lines in the 4.3.0 CHANGELOG block with this approved copy:

[+] Right-click a page to open reports and settings.
[*] Spot SEO issues more easily in the refreshed Quick View and Full Report.

Files: CHANGELOG.

Engineering checks

Verify: the rebuilt 4.3.0 package contains both lines exactly, including their [+] and [*] prefixes. In Quick View Settings, both lines, View all updates and Got it remain fully visible; text wraps within the What’s New column without clipping.

Visible headings with a leftover clip are treated as hidden Implemented · 4.2.2

Verified Sep 29: the 4.2.2 build honors clip only on absolute or fixed elements. The hidden-heading regression suite passes on the built code, including the static-clip case that failed in 4.2.0. Still to check on the final build: the live Google retest below.

Issue: hasCollapsedClip in src/utils/serp/google/headings.ts treats any collapsed clip: rect(...) as hidden. In CSS, clip only applies to elements positioned absolute or fixed. On a static or relative element it does nothing and the heading stays visible, but Chrome still reports the value. Two effects:

  • AI Overview detection skips the module, so the Analyze sources panel and the card metrics disappear. Reproduced in 4.2.1 on live Google with manually injected CSS (screenshots below).
  • An organic feature module’s visible title is skipped, so its cards can be counted as results and the numbering shifts. Shown in a real-browser fixture during the September 17 review.

Present since 4.2.0, when the September 17 review first flagged it. Not seen occurring naturally on Google.

Clip injected on the visible AI Overview heading: the heading still shows, but the Analyze sources pill and card metrics are gone.
Clip added to the visible “AI Overview” heading: SEOquake’s panel and card metrics disappear.
Clip removed: the Analyze sources pill with 11 sources and the card metrics are back.
Clip removed: the panel (11 sources) and card metrics return.

4.2.1 · September 28 · Clip injected with DevTools · Click a screenshot to open it full size.

Fix: only honor the legacy clip when the element carrying it is positioned absolute or fixed. hasCollapsedClip runs once per ancestor with that element’s own style, so the condition goes inside it:

if (clip?.[1] && (style.position === 'absolute' || style.position === 'fixed')) {

Leave the clip-path check and the other hiding checks (display, visibility, opacity, 1×1 size) unchanged.

Verify on a results page with an AI Overview, in DevTools. Set up once:

const h = [...document.querySelectorAll('h2, [role="heading"][aria-level="2"]')].find(el => /AI Overview/i.test(el.textContent) && el.getBoundingClientRect().height > 0);
const p = h.parentElement, saved = [h.style.cssText, p.style.cssText];
const reset = () => { h.style.cssText = saved[0]; p.style.cssText = saved[1]; };
  1. h.style.position = 'static'; h.style.clip = 'rect(0px, 0px, 0px, 0px)'; The heading stays visible, and so does the Analyze sources pill. Today the pill disappears. Then reset().
  2. p.style.position = 'absolute'; p.style.clip = 'rect(0px, 0px, 0px, 0px)'; The heading really hides, and the pill disappears too.
  3. p.style.position = 'static'; Same clip, now ignored: the heading and the pill come back. Today the pill stays gone. Then reset().

Regression: keep the hidden-heading checks green. The first result of each group keeps its strip and number, and module exclusions (People also ask, AI Overview, carousels) don’t change. An independent review applied this condition to the shipped code in memory and passed 33 of 33 real-Chrome checks and 18 of 18 applicable package regressions. The rebuilt extension still needs the checks above.

Files: src/utils/serp/google/headings.ts.

Analyze opens the whole domain, not the result’s page Implemented · 4.2.2

Verified Sep 29: Analyze on the SERP strip, in the Analyze sources panel and on the source cards opens the result’s page in Exact URL mode, tracked as serp_page_overview or serp_ai_page_overview. The cleanup cases pass on the built code, and live clicks opened the page on the search country’s database (US and France). Rank, Traffic and Costs stay on the domain.

Issue: on the SERP strip, in the Analyze sources panel and on the source cards, Analyze opens Domain Overview for the root domain, the same place the Rank, Traffic and Costs links go. All four links share one campaign (serp_domain_overview or serp_ai_domain_overview). Their utm_content already differs (…_cta_analyze vs …_metric_semrush_rank), but our Stork reports group by campaign, so Analyze clicks can’t be told apart there. For a single result or cited source, the page itself is the more useful report: Domain Overview in Exact URL mode shows that page’s organic traffic, keywords and backlinks. This replaces the domain-level Analyze accepted for 4.2.1.

Fix:

  1. Point Analyze on the SERP strip, in the Analyze sources panel and on the source cards at the result’s own URL with searchType=url, for example https://www.semrush.com/analytics/overview/?q=https%3A%2F%2Fwww.visitflorida.com%2Fplaces-to-go%2Fsoutheast%2Ffort-lauderdale%2F&protocol=https&searchType=url&db=us. Keep the country from databaseCountry.ts.
  2. Keep Rank, Traffic and Costs on the domain. They’re domain metrics, so their links keep domain scope.
  3. Give Analyze its own tracking destination, for example page_overview in SemrushDestination (src/utils/semrush/utm.ts). The campaigns become serp_page_overview and serp_ai_page_overview.
  4. Build the link from the result’s or source’s own URL, cleaned. Exact URL is a literal match, so remove the # fragment (Google adds #:~:text= to cited links), tracking parameters such as utm_*, and t= on YouTube only. Keep everything else: the protocol, www, the trailing slash and query parameters that identify the page (YouTube’s v=, product IDs, pagination). Don’t reuse the current target normalizer, which strips trailing slashes, or the domain builder, which hard-codes protocol=https.

Files: SerpAnalyzeCta.tsx, AiSources.tsx, src/utils/semrush/overviewLinks.ts (add a page-level URL builder) and src/utils/semrush/utm.ts.

Coordinate with “AI Overview source cards wrap unevenly”. Both change AiSources.tsx and the Analyze component (SerpAnalyzeCta.tsx), but each can ship on its own.

Measure: compare the last full week before 4.2.2 ships with each full week after it, counting only weeks when that version is on about 90% of daily users (check “Daily users by item version”). From the same Stork report, report visitors, registrations and registrations per visitor for serp_domain_overview, serp_page_overview, serp_ai_domain_overview and serp_ai_page_overview, with the SERP strip and AI placements shown separately. For reference, September 21 to 27 on 4.2.0 had 136 registrations from 3,433 visitors (4.0%, Content Performing), counting Analyze and the Rank, Traffic and Costs links together. Treat the results as directional, not proof.

AI Overview source cards wrap unevenly Implemented · 4.2.2

Verified Sep 29: narrow columns show two rows, connected and not connected, and wide columns show one, with Analyze always visible. Still to check on the final build: very narrow cards and cards with fewer metrics.

Issue: Google’s source cards change width from one results page to the next, and the compact metrics wrap by the length of their values. Cards in the same column end up with one, two or three rows: “Traffic 98K” fits on a line where “Traffic 1.47M” wraps. The cause is in the compact branch of AiSources.tsx: the metric row is a wrapping flex row with right padding (pr-18, or pr-20 when tight) that holds space for Analyze. That padding applies to every line, not only the last, so AS and Traffic can’t share a line in a narrow column.

Two AI Overview source cards in a narrow column, connected to Semrush: AS, Traffic and L each on their own line, with Analyze beside L.
Connected, narrow column: AS, Traffic and L stack into three rows.
The same two source cards without a Semrush connection: Traffic on the first line, L, LD and Analyze on the second.
Not connected, same column: Traffic, L and LD wrap into two rows.
Two source cards in a wider column in dark mode: Traffic, L, LD and Analyze fit on one line.
Not connected, wider column: everything fits on one row.

4.2.1 · September 28 · Click a screenshot to open it full size.

Fix:

  1. Hold Analyze’s space on the last row only. Replace the wrapping row with a two-column grid: two metrics on row 1, the third metric on row 2, and Analyze in the free space to its right, where SerpAnalyzeCta already sits.
    • Connected, default parameters: AS and Traffic, then L and Analyze.
    • Not connected, default parameters: Traffic and L, then LD and Analyze.
  2. Wide columns stay on one row. The card already measures its width with a resize observer (it sets ai-compact-tight); use the same check to choose one row when the metrics and Analyze fit, otherwise the two-row grid. Two rows at most, unless a column is too narrow even for the grid: then wrap, and give Analyze its own row if it needs one.
  3. Keep the person’s metric selection and the current AI_COMPACT_PRIORITY order: up to three metrics, AS plus two when connected, three when not. Parameters that are turned off stay off, and cards with fewer metrics still lay out cleanly. This is a layout change only.
  4. Keep Analyze on the cards.
  5. Limit the change to the compact card. The SERP strip shares SerpAnalyzeCta, and its layout stays as it is.

Verify: connected and disconnected cards, long values, fewer metrics, and resizing across one-row and two-row widths. Every metric and Analyze stay visible, with nothing overlapping or clipped.

Files: src/components/serp/AiSources.tsx (compact branch) and src/assets/styles/serp.css; SerpAnalyzeCta.tsx only if its clearance check needs to know about the grid.

Coordinate with “Analyze opens the whole domain, not the result’s page”. Both change AiSources.tsx and the Analyze component (SerpAnalyzeCta.tsx), but each can ship on its own.

Settings don’t save until you click Save Implemented · 4.2.2

Verified Sep 29: the Save button is gone. Checkboxes save immediately, and text fields save after a pause, on blur and when leaving. Saves run in order, a confirmed Reset wins over pending saves, and a failed save keeps the edit with a working Try again. Controlled tests on the built code pass. Still to check in the running extension: typing a new line, closing Settings mid-edit and a failed save.

Issue: on the Parameters, SEObar and SERP Overlay tabs in Settings, each change only updates a draft. Nothing is stored until the person clicks Save. The SERP sidebar’s Parameters dropdown saves on every click (patchSerpSettings), and the General tab already saves its toggles right away. There is no unsaved-changes warning, so closing Settings or going back to the Full Report drops the changes without telling anyone.

Fix:

  • Save checkbox and radio changes as soon as they’re made on those three tabs, the same way the SERP sidebar dropdown does.
  • Text fields (stop words, whitelist, SEObar matches and excludes) save after a short pause, on blur, and before leaving Settings. Don’t rewrite a field with its trimmed value while the person is typing, or the new line they just started disappears.
  • Save one change at a time, in order. Each save writes the whole settings object, so two overlapping saves can lose an edit.
  • Remove the Save button once every field saves on its own. Keep “Reset to default” and its confirm step. A confirmed Reset clears queued edits and prevents an earlier save from overwriting the reset values.
  • Show a message only when saving fails, using the existing “Couldn’t save … Try again.” notice, and keep the edit so Try again can retry it. No success message.
  • The sidebar dropdown’s save (patchSerpSettings) reports success even when the write fails. Fix it along with the rest.

Files: ParametersPanel.tsx, SeobarPanel.tsx and SerpPanel.tsx in src/components/settings/panels/ (the draft state and handleSave), and SettingsStickyActions.

Some Semrush links open the wrong country database Implemented · 4.2.2

Verified Sep 29: on google.com, .co, .me and .ly results fall back to US unless Locale or gl picks the country, and the SEObar, Links table and Compare pass the page URL. Resolver cases pass on the built code, and a France Locale opened the FR database. Still to check on the final build: live clicks from those three surfaces.

Issue: two gaps remain after the 4.2.1 country fix.

  1. Generic-looking endings: on google.com with no Locale and no gl parameter, results ending in .co, .me or .ly open the Colombia, Montenegro or Libya database. These endings are mostly used like .com (angel.co, about.me, bit.ly).
  2. Still on US: three callers don’t pass a country, so they still open db=us:
    • SEObar Rank, Traffic and Costs links: SeobarParameters.tsx renders ParameterByKey without semrushCountry.
    • Full Report Links table: LinksTable.tsx calls getSemrushMetricHref(itemKey, target).
    • Compare: buildRows.ts calls getSemrushMetricHref(key, column.target).

Fix:

  1. Generic-looking endings: in countryFromTarget in src/utils/semrush/databaseCountry.ts, ignore co, me and ly, so they fall through to us. Keep them in the supported-country list, so a Locale or gl choice of Colombia, Montenegro or Libya still works.
  2. Still on US: resolve the country from the URL string, the country ending only, the same way Quick View does. In SEObar, pass resolveSemrushDatabaseCountry(pageUrl) as semrushCountry. In LinksTable use resolveSemrushDatabaseCountry(target.pageUrl), and in Compare resolveSemrushDatabaseCountry(column.target.pageUrl), then pass it to getSemrushMetricHref. Those targets are objects: passing the object itself silently falls back to US.

Percentages show up to two decimals Implemented · 4.2.2

Verified Sep 29: the shared formatter shows exactly one decimal (61.2%, 100.0% on the SERP strip and AI panel), and CSV exports keep two.

Issue: bounce rate and Traffic Channel Distribution use formatPercentage in src/utils/format.ts, which allows up to two decimals and drops trailing zeros. The same SERP strip shows “69.6%” next to “88.11%” and “56.23%”, and the channel chart shows “41.28%”. The second decimal is false precision on a Semrush estimate.

SERP overlay connected rows showing bounce rates of 88.11%, 69.6% and 56.23%.
SERP overlay: “88.11%”, “69.6%” and “56.23%” in one strip.
Traffic Analytics with Bounce Rate 88.11% and Traffic Channel Distribution percentages such as 41.28% and 55.03%.
Traffic Analytics: Bounce Rate and Traffic Channel Distribution.

4.2.1 · September 28 · Click a screenshot to open it full size.

Fix: format with exactly one decimal, toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 }): 88.11% becomes 88.1%, 41.28% becomes 41.3%, and 41% becomes 41.0%. formatPercentage has two callers, trafficAnalytics.ts (bounce rate) and trafficSources.ts (Traffic Channel Distribution), so the one change covers:

  • SERP overlay connected row: Bounce rate.
  • AI Overview sources panel connected row: Bounce rate.
  • Popup, Semrush tab: Bounce Rate tile and Traffic Channel Distribution.
  • Full Report, Semrush tab: Bounce Rate tile and Traffic Channel Distribution.

Leave as is: CSV exports keep two decimals, since they’re for analysis. Keyword density and text/HTML ratio already use one decimal. Image alt text, image formats and the backlink country breakdown use whole numbers.

Semrush Rank and Traffic Cost links open a subfolder report Implemented · 4.2.2

Verified Sep 29: Rank, SE Traffic and Traffic Cost all use the domain link builder, each with its own tracking. Still to check on the final build: live clicks in the Full Report and Quick View.

Issue: in the shared Semrush overview, the Semrush Rank and Traffic Cost links open Domain Overview with searchType=subfolder for the page URL, while their tooltips describe the domain and the SE Traffic link next to them opens the domain. The Full Report shows all three. Quick View hides Rank but shows Traffic Cost.

Fix: build both links with domainAnalyticsOverviewUrl(target, country), like SE Traffic, in src/components/shared/semrush/SemrushOverview.tsx. Keep each link’s own tracking. Verify Rank and Traffic Cost in the Full Report and Traffic Cost in Quick View, on a deep page URL with a non-US country ending.

Lookalike domains pass the Google check Implemented · 4.2.1 chrome-3

Verified Sep 24: The host check now matches Google’s real domains only. A lookalike domain gets no sidebar and no strips.

Issue: The Google host rule in src/utils/serp/google/match.ts accepts any two words after “google.”, so www.google.example.com gets the SERP sidebar and overlays. Reproduced in the shipped 4.2.0 build and unchanged on the 4.2.1 ai branch, where the AI Overview detection uses the same check. The same check gates the background lookup for Google’s /goto redirect links, so on a lookalike page SEOquake also sends requests to that site’s own server, without cookies. The SERP script scope fix neither causes nor fixes it. Risk is low: a lookalike site gets metric strips and those requests, and SEObar already analyzes every site. It’s a one-line change, so include it in 4.2.1 while this code is open.

Fix: Require a real Google ending:

// Current: /^(?:www\.)?google\.[a-z]{2,}(?:\.[a-z]{2,})?$/i
const GOOGLE_HOST_PATTERN =
  /^(?:www\.)?google\.(?:com?\.[a-z]{2}|[a-z]{2,3})$/i;

Tested against Google’s official list of 187 search domains (google.com/supported_domains), with and without www.: the new rule accepts all of them. It rejects google.example.com, google.evil.co, google.company.io, google.co.evil and google.com.evil, which the current rule accepts. urls.ts uses the same rule for redirect detection, so rerun the URL tests after the change.

SERP sidebar keyboard focus Implemented · 4.3.0 chrome-4

Verified October 13, 2026: The focus implementation is complete in chrome-4. Fresh exact-component/CSS checks cover 66 keyboard records, dark mint focus, light focus, Reset, Parameters and collapse/reopen recovery; theme and layout checks pass. This closes the implementation ticket. Live Google, native locale option selection and restart/Store checks remain release validation, not demonstrated unfinished source work.

Original implementation requirements · reference

Earlier requirements retained as history. The remaining Fix and Engineering checks above define the current work.

Implemented October 13: The sidebar, Parameters menu and locale fields now follow the saved SERP theme. Package review and Beatus’s live review confirm the dark appearance. Keyboard-focus styling remains open.

Issue: Parameters, Export CSV, Country and Language can receive keyboard focus without a visible indicator. Collapse/reopen use dark green instead of the specified mint. Locale has a visible blue outline in the supplied screenshot; it needs the same dark-theme focus treatment.

Fix:

  • Add a visible 2px mint #18F0BF keyboard-focus outline in dark mode to Parameters, Export CSV and both native locale selects. Replace outline suppression with an explicit :focus-visible treatment.
  • Apply the same dark-mode focus treatment to collapse/reopen and Locale. Check the remaining sidebar and Parameters-menu controls for a visible, consistent indicator, including the overlay checkbox, parameter checkboxes, More settings, Set locale and Reset. Keep More settings’ lavender text and the existing blue checked/action states.
  • Scope the styles to SERP and preserve the working Light / Dark / Match Google behavior, native selects, control sizes and menu positions. Use an outline or ring that does not change layout, and retain visible focus in light mode.

Files: src/components/serp/SerpControlPanel.tsx, src/components/serp/control/SerpParametersDropdown.tsx, src/components/serp/control/SerpLocalePanel.tsx, src/components/serp/control/LocaleSelect.tsx and src/assets/styles/serp.css. Keep shared button, dropdown and checkbox changes gated to SERP.

Engineering checks

Chrome-3 evidence: Tab traversal with the shipped stylesheet confirmed :focus-visible on Parameters, Export CSV and both selects while outline and shadow were absent. Collapse/reopen settled at #00785F. The Locale screenshot shows an existing visible blue indicator; it does not demonstrate the missing indicators on the other controls.

  • Rebuild the stylesheet. Tab and Shift+Tab through the expanded sidebar, open Parameters menu, expanded Locale fields and collapsed/off states. Every reachable control must show focus without needing hover.
  • Check the final computed focus style after transitions settle. Dark-mode focus uses mint #18F0BF; the indicator remains visible against the shell and fields, without clipping at edges or changing dimensions.
  • Verify keyboard activation, native select navigation, Escape/menu close and focus recovery after collapse/reopen. Check Google Light/Dark and saved Match Google/Light/Dark, including Overlay off.
  • Retain visible focus in light mode and preserve the implemented theme, checkbox ticks, locale actions, autosave, Reset and export states.

Verification boundary: missing-focus findings are supported by package code and isolated keyboard checks. Confirm the correction in the rebuilt extension before closing this ticket; release restart and Store-update checks remain separate.

Screenshot · Locale focus, October 13
Current dark sidebar · visible blue Locale focus
Dark SEOquake sidebar with a visible blue keyboard-focus outline around Locale.

Original user-supplied capture, retained unchanged. Parameters, Export CSV, Country and Language require their own keyboard-focus checks.

Implemented theme requirements · reference

Implemented in chrome-3. Preserve these accepted theme requirements during the focus correction.

  • Reuse Full Report → Settings → SERP Overlay → Appearance → Theme: Match Google (default), Light and Dark. Save automatically. Do not add a separate sidebar setting. Match Google follows the actual Google page theme; forced Light and Dark apply to the sidebar and its menus too.
  • Call setSerpTheme(settings.theme) at the start of syncSerpControlPanel, before rendering or returning for an existing panel. This resolves the saved theme in both entrypoint paths before their Overlay-off return. Register the sidebar with the shared theme by removing the control-host exception in shadowStyles.ts, and retain subscription cleanup when the host is removed.
  • Keep the current layout, spacing, labels, fonts and icons. Use #181E15 for the sidebar and Parameters menu, #2A3028 for hovered rows and locale fields, white for primary text and #A8A9AD for secondary labels and icons. Keep subtle dividers; use mint #18F0BF for hover and keyboard focus, lavender #C190FF for More settings, and blue #2969FF with white text or ticks for Set locale and checked boxes.
  • Scope dark variants and overrides to SERP. They must win against the Parameters headings’ existing text-gray! and the global heading/link rules, including the More settings anchor. Preserve white checkbox ticks and keep shared SEObar and report controls unchanged.
  • Theme all six states below, including the expanded and collapsed off states. Turning SERP Overlay off must keep the chosen theme. Keep the off logo muted, but leave the checkbox and reopening controls readable and usable.
  • Add a subtle 1px #FFFFFF26 edge around the dark sidebar in every state, matching the Parameters menu. Outline the top, right and bottom, following the existing corner rounding. Draw it inside the shell so widths, spacing and menu positions stay the same. Keep internal dividers subtle.
  • Keep country and language as native selects. Use a visible dark field outline and arrow; set the appropriate color scheme for the native option menu. Unchecked boxes remain interactive and need a visible outline. Keep existing autosave, Set locale, Reset, export and collapse behavior.
Theme previews and earlier screenshots · October 12 reference

Historical chrome-2 sidebar markup, stylesheet, Inter fonts and SVG assets. Chrome-3 implements the dark theme; these earlier comparisons retain the approved appearance reference. Google’s dark page backdrop is #22242B. Proposed examples change theme styling only. Controls are local previews; they do not change extension preferences.

Expanded · overlay on

Earlier chrome-2 appearance
Approved dark target

Expanded · overlay off

Earlier chrome-2 appearance
Approved dark target

Collapsed · overlay on

Earlier chrome-2 appearance
Approved dark target

Collapsed · overlay off

Earlier chrome-2 appearance
Approved dark target

Locale expanded

Earlier chrome-2 appearance
Approved dark target

Parameters open

Earlier chrome-2 appearance
Approved dark target
Actual extension screenshots · October 12

Original supplied captures. Their scale differs from the native-size comparisons above.

Expanded · overlay on
Actual SEOquake sidebar: Expanded · overlay on
Expanded · overlay off
Actual SEOquake sidebar: Expanded · overlay off
Collapsed · overlay on
Actual SEOquake sidebar: Collapsed · overlay on
Collapsed · overlay off
Actual SEOquake sidebar: Collapsed · overlay off
Locale expanded
Actual SEOquake sidebar: Locale expanded
Parameters open
Actual SEOquake sidebar: Parameters open
Theme regression checks

Historical package evidence: chrome-2 excluded the sidebar host from shared SERP theme registration and used light-only sidebar styles. Chrome-3 resolves that theme work; the focus correction above remains open. The comparisons execute the native sidebar component in an isolated capture, then reuse its rendered DOM and assets; they are appearance references, not a rebuilt extension.

  • Start with Overlay off and saved Dark on light Google, then saved Light on dark Google. The sidebar must use the saved choice on first load. Change the preference while off and verify an immediate update without reloading.
  • Check all six states on light and dark Google pages with Match Google, Light and Dark. Change Google’s theme and the saved choice without reloading; the sidebar, overlays and AI surfaces must agree. Keep result-number contrast tied to Google’s background independently.
  • Verify initial defaults, reload and restart persistence, automatic saving, Reset to Match Google, failure/retry and an existing installation with no saved theme. The setting remains independent of SEObar.
  • Verify checkbox labels/ticks, menu close and Escape, collapse/reopen, focus after enabling, both native locale selects and Reset, plus Load all, export busy/error and disabled states. Keep controls reachable at narrow widths and Google zoom levels.
  • Check computed dark colors on Parameters headings and More settings, including hover/focus. Confirm the white checkbox tick is retained and shared SEObar/report controls keep their current styling. Check normal text at 4.5:1 and essential control/icon contrast at 3:1; decorative dividers can remain subtle.

Files: src/utils/serp/theme.ts, src/utils/serp/shadowStyles.ts, src/utils/serp/syncControlPanel.ts, src/components/serp/SerpControlPanel.tsx, src/components/serp/control/SerpParametersDropdown.tsx, src/components/serp/control/LocaleSelect.tsx, src/components/shared/form/Checkbox.tsx, src/components/shared/Dropdown.tsx and src/assets/styles/serp.css. Reuse the existing saved SERP theme rather than adding another preference.

Full Report Audit info icon alignment Implemented · 4.3.0 chrome-4

Verified October 13, 2026: All 26 Full Report Audit check-label SVGs have the scoped 2px lift in chrome-4. Computed styles were checked in the supplied extension with controlled page data.

Implemented fix · reference
  • AuditItemHeader.tsx applies [&>svg]:-translate-y-[2px] to the check-label tooltip’s anchorClass. Only the SVG moves; preserve the label’s relative top-px, anchor and existing geometry.
  • Keep all 8 Page Analysis, 2 Mobile Compliance and 16 Technical Compliance rows, label sizes/wrapping, 14 × 14px anchors/SVGs, 4px gap, status icons and tooltip behavior. No global Tooltip lift.

Files: src/components/shared/info/AuditItemHeader.tsx; caller src/components/report/panels/audit/AuditGroup.tsx. Release checks for zoom, wrapping and tooltip interactions remain separate from this implementation closeout.

Original screenshot · reference
Before the chrome-4 correction · Full Report Audit
Earlier Full Report Audit check labels with low info icons.
Page shortcuts

Right-click menu

Implemented · 4.3.0

Implemented in the supplied 4.3.0 package. The user tested Page Info, Audit, Keyword Density, Compare URLs and Settings on October 12; all five opened the correct destinations. It adds the contextMenus permission, which does not add a Chrome permission warning. Legacy 3.x had the same permission. This installed-package check does not establish Store-delivered update behavior.

Right-click a webpage → SEOquake → choose a report. Open the destination directly, without passing through Quick View. Use the browser’s native submenu and styling.

Menu labelDestination / behavior
Page InfoFull Report → Page Info for the source page.
AuditFull Report → Audit for the source page.
Keyword DensityFull Report → Keyword Density for the source page.
Compare URLsFull Report → Compare, carrying the source page URL into the comparison. Preserve existing comparison entries.
SettingsOpen Settings. Place a separator before this item.

Behavior: Use the tab where the right-click occurred. Reuse existing report-opening and tab-reuse behavior; preserve paused, reload-required and unsupported-page handling. Match legacy page-context availability; link-target analysis is outside this scope.

Implementation: the native menu uses the contextMenus API and permission, a background click listener and existing report/settings routing.

Remaining release checks: restart Chrome and confirm one SEOquake submenu, with no duplicate items. Check background-worker wakeup, source-page targeting across tabs/windows and preserved Compare entries. A Store-delivered upgrade must keep SEOquake enabled and saved preferences intact. These checks remain release QA; the five destination checks above passed on the installed 4.3.0 package.

Package 4.2.0 · chrome-3 · Follow-up fix

Revisions · September 17, 2026

1. Hidden headings — missing results and incorrect numbering Passed in chrome-4

Verified September 17: Robert’s chrome-4 package restores the skipped results. The bundled regression fixture passed, and the user confirmed normal/incognito smoke tests. The original diagnosis and proposed fix below are retained as history.

Issue: Google inserts a visually hidden “Web results” heading before some organic cards. The current S() filter mistakes those cards for special sections and skips them before counting, causing missing strips and incorrect subsequent positions.

Fix: In S(), replace the first-heading lookup with the first visually rendered heading:

// Replace: let t = e.querySelector(b);
let t = Array.from(e.querySelectorAll(b))
  .find(isVisuallyRenderedHeading);

The helper should ignore headings hidden by CSS: display: none, visibility: hidden, fully collapsed clipping, or the screen-reader-only 1×1px pattern.

  • Don’t treat aria-hidden="true" alone as visually hidden.
  • Check the actual clipping rectangle; a value merely starting with rect(1px can still be visible.
  • Avoid Google class names. Keep the other filters unchanged for this fix.

Historical test reference: the original regression fixture, including the single-citation module case, and retest both queries in normal and incognito. Adapt the fixture’s bundle path to the rebuilt package and add cases for visible aria-hidden headings and partially clipped headings.

Screenshot: normal/light — missing results and shifted positions
Normal Google results with Google Developers, Google How Search Works and Neil Patel highlighted as missing overlays; subsequent positions are understated.
4.2.0 chrome-3 · September 17 · Click the screenshot to open full size.
Screenshot: incognito — missing results and shifted positions
Incognito iPhone results with Apple Newsroom, T-Mobile and Apple technical specifications highlighted as missing overlays; Reddit starts at position 1 instead of 4.
4.2.0 chrome-3 · September 17 · Click the screenshot to open full size.

Dynamic numbering · Verified in bundled-handler test: Chrome-4 now rescans the full document after result changes and updates overlay positions and CSV rows. Insertion/removal tests passed; this verification was isolated, not a live Google mutation test.

Package 4.2.0 · Follow-up fixes

Revisions · September 16, 2026

Originally retested with chrome-3; resolution statuses updated September 17 for chrome-4. Original issue descriptions remain for context.

1. Google /goto links — missing overlays Passed

Issue: In the tested incognito results, Google uses /goto links. The current parser rejects them, leaving some queries with one overlay and others with none. Legacy instead treats these links as Google destinations and repeats Google’s metrics across unrelated results.

Fix: Update the Google redirect resolver, which currently recognizes only /url and /url/…, to handle the observed /goto format. Inspect an actual link and its destination metadata to determine the extraction method, then pass the resolved HTTP(S) URL through the existing validation and metric pipeline, preserving its path and query. Never pass the Google redirect itself as the target; skip its overlay if unresolved.

Screenshot: missing overlays in incognito
Incognito Google results for things to do in Fort Lauderdale: SEOquake’s sidebar is visible, but the organic results have no metric strips.
4.2.0 · Click the screenshot to open full size.

2. Skipped Google results — incorrect numbering Resolved in chrome-4

History: Failed in chrome-3; resolved in chrome-4. See the September 17 diagnosis and verification.

Issue: Legitimate www.google.com results are filtered out. Positions count only accepted results, so Reddit appears as #2 instead of #3; a second skipped Google result shifts later positions again.

Fix: Replace the URL validator’s blanket rejection of www.google.com destinations with filtering that distinguishes genuine organic pages from Google navigation and redirects. Replace numbering based on the accepted-results array (position: r + a.length + 1 in the supplied bundle) with the eligible organic result’s position, calculated before overlay-specific skips. Exclude AI Overview, People also ask and video carousels from this count.

In the screenshot: Google Developers #1, Google #2, Reddit #3, Neil Patel #4, Medium #5, Google #6, GeeksforGeeks #7, Semrush #8.

Screenshot: skipped results and shifted positions
Google results for how does Google search work: two Google-hosted organic results have no overlays, causing Reddit and subsequent results to have understated position numbers.
4.2.0 · Click the screenshot to open full size.

3. Dark Google pages — unreadable top row Passed

Issue: The top row uses bg-gray-light/50 with dark text. Google’s dark background shows through the 50% transparent gray, reducing contrast. The opaque bottom strip stays readable.

Fix: Replace bg-gray-light/50 with an opaque background matching the approved light-page appearance, approximately #ECECEC. Apply it to both connected metrics and the disconnected teaser so the same design stays readable on light and dark Google pages.

Slack discussion

Screenshot: low-contrast top row on dark Google
SEOquake’s disconnected top row has dark text on muddy gray against a dark Google page, while the opaque bottom strip remains readable.
4.2.0 · Click the screenshot to open full size.

4. Strips and tooltips overlap Google’s interface Passed

Issue: Near-maximum layers put SEOquake above Google’s sticky header and autocomplete in both themes: overlays 2147483645, sidebar 2147483646, tooltips 2147483647. An opaque background alone will not fix this.

Fix: Keep each result overlay in the page’s normal layer and contain its tooltip within it. Start by changing the result overlay’s shadow-host CSS:

:host {
  position: relative;
  z-index: 0; /* replace 2147483645 */
}

This creates a local stacking context. The existing tooltip portal stays inside the overlay’s shadow root, so its high internal layer cannot lift it above the host’s layer.

  • Lower the sidebar’s layer below Google’s menus. If needed, raise only the active result overlay slightly to let its tooltip overlap adjacent strips, keeping it below Google’s header and suggestions.
  • Dismiss any open SEOquake tooltip when focus enters Google’s search field. Confirm the final layers keep both strips and tooltips below the header and autocomplete.
  • Change SEOquake’s elements only; leave Google’s styles alone.

Slack discussion

Screenshot: strips above autocomplete in both themes
Side-by-side dark and light Google pages show SEOquake metric strips appearing above Google’s autocomplete suggestions.
4.2.0 · Click the screenshot to open full size.
Engineering handoff

More technical fixes

Implemented. See each item’s verification and remaining checks. The original diagnosis and guidance are kept as history.

Destination URL Implemented · 4.2.0

Background: Diagnosed September 11 against the supplied 4.1.2 package and the SERP branch at 51b50b5. Implemented in 4.2.0 and passed the September 17 smoke tests. The original guidance below is kept as history.

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

  1. Use the title anchor already selected by findHeadingLink(). Parse its non-empty href against the document base URL. Remove breadcrumb reconstruction from URL identity; do not fall back to it when a link is missing or invalid.
  2. Unwrap only recognized Google-hosted redirects. For supported /url links, extract a valid q or url destination and validate it again. Do not unwrap a third-party site merely because its path is /url. Keep existing ad and result-eligibility exclusions.
  3. 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.
  4. 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.

TestRequired result
Different pages, same domainLinks to /a and /b remain distinct even when their displayed breadcrumbs show only the domain.
Misleading or absent breadcrumbThe 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 pageSupported Google /url?q=… and /url?url=… links resolve correctly. An external site’s /url?q=… address remains that site’s URL.
Invalid or unresolved destinationMissing 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.

Verification boundary: isolated original-code tests reproduce the URL-resolution defect. The acceptance cases above still require the implemented extension, including mixed Google results and coexistence with other extensions. This handoff is not release approval.

Archive 4

Earlier release checks, browser examples and build comparisons.

4.3.1 release details

Package, submission and verification

Final package: 4.3.1-chrome-3-seobar-3. All 19 release-review cards are complete.

Milestones: Beatus confirmed submission October 29 at 11:42 a.m. EDT and rollout set to 100% November 2 at 11:22 a.m. EST. Distribution is not measured adoption.

Verification: 12 tooltip scenario groups passed. Beatus’s live review confirmed report tooltips, SEObar/SERP appearance, typing and nonediting S shortcuts, reports, metrics and the retained Semrush connection. The existing Store installation passed his November 2 upgrade smoke test.

4.2.0 release verification · September 17

Historical checks and browser examples

Shipped in 4.2.0

6 areas passed · chrome-4 package

Release package: Robert’s chrome-4. All 35 files match the reviewed build.

AreaStatus
SERP Overlay, missing listings and initial numberingImplemented · Tested
Semrush connection and connected metricsImplemented · Tested
Quick Parameters autosave, country/language and ResetImplemented · Tested
Dark backgrounds, header and autocomplete layeringPassed smoke tests
SERP CSV exports and page-two offsetVerified exports
Dynamic numbering after insertion/removalBundled-handler test passed

Evidence: Chrome smoke tests confirmed on this exact package. Nine CSV exports contained 66 rows, with consistent numbering and columns. Fort Lauderdale page two runs from #11 to #20. Locale exports include German, Chinese-language and Russian destinations; the files do not record the selected locale.

Package checks: 12 JavaScript files parse; referenced resources exist. Regression suite: 18 of 19 checks passed. This records the September 17 package result. It is not the current 4.3.1 open-work count.

Browser examples

2 captures · September 17

User-supplied captures from chrome-4 testing.

Wikipedia result · connected metrics
Wikipedia result with connected SEOquake metrics and position 1 on dark Google.
IMDb result · video section excluded
IMDb organic result with position 2 and metrics, followed by video entries without overlays.

Legacy version

3.13.5
Apple
https://www.apple.com › iphone
3.iPhone – Apple

Explore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.

Original styling; result number outside the bar.

Previous build

Package 4.1.2
Apple
https://www.apple.com › iphone
iPhone – Apple

Explore the iPhone lineup. Compare models, discover their features, and find the right iPhone for you.

Current styling reference.

SERP Overlay parameters

Settings preview only. No extension preferences are changed.

Core metrics
Other parameters
9 of 9 visible