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

If Selenium stops at “Launching Firefox…”, first preserve a geckodriver trace log, then verify the Firefox executable, geckodriver executable, and temporary-profile directory. The most important distinction is whether Firefox is a native install or a Snap/Flatpak package: sandboxed Firefox may not be able to read the profile directory that geckodriver creates, causing startup to wait indefinitely.

What the stall means

Before a test can open a page, Selenium starts the separate geckodriver WebDriver server, launches Firefox, creates or copies a profile, and completes the Marionette handshake. “Launching Firefox…” means one of those startup exchanges has not completed; it does not identify the failing component by itself.

Mozilla’s Firefox Source Docs says trace-level output is vital when debugging geckodriver or Firefox. Trace output includes WebDriver requests, protocol traffic, and Marionette messages, so it shows the last successful step instead of leaving you to guess.

Fix it in the right order

  1. Capture evidence. Enable trace logging and preserve the complete output, especially in CI.
  2. Identify both executables. Confirm which Firefox binary and which geckodriver Selenium is actually using.
  3. Test a clean temporary profile. A custom, locked, oversized, or inaccessible profile can hide the original failure.
  4. Check package confinement. Snap and Flatpak can give Firefox and geckodriver different views of the filesystem.
  5. Check versions and PATH. Make sure Selenium, Firefox, and geckodriver are intended to work together.
  6. Add headless mode last. Headless removes display-server requirements but cannot repair a bad binary path or profile permission.

1. Turn on geckodriver trace logging

Run geckodriver directly

Start the driver with maximum verbosity while reproducing the failure:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
geckodriver -vv 2> geckodriver.log

Leave that process running, execute the Selenium test in another terminal, and inspect the final lines in geckodriver.log. In a CI job, redirect standard error to an artifact so a timeout does not discard the evidence.

Enable logging from Selenium (Python)

from selenium import webdriver
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
# Add this only after a normal launch works:
# options.add_argument("-headless")

service = Service(log_output="geckodriver.log")
driver = webdriver.Firefox(service=service, options=options)
try:
    driver.get("https://example.com")
finally:
    driver.quit()

Use the equivalent Firefox service log setting in your language binding. The useful clue is normally the last completed action: executable detection, profile creation, port connection, or Marionette communication.

2. Verify the Firefox executable

Selenium can be told explicitly which Firefox binary to launch. First find the real executable rather than assuming the command on your PATH is the browser itself:

  • On a native Linux installation, inspect the path returned by your package manager or which firefox.
  • On Windows and macOS, use the installed application’s executable, not a shortcut or shell wrapper.
  • On Ubuntu Snap, /snap/bin/firefox is a launcher. Mozilla documents that supplying it as the binary path can produce “binary is not a Firefox executable”.

Set an explicit binary when multiple installations exist:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.binary_location = "/path/to/the/real/firefox"
driver = webdriver.Firefox(options=options)

Do not mix a native Firefox binary with a driver confined for Snap, or a Snap launcher with an unrelated native geckodriver. The pair must be able to inspect and start one another.

3. Verify geckodriver discovery and compatibility

Geckodriver is a separate WebDriver server. Selenium normally finds it through PATH, unless you configure a service with an explicit path. Check the selected executable in the same user and CI environment that runs the test:

which geckodriver
geckodriver --version
which firefox
firefox --version

If more than one result is possible, configure the intended path explicitly:

from selenium.webdriver.firefox.service import Service
service = Service(executable_path="/absolute/path/to/geckodriver")

Mozilla’s usage documentation requires Selenium 3.11 or newer for geckodriver. Selenium’s current Firefox guidance recommends the latest geckodriver and states that Selenium 4 requires Firefox 78 or newer. In practice, update the Selenium binding, Firefox, and geckodriver together rather than replacing only one component.

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

4. Fix Snap and Flatpak profile visibility

A startup hang is frequently a filesystem-visibility problem with containerized Firefox. Selenium asks geckodriver to create a temporary profile; Firefox may run inside a sandbox that cannot see that directory, while geckodriver runs outside it. Firefox then never completes startup.

Ubuntu Snap Firefox

Use the Snap-confined geckodriver so both processes share the expected confinement:

/snap/bin/geckodriver -vv 2> geckodriver.log

Alternatively, install a non-container Firefox release and its matching geckodriver. Do not pass /snap/bin/firefox as though it were the underlying browser executable; use the documented full binary path only with the matching confined driver.

