7 UX Problems That Were Also Hurting SEO (From a Real SaaS Audit)

A while ago I audited a small SaaS that turns photos into short videos. The brief was simple: people visit, few of them sign up, figure out why.
When we rebuilt the funnel from their analytics, roughly 2.8% of homepage visitors got as far as starting a free trial. That's an estimate, not a precise number, but it was clearly below where it should be.
I kept two columns in my notes: "hurts users" and "hurts search visibility". By the end, most items sat in both. Below are the seven that overlapped, with the fix and a quick way to check your own site for each one.
1. The pricing page was behind a login
What users saw. A "Pricing" link that opened a sign-up form. To find out what the product costs, you had to create an account first. Most people who just want a price won't trade their email for it, so they left.
This was also the biggest single drop in the estimated funnel:
| Step | Visitors | Lost since the row above |
|---|---|---|
| Homepage visit | 1,000 | |
| Clicked a CTA | 320 | 68% |
| Viewed pricing | 180 | 44% |
| Started sign-up | 120 | 33% |
| Started free trial | 28 | 77% |
What search engines saw. A redirect to the login page. Crawlers don't create accounts, so /pricing was never indexed. Searches like "[product] pricing" or "[product] cost" ended up on review sites and competitor comparison pages. AI assistants answering "how much does [product] cost" pulled from the same third-party pages, some with outdated prices.
Fix. Make the pricing page public and put the prices in the HTML. Keep checkout, billing and the app itself behind auth.
If you protect routes in middleware, look at the matcher first. A broad rule often catches marketing pages by accident.
Before:
export const config = { matcher: ['/((?!$).*)'] }; After:
export const config = { matcher: ['/app/:path*', '/account/:path*', '/billing/:path*'] }; Check.
curl -sI https://yoursite.com/pricing | head -n 3 You want a 200. A 301 or 302 to /login means crawlers never see the page. Then run the URL through URL Inspection in Google Search Console to confirm it can be indexed.
2. The homepage had no H1 and no clear offer
What users saw. A short line of small text and a "See examples" button. Nothing said what the product does, who it's for, or why it beats doing the same thing by hand.
What search engines saw. No H1 at all, and almost no text above the fold. The page ranked for the brand name and very little else, because nothing on it stated the topic in the words people search with.
Fix. One H1 that says what the product does in your customers' words, and one line under it with who it's for and the main benefit.
<h1>Turn your photos into a short video in minutes</h1> <p>For creators and small teams. Upload, pick a style, export. No editing skills needed.</p> Check. Paste this into the browser console:
[...document.querySelectorAll('h1')].map(h => h.textContent.trim()) You want one H1 that a stranger would understand. Then do the five-second test: show the first screen to someone who has never seen the site, hide it after five seconds, and ask what the product does.
3. After the hero, the page jumped straight to reviews
What users saw. No "how it works", no features. Just testimonials praising a product the visitor still didn't understand.
What search engines saw. Very little text describing the product, so little to match against queries like "photo to video maker" or "make a video from pictures online". A homepage that thin competes on its brand name only.
Fix. Add a three-step "How it works" and a features block with real headings. Not a wall of SEO copy, just the answers a buyer looks for.
<section> <h2>How it works</h2> <ol> <li><h3>Upload your photos</h3><p>JPG, PNG or HEIC, straight from your phone.</p></li> <li><h3>Pick a style</h3><p>Change colors, timing and music.</p></li> <li><h3>Export</h3><p>Download in 1080p and share anywhere.</p></li> </ol> </section> Check. Open the homepage in reader mode or with images turned off. If you can't tell how the product works from the text alone, a crawler can't either.
4. Navigation hid the pages people look for
What users saw. A header with a couple of links. No Pricing, no FAQ, no About. Anyone looking for basic answers had nowhere to click.
What search engines saw. Internal links are how crawlers find pages and judge which ones matter. Pages linked only from the footer, or not linked at all, get crawled less often and look less important.
Fix. Put the pages buyers look for in the header, as plain links.
<nav> <a href="/features">Features</a> <a href="/pricing">Pricing</a> <a href="/examples">Examples</a> <a href="/faq">FAQ</a> <a href="/about">About</a> </nav> Avoid links built from click handlers, like <span>. Crawlers follow href, not JavaScript events.
Check. In Google Search Console, open Links → Internal links. Your pricing and feature pages should be near the top of the list, not at the bottom.
5. Images had no alt text
What users saw. Screen reader users heard file names or nothing. Everyone else saw the same blank boxes when an image failed to load on a slow connection.
What search engines saw. For a video tool, the example gallery was the most convincing content on the site. Without alt text, none of it existed as text: no image search traffic, and no description of what the product produces.
Fix. Describe what the image shows, briefly. Decorative images get an empty alt so screen readers skip them. Set width and height while you're there, so the layout doesn't jump when images load.
<img src="example-beach.webp" alt="30-second video made from 12 beach photos with fade transitions" width="1200" height="675"> <img src="divider.svg" alt=""> Check. In the console:
[...document.images].filter(i => !i.hasAttribute('alt')).map(i => i.src) An empty array is what you want.
6. Mobile was slow: LCP 3.2 s, INP 280 ms
| Metric (mobile) | Measured | Good |
|---|---|---|
| Performance score | 60 | 90+ |
| LCP | 3.2 s | under 2.5 s |
| INP | 280 ms | under 200 ms |
| CLS | 0.08 | under 0.1 (passed) |
What users saw. On a phone, the hero took over three seconds to appear, and buttons felt sluggish after a tap.
What search engines saw. LCP and INP are part of Core Web Vitals, which search engines use as a page experience signal. It's not the strongest ranking factor, but with mobile-first indexing the mobile version is the one being evaluated.
Fix. Two changes usually move these numbers the most.
For LCP, load the hero image early and never lazy-load anything in the first screen:
<link rel="preload" as="image" href="/img/hero.webp" fetchpriority="high"> <img src="/img/hero.webp" alt="Video editor showing a finished clip" width="1200" height="675" fetchpriority="high"> For INP, keep third-party scripts (chat widgets, heatmaps, extra analytics) out of the critical path, and give the browser a chance to paint before heavy work runs after a click:
<script src="https://chat-widget.example/loader.js" defer></script> button.addEventListener('click', async () => { showSpinner(); await new Promise(resolve => setTimeout(resolve, 0)); runHeavyWork(); }); Check. Run PageSpeed Insights on mobile. If your site has enough traffic, look at the field data section, not only the lab score. The Core Web Vitals report in Search Console groups slow URLs for you.
7. Nothing was tracked beyond pageviews
What users saw. Nothing. But this is why the team couldn't say where people dropped off, and why the funnel above is an estimate.
What search engines saw. Nothing either. The SEO cost is indirect: Search Console tells you which pages get search traffic, but without conversion events you can't tell which of those pages bring sign-ups. So you end up chasing clicks instead of customers.
Fix. A handful of GA4 events covers most of it:
document.querySelectorAll('[data-cta]').forEach(el => { el.addEventListener('click', () => { gtag('event', 'cta_click', { location: el.dataset.cta }); }); }); if (location.pathname === '/pricing') { gtag('event', 'view_pricing'); } Mark sign_up as a key event, then compare organic landing pages by sign-ups, not by sessions.
Check. Open DebugView in GA4, click through your own site, and watch the events arrive.
What didn't overlap
Not everything on the list was an SEO problem, and I don't want to pretend otherwise. These hurt users only, and they still mattered:
- Text contrast of 1.8:1 on the homepage, against a WCAG AA minimum of 4.5:1. Unreadable in sunlight on a phone.
- Buttons around 32 px tall on mobile. Google and Apple both recommend at least 44–48 px touch targets.
- A sign-up form with 12 fields, including company, job title and phone, for a free trial of a video tool. Email and password were enough.
- Pricing cards that all looked the same. No highlighted plan, no comparison table, so people couldn't decide.
None of these will move rankings. All of them move sign-ups, which is the reason anyone cares about rankings in the first place.
A 15-minute check for your own site
-
curl -sIyour pricing page. Is it a200without logging in? - Count the H1s on your homepage. Is there one, and does it say what you do?
- Read the homepage in reader mode. Can you explain the product from the text alone?
- Is Pricing in the header as a real
<a href>link? - Run the alt text snippet. Any images left without
alt? - Run PageSpeed Insights on mobile. Are LCP under 2.5 s and INP under 200 ms?
- Click your main CTA with GA4 DebugView open. Does an event show up?
If you fail two or more, start with the pricing page. It's usually the cheapest fix with the biggest effect on both sides.
The common thread: most of these were never "SEO tasks" or "UX tasks" on anyone's list. They fell between the designer, the developer and whoever handled marketing. That gap is why I look at both together in a UX SEO audit instead of splitting them into two reports.
What's the worst one you've found on a site you worked on? I'm curious whether gated pricing is as common as it seems.