A fragment identifier is the portion of a URL following the hash symbol (#) that directs browsers to a specific section within a document. Understanding how fragments work—and their limitations—is essential for managing anchor navigation, JavaScript frameworks, and crawlability.
The fragment identifier is the terminal component of a URL, appearing after the hash symbol. In the URL example.com/services#pricing, the string 'pricing' is the fragment. When a browser encounters this URL, it loads the full page at example.com/services, then searches the DOM for an element with id='pricing' or a named anchor with name='pricing'. If found, the viewport scrolls to that element. This happens entirely on the client side—the fragment is never sent to the server in the HTTP request. The server receives only example.com/services, processes that resource, and returns the complete document. The browser then applies the fragment instruction locally. This client-side behavior has significant implications: fragments cannot influence which content the server generates, they do not create distinct pages from a server perspective, and refreshing a URL with a fragment reloads the same resource then re-applies the scroll. Because fragments operate after page load, they depend on the target element existing in the rendered DOM at the moment the browser attempts the scroll.
Search engines treat URLs with different fragments as a single canonical resource. Google, Bing, and other crawlers strip the fragment before indexing, so example.com/page#section-one and example.com/page#section-two both resolve to example.com/page in the index. This means you cannot create distinct indexed pages by varying only the fragment. If you need separate indexable URLs for different content blocks, use distinct paths or query parameters instead. The one historical exception was the hash-bang (#!) scheme used by early AJAX applications, which Google deprecated years ago. Modern crawlers execute JavaScript and render pages, but they still ignore traditional fragments when determining URL identity. This behavior prevents fragment-based duplication but also means deep links using fragments won't show up as separate entries in search results. When planning site architecture, fragments are ideal for navigation within a page—table of contents, footnote jumps, accordion sections—but never for separating content that should rank independently. Understanding this boundary prevents the mistake of building a content structure that appears multi-page to users but collapses into a single URL for indexing.
JavaScript frameworks often use fragment identifiers to simulate multi-page navigation without triggering full page reloads. In hash-based routing, changing the fragment (example.com/#/about to example.com/#/contact) updates the application state and renders different components, but from the browser's perspective it remains a single resource. This approach avoids server round-trips and preserves application state in memory, which is why it became popular early in the SPA era. The tradeoff is crawlability: because fragments are not sent to the server, a crawler requesting example.com/#/contact receives the same HTML as example.com, typically a shell with minimal content. If the application does not implement server-side rendering or prerendering for bots, the distinct views accessible via hash routes remain invisible to search engines. Modern SPAs more commonly use the History API with clean URLs, which allows framework routing without fragments and lets the server respond appropriately to each route. If you inherit or maintain a hash-routed application, verify that critical content renders in the initial HTML or implement dynamic rendering to serve crawlers a static snapshot of each route's state.
Fragment identifiers excel in scenarios where you want to link directly to a subsection of a long document. Common patterns include linking from a table of contents to headings further down the page, jumping to a specific FAQ answer, or scrolling to a footnote reference. To implement this, assign a unique id attribute to the target element: <h2 id='implementation-guide'>Implementation Guide</h2>. A link formatted as <a href='#implementation-guide'> will scroll to that heading when clicked. For accessibility, ensure fragment targets are meaningful and that keyboard navigation works as expected. Some sites dynamically update the fragment as users scroll through sections, providing a shareable URL that reflects the current position without requiring manual anchor clicks. This pattern improves user experience by making deep links contextually relevant. When using fragments for navigation, test across browsers—especially mobile Safari and older versions of Chrome—to confirm smooth scrolling behavior. Avoid conflicts where JavaScript event handlers intercept fragment clicks and break native scrolling. Fragment identifiers also appear in API documentation and technical references, where linking to a specific method or parameter definition saves users from scrolling through long pages.
The most frequent error is linking to a fragment identifier that does not exist in the target document. If the browser cannot find the matching id or name attribute, the link simply loads the top of the page, frustrating users who expected to land on specific content. This often happens when content is dynamically loaded or when IDs change during site updates. Always validate that fragment targets persist across template changes. Another mistake is assuming fragments will pass through analytics tools the same way paths do. By default, Google Analytics and similar platforms strip fragments from pageview tracking, so example.com/page#section-one and example.com/page#section-two both record as example.com/page. You need explicit configuration to capture fragment values as events or custom dimensions if tracking distinct fragment interactions matters. Developers sometimes confuse fragments with query parameters: fragments are client-side and not sent to the server, while query parameters are part of the request and can influence server behavior. Finally, relying on fragments for critical navigation in JavaScript-disabled environments will fail, since fragment scrolling depends on the element existing in the initial DOM or being rendered by a script the browser can execute.
Deciding whether to use a fragment identifier, a query parameter, or a distinct path depends on whether the content variation should be indexed separately and whether the server needs to know about it. Use fragments when the server response is identical and you simply want to scroll to a subsection—no new HTTP request, no separate indexing. Use query parameters when the server must generate different content or apply filters, and you want those variations to be indexable (example.com/products?category=shoes). Use distinct paths when the content is fundamentally different and deserves its own URL in search results (example.com/products/shoes versus example.com/products/boots). Fragments are appropriate for within-page anchors, state changes in SPAs where indexing is handled separately, and transient UI states like open modals or tabs that do not require a unique indexed URL. Query parameters suit filtering, sorting, pagination, and any scenario where the server logic changes. Paths suit discrete content entities. Mixing these incorrectly leads to indexation problems: fragments where you need indexable parameters, or parameters where a simple fragment would suffice and avoid duplicate content. Understanding the behavior of each component ensures your URL structure aligns with both user expectations and search engine requirements.
A fragment identifier appears after the hash symbol and operates entirely on the client side—the browser scrolls to a matching element ID without sending the fragment to the server. A query string appears after the question mark and is sent to the server with the HTTP request, allowing the server to generate different content or apply filters. Search engines can index different query strings as separate URLs, but fragments are ignored and do not create distinct indexed pages.
Search engines strip fragment identifiers before indexing, treating URLs that differ only by fragment as the same canonical resource. Google and Bing do not crawl fragments or consider them when determining page uniqueness. This means example.com/page#intro and example.com/page#conclusion both index as example.com/page. If you need separate indexed URLs, use distinct paths or query parameters instead of relying on fragments.
Fragment scrolling works in browsers even without JavaScript, as long as the target element with the matching ID exists in the initial HTML. The browser natively handles scrolling to an anchor. However, if the target element is only rendered by JavaScript—such as in dynamically loaded content or single-page applications—then with JavaScript disabled, the fragment will fail because the element never appears in the DOM. Always ensure critical fragment targets exist in the base markup.
By default, most analytics platforms strip fragments from pageview URLs, so fragment-based navigation does not appear as distinct pages. To track fragment interactions, configure event tracking or virtual pageviews that explicitly capture the fragment value. In Google Analytics, you can use JavaScript to read window.location.hash and send it as a custom dimension or event parameter whenever the fragment changes, allowing you to see which anchors users interact with.
Early single-page applications used hash routing because changing the fragment does not trigger a server request or page reload, making it easy to update the visible content and maintain application state in memory. The browser's back and forward buttons still work because fragment changes are added to the history stack. However, hash routing creates indexability challenges since crawlers do not send fragments to the server. Modern SPAs typically use the History API with clean URLs, which allows client-side routing while still letting the server respond to each route for better SEO.
If the browser cannot find an element with an id or name attribute matching the fragment, it simply loads the page and scrolls to the top. No error is thrown, but the user does not land on the expected section, which creates a poor experience. This commonly occurs when content is loaded dynamically after the initial page render or when element IDs change during site updates. Always validate that fragment targets exist and remain stable across deployments to avoid broken deep links.