Free tools Windows power users keep installed

One-click scans. No signup required.

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

Start with the temporary profile directory, not with sudo. geckodriver normally creates a throwaway Firefox profile, and Firefox plus geckodriver must both be able to read and write that directory. With Snap or Flatpak Firefox, the browser may see a different filesystem from the host, so startup can hang even when your normal Firefox profile is accessible. Put the profile root in a location visible to both processes, use the matching driver path, and collect debug logs before changing permissions.

Why an unprivileged session hangs

WebDriver does not usually open your everyday Firefox profile. Selenium asks geckodriver to create a temporary profile, geckodriver launches Firefox with that profile, and geckodriver proxies the WebDriver HTTP API to Firefox’s remote protocol. On Unix, /tmp is the normal default. Selenium can also create a temporary copy when you provide an existing profile, so a readable source profile does not guarantee that the copied profile is usable.

The failure is especially common with container-packaged Firefox. Mozilla documents that the default Ubuntu Firefox shipped as a Snap (notably on Ubuntu 22.04 and later) can have a different filesystem view from the host. Firefox then cannot reach the generated profile, and startup may wait indefinitely. This is a documented packaging case, not proof that every Ubuntu installation or every unprivileged account has the same cause.

1. Identify Firefox packaging and the driver Selenium starts

Check the Firefox executable

On Linux, geckodriver normally finds Firefox through PATH. Confirm what your shell resolves:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
command -v firefox
readlink -f "$(command -v firefox)" 2>/dev/null || true
snap list firefox 2>/dev/null || true
flatpak info org.mozilla.firefox 2>/dev/null || true

A Snap or Flatpak result means you must consider the container boundary. If you deliberately installed a regular Mozilla release, record its actual executable path instead of assuming the shell alias is the binary Selenium should launch.

Check geckodriver

command -v geckodriver
geckodriver --version

For Ubuntu’s default Snap Firefox, Mozilla documents /snap/bin/geckodriver as the compatible driver location. Do not assume that a geckodriver found elsewhere can see the same Snap filesystem.

Use the correct Snap binary path in Selenium

If you set Selenium’s binary_location, Mozilla specifies the Snap Firefox executable as:

/snap/firefox/current/usr/lib/firefox/firefox

/snap/bin/firefox is a launcher, not the Firefox executable expected by this setting. Leaving binary_location unset can be preferable when the matching driver already resolves the packaged browser correctly.

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

2. Give both processes a shared profile root

The directory passed as the profile root must be readable and writable by both geckodriver and Firefox. Choose a per-user directory rather than changing system-wide permissions:

mkdir -p "$HOME/.cache/geckodriver-profiles"
chmod 700 "$HOME/.cache/geckodriver-profiles"
/snap/bin/geckodriver --profile-root "$HOME/.cache/geckodriver-profiles"

Keep that command running, then point Selenium at the geckodriver service you started. The exact temporary subdirectory is created by geckodriver. Do not pre-create a profile with a different owner and expect Selenium to reuse it.

Python example with an explicit driver service

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

service = Service(
    executable_path="/snap/bin/geckodriver",
    service_args=["--profile-root", "/home/alice/.cache/geckodriver-profiles", "--log", "debug"],
    log_output="geckodriver.log",
)
options = webdriver.FirefoxOptions()
options.binary_location = "/snap/firefox/current/usr/lib/firefox/firefox"

driver = webdriver.Firefox(service=service, options=options)
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit()

Replace /home/alice with the real home directory. The directory must not be mounted with permissions that block the unprivileged account, and every parent directory must be searchable by that account.

Use a process-specific TMPDIR instead

On Unix, TMPDIR overrides the default temporary directory. Mozilla notes that it only needs to be set in the geckodriver process environment; there is no need to alter the machine-wide temporary-directory configuration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
mkdir -p "$HOME/.cache/geckodriver-tmp"
chmod 700 "$HOME/.cache/geckodriver-tmp"
TMPDIR="$HOME/.cache/geckodriver-tmp" /snap/bin/geckodriver --log debug

If Selenium launches the service itself, set the environment on that service process. In Python:

import os
from selenium import webdriver
from selenium.webdriver.firefox.service import Service

env = os.environ.copy()
env["TMPDIR"] = "/home/alice/.cache/geckodriver-tmp"
service = Service(
    executable_path="/snap/bin/geckodriver",
    env=env,
    log_output="geckodriver.log",
)
driver = webdriver.Firefox(service=service)

Use either --profile-root or a process-specific TMPDIR first. Setting both is unnecessary unless you have a specific reason to control each location.

3. Keep Firefox and geckodriver in the same filesystem context

Run matching container packages

If the machine must keep Snap or Flatpak Firefox, run the driver in the same container context and ensure the shared profile path is available there. A host geckodriver that cannot see the browser's profile filesystem can hang before a WebDriver session is created.

