A common pattern when working with Camoufox in particular and Playwright in general is to use a context manager to handle the browser lifecycle. It’s clean, safe and ensures everything is torn down properly when your script completes. However, sometimes it’s not possible to wrestle all of your code into a context manager. There’s an alternative though.
Using a Context Manager
The normal approach to using Camoufox is via a context manager.
from camoufox.sync_api import Camoufox
with Camoufox(headless=False) as browser:
page = browser.new_page()
page.goto("https://www.example.com")
print(page.content())
This works well when your entire script fits neatly inside a single block. The context manager guarantees that the browser starts when the block opens and shuts down automatically when it ends.
However, this pattern isn’t always convenient. If you’re building a larger application, want to open and close pages at different times, or need to keep the browser available across multiple functions, nesting everything inside a with block can be restrictive. The lifecycle becomes tied to your code structure, rather than the other way around.
Alternative to a Context Manager
Fortunately, Camoufox (and Playwright) allow you to manage the browser manually. Instead of relying on the context manager, you can call .start() explicitly and keep the browser instance in a variable. This gives you complete flexibility to control the browser lifecycle.
from camoufox.sync_api import Camoufox
camoufox = Camoufox(headless=False)
# Start the browser manually (instead of using a context manager) and assign it to a variable.
browser = camoufox.start()
# Open a new page (tab) within the running browser instance.
page = browser.new_page()
page.goto("https://www.example.com")
print(page.content())
# Close the current page.
page.close()
# Close the browser instance and clean up associated resources.
browser.close()
This approach is more natural when you want full control over the browser object or when the code structure doesn’t fit neatly into a single with block. It also mirrors how Playwright works under the hood: context managers are a layer of convenience, not a requirement.
It does mean that you are responsible for browser cleanup. To ensure that these resources are freed you might use the atexit module or a finally clause in an exception handler.
Conclusion
Both styles are valid. The context manager version is safer and more concise, while the manual .start() pattern gives you flexibility and explicit control. Choose the one that matches the shape of your project rather than forcing your project to match the shape of the example.