--- slug: navigation-commit-pipeline type: concept summary: "Chromium's browser-owned navigation state machine, from a requested URL through redirects, throttles, process selection, renderer commit, and the update of committed security state." created: 2026-06-16 updated: 2026-06-18 last_link_verified: 2026-06-16 related: multi-process-architecture: relation: uses note: "The navigation pipeline is one of the browser process's central coordination duties across browser, renderer, and network-service processes." site-isolation: relation: implements note: "Site Isolation's cross-site process assignment becomes operational during navigation, when the browser selects the destination RenderFrameHost and renderer process before commit." browser-renderer-split: relation: enforces note: "The navigation pipeline enforces the browser-renderer privilege split by keeping pending URL, process choice, and committed security state browser-owned." untrusted-renderer-axiom: relation: complements note: "The untrusted-renderer axiom applies to renderer-initiated navigations because renderer-supplied URL and origin claims are inputs, not authority." rendering-pipeline: relation: upstream-of note: "The rendering pipeline begins after a document commits; failed navigations, downloads, error pages, and same-document updates branch before full rendering work starts." feature-flag-guarding: relation: related note: "Navigation throttles and commit-deferring conditions are common feature-gating surfaces, so navigation experiments need the same rollback discipline as other hot paths." --- # Navigation Commit Pipeline > **Concept** > > Vocabulary that names a phenomenon. *Chromium's browser-owned navigation state machine, from a requested URL through redirects, throttles, process selection, renderer commit, and the update of committed security state.* ## What It Is The navigation commit pipeline is the sequence that turns "load this URL" into "this document is now the committed page for this frame." It is browser-owned because the browser process, not the renderer, decides which URL is pending, which URL is visible to the user, which origin is last committed, which renderer process will host the destination document, and when session history changes. The renderer participates in the commit. It doesn't own the authority that makes the commit security-relevant. The pipeline begins when a navigation is requested. The request may come from the browser (the address bar, a bookmark, session restore, a prerender activation) or from the renderer (an anchor click, `window.location`, a form submission, or script). Chromium creates a `NavigationRequest` for the cross-document case and exposes observer-facing state through `NavigationHandle`. Before the network request, the source page may run `beforeunload`. The browser then creates or bypasses a URLLoader-backed request, follows redirects, applies `NavigationThrottle` checks, and processes the response. When the destination is known well enough to commit, the browser selects the destination `RenderFrameHost` and renderer process. That selection incorporates the process model and Site Isolation: a cross-site destination commonly needs a different renderer process from the source document, and the browser-side `RenderFrameHostManager` performs the handoff. The `ReadyToCommitNavigation` observer event marks the point where the browser has picked the destination process and is about to ask the renderer to commit the document. Only after the renderer acknowledges the commit does the browser finalize the last committed URL, committed origin, session-history entry, and the navigation's success or failure state. Same-document navigation is the important exception. A fragment jump, `history.pushState()`, or `history.replaceState()` changes the URL or session-history entry without loading a new document. It still passes through navigation bookkeeping, but it doesn't require the same network request or renderer-process selection path as a cross-document navigation. The distinction matters because security state changes at document commit boundaries, not at every visible URL change. ## Why It Matters Navigation is where Chromium's process trust model becomes operational. The [Browser-Renderer Privilege Split](browser-renderer-split.md) says the renderer is unprivileged. The [Untrusted Renderer Axiom](untrusted-renderer-axiom.md) says renderer claims are hostile inputs. The navigation commit pipeline is the mechanism that applies both rules to the most common boundary crossing in the browser: a page asks to go somewhere, and the browser has to decide what that request means, what process may host the result, and which origin is now authoritative. The URL vocabulary is the first security payoff. A pending URL, a visible URL, and a last committed URL are different facts. The pending URL is where an in-flight navigation is trying to go. The visible URL is what the browser may show while the navigation is in progress. The last committed URL is the document that actually owns the frame's committed security state. Treating those as interchangeable creates spoofing bugs, incorrect policy checks, and agent-generated code that looks plausible but trusts the wrong moment in the state machine. The pipeline also explains why a navigation fix often has to name its phase. A bug before request start has different blast radius from a bug in redirect handling, response processing, process assignment, commit deferral, or same-document history update. A `NavigationThrottle` can cancel or defer a request before a renderer sees a document. A `RenderFrameHost` swap can change which renderer process is allowed to receive the commit. A failed commit can leave the old document's security state in place. Without the pipeline vocabulary, those all collapse into "navigation failed," which isn't enough for code review, incident response, or downstream advisory work. For performance, the concept connects the process-trust section to the [Rendering Pipeline](rendering-pipeline.md). Parse begins after a document commits. A redirect chain, a download response, a 204/205 response, an interstitial, or an error page can stop or redirect the work before a normal document reaches rendering. Navigation isn't a prelude outside Chromium's architecture. It is the browser-owned gate that decides whether rendering is allowed to begin and which process will do it. ## How to Recognize It The source tree names the pipeline directly. `content/browser/renderer_host/navigation_request.h` carries the `NavigationRequest` state machine, including request start, redirect, response processing, commit-without-URLLoader, ready-to-commit, did-commit, and failure states. `content/public/browser/navigation_handle.h` is the observer-facing API that lets browser code inspect a navigation without owning the state machine. `content/public/browser/navigation_throttle.h` is the extension point for cancelling, deferring, or resuming navigations at defined phases. The browser-side frame machinery is the next signal. `content/browser/renderer_host/render_frame_host_manager.cc` manages the current, pending, and speculative `RenderFrameHost` choices for a frame. When a cross-site navigation needs a different renderer process, the manager creates or selects the destination host before commit. Code that changes process assignment during navigation is usually touching this machinery, even when the visible symptom is a URL, history, or security-state bug. The observer events are the public breadcrumb trail. `WebContentsObserver::DidStartNavigation` marks the creation of the navigation. `DidRedirectNavigation` fires for redirects. `ReadyToCommitNavigation` fires when the browser has selected the destination renderer and is about to send the commit. `DidFinishNavigation` fires after the navigation succeeds, fails, or is cancelled. Code that records metrics, triggers feature behavior, or updates UI from those callbacks has to choose the callback that matches the state it needs. Reading the wrong callback is a common way to confuse pending and committed facts. The project documentation splits the same idea across two documents. `docs/navigation.md` describes the chronological path: `beforeunload`, request creation, redirects, response handling, renderer selection, commit acknowledgement, loading, and observer callbacks. `docs/navigation_concepts.md` defines the security-sensitive distinctions: browser-initiated versus renderer-initiated, same-document versus cross-document, pending versus visible versus last committed URL, concurrent navigation, cancellation, error page, interstitial, and download. The concept lives at their intersection. ## How It Plays Out A downstream enterprise browser adds policy code that blocks navigation to selected domains. The first draft reads the visible URL from the UI layer and applies the block when the omnibox changes. That catches browser-initiated address-bar navigations, but it misses a renderer-initiated navigation that redirects through an allowed URL before committing to a blocked one. It also risks showing the user a blocked URL while the old document still owns the frame. The corrected implementation hooks a `NavigationThrottle`, validates each redirect target, and applies the policy before commit. The block now runs at the phase where the browser still owns the request and can cancel it without committing wrong security state. A Site Isolation regression report says a cross-site iframe sometimes lands in the wrong renderer process after a redirect. The report isn't about rendering yet; no pixels have been produced. The relevant question is which `SiteInstance` and `RenderFrameHost` the navigation selected at ready-to-commit time. The investigation reads `NavigationRequest`, the redirect chain, and `RenderFrameHostManager`, then checks whether the final response URL, not the original request URL, drove process selection. The bug is a navigation commit bug because the renderer choice was made from stale pre-redirect state. A feature team experiments with a new condition that defers some navigations while enterprise policy is fetched. The code is hidden behind a Finch flag, but the initial patch defers in `ReadyToCommitNavigation` and resumes after policy arrives. Canary reports show stuck pages after same-document history updates. The problem is phase choice: same-document navigation doesn't follow the same commit path as a cross-document load, and the deferral code assumed it did. The fix moves the experiment to a `NavigationThrottle` phase that applies only to cross-document requests, adds a same-document bypass, and keeps the flag default-off until the metrics separate the two cases. ## Consequences The pipeline gives reviewers a phase map. A navigation change can be read against the specific state it touches: request start, redirect, response, process selection, commit, or finish. That reduces vague review questions ("is navigation safe?") to concrete ones ("which URL is this check reading, and has the navigation committed yet?"). It also keeps UI state and security state apart. The browser may show a pending destination to the user before the destination document commits, but the old document may still be the committed document for the frame. Security checks that need the committed origin must read committed browser-side state, not the address bar and not a renderer-supplied field. The bookkeeping is tedious, but it's what prevents spoofing and privilege mistakes. The cost is complexity. Navigation code has many observer hooks, several URL concepts, two initiation classes, same-document exceptions, redirects, downloads, error pages, interstitials, and process swaps. The names are easy to misuse, and a patch can pass local tests while choosing the wrong phase for a rare redirect or cancellation path. The complexity is not accidental. It is the price of keeping browser-owned authority, renderer participation, network behavior, and session history in a single auditable state machine. For downstream Chromium-based products, the pipeline is inherited rather than optional. Custom protocols, enterprise policy gates, WebView2 integrations, Electron navigation handlers, and browser-fork UI changes all run through the same distinctions. A downstream feature that trusts the renderer's URL, treats the omnibox URL as committed authority, or updates session state before renderer acknowledgement has weakened the browser-owned boundary, even when the feature doesn't touch low-level security code. ## Notes for Agent Context When writing Chromium navigation code, distinguish `NavigationRequest`, `NavigationHandle`, `RenderFrameHost`, `NavigationController`, pending URL, visible URL, and last committed URL before choosing an API. Use browser-side navigation state as authority for security decisions: `RenderFrameHost` and `SiteInstance` identity, the committed origin, and the final response URL after redirects. Never trust a renderer-supplied URL or origin claim as the committed fact, and never use the visible URL as a substitute for the last committed URL in a policy or permission check. When adding navigation policy, prefer `NavigationThrottle` at the phase that matches the decision: start, redirect, or response. Check whether the code applies to cross-document navigation, same-document history updates, browser-initiated navigation, renderer-initiated navigation, downloads, error pages, and interstitials. If a change selects or swaps renderer processes, audit `RenderFrameHostManager` and `SiteInstance` behavior explicitly; Site Isolation is enforced at process-selection time, not after rendering starts. ## Sources The canonical chronological source is the Chromium project's `docs/navigation.md`, which describes `beforeunload`, request creation, redirects, response handling, renderer selection, commit acknowledgement, loading, and the `WebContentsObserver` callbacks around the sequence. `docs/navigation_concepts.md` is the companion source for the security vocabulary: browser-initiated versus renderer-initiated navigation, same-document versus cross-document navigation, pending URL, visible URL, last committed URL, redirects, concurrent navigation, cancellation, error pages, interstitials, and downloads. The `content/browser/renderer_host/README.md` file places navigation in the renderer-host subsystem and names `NavigationRequest`, `NavigationController`, `NavigationEntry`, and `FrameNavigationEntry` as the browser-side objects that own the state. `content/browser/renderer_host/navigation_request.h` exposes the concrete state enum that makes the pipeline auditable in code. `docs/process_model_and_site_isolation.md` supplies the process-assignment context the pipeline applies when a navigation crosses sites. ## Technical Drill-Down - [`docs/navigation.md`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/docs/navigation.md) — chronological walk through the navigation path from request start through commit acknowledgement and loading. - [`docs/navigation_concepts.md`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/docs/navigation_concepts.md) — definitions for same-document, cross-document, browser-initiated, renderer-initiated, pending URL, visible URL, and last committed URL. - [`content/browser/renderer_host/README.md`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/content/browser/renderer_host/README.md) — map of the renderer-host subsystem, including the browser-side navigation and session-history objects. - [`content/browser/renderer_host/navigation_request.h`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/content/browser/renderer_host/navigation_request.h) — the concrete `NavigationRequest` state machine, including start, redirect, response, ready-to-commit, did-commit, and failure states. - [`content/public/browser/navigation_handle.h`](https://chromium.googlesource.com/chromium/src/+/8fd3520bac845685e87a7450ebbf9f868ff7197f/content/public/browser/navigation_handle.h) — observer-facing navigation API used by browser code that needs to inspect a navigation without owning the state machine. - [`content/public/browser/navigation_throttle.h`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/content/public/browser/navigation_throttle.h) — extension point for cancelling, deferring, resuming, or proceeding at defined navigation phases. - [`content/browser/renderer_host/render_frame_host_manager.cc`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/content/browser/renderer_host/render_frame_host_manager.cc) — browser-side frame-host selection and speculative host management for navigations that may swap processes. - [`docs/process_model_and_site_isolation.md`](https://chromium.googlesource.com/chromium/src/+/ec196468c56ce97ccb4b2042c6ab5b503703280a/docs/process_model_and_site_isolation.md) — process-model and Site Isolation context for cross-site navigations. --- - [Next: Process Consolidation Under Memory Pressure](process-consolidation-memory.md) - [Previous: Browser-Renderer Privilege Split](browser-renderer-split.md)