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:
- The batch parser sees
%%{http_code}and converts%%to a single literal%. curl.exereceives-w "%{http_code}"which is exactly what curl expects.curlreplaces%{http_code}with the actual numeric status code (e.g.,200).
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:
| 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.