ScreenshotNeo

BlogHow-to

Why Instagram Fails in Headless Chrome with Selenium and How to Fix It

Diagnose Instagram failures in Selenium headless Chrome with version checks, waits, logging, and controlled headful comparisons.

By the ScreenshotNeo team1 October 20269 min read

Headless Chrome is an execution mode, not proof that Instagram blocked your script. When Instagram fails under Selenium, first separate browser startup, ChromeDriver compatibility, navigation, network access, waits, and the page response. Then run the same workflow in visible Chrome and headless Chrome with every other variable held constant.

This guide shows a reproducible Selenium diagnostic workflow in Python, explains the relevant Chrome and Selenium settings, and lists fixes for common errors. The official Selenium and Chrome documentation does not establish an Instagram-specific headless bug or a verified Instagram bypass, so treat any site challenge or alternate response as an observation to document rather than a confirmed cause.

What “headless” changes

Headless Chrome runs without displaying a browser window. Chrome’s documentation says that since Chrome 112, headless and headful modes use the unified Chrome implementation; the browser still creates platform windows, but they are not shown. This means headless mode alone does not prove that a site should behave differently, although a site can return different content for many reasons.

Selenium’s Chrome documentation lists --headless=new as the current argument and says Selenium 4 is compatible by default with Chrome 75 and later. Chrome and ChromeDriver major versions should match. See the Selenium Chrome documentation and Chrome Headless documentation.

1. Capture the actual failure

Do not reduce the incident to “Instagram does not load.” Record:

  • The complete exception and stack trace.
  • The URL requested and the final URL reached.
  • Chrome, ChromeDriver, Selenium, and Python versions.
  • The exact Chrome arguments and page-load strategy.
  • Whether navigation returned, timed out, or failed to start.
  • The page title, a short body-text sample, and a screenshot at failure time.
  • Whether the visible run produces the same page, prompt, or challenge.

A screenshot and the real exception distinguish startup errors from a missing element, an overlay, a timeout, or a site response.

2. Install Selenium and verify the browser

python -m pip install -U selenium

Recent Selenium releases include Selenium Manager, which bindings use by default to obtain a compatible driver. If Selenium cannot locate a driver, either allow Selenium Manager to resolve it or provide a valid executable path through the Chrome Service object. Selenium’s installation guidance explains both approaches: Selenium Manager.

Check the installed versions before changing code:

google-chrome --version
chromedriver --version
python -c "import selenium; print(selenium.__version__)"

Compare the major Chrome and ChromeDriver versions. A mismatch is a setup fault, not an Instagram diagnosis. For reproducible CI runs, Chrome for Testing provides matching browser and driver binaries; see Chrome for Testing.

3. Minimal headless Selenium script in Python

This script starts Chrome, opens Instagram, waits for the document body, saves a screenshot, and prints the final URL. It uses Selenium Manager by default.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

HEADLESS = True
URL = "https://www.instagram.com/"

options = Options()
if HEADLESS:
    options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1200")
options.add_argument("--disable-dev-shm-usage")

# Selenium Manager resolves ChromeDriver when no executable_path is supplied.
service = Service(log_output="chromedriver.log")
driver = webdriver.Chrome(service=service, options=options)

try:
    driver.get(URL)
    WebDriverWait(driver, 30).until(
        EC.presence_of_element_located((By.TAG_NAME, "body"))
    )
    print("Final URL:", driver.current_url)
    print("Title:", driver.title)
    print(driver.find_element(By.TAG_NAME, "body").text[:500])
    driver.save_screenshot("instagram-result.png")
finally:
    driver.quit()

The body wait only proves that a document exists. If your next operation needs a login form, a profile link, or another specific element, wait for that element instead.

4. Use waits that match the next action

Selenium recommends explicit waits for the condition required by the next operation. Fixed sleeps and simply increasing a global timeout hide the real problem. A dynamic page can return from get() before the element your script needs is rendered.

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 30)

# Examples: choose a condition that matches your workflow.
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "main")))
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[name='username']")))
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']")))

Selectors can change as the site changes. When an expected selector is absent, save the page source and screenshot before concluding that headless mode caused the failure.

5. Page-load strategy and navigation

Selenium’s page-load strategy controls when navigation returns:

Strategy Navigation returns after Use when
normal The load event and dependent resources finish You need the usual full navigation behavior
eager DOMContentLoaded fires You will explicitly wait for application content
none The initial document download starts You have a carefully designed readiness check
options.page_load_strategy = "eager"

A faster return requires a sufficient subsequent wait. If your code assumes that get() means the feed or login controls are ready, it can fail in both headless and visible modes.

6. Log startup and navigation failures

Enable ChromeDriver logs and preserve a screenshot at the point of failure:

from selenium.webdriver.chrome.service import Service

service = Service(log_output="chromedriver.log")
driver = webdriver.Chrome(service=service, options=options)

try:
    driver.get(URL)
    # workflow here
except Exception:
    driver.save_screenshot("failure.png")
    print("URL at failure:", driver.current_url)
    print("Title at failure:", driver.title)
    raise
finally:
    driver.quit()

Read the first meaningful exception, not only the final timeout. A driver service failure, DNS error, TLS error, renderer crash, and missing element require different fixes.

