TheBeginning· Networking · Web fundamentals

What Actually Happens
When You Press Enter on a URL?

Understanding what really happens between pressing Enter and seeing a webpage.

N
jonathanbuilds
Flask backend developer
12 min read
Nov 2025
Most developers skip this. Here's why you shouldn't.

Before I learned Flask, before I wrote a single line of backend code, my teacher asked me a question I couldn't answer:

"What actually happens when you type a URL and press Enter?"

I said something like "the browser loads the page."

He smiled. That was the wrong answer — or at least, a very incomplete one.

Here's what I now know happens in that half-second between pressing Enter and seeing a webpage. We'll walk through every layer — from a string of characters in your address bar to pixels lit up on your screen — and along the way I'll point out the bits that matter most when you start writing backend code.

zsh — what-happens.sh
$open https://stripe.com/pricing
→ parsing URL…
→ resolving DNS for stripe.com
→ opening TCP connection to 18.66.x.x:443
→ negotiating TLS 1.3
→ sending GET /pricing
← 200 OK · 142 kB · 612ms
STEP 01

The browser parses the URL

It's not just text — it's a tiny structured object.

URL parser — click to tear apart

https://stripe.com/pricing?ref=blog#enterprise

When you press Enter, the browser tears the URL apart into pieces: the scheme (https), the host (stripe.com), an optional port, a path, a query string, and a fragment. If you typed something that isn't a valid URL, the browser hands it off to your default search engine instead.

url-parsing.js
1const url = new URL("https://stripe.com/pricing?ref=blog#enterprise");
2 
3url.protocol; // "https:"
4url.host; // "stripe.com"
5url.pathname; // "/pricing"
6url.search; // "?ref=blog"
7url.hash; // "#enterprise"
Why you should care
Every Flask route you write is matched against url.pathname. The browser already did most of the parsing — your framework just dispatches on it.
STEP 02

DNS turns the name into an address

The internet doesn't speak in words. It speaks in numbers.

Servers are reachable by IP address, not by name. So the browser asks: "what IP belongs to stripe.com?" That question travels through a chain of caches before it ever hits a real DNS server.

DNS resolution flow

Browser cache
OS cache
Recursive resolver
Root server
TLD (.com)
Authoritative
IP returned

Most of the time the answer comes from a cache one or two steps in — your browser's, your OS's, or your ISP's recursive resolver. Only on a cold lookup do you walk all the way up to the root and back down through the TLD.

The TTL trick
DNS records have a TTL (time-to-live). It's the single most important number when you're migrating servers. Set it low before the migration, not after.
STEP 03

TCP opens a reliable pipe

Three packets later, you have a connection.

Now the browser has an IP. It opens a TCP connection — the protocol that guarantees bytes arrive in order, exactly once, even over an unreliable network. The opening ritual is the famous three-way handshake.

TCP three-way handshake

Client
Server
SYN — seq=x
SYN-ACK — seq=y, ack=x+1
ACK — ack=y+1

Connection established. Both sides agree on sequence numbers.

Each round-trip costs whatever your latency is. If your server is in Frankfurt and you're in São Paulo, that's ~200ms just to say hello. This is one reason CDNs exist: terminate TCP closer to the user, then reuse a warm connection to the origin.

STEP 04

TLS makes it private

Because plain HTTP is a postcard. HTTPS is a sealed envelope.

HTTPS is just HTTP on top of TLS. Before any HTTP byte is sent, both sides exchange a few more messages to agree on a cipher, verify the server's certificate, and derive a shared session key.

TLS handshake

Client
ClientHello (TLS version, cipher suites, random)
Server
ServerHello + Certificate + ServerKeyExchange
Client
Verify cert → ClientKeyExchange → ChangeCipherSpec
Server
ChangeCipherSpec + Finished

Encrypted session key established. All future bytes are encrypted.

A subtle gotcha
Self-signed certificates work fine for curl -k but browsers will refuse them. In Flask dev, always test against a real cert (mkcert is your friend) before shipping.
STEP 05

The browser sends an HTTP request

A few lines of text — that's all a request really is.

With an encrypted pipe in place, the browser finally sends what we usually think of as "the request": a method, a path, a stack of headers, and (sometimes) a body. It's plain text. You can read it.

Request
GET /pricing HTTP/1.1
Host: stripe.com
User-Agent: Mozilla/5.0
Accept: text/html
Accept-Encoding: gzip
Cookie: session=…
Response
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Cache-Control: max-age=3600
Server: nginx

<!doctype html>…
app.py
1from flask import Flask, request
2 
3app = Flask(__name__)
4 
5@app.route("/pricing")
6def pricing():
7 # Everything you saw on the left is now available here
8 print(request.method) # "GET"
9 print(request.headers) # all those Header: value lines
10 print(request.cookies.get("session"))
11 return render_template("pricing.html")
STEP 06

The server figures out what to send back

This is where your code finally runs.

The request hits a load balancer, gets routed to one of many app processes, walks through middleware, matches a route, runs your view function, hits a database, renders a template, and ships bytes back down the same TCP connection — usually compressed, often cacheable.

The whole 'backend' is one step
Everything you spend your day building — auth, ORMs, queues, Redis, S3 — fits inside this single step from the browser's perspective. The browser doesn't care. It just wants bytes.
response.py
1# What Flask actually sends on the wire
2HTTP/1.1 200 OK
3Content-Type: text/html; charset=utf-8
4Content-Encoding: gzip
5Cache-Control: public, max-age=3600
6Set-Cookie: session=abc123; HttpOnly; Secure
7Content-Length: 14302
8 
9<!doctype html><html>...</html>
STEP 07

The browser renders the page

Bytes become pixels through a long, beautiful pipeline.

The HTML arrives as a stream. The browser starts parsing immediately — it doesn't wait for the whole document. As it discovers<link>,<script>, and<img> tags, it fires off more requests in parallel and tries to keep the main thread busy laying out what it already has.

Network waterfall (browser rendering)

document (HTML)
style.css
app.js
hero.webp
font.woff2
analytics.js
xhr /api/me
0ms250ms500ms750ms1s

The DOM and CSSOM are built, combined into a render tree, laid out, painted, and composited. Anywhere along this chain a slow font, a render-blocking script, or a giant hero image can ruin everything.

STEP 08

The full picture

Half a second, eight protocols, one moment of magic.

None of these steps are optional. Skip DNS and you don't know where to go. Skip TCP and your bytes scatter. Skip TLS and the internet reads your password. Skip rendering and you stare at raw HTML.

The reason senior engineers seem to magically know where to look when a request is slow is that they've internalized this map. Now you have it too.

What to do with this
Next time something is slow, ask: which step? DNS resolution? TLS handshake? TTFB (your code)? Asset download? Render? Each one has its own tools, its own fixes, and its own villains.