Skip to content

How to Check the HTTP Response Code of a URL in Batch Script

Learn how to extract and interpret HTTP status codes (200, 404, 500) in Windows Batch scripts using curl.exe for website monitoring, API validation, and link checking.

In the early days of Batch, checking a website's status was nearly impossible without third-party tools. However, modern Windows (10 and 11) now includes curl.exe, which is the industry-standard tool for interacting with web servers. By checking the HTTP Response Code (e.g., 200 OK, 404 Not Found, or 500 Server Error), your script can determine if a website is online, if a download link is still valid, or if an API is responding correctly before it attempts to process any data.

This guide will explain how to extract and react to HTTP status codes using Batch.

Method 1: Using CURL (Modern Standard)

The curl command can be configured to return only the status code using the -w (write-out) parameter. Windows 10 (version 1803+) and Windows 11 include curl.exe in System32 by default.

@echo off
setlocal EnableDelayedExpansion

set "URL=%~1"
if "%URL%"=="" set "URL=https://www.google.com"
set "Timeout=10"

echo ============================================================
echo   URL Availability Check
echo ============================================================
echo.
echo Target:  %URL%
echo Timeout: %Timeout% seconds
echo.

rem --- Verify curl is available ---
where curl.exe >nul 2>&1
if !errorlevel! neq 0 (
    echo [ERROR] curl.exe is not available on this system. >&2
    echo.
    echo [INFO] curl is included in Windows 10 version 1803 and later.
    echo [INFO] For older systems, use PowerShell method instead.
    echo.
    endlocal
    pause
    exit /b 1
)

echo [CHECK] Testing connection...
echo.

rem --- Run curl and capture ONLY the HTTP status code ---
rem   -s             = Silent mode (no progress bar)
rem   -o nul         = Discard response body
rem   -w             = Write-out format (only HTTP code)
rem   --connect-timeout = Connection timeout in seconds
rem   -L             = Follow redirects (optional)
rem   -m             = Maximum time allowed for transfer

set "code="
for /f "delims=" %%a in (
    'curl.exe -s -o nul -w "%%{http_code}" --connect-timeout %Timeout% -m %Timeout% "%URL%" 2^>nul'
) do (
    set "code=%%a"
)

rem --- Validate output ---
if not defined code (
    echo [ERROR] curl produced no output. >&2
    echo [INFO] The command may have failed or timed out.
    echo.
    endlocal
    pause
    exit /b 1
)

rem --- Remove any whitespace ---
set "code=!code: =!"

echo ============================================================
echo   HTTP Status Code: !code!
echo ============================================================
echo.

rem --- Interpret the status code ---
if "!code!"=="000" (
    echo [ERROR] Could not connect to the server
    echo.
    echo Possible causes:
    echo   - No internet connection
    echo   - DNS resolution failure
    echo   - Firewall blocking the request
    echo   - Server is completely offline
    echo   - Invalid URL format
    set "ExitCode=1"
    
) else if "!code:~0,1!"=="2" (
    echo [OK] Success - Server responded normally
    echo.
    if "!code!"=="200" echo Details: Standard OK response
    if "!code!"=="201" echo Details: Resource created successfully
    if "!code!"=="204" echo Details: No content (operation successful^)
    set "ExitCode=0"
    
) else if "!code:~0,1!"=="3" (
    echo [REDIRECT] Server is redirecting the request
    echo.
    if "!code!"=="301" echo Details: Permanent redirect - URL has moved
    if "!code!"=="302" echo Details: Temporary redirect
    if "!code!"=="307" echo Details: Temporary redirect (method preserved^)
    if "!code!"=="308" echo Details: Permanent redirect (method preserved^)
    echo.
    echo [TIP] Add -L flag to follow redirects automatically
    set "ExitCode=0"
    
) else if "!code:~0,1!"=="4" (
    echo [CLIENT ERROR] Request was rejected by the server
    echo.
    if "!code!"=="400" echo Details: Bad request - malformed syntax
    if "!code!"=="401" echo Details: Authentication required
    if "!code!"=="403" echo Details: Access forbidden
    if "!code!"=="404" echo Details: Page not found
    if "!code!"=="408" echo Details: Request timeout
    if "!code!"=="429" echo Details: Too many requests - rate limited
    set "ExitCode=1"
    
) else if "!code:~0,1!"=="5" (
    echo [SERVER ERROR] Server encountered a problem
    echo.
    if "!code!"=="500" echo Details: Internal server error
    if "!code!"=="502" echo Details: Bad gateway - upstream server issue
    if "!code!"=="503" echo Details: Service unavailable (maintenance/overload^)
    if "!code!"=="504" echo Details: Gateway timeout - upstream not responding
    set "ExitCode=2"
    
) else (
    echo [?] Received status code: !code!
    echo.
    echo [INFO] Consult HTTP status code documentation for details
    set "ExitCode=3"
)

