Are Your “Read more” Links Hurting Your Deep Links SEO in Google Search?
- All things tech
- Apr 24
- 8 min read

You know that “Read more” link in Google that feels like a magical shortcut straight to the good part of your page? Yeah… it’s great until it drops people into a blank accordion, a collapsed tab, or a page that decides to scroll somewhere else like it has free will. Google just updated its snippet documentation with some best practices around these deep links (it’s a doc update, not a shiny new search feature), and it’s basically a friendly reminder: if you’re going to offer shortcuts, make sure the door actually opens when people walk through it.
What actually changed (and what didn’t): the “Read more” links you already have
If you’ve ever seen a Google result with a little “Read more” link that jumps you halfway down the page, you’ve already met the star of today’s story.
What changed isn’t the search feature. Google didn’t wake up and invent a new kind of snippet this week. The change is that Google updated its snippet documentation and finally wrote down some plain best practices for these deep links.
Google’s name for them is basically what you’d expect: a “Read more” deep link is a link inside the search snippet that takes users to a specific section of the page. In the wild, it usually looks like a jump-to-section URL (often with a #fragment at the end).
Here’s the part people get wrong: this isn’t “Google hates ‘Read more’ links now.” It’s more like: Google’s getting pickier about showing them when your page can’t stick the landing.
Because when that deep link works, it’s great:
it drops the searcher straight into the relevant answer,
it cuts down on pogo-sticking,
it can help the result feel more “dialed in” to the query.
But when it doesn’t work, it’s a trust-killer. You click, you land… and the section is hidden, or the page scrolls somewhere random, or the URL loses the fragment. Google’s updated doc basically says: if you want these snippet deep links to show up more often, make sure the page behaves like a normal human expects when they click one.
Also worth knowing: these “Read more” links can show up as anchor URLs in Search Console reporting, and Google has treated that as normal behavior (not some penalty situation).
The #1 way to accidentally break deep links: hiding the target content
So you’ve got a shiny “Read more” deep link showing in Google. Someone clicks it… and lands on a page where the “answer” is tucked inside a closed accordion or a tab that isn’t selected.
That’s the easiest way to turn a jump-to-section link into a “cool, where did it go?” moment.
Google’s guidance here is refreshingly blunt: the destination content should be immediately visible to a human on page load. If it’s hidden behind expandable sections or tabbed interfaces, you can reduce the likelihood of those “Read more” snippet deep links showing up (and even when they do show up, the click experience can be messy).
What “hidden” looks like in real life
This isn’t just “content behind a paywall.” It’s the everyday UI stuff we all ship:
Accordions that load collapsed by default
Tabbed blocks where the default tab isn’t the one with the anchor target
FAQ sections that render fine… after a JS bundle finishes loading
Content injected late (client-side rendering that adds the target heading a second or two later)
If the deep link drops a user at example.com/page#pricing but the #pricing section is inside a closed panel, the browser can’t show what isn’t visible.
Tactical fixes (so the link actually lands on something)
1) Open the right accordion/tab when a hash is present
If your page supports hash fragments (#something), treat that fragment like a “request.”
On load, read window.location.hash
If it matches an element inside a tab/accordion, open that container first
Then allow the browser to jump to the element (or scroll to it after the container is open)
Keep it simple: the goal is visible content immediately, not a fancy animation.
2) Don’t render the target late (or at least don’t act like it’s there when it isn’t)
If the section header with the id="pricing" only exists after React/Vue finishes rendering, the deep link is basically knocking on a door that hasn’t been built yet.
Quick ways to reduce pain:
Server-render (or pre-render) the target headings/IDs if you can
If you can’t, at least make sure the container opens and the target is inserted ASAP, before running any scroll logic
3) Test like a cranky user (because Google traffic is full of them)
This is where “it works on my machine” goes to die.
Run this mini QA:
Open the deep link in an incognito window.
Throttle the network (Slow 3G is perfect).
Try with JavaScript disabled.
If your deep link only works when everything loads instantly, that’s not a deep link. That’s a coincidence.
The point of Google’s best practice is basic: when someone lands, they should instantly see the thing they came for.
When your page fights the hash: auto-scroll scripts, sticky headers, and “helpful” UX
Let’s say your content is visible and your IDs are correct. Great. You can still wreck a “Read more” deep link with one innocent line of JavaScript.
Google calls this out directly: don’t use JavaScript to control the user’s scroll position on page load. Their example is a script that forces the page back to the top.
If a Google snippet deep link is basically yoursite.com/post#answer, the browser does a normal anchor jump… and then your script goes, “Cute. Anyway,” and scrolls somewhere else.
The usual suspects (aka: “why did it scroll up?”)
1) Auto-scroll on load
Common patterns that break anchor links:
window.scrollTo(0,0) on DOMContentLoaded
“scroll to top” on route change (even on a normal page load)
custom scroll restoration code that always picks a saved position
Result: users click a jump link and land at the wrong spot. Google’s guidance is basically: stop wrestling the page on load.
2) Sticky headers that cover the heading
This one’s sneaky. The anchor works… but the H2 you jumped to is hidden under a fixed header, so the user sees a random mid-paragraph start and thinks the link is broken.
Quick fix: add scroll-margin-top to anchor targets (usually headings), sized to your sticky header.
/* example: if your sticky header is ~80px tall */
h2[id], h3[id], section[id] { scroll-margin-top: 90px; }
No JS required. No scroll animations. It just makes anchor jumps land cleanly.
3) “Smooth scroll” that runs without being asked
Smooth scrolling is fine when a user clicks something on the page. It’s a headache when it hijacks initial load and changes where the browser would naturally land.
Guardrails that keep deep links behaving like deep links
Use these as your house rules:
If location.hash exists on initial load, don’t override scroll. Let the browser do its anchor jump.
Only run scroll animations after user interaction (click/tap), not automatically on page load.
If you must run scroll code, special-case hash URLs so the deep link stays the boss.
The goal is boring, predictable behavior: click “Read more,” see the right section, no surprise detours—exactly what Google is nudging sites toward with its “avoid scroll control on load” advice.
SPA and JavaScript-heavy sites: don’t lose the hash (History API traps to avoid)
If your site is JavaScript-heavy, there’s a special kind of deep-link breakage that feels supernatural.
The URL loads with a nice clean fragment like #shipping, you blink, and… it’s gone. No error. No warning. Just poof. And now your “Read more” jump link is basically a regular page visit with extra disappointment.
Google’s guidance calls this out: if your page uses History API calls or window.location.hash modifications on page load, keep the hash fragment in the URL. Removing it breaks deep linking behavior.
The common failure mode in SPAs
This usually happens when the app “helpfully” normalizes the URL:
A router runs on load and does a replaceState() to “clean up” the address bar
A canonicalization script strips fragments because it thinks they’re “noise”
A redirect (even client-side) rebuilds the URL but forgets to carry #fragment along
So the deep link might work once (maybe the browser jumps before the router rewrites things), then mysteriously fails on the next refresh or on certain devices.
History API traps (and how to avoid them)
Here’s a practical punch list you can hand to whoever owns your routing:
When calling history.pushState() / history.replaceState(), preserve location.hash.If you rebuild URLs from location.pathname + location.search and forget location.hash, you’re deleting the deep link.
Don’t clobber window.location.hash on load.Any “set hash to empty” or “force hash to #top” logic will break jump-to-section behavior. Google explicitly warns against hash modifications that remove the fragment.
Make sure the fragment matches a real id in the final rendered DOM.In SPAs, content can render after routing finishes. If your target heading is generated later (or its ID changes), the deep link has nowhere to land.
Watch for “helpful” redirects inside the app.If /page#faq becomes /page/ via a client-side redirect, your fragment is collateral damage unless you carry it across.
A quick sanity test that catches most of this
Take a real “Read more” URL that includes a #fragment and:
hard refresh it
open it in a new tab
copy/paste it into the address bar and press enter
If the hash disappears during any of those, your app is rewriting the URL in a way Google told you not to.
Your quick checklist: what to check today (plus how it shows up in Search Console)
At this point, you don’t need another meeting about deep links. You need a quick “does this actually work?” pass you can run in 15 minutes.
A tight QA routine (steal this)
Grab an actual Google “Read more” deep link URL (the one with the #fragment) and test it like a suspicious stranger would.
1) Fresh click test (no cookies, no memory)
Open a new incognito/private window
Paste the full URL, hit Enter
Watch what happens for the first 3 seconds
Pass criteria:
You land at the intended section
The section is visible immediately
The page doesn’t jump again a moment later (a classic JS “second scroll”)
2) Slow network test (catches the “it loads… eventually” problem)
In Chrome DevTools:
Network → set to Slow 3G
Hard refresh
Repeat the same deep link
Pass criteria:
The content you jumped to doesn’t appear only after a delayed render
The URL keeps its #hash the whole time
3) Mobile test (where sticky headers love causing trouble)
Open the same deep link on a real phone (or device emulation)
Confirm the heading isn’t hidden under the fixed header
Try rotating the device once (sounds silly, catches layout shift + re-scroll bugs)
4) JavaScript-off spot check (optional, but eye-opening)
Turn off JS and try the deep link again. If the page becomes useless, fine—you’re a JS app. But if your key headings and IDs disappear entirely, you’ve learned something important about how fragile your jump-to-section experience is.
How “Read more” deep links show up in Search Console (don’t panic)
Two things can be true at once:
You’re tracking one page
Search Console shows what looks like “extra URLs” with #fragments
That’s normal. Google has said these “Read more” deep links are a type of anchor URL and they can show up in Search Console performance reports. John Mueller has also previously addressed these hashtag/anchor URLs, confirming they come from Google and point to sections on your page.
Here’s the calm way to use that info:
What to look for in Performance
If you see URLs that include #something, treat them as clues about what Google thinks is jump-worthy.
Click into them and sanity-check the landing experience with the QA steps above.
What not to do
Don’t assume #fragment URLs mean duplicate content problems.
Don’t start “fixing” them by stripping hashes sitewide. Google’s own best practice warns that removing the hash fragment can break deep linking behavior.
If you run the checklist and the deep link lands cleanly, you’re in good shape. If it’s wobbly, Search Console is basically handing you a list of where users are getting dropped into the weird parts of your UX.



Comments