Skip to main content

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

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).
info

curl.exe vs. curl: In CMD/Batch, running curl invokes curl.exe from System32. In PowerShell, however, curl is an alias for Invoke-WebRequest. Always use curl.exe explicitly if your script might be called from a PowerShell context, or if you want to be unambiguous.

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:

ScenarioWithout -LWith -L
URL redirects to working pageReturns 301 or 302Returns 200
URL redirects to missing pageReturns 301 or 302Returns 404
URL redirects in a loopReturns 301 or 302Returns error (max redirects exceeded)
URL does not redirectReturns the actual statusReturns 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

CodeMeaningScript Action
000No connection (DNS failure, timeout, no internet)Treat as network error
200OK, request succeededProceed normally
301Permanent redirectUse -L to follow, or update the URL
302Temporary redirectUse -L to follow
403Forbidden, access deniedCheck authentication or User-Agent
404Not found, URL does not existURL is broken or page was removed
500Internal server errorServer-side problem; retry later
502Bad gatewayUpstream server problem
503Service unavailableServer 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.