Use a non-container Firefox build

Mozilla lists installing a regular Firefox release together with a compatible geckodriver release as a workaround. This removes the container filesystem boundary, but it changes how Firefox is installed and updated. Record the executable path and select it explicitly only when necessary.

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

4. Capture logs before changing privileges

Run geckodriver with --log debug (or -v) for debug output. Use -vv for trace logging when debug output does not identify the failure.

/snap/bin/geckodriver --profile-root "$HOME/.cache/geckodriver-profiles" --log debug 2>geckodriver.log

When Selenium starts the service, direct output to a file and inspect lines showing the Firefox executable, profile directory, and launch result. Selenium's Firefox service supports file logging, as shown in the Python examples above. A log that stops after profile creation strongly suggests a visibility, mount, or write-access problem; a log that reports an executable error points to the binary path instead.

Common symptoms and targeted fixes

Firefox never opens and the test times out

  • Check whether Firefox is Snap or Flatpak.
  • Set --profile-root or process-specific TMPDIR to a directory both processes can access.
  • For Snap, use /snap/bin/geckodriver and the documented Firefox binary path if setting binary_location.
  • Read debug logs before retrying with broader permissions.

“Unable to find a matching set of capabilities” or an immediate session error

Verify that Selenium is launching the intended Firefox and geckodriver pair. Check command -v output, remove an incorrect binary_location, and make sure the driver executable is runnable by your account.

“Permission denied” for a profile or temporary file

Inspect the selected directory and every parent directory:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
namei -l "$HOME/.cache/geckodriver-profiles"
ls -ld "$HOME/.cache/geckodriver-profiles"

Fix ownership or choose a directory under your own home directory. Avoid chmod 777 and avoid running the entire test as root; those hide the real packaging or path mistake and create security risk.

The normal Firefox profile works manually, but WebDriver does not

That is expected when Selenium's temporary profile is on an inaccessible filesystem. Test the temporary root, not only the profile you open interactively. Also remember that Selenium may copy a supplied profile to a new temporary location.

Automation needs browser UI privileges

Firefox 138 and later require geckodriver's --allow-system-access for browser UI testing. Mozilla warns that this grants WebDriver clients privileges equivalent to the Firefox UI process. It is not a remedy for ordinary web-content automation or profile-path failures; enable it only when your test genuinely controls browser UI.

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

Choosing the least disruptive remedy

Remedy Best when Trade-off
Shared profile root You must keep Snap or Flatpak Firefox and can provide a common readable, writable directory. Requires careful path and mount configuration.
Matching container packaging Your deployment already standardizes on the browser container. Driver execution and diagnostics must occur inside that filesystem context.
Non-container Firefox plus geckodriver You want to remove the container boundary. Installation and update procedures change.

Reliability practices for CI and shared machines

  • Create a unique profile root per job or user under a directory with restrictive, user-owned permissions.
  • Do not reuse a live desktop Firefox profile; concurrent locks and extensions make sessions nondeterministic.
  • Keep the browser and driver paths explicit in CI so a package update cannot silently switch executables.
  • Preserve geckodriver logs as build artifacts when a session fails.
  • Clean abandoned temporary profiles after a killed job, while leaving active sessions untouched.
  • Apply the smallest change first: path visibility, then packaging alignment, then installation changes.

Or skip the browser setup

If your goal is simply a rendered screenshot rather than interactive browser automation, ScreenshotNeo makes one HTTP request and returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

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.

Read the complete parameter reference in the ScreenshotNeo documentation. A minimal cURL call is:

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

The same request in 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)

And 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}`);

Every plan includes full-page and element capture, device and viewport controls, retina scale, PDF settings, custom CSS and JavaScript, waits, request blocking, headers, cookies, user agents, timezone and geolocation, transparent backgrounds, resizing, selectable caching TTLs, signed links, async webhooks, bulk capture, usage data, and an OpenAPI specification. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Do I need to change the system /tmp directory?

No. Set TMPDIR only for the geckodriver process, or use --profile-root with a shared user-owned directory.

Is this problem limited to Ubuntu?

No. Mozilla's documented example concerns Ubuntu's Snap Firefox, but any containerized browser can create a filesystem-visibility mismatch. Confirm your packaging before choosing a fix.

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

Should I use --allow-system-access to make startup succeed?

No. That option is for browser UI testing beginning with Firefox 138 and grants broad privileges. It does not repair routine profile access.

Frequently Asked Questions

Can an unprivileged user run geckodriver at all?

Yes. The account needs a runnable driver, a launchable Firefox binary, and read-write access to the temporary profile root; root privileges are not normally required.

Where should a CI job store Firefox profiles?

Use a job-specific directory under the CI user's home or workspace, pass it with --profile-root or TMPDIR, and remove it after the session ends.

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.

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