echo ============================================================
echo.

pause
endlocal
exit /b !ExitCode!

How the %%{http_code} escaping works:

The % character is the variable expansion operator in Batch. To pass a literal % to an external program, you must escape it as %%. Inside a FOR /F command:

  1. The batch parser sees %%{http_code} and converts %% to a single literal %.
  2. curl.exe receives -w "%{http_code}" which is exactly what curl expects.
  3. curl replaces %{http_code} with the actual numeric status code (e.g., 200).

Method 2: Following Redirects to Get the Final Status

Sometimes a URL returns a 301 or 302 redirect to another location. Without following the redirect, you only see the redirect code, not whether the final destination is actually working. The -L flag tells curl to follow the entire redirect chain and report the final status.

@echo off
setlocal EnableDelayedExpansion

set "URL=%~1"
if "%URL%"=="" set "URL=http://example.com/old-page"
set "Timeout=10"

echo ============================================================
echo   URL Redirect Checker
echo ============================================================
echo.
echo Target URL: %URL%
echo Timeout:    %Timeout%s
echo.

rem --- Verify curl is available ---
where curl.exe >nul 2>&1
if !errorlevel! neq 0 (
    echo [ERROR] curl.exe is not available on this system. >&2
    echo [INFO] curl is included in Windows 10 version 1803+
    endlocal
    pause
    exit /b 1
)

rem --- Validate URL ---
if "%URL%"=="" (
    echo [ERROR] No URL specified. >&2
    echo Usage: %~nx0 ^<url^>
    endlocal
    pause
    exit /b 1
)

echo [CHECK] Following redirects...
echo.

rem --- Get redirect chain information ---
rem First, get the final code
set "FinalCode="
for /f %%a in (
    'curl.exe -s -L -o nul -w "%%{http_code}" --connect-timeout %Timeout% -m %Timeout% "%URL%" 2^>nul'
) do (
    set "FinalCode=%%a"
)

rem Get the final URL
set "FinalURL="
for /f "delims=" %%a in (
    'curl.exe -s -L -o nul -w "%%{url_effective}" --connect-timeout %Timeout% -m %Timeout% "%URL%" 2^>nul'
) do (
    set "FinalURL=%%a"
)

rem Get number of redirects
set "RedirectCount="
for /f %%a in (
    'curl.exe -s -L -o nul -w "%%{num_redirects}" --connect-timeout %Timeout% -m %Timeout% "%URL%" 2^>nul'
) do (
    set "RedirectCount=%%a"
)

rem --- Validate output ---
if not defined FinalCode (
    echo [ERROR] curl produced no output. >&2
    echo [INFO] Connection may have timed out or failed.
    endlocal
    pause
    exit /b 1
)

rem --- Display results ---
echo ============================================================
echo   Redirect Chain Analysis
echo ============================================================
echo.
echo Original URL:    %URL%

if defined FinalURL (
    echo Final URL:       !FinalURL!
)

echo Final HTTP Code: !FinalCode!

if defined RedirectCount (
    echo Redirects:       !RedirectCount!
)

echo.
echo ============================================================
echo.

rem --- Interpret results ---
if "!FinalCode!"=="000" (
    echo [ERROR] Could not connect to server
    echo.
    echo Possible causes:
    echo   - Initial URL is unreachable
    echo   - One of the redirect targets failed
    echo   - DNS resolution failure
    echo   - Network/firewall blocking
    set "ExitCode=1"
    
) else if "!FinalCode!"=="200" (
    echo [OK] Successfully reached final destination
    
    if defined RedirectCount (
        if !RedirectCount! gtr 0 (
            echo.
            echo [INFO] Followed !RedirectCount! redirect(s^) to reach destination
            if defined FinalURL (
                echo [INFO] Consider updating bookmarks to: !FinalURL!
            )
        ) else (
            echo [INFO] No redirects - direct access to resource
        )
    )
    set "ExitCode=0"
    
) else if "!FinalCode:~0,1!"=="3" (
    echo [WARNING] Redirect loop or maximum redirects exceeded
    echo.
    echo Final status: !FinalCode!
    echo This may indicate:
    echo   - Circular redirect chain
    echo   - Too many redirects (curl default limit: 50^)
    echo   - Misconfigured server
    set "ExitCode=1"
    
) else if "!FinalCode:~0,1!"=="4" (
    echo [ERROR] Client error at final destination
    echo.
    if "!FinalCode!"=="404" echo Final destination: Page not found
    if "!FinalCode!"=="403" echo Final destination: Access forbidden
    if "!FinalCode!"=="401" echo Final destination: Authentication required
    set "ExitCode=1"
    
) else if "!FinalCode:~0,1!"=="5" (
    echo [ERROR] Server error at final destination
    echo.
    if "!FinalCode!"=="500" echo Final destination: Internal server error
    if "!FinalCode!"=="503" echo Final destination: Service unavailable
    set "ExitCode=2"
    
) else (
    echo [?] Unusual response code: !FinalCode!
    set "ExitCode=3"
)

