treeru.com

"What if we spawn Chrome with undetected-chromedriver in a subprocess, then hand it off to the main process via a debug port?" The design looked clean — subprocess handles Chrome initialization and login, main process just picks up the ready session. In theory, it was perfect. After a full day of trying, the conclusion was clear: it’s completely impossible for 4 reasons.

4

Problems hit

1 day

Time wasted

0%

Success rate

Single process

Correct design

1Why Hand Off via Subprocess?

The existing codebase was built on a multiprocess architecture. Each task spawned a subprocess for processing, while the main process acted purely as an orchestrator. Adding Selenium-based tasks into this pattern is where things went wrong.

Chrome is heavy, so the plan was to launch it in a subprocess using--remote-debugging-port, then connect from the main process. The subprocess would handle login, and the main process would receive the authenticated session. But the requirement to use UC (undetected-chromedriver) for anti-bot bypass is where the real problems began.

# Intended design (conclusion: doesn’t work)

# In subprocess:
# UC starts Chrome → login → open debug port

# In main process:
# Connect via regular selenium to debug port
options.add_experimental_option("debuggerAddress", "localhost:9222")
driver = webdriver.Chrome(options=options)

2Problem 1: UC Ignores --remote-debugging-port

First wall

UC internally assigns a random port when launching chromedriver. Even if you pass --remote-debugging-port=9222 in options, UC silently overrides it with its own random port.

# What we tried

options = uc.ChromeOptions()
options.add_argument("--remote-debugging-port=9222")  # ← ignored

driver = uc.Chrome(options=options)
# Actual port: random (not 9222)

Digging into UC’s source code revealed it manages port assignment internally and overwrites any user-specified port. You can technically read UC’s internal port at runtime, but safely passing that value between subprocesses introduces yet another layer of complexity.

3Problem 2: No detach Support

Second wall

When the subprocess exits, Chrome dies with it. Regular chromedriver supports detach=True to keep Chrome alive after the driver process ends. UC does not support this option.

# Works with regular selenium, not with UC

# Regular selenium (works)
options.add_experimental_option("detach", True)
driver = webdriver.Chrome(options=options)
# Chrome survives after process exit

# UC (does NOT work)
options = uc.ChromeOptions()
options.add_experimental_option("detach", True)  # ← ignored or errors
driver = uc.Chrome(options=options)
# Chrome dies when driver exits

UC tightly couples the lifecycle of chromedriver and Chrome. This design makes detach fundamentally incompatible. The entire concept of spawning Chrome in a subprocess and handing it off conflicts with UC’s architecture.

4Problem 3: stdout Pipe Inheritance Hell

Third wall — the most baffling one

Running UC inside a subprocess caused the main process’s communicate() to hang forever. UC’s chromedriver inherits the parent process’s stdout pipe and keeps it open. As long as the pipe stays open, communicate() never receives EOF and blocks indefinitely.

# communicate() hangs forever

proc = subprocess.Popen(
    ["python", "worker.py"],  # worker.py runs UC inside
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)
# This line never returns
stdout, stderr = proc.communicate()  # ← infinite wait

# close_fds=True workaround — only partial effect

proc = subprocess.Popen(
    ["python", "worker.py"],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    close_fds=True  # ← UC still inherits some pipes
)

UC’s chromedriver launch mechanism makes it difficult to prevent pipe inheritance. Even if you solve this issue, the previous problems still remain — by this point the limitations were clear.

5Problem 4: Invisible Tabs with Regular chromedriver

Fourth wall

After giving up on UC, we tried launching Chrome with regular chromedriver in the subprocess and connecting from the main process via debug port. The connection succeeded. But the tabs Selenium recognized didn’t match the actual tabs where the work had been done. The logged-in tab was invisible to the main process.

# Tab mismatch after debug port connection

# In main process
options.add_experimental_option("debuggerAddress", f"localhost:{port}")
driver = webdriver.Chrome(options=options)

# Visible tabs
print(driver.window_handles)  # ['CDP_unknown_handle']

# The tab opened by subprocess is under a different handle
# Not properly listed in window_handles

There’s a fundamental mismatch between Selenium’s managed tab context and the actual browser tabs when connecting via debug port. And with regular chromedriver, bot detection triggers anyway — defeating the whole purpose.

6Conclusion: UC Must Run in a Single Process

We abandoned the multiprocess design. UC now runs directly in the main process, and any Selenium work is handled there. The code structure diverged from the original intent, but it runs reliably.

Final Solution

Use UC directly in the main process. Never share or transfer Chrome sessions across subprocesses. If multiprocessing is needed, carve out the Chrome work to run in the main process while delegating everything else to workers.

AttemptResultReason
UC + fixed --remote-debugging-portFailedUC internally overrides the port
UC + detach=TrueFailedUC does not support detach
subprocess communicate() waitFailedstdout pipe inheritance causes infinite blocking
Regular chromedriver + debug portFailedTab context mismatch + bot detection
UC directly in main processSuccessAligns with UC’s intended design

Key Takeaways

Why UC Subprocess Handoff Doesn’t Work

  • UC manages chromedriver internally — port pinning and session transfer are not supported
  • No detach support — Chrome dies when the subprocess exits
  • UC chromedriver inherits the parent process's stdout pipe, causing communicate() to block forever
  • Connecting via debug port with regular chromedriver causes tab context mismatch
  • UC is designed to be used in a single process from start to finish

This article is based on hands-on debugging experience from March 2026. Behavior may vary depending on the undetected-chromedriver version. Non-commercial sharing is welcome; for commercial use, please contact us via the contact page.

Need Help Designing Automation Architecture?

Multiprocess automation, Selenium system design, reliable anti-bot bypass — we’ve been through it firsthand and can help you get it right.

Request Automation Consultation