7. Compare headful and headless runs correctly

Run the same script twice and change only the headless argument. Keep the account or session state, network and proxy, Chrome and driver versions, Selenium version, viewport, URL, actions, waits, and page-load strategy constant.

Compare What to record
Startup Driver creation, Chrome logs, and exceptions
Navigation Return time, final URL, redirects, and title
Page response Visible prompt, login page, challenge, blank document, or expected content
Readiness Which explicit wait succeeds or times out
Evidence Screenshot, page source, console or driver log

If only the site response differs, document exactly what appeared. The available evidence does not establish whether Instagram attributed that response to headless detection, account status, request rate, network reputation, or another internal rule. Do not present an evasion technique as an official fix.

8. Network, proxy, and container checks

Verify that the same machine or container can reach the target outside Selenium. Check DNS resolution, outbound firewall rules, TLS interception, proxy settings, and authentication requirements. Selenium’s documentation notes that proxy configuration can be necessary in corporate environments.

curl -I https://www.instagram.com/

When a proxy is required, configure it deliberately and use the same proxy for the controlled headful/headless comparison:

options = Options()
options.add_argument("--headless=new")
options.proxy = {
    "proxyType": "manual",
    "httpProxy": "proxy.example:8080",
    "sslProxy": "proxy.example:8080",
}

Replace the example host with your real proxy configuration. A proxy error is not evidence of an Instagram headless block.

9. Common errors and fixes

Error or symptom Likely cause Fix
Unable to obtain driver or driver not found Selenium Manager cannot resolve a driver, or no executable is available Upgrade Selenium, check network access for Selenium Manager, or pass a valid Service path.
SessionNotCreatedException Chrome and ChromeDriver major versions do not match, or Chrome cannot start Record both versions, install matching binaries, and inspect chromedriver.log.
Chrome exits immediately in a container Sandbox, shared-memory, permissions, or missing dependencies Check the container image and permissions. --disable-dev-shm-usage can help with small shared-memory mounts; do not treat it as a universal fix.
TimeoutException waiting for an element Wrong selector, page not ready, redirect, prompt, or different content Save a screenshot and URL, inspect page source, and wait for the actual next condition.
Blank page or renderer crash Browser startup, resource, or environment failure Inspect ChromeDriver logs, memory limits, dependencies, and the final URL before changing selectors.
Login form or challenge appears only in one mode Different site response or session state Repeat with controlled variables and document the exact prompt. The dossier does not verify an Instagram-specific cause.
Navigation hangs Network, proxy, TLS, page-load strategy, or a page that keeps connections open Check connectivity, choose an appropriate page-load strategy, and add an explicit readiness wait.

10. Reproducibility and reliability checklist

  • Pin or record Chrome, ChromeDriver, Selenium, and the binding version.
  • Use Chrome for Testing when you need matching, reproducible binaries.
  • Keep the viewport and timezone consistent between runs.
  • Use a fresh temporary profile for clean diagnostics, or intentionally reuse a profile when session state is part of the test.
  • Capture the final URL, title, screenshot, page source, and driver log on every failure.
  • Use explicit waits tied to the next operation.
  • Retry only transient startup or network failures, with a bounded retry count; do not retry a site challenge indefinitely.
  • Respect Instagram’s terms, authentication requirements, and rate limits.

11. Performance and cost considerations

Headless mode can reduce desktop overhead in CI, but the dossier contains no verified Instagram or Selenium benchmark. Measure your own workflow if runtime matters. The largest delays usually come from navigation, network conditions, browser startup, rendering, and waits rather than from the visibility of the window alone.

Reuse a driver for a bounded sequence of pages when session continuity helps, then quit it to avoid leaked processes. For parallel jobs, give each driver its own profile and resources. Set timeouts that reflect the page and environment, and collect timing data around startup, navigation, readiness, and capture.

Or skip the browser setup

If your goal is a clean screenshot rather than browser automation, ScreenshotNeo provides a single GET request that returns a PNG, JPEG, WebP, or PDF. Its capture flow accepts cookie and consent banners before removing more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

See the ScreenshotNeo API documentation for all options.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://www.instagram.com/ -o instagram.webp

Python

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

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://www.instagram.com/' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('instagram.webp', image);

ScreenshotNeo also supports full-page capture with lazy images loaded, CSS element capture, dark mode, device presets and custom viewports, retina scale, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request blocking, custom headers and cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous jobs with signed webhooks, bulk capture, usage reporting, and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

Does Instagram definitely block headless Chrome?

The supplied official sources do not establish that. A controlled comparison can show that responses differ, but it cannot reveal Instagram’s internal reason.

Should I add a user-agent switch to fix it?

Do not treat a user-agent change as a verified fix. First capture the exception, URL, screenshot, and logs, then compare modes with controlled variables.

Is --headless=new guaranteed to work?

It is the current Chrome argument documented by Selenium, but it does not guarantee a particular website response.

What if visible Chrome works and headless Chrome does not?

Repeat the comparison with identical versions, account or session state, network, viewport, waits, and actions. Record the exact page or prompt shown in each mode.

Can I use Selenium Manager in CI?

Yes, when the environment allows it to obtain or locate a compatible driver. For repeatable builds, pin Chrome for Testing and its matching driver.