Checks
Strands Version
1.30.0
Tools Package Version
0.2.22
Tools used
Browser (LocalChromiumBrowser)
Python Version
3.13.6
Operating System
macOS
Installation Method
pip
Steps to Reproduce
from strands_tools.browser import LocalChromiumBrowser
# Pass custom context_options to the constructor
browser = LocalChromiumBrowser(
context_options={
"viewport": {"width": 1920, "height": 1080},
"user_agent": "MyCustomAgent/1.0",
}
)
# Start the browser and create a session
browser.browser({
"action": {
"type": "init_session",
"session_name": "test-session",
"description": "test"
}
})
# Navigate to any page and check the viewport
browser.browser({
"action": {
"type": "navigate",
"url": "https://example.com",
"session_name": "test-session"
}
})
# Take a screenshot — viewport will be 1280x720 (Playwright default),
# NOT 1920x1080 as specified in context_options
Expected Behavior
The browser context should use the context_options passed to the constructor.
The viewport should be 1920x1080 and the user agent should be "MyCustomAgent/1.0".
All Playwright BrowserContext options passed via context_options should be
applied when creating new browser contexts — this includes viewport,
user_agent, storage_state, locale, timezone_id, permissions,
geolocation, color_scheme, etc.
Actual Behavior
All context_options are silently ignored. The viewport is 1280x720 (Playwright
default) regardless of what was passed to the constructor.
The constructor accepts and stores the options correctly:
LocalChromiumBrowser.__init__ stores them in self._context_options
start_platform() merges them into self._default_context_options
But the base class Browser._setup_session_from_browser creates contexts with
no arguments:
# browser.py line ~241
session_context = await session_browser.new_context() # ← no arguments
self._default_context_options is never passed through.
Additional Context
This is particularly impactful for storage_state, which is the standard
Playwright mechanism for reusing authentication across browser contexts. There
is no workaround using the public API — the only option is to subclass and
override _setup_session_from_browser.
Full reproduction script (runs 4 tests confirming the bug):
reproduce_context_options_bug.py (click to expand)
"""
Requires: pip install playwright strands-agents-tools && playwright install chromium
"""
import asyncio
import inspect
async def test_context_options_ignored():
from strands_tools.browser import LocalChromiumBrowser
from playwright.async_api import async_playwright
# [1] Constructor accepts context_options
sig = inspect.signature(LocalChromiumBrowser.__init__)
assert "context_options" in sig.parameters
print("[1] ✅ context_options IS accepted by constructor")
# [2] Options are stored in _default_context_options
custom_viewport = {"width": 1920, "height": 1080}
custom_user_agent = "TestBot/1.0"
browser_tool = LocalChromiumBrowser(
context_options={"viewport": custom_viewport, "user_agent": custom_user_agent}
)
browser_tool.start_platform()
stored = browser_tool._default_context_options
assert stored.get("viewport") == custom_viewport
assert stored.get("user_agent") == custom_user_agent
print("[2] ✅ Options stored correctly in _default_context_options")
# [3] _setup_session_from_browser ignores stored options
source = inspect.getsource(
LocalChromiumBrowser.__mro__[1]._setup_session_from_browser
)
if "new_context()" in source and "_default_context_options" not in source:
print("[3] ❌ BUG: new_context() called with NO arguments")
else:
print("[3] ✅ Bug may be fixed")
# [4] Proof: viewport is Playwright default despite custom options
async with async_playwright() as p:
chromium = await p.chromium.launch(headless=True)
ctx_no_opts = await chromium.new_context()
page = await ctx_no_opts.new_page()
size_default = page.viewport_size
await page.close()
await ctx_no_opts.close()
ctx_with_opts = await chromium.new_context(**stored)
page = await ctx_with_opts.new_page()
size_fixed = page.viewport_size
await page.close()
await ctx_with_opts.close()
await chromium.close()
print(f"[4] new_context() → {size_default}")
print(f" new_context(**opts) → {size_fixed}")
print(f" Expected → {custom_viewport}")
if size_default != custom_viewport:
print(" ❌ Without options: viewport does NOT match constructor value")
if size_fixed == custom_viewport:
print(" ✅ With options: viewport matches — proves fix works")
asyncio.run(test_context_options_ignored())
Affected code path:
LocalChromiumBrowser.__init__ (stores options) → start_platform() (merges
into _default_context_options) → Browser._setup_session_from_browser
(ignores them)
Possible Solution
Two changes in browser.py:
1. Add _default_context_options to Browser.__init__:
def __init__(self):
# ... existing attributes ...
self._default_context_options: Dict[str, Any] = {}
This makes context options part of the base class contract. The default {}
means no behavioral change for existing code.
2. Pass the options in _setup_session_from_browser:
session_context = await session_browser.new_context(**self._default_context_options)
This follows the existing pattern where LocalChromiumBrowser.create_browser_session
passes **self._default_launch_options to chromium.launch().
I'm happy to submit a PR for this fix if you'd like.
Related Issues
#287 (networkidle timeout) — separate bug in the same base class. Both affect Browser methods in browser.py. Could be addressed in the same PR or separately.
Checks
Strands Version
1.30.0
Tools Package Version
0.2.22
Tools used
Browser (LocalChromiumBrowser)
Python Version
3.13.6
Operating System
macOS
Installation Method
pip
Steps to Reproduce
Expected Behavior
The browser context should use the
context_optionspassed to the constructor.The viewport should be 1920x1080 and the user agent should be "MyCustomAgent/1.0".
All Playwright
BrowserContextoptions passed viacontext_optionsshould beapplied when creating new browser contexts — this includes
viewport,user_agent,storage_state,locale,timezone_id,permissions,geolocation,color_scheme, etc.Actual Behavior
All
context_optionsare silently ignored. The viewport is 1280x720 (Playwrightdefault) regardless of what was passed to the constructor.
The constructor accepts and stores the options correctly:
LocalChromiumBrowser.__init__stores them inself._context_optionsstart_platform()merges them intoself._default_context_optionsBut the base class
Browser._setup_session_from_browsercreates contexts withno arguments:
self._default_context_optionsis never passed through.Additional Context
This is particularly impactful for
storage_state, which is the standardPlaywright mechanism for reusing authentication across browser contexts. There
is no workaround using the public API — the only option is to subclass and
override
_setup_session_from_browser.Full reproduction script (runs 4 tests confirming the bug):
reproduce_context_options_bug.py (click to expand)
Affected code path:
LocalChromiumBrowser.__init__(stores options) →start_platform()(mergesinto
_default_context_options) →Browser._setup_session_from_browser(ignores them)
Possible Solution
Two changes in
browser.py:1. Add
_default_context_optionstoBrowser.__init__:This makes context options part of the base class contract. The default
{}means no behavioral change for existing code.
2. Pass the options in
_setup_session_from_browser:This follows the existing pattern where
LocalChromiumBrowser.create_browser_sessionpasses
**self._default_launch_optionstochromium.launch().I'm happy to submit a PR for this fix if you'd like.
Related Issues
#287 (networkidle timeout) — separate bug in the same base class. Both affect
Browsermethods inbrowser.py. Could be addressed in the same PR or separately.