- Home
- HTTP Status Codes
- 300 Multiple Choices
Status Code
300 Multiple Choices
The request has multiple possible responses. Learn when to use 300 Multiple Choices for content negotiation and alternative resource locations.
What is 300 Multiple Choices?
TL;DR: Resource has multiple formats available (PDF, HTML, etc.). Choose your preferred option from the provided list.
A 300 Multiple Choices status code indicates that the requested resource has multiple representations available, and the client should choose one. Think of it like a menu at a restaurant offering the same dish in different sizes or preparation styles—you get to pick which variation you want.
This status code is used for content negotiation when a server can provide the same resource in different formats, languages, or locations, giving the client the power to select the most appropriate option.
When Does This Happen?
You’ll see a 300 Multiple Choices response in these situations:
1. Multiple Format Options
/document can be:
→ /document.pdf
→ /document.html
→ /document.txt
2. Language Variants
/page has translations:
→ /page/en (English)
→ /page/es (Spanish)
→ /page/fr (French)
3. Resolution Options
/image.jpg available as:
→ /image-hd.jpg (1920x1080)
→ /image-sd.jpg (1280x720)
→ /image-thumb.jpg (320x240)
4. Mirror Locations
/download available from:
→ /download/us-east
→ /download/eu-west
→ /download/asia-pacific
5. API Version Selection
/api/resource supports:
→ /api/v1/resource
→ /api/v2/resource
→ /api/v3/resource
Example Responses
Multiple Format Choices:
HTTP/1.1 300 Multiple Choices
Content-Type: text/html
Location: /document.pdf
<!DOCTYPE html>
<html>
<head><title>Multiple Choices</title></head>
<body>
<h1>Multiple Formats Available</h1>
<p>This document is available in multiple formats:</p>
<ul>
<li><a href="/document.pdf">PDF Format</a> (Recommended)</li>
<li><a href="/document.html">HTML Format</a></li>
<li><a href="/document.docx">Word Document</a></li>
<li><a href="/document.txt">Plain Text</a></li>
</ul>
</body>
</html>
```text
**Language Selection:**
```http
HTTP/1.1 300 Multiple Choices
Content-Type: application/json
Vary: Accept-Language
{
"message": "Multiple language versions available",
"choices": [
{
"lang": "en",
"url": "/page/en",
"title": "English Version"
},
{
"lang": "es",
"url": "/page/es",
"title": "Spanish Version"
},
{
"lang": "fr",
"url": "/page/fr",
"title": "French Version"
}
]
}
Mirror Selection:
HTTP/1.1 300 Multiple Choices
Content-Type: text/html
Link: </download/us-east>; rel="alternate"; geo="US"
Link: </download/eu-west>; rel="alternate"; geo="EU"
<!DOCTYPE html>
<html>
<head><title>Choose Download Location</title></head>
<body>
<h1>Select Download Mirror</h1>
<ul>
<li><a href="/download/us-east">US East Coast</a> (Fastest for Americas)</li>
<li><a href="/download/eu-west">EU West</a> (Fastest for Europe)</li>
<li><a href="/download/asia">Asia Pacific</a> (Fastest for Asia)</li>
</ul>
</body>
</html>
```text
## Real-World Example
Imagine you're requesting a technical whitepaper that's available in multiple formats:
**Client Request:**
```http
GET /whitepaper HTTP/1.1
Host: docs.example.com
User-Agent: Mozilla/5.0...
Accept: */*
300 Multiple Choices Response:
HTTP/1.1 300 Multiple Choices
Content-Type: text/html; charset=utf-8
Location: /whitepaper.pdf
Link: </whitepaper.pdf>; rel="alternate"; type="application/pdf"
Link: </whitepaper.html>; rel="alternate"; type="text/html"
Link: </whitepaper.epub>; rel="alternate"; type="application/epub+zip"
Content-Length: 892
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Download Options - Technical Whitepaper</title>
</head>
<body>
<h1>Choose Your Preferred Format</h1>
<p>This whitepaper is available in multiple formats:</p>
<div class="format-options">
<div class="option">
<h2>PDF (Recommended)</h2>
<p>Best for printing and archiving</p>
<a href="/whitepaper.pdf">Download PDF (2.4 MB)</a>
</div>
<div class="option">
<h2>HTML</h2>
<p>Read online with interactive examples</p>
<a href="/whitepaper.html">View HTML Version</a>
</div>
<div class="option">
<h2>EPUB</h2>
<p>For e-readers and mobile devices</p>
<a href="/whitepaper.epub">Download EPUB (1.8 MB)</a>
</div>
<div class="option">
<h2>Markdown</h2>
<p>Source format for developers</p>
<a href="/whitepaper.md">Download Markdown (456 KB)</a>
</div>
</div>
</body>
</html>
```text
## 300 vs Other Redirect Codes
| Code | Meaning | Use Case | Client Choice |
| ------- | ----------------- | ------------------------- | ---------------------- |
| **300** | Multiple choices | Multiple valid options | Client selects |
| **301** | Moved Permanently | Single permanent redirect | Automatic redirect |
| **302** | Found | Single temporary redirect | Automatic redirect |
| **303** | See Other | After POST operation | Automatic GET redirect |
## Important Characteristics
**Client-Driven Selection:**
```http
HTTP/1.1 300 Multiple Choices
↑
Server provides options, client decides
Optional Location Header:
HTTP/1.1 300 Multiple Choices
Location: /document.pdf ← Optional: Server's preferred choice
HTML body lists all options
```text
**Rarely Used in Practice:**
- Most servers auto-negotiate based on Accept headers
- Direct 301/302 redirects are more common
- Modern APIs use content negotiation instead
**Content Negotiation Alternative:**
```http
Instead of 300:
Accept: application/json → 200 OK (JSON response)
Accept: text/html → 200 OK (HTML response)
Common Mistakes
❌ Using 300 instead of content negotiation
GET /data
Accept: application/json
HTTP/1.1 300 Multiple Choices ← Bad
[List of format options]
Better: Return JSON directly (200 OK)
```text
**❌ No meaningful choices**
```http
HTTP/1.1 300 Multiple Choices
<html>
<a href="/same-content">Option 1</a> ← All links are identical
<a href="/same-content">Option 2</a>
</html>
❌ Missing response body
HTTP/1.1 300 Multiple Choices
Location: /option1
← No body explaining choices
```text
**✅ Correct usage**
```http
HTTP/1.1 300 Multiple Choices
Content-Type: text/html
Location: /document.pdf
<!DOCTYPE html>
<html>
<body>
<h1>Choose Format</h1>
<ul>
<li><a href="/document.pdf">PDF</a> - Best for printing</li>
<li><a href="/document.html">HTML</a> - Best for reading online</li>
</ul>
</body>
</html>
Best Practices
Provide Clear Descriptions:
<!-- Good: Explains each choice -->
<div class="choices">
<div>
<h3>PDF Version</h3>
<p>Best for: Printing, offline reading, archiving</p>
<p>Size: 2.4 MB</p>
<a href="/doc.pdf">Download PDF</a>
</div>
<div>
<h3>Interactive HTML</h3>
<p>Best for: Online reading, searchable, mobile-friendly</p>
<p>Includes: Interactive code examples</p>
<a href="/doc.html">View HTML</a>
</div>
</div>
```http
**Include Machine-Readable Metadata:**
```http
HTTP/1.1 300 Multiple Choices
Link: </data.json>; rel="alternate"; type="application/json"
Link: </data.xml>; rel="alternate"; type="application/xml"
Link: </data.csv>; rel="alternate"; type="text/csv"
Content-Type: text/html
<html>...</html>
Recommend a Default:
HTTP/1.1 300 Multiple Choices
Location: /document.pdf ← Recommended default
<html>
<p>Recommended: <a href="/document.pdf">PDF Version</a></p>
<p>Other options: ...</p>
</html>
```javascript
**Consider Auto-Negotiation Instead:**
```javascript
// Modern approach: Auto-negotiate based on Accept header
app.get('/document', (req, res) => {
const acceptHeader = req.headers.accept
if (acceptHeader.includes('application/pdf')) {
res.redirect('/document.pdf')
} else if (acceptHeader.includes('text/html')) {
res.redirect('/document.html')
} else {
// Fall back to 300 if can't determine
res.status(300).render('choices', { options })
}
})
Implementation Examples
Express.js:
app.get('/download', (req, res) => {
const options = [
{ url: '/download.pdf', type: 'application/pdf', label: 'PDF' },
{ url: '/download.epub', type: 'application/epub+zip', label: 'EPUB' },
{ url: '/download.mobi', type: 'application/x-mobipocket-ebook', label: 'MOBI' }
]
res
.status(300)
.set('Location', '/download.pdf') // Default
.set('Link', options.map((o) => `<${o.url}>; rel="alternate"; type="${o.type}"`).join(', '))
.render('multiple-choices', { options })
})
```text
**Apache .htaccess:**
```apache
# Rarely used, but possible
<Files "document">
# Return 300 with choices
ErrorDocument 300 /choices.html
Header set Status "300 Multiple Choices"
</Files>
Nginx:
location /resource {
return 300;
add_header Content-Type text/html;
add_header Location /resource.pdf;
# Serve choice page
try_files /choices.html =404;
}
```javascript
**Python Flask:**
```python
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/document')
def document():
options = [
{'url': '/document.pdf', 'format': 'PDF', 'size': '2.4 MB'},
{'url': '/document.html', 'format': 'HTML', 'size': 'N/A'},
{'url': '/document.txt', 'format': 'Plain Text', 'size': '45 KB'}
]
response = render_template('choices.html', options=options)
return response, 300, {
'Location': '/document.pdf',
'Link': '</document.pdf>; rel="alternate"; type="application/pdf"'
}
Try It Yourself
Visit our request builder and see 300 Multiple Choices:
- Set method to GET
- Set path to /multi-format-demo
- Click Send request
- See 300 response with multiple format options
- Explore different choice presentations
Related Status Codes
- 301 Moved Permanently - Single permanent redirect
- 302 Found - Single temporary redirect
- 406 Not Acceptable - No acceptable representation available
- 200 OK - Single successful response (after choice made)
Frequently Asked Questions
What does 300 Multiple Choices mean?
A 300 response indicates the requested resource has multiple representations available. The response includes a list of alternatives for the client to choose from.
When is 300 Multiple Choices used?
It is rarely used in practice. Common scenarios include offering different file formats (PDF vs HTML), language versions, or video quality options. Most sites use content negotiation headers instead.
How does 300 differ from content negotiation?
Content negotiation (using Accept headers) lets the server choose automatically. 300 Multiple Choices presents options to the user or client to select manually.
Why is 300 rarely used?
Most applications prefer automatic content negotiation or separate URLs for variants. 300 requires client-side handling that many browsers do not implement well.