Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

requests.exceptions.MissingSchema means Requests could not find a URL scheme—usually https:// or http://—in the URL it was preparing. Pass a complete absolute URL, inspect the exact value immediately before the request, and check proxy configuration separately if you use one. In Requests 2.x, a proxy URL also needs a scheme.

What MissingSchema means

Requests prepares and parses a URL before it can send an HTTP request. If the parsed URL has no scheme, Requests raises MissingSchema. A typical message is Invalid URL 'example.com': No scheme supplied. Perhaps you meant https://example.com? The important clue is No scheme supplied: Requests has not been given a complete web address.

A scheme is the part before the host that tells a client how to address the resource, commonly https:// or http://. For an ordinary web request, use the scheme that is correct for the site. Do not assume that every site supports plain HTTP just because adding http:// makes the string look complete.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This is distinct from an address that has a scheme but no host. In Requests 2.34.2, that malformed-URL path raises InvalidURL with No host supplied, rather than MissingSchema. The exception name and message help decide whether to add a scheme or inspect a different part of the URL.

Fix the destination URL

1. Inspect the value that actually reaches Requests

The value in a source file, debugger watch, or earlier log is not necessarily the value passed to requests.get(). Log the runtime value and its type immediately before the call:

import requests

url = "https://example.com"
print("url:", repr(url), "type:", type(url).__name__)
response = requests.get(url, timeout=15)
print(response.status_code)

repr(url) makes invisible whitespace and some unexpected values easier to notice; the type check helps catch a value that is not a string. Confirm that it is the expected non-empty absolute URL, rather than None, an empty string, a relative path, or a different variable than the one you meant to use. Once diagnosed, remove or appropriately protect debugging output; URLs can contain sensitive query values.

2. Add the correct scheme to a hostname

A hostname and path such as example.com/products are not a complete absolute web URL. Use the full address:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import requests

url = "https://example.com/products"
response = requests.get(url, timeout=15)
response.raise_for_status()
print(response.url)

response.url shows the URL associated with the resulting response, which can help confirm what Requests used. raise_for_status() makes an HTTP error status visible as an exception; it does not correct a malformed URL. Likewise, a timeout controls how long the request waits, not whether the URL has a scheme.

3. Resolve relative links before requesting them

A scraped link such as /products/1 is relative to a page, not independently requestable as an absolute web address. Combine it with the page URL that supplied the link, then inspect the result:

from urllib.parse import urljoin
import requests

page_url = "https://example.com/catalog/"
href = "/products/1"
target_url = urljoin(page_url, href)
print(repr(target_url))

response = requests.get(target_url, timeout=15)
response.raise_for_status()

For this example, the resolved target is https://example.com/products/1. Use the actual page URL as the base: a relative link’s destination depends on its base, and blindly prefixing a scheme to a path does not resolve it correctly. If links come from markup, also check that the extracted value is the expected href and not a missing attribute or a different field.

Check proxy configuration separately

The destination URL is not the only URL-like value Requests may parse. If you configure a proxy, inspect its value independently. Requests 2.x requires a scheme in the proxy address; a bare value such as 10.10.1.10:3128 can result in MissingSchema. Configure it with the appropriate proxy protocol, for example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
proxies = {
    "http": "http://10.10.1.10:3128",
    "https": "http://10.10.1.10:3128",
}

response = requests.get(
    "https://example.com",
    proxies=proxies,
    timeout=15,
)

The example uses an HTTP proxy endpoint for both destination schemes; the destination still uses HTTPS for its own connection. Use the protocol and address supplied for your actual proxy rather than copying the example values. If the exception persists after correcting the destination, temporarily inspect or disable the proxy configuration in a controlled environment to determine which value is malformed.

Keep query parameters separate from the base URL

Requests can encode query values supplied through params, but query parameters do not supply a missing scheme. The base URL must already be absolute:

import requests

url = "https://example.com/search"
params = {"q": "python requests", "page": 2}
response = requests.get(url, params=params, timeout=15)
print(response.url)

This separation is useful when values may contain spaces or other characters that need encoding. It does not make example.com/search valid as the base URL; use https://example.com/search first. If you construct the URL yourself, inspect the finished value before making the request.

Trace the value back to its source

If inspection reveals None, an empty string, or an unexpected relative route, fix the point where that value is produced rather than patching it blindly at the request call. Common places to check include configuration loading, function arguments, scraped attributes, environment variables, and string transformations. A value that was expected to be present can still be absent at runtime.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def fetch_page(url):
    if not isinstance(url, str) or not url.strip():
        raise ValueError(f"Expected a non-empty URL string; got {url!r}")
    if not url.startswith(("http://", "https://")):
        raise ValueError(f"Expected an absolute HTTP(S) URL; got {url!r}")

    return requests.get(url, timeout=15)

response = fetch_page("https://example.com")

This guard is deliberately narrow: it catches common input mistakes before the request. It is not a complete URL validator, and a string passing this check can still have a missing host or another malformed component. If your application accepts other valid schemes or has a different URL policy, adjust the check to match that policy.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Diagnose the error by its source

What you find Likely issue Next step
example.com/path The destination has no scheme. Use the correct absolute address, such as https://example.com/path.
/products/1 The value is a relative path. Resolve it against the page’s absolute URL before requesting it.
None, '', or an unexpected value The runtime input is missing or differs from what was expected. Trace its assignment or extraction; validate it before the call.
A proxy value such as 10.10.1.10:3128 The proxy address lacks a scheme. Use the appropriate scheme and verify the proxy’s actual configuration.
InvalidURL: No host supplied The URL may have a scheme but no host. Inspect the complete URL; this is not the missing-scheme case.

To narrow down a persistent problem, check in this order: the destination passed to the request, any transformation that creates it, and proxy settings. Test with a known absolute URL only when doing so is safe and appropriate for your environment. If that works but the application value fails, focus on the application’s input path rather than changing unrelated request settings.

Or skip the browser setup

If your actual task is to get a screenshot of a web page rather than build a browser-capture workflow, ScreenshotNeo is a website screenshot API and MCP server. A request still needs an absolute URL; the example below uses the supplied endpoint and target. See the ScreenshotNeo documentation for request options.

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Here are the equivalent one-request examples in cURL and Node.js:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners are accepted before capture, and 60+ known consent platforms, newsletter popups, and chat widgets are removed; each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients.
  • The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.

Frequently Asked Questions

Does MissingSchema mean the website returned an error?

No. It is raised while Requests is preparing the URL, before a normal HTTP response from the destination is available.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.