Accept Header

Fundamentals Jan 9, 2026 HTTP
http headers content-negotiation mime rest

Definition

The Accept header is an HTTP request header that tells the server which media types (MIME types) the client can understand and process in the response. It enables content negotiation, allowing servers to return data in the format preferred by the client.

The header consists of:

  1. Media Type List - Comma-separated MIME types (e.g., application/json, text/html)
  2. Quality Values (q) - Priority weights from 0 to 1 (e.g., application/json;q=0.9)

Common Accept values:

  • application/json - Prefer JSON responses
  • text/html - Prefer HTML (browsers)
  • application/xml - Prefer XML
  • */* - Accept any format (default if not specified)

The server selects the best matching format based on what it supports and the client’s preferences.

Example

JSON Preference:

GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer YOUR_TOKEN

Multiple Formats with Priorities:

GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json;q=0.9, application/xml;q=0.7, text/plain;q=0.5, */*;q=0.1
Authorization: Bearer YOUR_TOKEN

Browser Request (HTML preferred):

GET /page HTTP/1.1
Host: example.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0

Server Response (matching Accept):

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 142

{
  "id": 123,
  "name": "Alice Smith"
}

Code Example

JavaScript (Fetch API):

// Request JSON specifically
const fetchUser = async (userId) => {
  const response = await fetch(`https://api.example.com/users/${userId}`, {
    headers: {
      'Accept': 'application/json', // Only accept JSON
      'Authorization': 'Bearer YOUR_TOKEN'
    }
  });
  
  // Check if server returned JSON
  const contentType = response.headers.get('Content-Type');
  if (!contentType || !contentType.includes('application/json')) {
    throw new Error(`Expected JSON, got ${contentType}`);
  }
  
  return await response.json();
};

// Accept multiple formats with priorities
const fetchData = async (resourceId, format = 'json') => {
  const acceptHeaders = {
    'json': 'application/json',
    'xml': 'application/xml',
    'html': 'text/html',
    'any': '*/*'
  };
  
  const response = await fetch(`https://api.example.com/resource/${resourceId}`, {
    headers: {
      'Accept': acceptHeaders[format] || 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN'
    }
  });
  
  const contentType = response.headers.get('Content-Type');
  
  // Parse based on actual Content-Type returned
  if (contentType.includes('application/json')) {
    return await response.json();
  } else if (contentType.includes('application/xml')) {
    return await response.text(); // Parse XML as text
  } else if (contentType.includes('text/html')) {
    return await response.text();
  } else {
    throw new Error(`Unsupported Content-Type: ${contentType}`);
  }
};

// Example: Accept with quality values
const fetchWithPriorities = async (userId) => {
  const response = await fetch(`https://api.example.com/users/${userId}`, {
    headers: {
      'Accept': 'application/json;q=0.9, application/xml;q=0.7, text/plain;q=0.5',
      'Authorization': 'Bearer YOUR_TOKEN'
    }
  });
  
  return await response.json();
};

Python (requests library):

import requests

# Request JSON specifically
def fetch_user(user_id):
    response = requests.get(
        f'https://api.example.com/users/{user_id}',
        headers={
            'Accept': 'application/json',  # Only accept JSON
            'Authorization': 'Bearer YOUR_TOKEN'
        }
    )
    
    # Check if server returned JSON
    content_type = response.headers.get('Content-Type', '')
    if 'application/json' not in content_type:
        raise ValueError(f'Expected JSON, got {content_type}')
    
    response.raise_for_status()
    return response.json()

# Accept multiple formats with priorities
def fetch_data(resource_id, format='json'):
    accept_headers = {
        'json': 'application/json',
        'xml': 'application/xml',
        'html': 'text/html',
        'any': '*/*'
    }
    
    response = requests.get(
        f'https://api.example.com/resource/{resource_id}',
        headers={
            'Accept': accept_headers.get(format, 'application/json'),
            'Authorization': 'Bearer YOUR_TOKEN'
        }
    )
    
    content_type = response.headers.get('Content-Type', '')
    
    # Parse based on actual Content-Type returned
    response.raise_for_status()
    
    if 'application/json' in content_type:
        return response.json()
    elif 'application/xml' in content_type:
        return response.text  # Parse XML as text
    elif 'text/html' in content_type:
        return response.text
    else:
        raise ValueError(f'Unsupported Content-Type: {content_type}')

# Example: Accept with quality values
def fetch_with_priorities(user_id):
    response = requests.get(
        f'https://api.example.com/users/{user_id}',
        headers={
            'Accept': 'application/json;q=0.9, application/xml;q=0.7, text/plain;q=0.5',
            'Authorization': 'Bearer YOUR_TOKEN'
        }
    )
    
    response.raise_for_status()
    return response.json()

Diagram

sequenceDiagram
    participant Client
    participant Server
    
    Note over Client: Set Accept Header
    Client->>Client: Accept: application/json;q=0.9,
application/xml;q=0.7 Client->>Server: GET /api/users/123
Accept: application/json;q=0.9, application/xml;q=0.7 Note over Server: Content Negotiation Server->>Server: Check supported formats Server->>Server: Match with Accept preferences Server->>Server: Select best format (JSON - q=0.9) Server->>Client: HTTP 200 OK
Content-Type: application/json
Body: {"id": 123, ...} Note over Client: Verify Content-Type Client->>Client: Parse as JSON Client->>Client: Update UI

Analogy

Think of the Accept header like ordering at a restaurant:

  • Accept: application/json β†’ “I want JSON format, nothing else”
  • Accept: application/json;q=0.9, application/xml;q=0.7 β†’ “I prefer JSON, but XML is also fine”
  • **Accept: /" β†’ “I’ll take whatever you’ve got”

The waiter (server) checks what’s available and gives you the dish (format) that best matches your preferences.

Best Practices

  1. Always Set Accept - Specify expected response format explicitly
  2. Use Quality Values - Add priorities (q values) when accepting multiple formats
  3. Validate Content-Type - Check the response Content-Type matches your Accept
  4. **Avoid /" - Be explicit about formats unless you can truly handle anything
  5. Handle 406 Not Acceptable - Gracefully handle cases where server can’t provide requested format
  6. Set Accept-Language - Use for internationalization alongside Accept
  7. Use Versioning - Combine with Accept: application/vnd.api.v2+json for API versioning

Common Mistakes

  • Not Setting Accept - Relying on server defaults instead of being explicit
  • Ignoring Content-Type - Assuming response format without checking Content-Type header
  • Using / Always - Not specifying preferences, making content negotiation useless
  • Wrong Quality Values - Using q > 1.0 or negative values (q must be 0.0 to 1.0)
  • Not Handling 406 - Failing to handle “406 Not Acceptable” when server can’t provide requested format
  • Conflicting Headers - Setting Accept: application/json but expecting XML
  • Browser Defaults - Not overriding browser’s default Accept: text/html in API calls

Standards & RFCs