Back to HTTP Headers

Location general response

Points the client to a different URL — used for redirects and to identify newly created resources.

What it does

Location tells the client where to go next. It's used in two distinct contexts:

  1. Redirects — on 3xx responses, it specifies the URL the client should follow
  2. Resource creation — on 201 Created, it identifies the URL of the newly created resource

It's one of the most fundamental response headers — virtually every web framework uses it constantly for redirects after form submissions, auth flows, and resource creation.

Syntax

Location: <url>

Can be an absolute URL or a relative path:

Location: https://www.example.com/new-page
Location: /dashboard
Location: /users/42
Location: ../

Absolute URLs are safer — relative URLs are resolved against the request URL, which can behave unexpectedly through proxies. For redirects to different origins, absolute is required.

Location on redirect status codes

Status Name Behaviour
301 Moved Permanently Permanent redirect Browser follows and caches the redirect. Future requests go directly to new URL. Method may change to GET.
302 Found Temporary redirect Browser follows but doesn't cache. Method may change to GET.
303 See Other See Other Always redirects to a GET. Used after POST to prevent form resubmission.
307 Temporary Redirect Temporary, method preserved Like 302 but method preserved (POST stays POST).
308 Permanent Redirect Permanent, method preserved Like 301 but method preserved.

The classic POST-Redirect-GET pattern uses 303:

POST /login HTTP/1.1
→
HTTP/1.1 303 See Other
Location: /dashboard
→
GET /dashboard HTTP/1.1

Location on 201 Created

After a successful resource creation, Location points to the newly created resource:

POST /api/users HTTP/1.1
Content-Type: application/json

{"name": "Sainesh", "email": "[email protected]"}

HTTP/1.1 201 Created
Location: /api/users/42
Content-Type: application/json

{"id": 42, "name": "Sainesh"}

The client now knows the canonical URL of the new resource without making a separate GET request.

Location vs Content-Location

These are frequently confused:

Header Status codes Means
Location 3xx (redirect), 201 "Go to this URL" — a redirect or pointer to new resource
Content-Location Any response with body "The content in this response lives at this URL" — no redirect

Location changes where the client goes next. Content-Location labels what was just returned, without triggering any navigation.

Open redirect vulnerability

A classic security mistake: using user-supplied input directly in Location without validation:

// VULNERABLE
$redirect = $_GET['return'];
header("Location: $redirect");

// An attacker sends:
// /login?return=https://evil.com/phishing
// → Location: https://evil.com/phishing

The user clicks a legitimate-looking link to your site and gets redirected to a phishing page. Always validate redirect targets against an allowlist of safe destinations.

// Safe pattern — allowlist
$safe_urls = ['/dashboard', '/profile', '/settings'];
$redirect = in_array($_GET['return'], $safe_urls) ? $_GET['return'] : '/dashboard';
header("Location: $redirect");

Protocol-relative URLs

Avoid Location: //evil.com/path — some parsers treat //example.com as a protocol-relative URL (inheriting the current scheme). Always use full absolute URLs for cross-origin redirects or fully-qualified relative paths for same-origin ones.

Common mistakes and gotchas

Sending Location without the right status code. Location is only meaningful on 3xx and 201 responses. Setting it on a 200 OK response (without Content-Location) is confusing and non-standard.

Relative URLs through proxies. A Location: /new-path relative URL is resolved against the request URL. Through proxies and load balancers, the resolved URL may not be what you expect if the internal request URL differs from the external one. Absolute URLs are safer for redirects.

Not following 301 redirects in API clients. By default, many HTTP clients don't follow redirects on non-GET methods. A 301 from a POST endpoint won't automatically re-POST to the new URL — the client needs explicit redirect-following configuration.

Real-world examples

Login redirect (POST → GET via 303):

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

[email protected]&password=secret

HTTP/1.1 303 See Other
Location: /dashboard
Set-Cookie: session=abc123; HttpOnly; Secure

Permanent URL change (SEO redirect):

GET /old-article-url HTTP/1.1

HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-article-url
Cache-Control: max-age=31536000

Resource created:

POST /api/orders HTTP/1.1

HTTP/1.1 201 Created
Location: /api/orders/9876
Content-Type: application/json

{"id": 9876, "status": "pending"}

FAQ

What's the difference between 301 and 308?

Both are permanent redirects that browsers cache. The difference: 301 may change the method to GET (browsers historically changed POST→GET on 301, though modern browsers often preserve it). 308 guarantees method preservation — a POST to a 308-redirected URL will POST to the new URL. Use 308 when you explicitly need method preservation on a permanent redirect.

Does Location work with JavaScript?

Location is an HTTP header — it's processed by the HTTP client (browser), not JavaScript. But window.location in JavaScript achieves the same effect at the browser level. These are different mechanisms. JavaScript can read the Location header from a fetch response (response.headers.get('Location')) but the browser itself will have already followed it.

Can I use Location to redirect to a mailto: or tel: URL?

Technically, Location accepts any URI. Location: mailto:[email protected] or Location: tel:+1234567890 are valid and browsers should handle them. In practice, behaviour varies by browser and context.

Fun fact

The Location header is indirectly responsible for one of the web's most ubiquitous UX patterns: the "logged in" experience. The POST-Redirect-GET pattern (login form → 303 See Other with Location: /dashboard) was invented specifically to prevent the "do you want to resubmit this form?" browser dialog that appeared when users refreshed a page they'd reached via POST. Before this pattern became standard, every website had users accidentally double-submitting login forms, purchase confirmations, and comments. A single redirect header solved a problem that affected every user of every web form ever built.

Related Headers