URLs & Web Fundamentals
What is a URL hash?
A URL hash, also called a fragment identifier or anchor, is the portion of a URL that follows a # character and identifies a specific section or position within a page. In https://example.com/page#specifications the hash is #specifications: it tells the browser to navigate to the element on the page with the ID specifications after loading the page content. The hash is the mechanism that enables deep linking within a page, sending visitors directly to a specific section rather than to the top of the page.
The # character marks the boundary between the main URL, the part that identifies the resource, and the fragment identifier, the part that identifies a location within the resource. Everything before the # identifies the page. Everything after the # identifies a position within that page. From the server’s perspective the fragment identifier is invisible, it is never included in the HTTP request sent to the server. The server receives a request for https://example.com/page: the #specifications portion exists only in the browser.
URL hashes are one of the most widely misunderstood components of URLs, particularly regarding their interaction with redirects, SEO, and JavaScript applications. The fact that hashes are processed entirely by the browser, never reaching the server, has fundamental implications for how redirects handle fragment identifiers and how search engines index and process URLs containing hashes.
How URL hashes work
The URL hash operates through a specific browser-side mechanism, entirely distinct from how the path and query string are processed.
Server never receives the hash: when a browser requests https://example.com/page#specifications it makes an HTTP GET request for https://example.com/page: the hash is stripped before the request is sent. The server receives and responds to /page: it has no knowledge of the #specifications fragment. The server response is the same regardless of whether the URL has a hash or not.
This server invisibility is the defining characteristic of URL hashes, and the source of most hash-related misconceptions. Since the server never receives the hash server-side redirect rules cannot access or match hash values. A redirect rule configured to redirect example.com/page#section-1 to a different destination will not work as intended, the redirect rule matches example.com/page: the hash is never received by the server.
Browser-side fragment navigation: after the server responds with the page content the browser processes the hash. The browser scrolls the page to the element matching the hash, the element with id="specifications" for the hash #specifications. If no matching element exists the browser remains at the top of the page, the hash has no visible effect.
The scroll-to-element behaviour happens client-side after the page has loaded, the server response is complete and the browser is rendering the page. This is why hash navigation feels instantaneous, there is no round trip to the server for hash changes.
Hash changes without page reload: browsers can update the URL hash without reloading the page, changing from #section-1 to #section-2 does not trigger a new HTTP request. This client-side hash change behaviour is what enables single-page applications and infinite scroll implementations to update the URL as the user navigates, providing shareable URLs for different application states without full page reloads.
URL hashes in HTML
HTML uses fragment identifiers through anchor elements, the id attribute and the <a> element with a # href.
Target elements with id attributes: any HTML element can have an id attribute that makes it a fragment identifier target. <h2 id="specifications">Specifications</h2> creates a target for the #specifications hash. <div id="section-3"> creates a target for #section-3. Element IDs must be unique within a page, duplicate IDs create ambiguity about which element the hash refers to.
Named anchors, legacy syntax: older HTML used <a name="section"> as fragment targets rather than id attributes. Both #section hashes and named anchor links still work in modern browsers, they are treated identically. Modern HTML uses id attributes rather than named anchors, named anchor syntax is a legacy pattern.
Smooth scrolling: CSS scroll-behavior: smooth and JavaScript scroll APIs enable smooth animated scrolling to fragment targets rather than instantaneous jumps. The URL hash works the same way regardless of scroll behaviour, the hash identifies the target element, the scroll behaviour determines how the browser navigates to it.
URL hashes and search engines
Search engines treat URL hashes differently from paths and query strings, the browser-side processing of hashes creates specific indexing behaviour that has important implications for SEO.
Search engines generally ignore hashes: Google and other major search engines treat https://example.com/page and https://example.com/page#specifications as the same URL for indexing purposes. The hash does not create a separate indexable URL, the page is indexed once at the hash-free URL. A backlink to example.com/page#specifications contributes its link juice to example.com/page: the hash is ignored in the link equity attribution.
This hash-ignorance means that using hashes to create “sub-page” content that should rank independently in search results does not work, the hash fragments are not independently indexed. Content that should rank for specific queries needs its own URL, a path-based URL, not just a hash fragment on a parent page.
Hash URLs in internal links: internal links using hash fragments are treated by search engines as links to the parent page, the hash is ignored. A page with many internal links to example.com/page#section-1, example.com/page#section-2, example.com/page#section-3 effectively has many internal links all pointing to example.com/page: the hash fragments do not distribute link equity to different destinations.
JavaScript application hashes and search engines: single-page applications that use hash-based routing, example.com/#/products, example.com/#/about: create a content accessibility challenge for search engines. The server always serves the same response for all hash-based routes, the hash is never sent to the server. Different application states are entirely client-side, reached through JavaScript after the initial page load.
Googlebot now renders JavaScript and can in some cases discover and index hash-based SPA routes, but indexation of hash-based routes is less reliable than path-based routes. Modern SPAs have largely moved from hash-based routing to pushState history API routing, which uses real URL paths rather than hashes, providing better search engine indexability.
URL hashes and redirects
The server invisibility of URL hashes creates specific challenges and limitations for redirect management.
Server-side redirects cannot match hashes: the most important practical limitation. Server-side redirect rules: whether configured in web server configuration, redirect management platforms, or application code, operate on the URL as received by the server. Since the server never receives the hash fragment redirect rules cannot match, inspect, or act on hash values.
A redirect rule intended to redirect example.com/page#old-section to example.com/page#new-section does not work. The server receives example.com/page: matches the rule for the path, and redirects to wherever the rule specifies. The hash #old-section is lost, the redirect destination does not carry the hash unless the redirect rule explicitly appends it, and even then the original hash value cannot be read by the server.
301 redirects strip hash fragments: when a user follows a URL containing a hash to a page that has a server-side redirect the hash is stripped in the process. The browser sends the request without the hash, the server returns the redirect, the browser follows the redirect to the destination. The original hash is not preserved through the redirect unless the destination URL explicitly includes a hash.
This hash-stripping behaviour is rarely problematic because hashes identify positions within the original page, and the redirect destination is a different page where the same hash may not be meaningful. But in cases where the redirect destination has equivalent sections with equivalent IDs explicitly including the appropriate hash in the redirect destination URL provides the best deep-linking experience.
JavaScript redirects can preserve hashes: the only way to implement hash-aware redirects is through client-side JavaScript. A JavaScript redirect can read window.location.hash: the current hash value, and include it when setting window.location.href for the redirect destination. This enables hash-preserving redirects for cases where the destination page has equivalent anchor targets.
However JavaScript redirects are not appropriate as the primary redirect mechanism for SEO purposes, they are not as reliable as server-side 301 redirects for link juice transfer and index updates. JavaScript redirects that preserve hashes should be a user experience enhancement, in addition to, not instead of, server-side 301 redirects.
Hash changes in history API applications: single-page applications using the pushState history API, which creates real URL paths rather than hash routes, can implement client-side navigation that updates the URL without server requests. These URL changes are real path changes visible to the server, not hash changes, so they interact with server-side redirect rules normally.
URL hashes in practice
Several common use cases for URL hashes illustrate their practical applications and limitations.
Table of contents navigation: long-form content pages use hash links in table of contents to enable direct navigation to specific sections. A documentation page or comprehensive guide with sections on Installation, Configuration, and Troubleshooting provides hash links, #installation, #configuration, #troubleshooting: in a table of contents. Each hash link scrolls the page to the corresponding section heading, providing navigation without additional page loads.
These hash fragments are not independently indexed by search engines, the entire page is indexed as one URL. The in-page navigation improves user experience without affecting URL structure or SEO indexation.
Shared links to specific sections: users sharing long content can append a hash to link directly to the relevant section. A user who finds the #specifications section of a product page valuable can share the URL example.com/products/blue-widget#specifications: the recipient arrives at the specifications section directly. The hash fragment provides value through improved user experience even though search engines ignore it.
Accordion and tab navigation: some implementations use hash fragments to track the state of expandable sections, accordions, and tabs, so that the URL reflects the current state and can be shared. example.com/faq#question-5-answer might indicate that the fifth FAQ answer is expanded. These implementations require JavaScript to read the hash on page load and set the appropriate UI state.
Single-page application routing, legacy pattern: hash-based SPA routing, example.com/#/products, example.com/#/about: was a common pattern when the pushState API was not yet universally supported. The hash route allowed different application states without requiring server-side support for the routes, the server always served the same response for example.com/ regardless of the hash. Modern SPAs have moved to pushState routing which provides real path-based URLs with better SEO support.
URL hashes and page performance
URL hashes interact with page performance in specific ways, primarily through how browsers handle hash navigation and how page load events fire.
No server round trip for same-page hash navigation: clicking a hash link on the same page, <a href="#section-2"> on a page at example.com/page#section-1: does not trigger a network request. The browser updates the URL hash and scrolls to the target element entirely client-side. Same-page hash navigation is instantaneous from a network perspective, it eliminates the latency of a full page load.
Hash navigation on first load: when a user arrives at a page with a hash, example.com/page#specifications: the browser loads the full page through the normal HTTP request process, then scrolls to the hash target after the page has rendered. The hash does not speed up the initial page load, the full page must load before hash navigation occurs.
Preloading hash target content: for long pages where hash targets are far down the page lazy loading of images and other resources above the hash target may delay the hash target’s visibility, the page loads but the user must wait for above-the-fold resources to load before the browser can accurately scroll to the hash target. Careful implementation of lazy loading avoids this issue, or the hash target’s immediate context can be prioritised in load order.