echo ============================================================
echo.

pause
endlocal
exit /b !ExitCode!

With vs. without -L:

Scenario Without -L With -L
URL redirects to working page Returns 301 or 302 Returns 200
URL redirects to missing page Returns 301 or 302 Returns 404
URL redirects in a loop Returns 301 or 302 Returns error (max redirects exceeded)
URL does not redirect Returns the actual status Returns the actual status

Use -L when you care about whether the final destination works. Omit -L when you want to detect the redirect itself (e.g., checking if a URL has been moved).

Method 3: Monitoring Multiple URLs

For site uptime monitoring or checking a list of endpoints, this script iterates through multiple URLs and logs the results.

@echo off
setlocal enabledelayedexpansion

set "Timeout=10"
set "LogFile=%~dp0uptime_log.csv"

rem --- Verify curl is available ---
where curl.exe >nul 2>&1
if %errorlevel% neq 0 (
    echo [ERROR] curl.exe is not available.
    endlocal
    pause
    exit /b 1
)

rem --- Add CSV header if the log file does not exist ---
if not exist "%LogFile%" (
    echo Date,Time,URL,StatusCode,Result > "%LogFile%"
)

echo [MONITOR] Checking endpoints...
echo.

rem --- Define URLs to check ---
for %%u in (
    "https://www.google.com"
    "https://www.github.com"
    "https://httpstat.us/500"
    "https://nonexistent.invalid"
) do (
    set "code="
    for /f %%a in (
        'curl.exe -s -o nul -w "%%{http_code}" --connect-timeout !Timeout! %%u 2^>nul'
    ) do (
        set "code=%%a"
    )

    if not defined code set "code=ERR"

    rem --- Determine result label ---
    if "!code!"=="200" (
        set "result=OK"
    ) else if "!code!"=="000" (
        set "result=UNREACHABLE"
    ) else (
        set "result=PROBLEM"
    )

    echo   [!result!] %%~u  -  HTTP !code!

    rem --- Log to CSV ---
    echo %date%,%time%,%%~u,!code!,!result! >> "%LogFile%"
)

echo.
echo [INFO] Results logged to: %LogFile%

endlocal
pause

Method 4: PowerShell Fallback (Legacy Systems)

If you are on an older Windows version without curl.exe (pre-Windows 10 1803), you can use PowerShell. The key challenge is that Invoke-WebRequest throws an exception on non-2xx status codes (like 404 or 500), so the basic .StatusCode approach fails for error responses. The script must use a try/catch block to handle all status codes.

@echo off
setlocal

set "URL=https://example.com"

rem --- Verify PowerShell is available ---
where powershell.exe >nul 2>&1
if %errorlevel% neq 0 (
    echo [ERROR] PowerShell is not available on this system.
    endlocal
    pause
    exit /b 1
)

echo [CHECK] Testing URL: %URL% (via PowerShell)

rem --- PowerShell command that handles both success and error responses ---
rem --- Invoke-WebRequest throws on non-2xx codes, so we catch the exception ---
rem --- and extract the status code from the error response ---
set "PSCmd=try { $r = Invoke-WebRequest -Uri '%URL%' -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop; $r.StatusCode } catch { if ($_.Exception.Response) { [int]$_.Exception.Response.StatusCode } else { Write-Output '000' } }"

set "code="
for /f %%a in ('powershell -NoProfile -Command "%PSCmd%" 2^>nul') do (
    set "code=%%a"
)

if not defined code (
    echo [ERROR] PowerShell produced no output.
    echo [INFO] The URL may be malformed or PowerShell execution policy
    echo        may be blocking the command.
    endlocal
    pause
    exit /b 1
)

echo [RESPONSE] HTTP Status Code: %code%

if "%code%"=="000" (
    echo [ERROR] Could not connect to the server.
) else if "%code%"=="200" (
    echo [OK] Website is reachable and responding normally.
) else (
    echo [WARN] Received status code %code%.
)

endlocal
pause

Why the try/catch is necessary: PowerShell's Invoke-WebRequest treats HTTP error codes (4xx, 5xx) as PowerShell exceptions. Without error handling, a 404 Not Found response causes the entire command to fail, and the for /f loop captures nothing. The try/catch block catches the exception and extracts the status code from the error response object, ensuring all HTTP codes are captured correctly.