Flatpak or another sandbox

Either run the compatible driver inside the same sandbox or provide a profile root that both processes can access. Set TMPDIR before starting the test, or use geckodriver’s --profile-root option:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
mkdir -p "$HOME/selenium-tmp"
chmod 700 "$HOME/selenium-tmp"
export TMPDIR="$HOME/selenium-tmp"
geckodriver --profile-root "$HOME/selenium-tmp" -vv

The directory must be writable by the test user and visible from the Firefox sandbox. A directory that exists for the host but not inside the container does not solve the problem.

5. Eliminate custom-profile variables

Start with Selenium’s anonymous temporary profile. If you pass a custom profile, Selenium copies it into a new temporary directory; extensions, file locks, a large cache, or permissions inherited from another user can all obscure the real cause.

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()                 # no profile supplied
# options.add_argument("-headless") # add after baseline launch succeeds
driver = webdriver.Firefox(options=options)
try:
    driver.get("https://example.com")
finally:
    driver.quit()

Once this launches, add preferences, certificates, extensions, and a custom profile one change at a time. If the stall returns, the last change identifies the suspect.

6. Add headless mode only after a normal launch

Firefox accepts the -headless argument, which is useful on CI hosts without a display server:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
options.add_argument("-headless")

First prove that the same executable and clean profile launch without headless mode when a local display is available. Then enable headless mode in CI. A headless flag cannot fix an inaccessible profile, an incorrect binary, or an incompatible driver.

Choose the remedy by installation type

Environment Best baseline What to verify Typical recovery
Native Firefox Clean temporary profile PATH, executable permissions, versions Explicit binary and geckodriver paths; update components
Ubuntu Snap Matching confined processes Firefox and driver confinement Use /snap/bin/geckodriver, or switch both to native packages
Flatpak Shared accessible profile root Sandbox filesystem visibility Use a compatible in-sandbox driver or set TMPDIR/--profile-root
CI headless Prove a clean non-headless launch first Display variables, writable temp directory Add -headless after the baseline passes

Troubleshooting by symptom

The log says “binary is not a Firefox executable”

The configured path is probably a wrapper such as /snap/bin/firefox, not the browser binary geckodriver expects. Remove the override, use the actual executable, or use the matching Snap-confined geckodriver.

The log stops while creating or copying a profile

Check ownership, write permission, free space, and sandbox visibility for the temporary directory. Remove the custom profile, set a known-writable TMPDIR, and retry with --profile-root.

The log shows a port or Marionette timeout

Confirm that the selected Firefox binary can run as the test user and that the driver is not from a different installation. Run both version commands, inspect the trace immediately before the timeout, and test the clean-profile example.

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

It works locally but hangs in CI

Compare the CI user, PATH, package type, temporary-directory mount, and display environment with the local machine. Preserve the trace log as a build artifact. Add headless mode only after those values are known to be correct.

A custom profile works once and then hangs

Do not reuse a profile directory concurrently. Close every Firefox process, return to Selenium’s temporary profile, and reintroduce extensions and preferences individually.

It starts, but the first page load fails

Separate browser startup from navigation. Keep the startup trace, then diagnose DNS, proxy, certificates, or application errors independently; changing profile roots will not repair a page-level network failure.

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

Or skip the browser setup

If your goal is a rendered image or PDF rather than an interactive Selenium session, ScreenshotNeo provides a single HTTP request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

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

cURL (options and API details: ScreenshotNeo documentation):

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

Python:

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)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Is this always a Firefox bug?

No. The same symptom can come from Selenium selecting the wrong executable, geckodriver incompatibility, or a profile directory that Firefox cannot access.

Should I delete every Firefox profile?

No. First test Selenium’s temporary profile. Delete or alter a persistent profile only when trace evidence points to that profile.

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.

Can increasing the Selenium timeout fix the stall?

It may make the failure slower, but it does not correct a blocked filesystem, wrong binary, or incompatible driver. Capture trace output before changing timeouts.

Does ScreenshotNeo replace Selenium?

Only for capture tasks. Selenium remains the appropriate choice when a test must interact with a browser, click through an application, or assert behavior between steps.

Frequently Asked Questions

Which component should I update first?

Update Selenium, Firefox, and geckodriver as a compatible set, then rerun the clean-profile test with trace logging.

Where should CI logs be stored?

Redirect geckodriver’s trace output to a file and publish that file as a CI artifact so timeout cleanup does not erase the final startup exchange.

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

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.