How to Avoid Common Errors

Wrong Way: Parsing the HTML Body for Success Indicators

Some scripts search the downloaded HTML for words like "Success" or "Welcome". This is unreliable because error pages often contain the same words in headers, footers, or navigation menus.

rem *** BAD: a 404 error page might contain the word "Success" in its footer ***
curl -s "%URL%" | findstr "Success" >nul && echo Site is working!

Correct Way: Always depend on the HTTP status code. It is the server's official signal of success or failure, independent of page content.

Wrong Way: Not Setting a Connection Timeout

If a server is completely unresponsive (not refusing connections but not responding at all), curl can hang for 30–60 seconds or more.

rem *** BAD: can hang indefinitely on an unresponsive server ***
curl -s -o nul -w "%%{http_code}" "%URL%"

Correct Way: Always set --connect-timeout to limit how long curl waits for the initial connection.

rem *** GOOD: fails after 10 seconds if server does not respond ***
curl.exe -s -o nul -w "%%{http_code}" --connect-timeout 10 "%URL%"

Wrong Way: Not Handling Code 000

If curl returns 000, it means no HTTP response was received at all. This is not an HTTP error, it is a connection-level failure (DNS resolution failed, network unreachable, connection refused, or timeout).

rem *** BAD: treats 000 as a valid HTTP response ***
if "%code%" neq "200" echo Website returned error %code%

Correct Way: Check for 000 separately and report it as a network/connection error, not a website error.

Wrong Way: Using curl Instead of curl.exe

In CMD/Batch files, curl correctly invokes curl.exe. However, if your Batch script is ever called from PowerShell, curl in PowerShell is an alias for Invoke-WebRequest, not the real curl. Using curl.exe explicitly avoids this ambiguity.

rem *** SAFER: unambiguous on all platforms ***
curl.exe -s -o nul -w "%%{http_code}" "%URL%"

Wrong Way: Using -o /dev/null on Windows

/dev/null is the Unix null device. On Windows, the equivalent is nul.

rem *** BAD: /dev/null does not exist on Windows ***
curl.exe -s -o /dev/null -w "%%{http_code}" "%URL%"

rem *** GOOD: nul is the Windows null device ***
curl.exe -s -o nul -w "%%{http_code}" "%URL%"

Common HTTP Status Codes Reference

Code Meaning Script Action
000 No connection (DNS failure, timeout, no internet) Treat as network error
200 OK, request succeeded Proceed normally
301 Permanent redirect Use -L to follow, or update the URL
302 Temporary redirect Use -L to follow
403 Forbidden, access denied Check authentication or User-Agent
404 Not found, URL does not exist URL is broken or page was removed
500 Internal server error Server-side problem; retry later
502 Bad gateway Upstream server problem
503 Service unavailable Server overloaded or in maintenance

Best Practices and Rules

1. Handle User-Agent Blocking

Some web servers block requests from command-line tools by checking the User-Agent header. If you receive a 403 Forbidden that works fine in a browser, try setting a browser-like User-Agent.

curl.exe -s -o nul -w "%%{http_code}" -A "Mozilla/5.0" --connect-timeout 10 "%URL%"

2. Log Results for Uptime Tracking

If you are monitoring a site's availability over time, log every check with a timestamp and status code to a CSV file. This creates a historical record for identifying patterns.

echo %date%,%time%,%code%,%URL% >> "%~dp0uptime_log.csv"

3. Always Set a Timeout

Without --connect-timeout, curl waits for the operating system's default TCP timeout, which can be 30 seconds or more. For automated scripts, 5–10 seconds is usually appropriate.

4. curl and HTTP Codes Are Language-Independent

The curl.exe command, its flags, and HTTP status codes are international standards. They work identically on every Windows display language. The response body content may be in any language, but the numeric status code is always the same.

5. Use setlocal / endlocal

Always wrap scripts in setlocal and endlocal to prevent variables from leaking into the parent environment.

6. Verify curl.exe Availability

Not all Windows installations have curl.exe. Always check with where curl.exe before using it, and provide a PowerShell fallback for older systems.

Final Thoughts

Checking HTTP response codes in Batch transforms your scripts from local automation into network-aware tools that can verify web resources, monitor uptime, and validate API endpoints before processing data. The key techniques are: use curl.exe with -w "%%{http_code}" to extract just the status code, always set --connect-timeout to prevent hanging, handle the special 000 code as a connection failure rather than an HTTP error, and use -L when you need to follow redirects to the final destination. For older systems without curl, PowerShell's Invoke-WebRequest with proper try/catch error handling provides a reliable fallback. Since both HTTP status codes and curl's command syntax are international standards, these scripts work identically on every Windows installation worldwide.

Navigation