Open
Conversation
🦋 Changeset detectedLatest commit: aa4b462 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
Greptile OverviewGreptile SummaryAdded comprehensive cookie management APIs mirroring Playwright's interface, enabling users to get, set, clear, and persist cookies across browser sessions. Key changes:
Implementation quality:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Stagehand
participant V3Context
participant CDP as Chrome DevTools Protocol
Note over User,CDP: Getting Cookies
User->>Stagehand: cookies(urls?)
Stagehand->>V3Context: cookies(urls?)
V3Context->>CDP: Network.getAllCookies
CDP-->>V3Context: {cookies: Cookie[]}
V3Context->>V3Context: filterCookies(cookies, urls)
V3Context-->>Stagehand: Cookie[]
Stagehand-->>User: Cookie[]
Note over User,CDP: Adding Cookies
User->>Stagehand: addCookies(cookies)
Stagehand->>V3Context: addCookies(cookies)
V3Context->>V3Context: normalizeCookieParams(cookies)
loop for each cookie
V3Context->>CDP: Network.setCookie(cookie)
CDP-->>V3Context: {success: boolean}
alt success === false
V3Context-->>User: throw Error
end
end
V3Context-->>Stagehand: void
Stagehand-->>User: void
Note over User,CDP: Clearing Cookies
User->>Stagehand: clearCookies(options?)
Stagehand->>V3Context: clearCookies(options?)
V3Context->>CDP: Network.getAllCookies
CDP-->>V3Context: {cookies: Cookie[]}
V3Context->>V3Context: filter matching cookies
loop for each matching cookie
V3Context->>CDP: Network.deleteCookies(cookie)
CDP-->>V3Context: {}
end
V3Context-->>Stagehand: void
Stagehand-->>User: void
Note over User,CDP: Storage State (Snapshot & Restore)
User->>V3Context: storageState()
V3Context->>CDP: Network.getAllCookies
CDP-->>V3Context: {cookies: Cookie[]}
V3Context-->>User: {cookies: Cookie[]}
User->>V3Context: setStorageState(state)
V3Context->>V3Context: clearCookies()
V3Context->>V3Context: filter expired cookies
V3Context->>V3Context: addCookies(validCookies)
V3Context-->>User: void
|
Contributor
There was a problem hiding this comment.
2 issues found across 8 files
Confidence score: 3/5
- The cookie validation in
packages/core/lib/v3/understudy/cookies.tsmisses thesecureundefined case, which can allowsameSite: "None"cookies without secure to slip through and behave unexpectedly for users. - The cookie clearing flow in
packages/core/lib/v3/understudy/context.tsis O(N) roundtrips with a race window; this can leave cookies behind or impact performance when no filter is provided. - These are medium-severity, user-impacting behaviors, so there’s some risk despite the changes being localized.
- Pay close attention to
packages/core/lib/v3/understudy/cookies.tsandpackages/core/lib/v3/understudy/context.ts- cookie validation and clearing behavior.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/lib/v3/understudy/cookies.ts">
<violation number="1" location="packages/core/lib/v3/understudy/cookies.ts:123">
P1: Bug: `copy.secure === false` misses the `undefined` case. When a user sets `sameSite: "None"` with `domain`+`path` but omits `secure`, this validation is skipped because `undefined === false` is `false`. Use `!copy.secure` to also catch `undefined`, matching the stated intent of preventing silent CDP failures.</violation>
</file>
<file name="packages/core/lib/v3/understudy/context.ts">
<violation number="1" location="packages/core/lib/v3/understudy/context.ts:892">
P2: When no filter is provided, use `Network.clearBrowserCookies` instead of fetching all cookies and deleting them one by one. The current approach makes O(N) CDP roundtrips and still has a race condition (cookies set between the fetch and the deletion loop will be missed). `Network.clearBrowserCookies` is a single atomic CDP call.</violation>
</file>
Architecture diagram
sequenceDiagram
participant User
participant V3 as Stagehand (V3)
participant Ctx as V3Context
participant Util as Cookie Utils
participant Browser as Browser (CDP)
Note over User, Browser: Cookie Management Flow
User->>V3: NEW: addCookies(cookies)
V3->>Ctx: addCookies(cookies)
Ctx->>Util: NEW: normalizeCookieParams()
Note right of Util: Validates url OR domain/path<br/>Enforces sameSite=None + secure
Util-->>Ctx: Normalized CookieParams
loop Each Cookie
Ctx->>Browser: Network.setCookie
Browser-->>Ctx: { success: boolean }
alt NEW: Browser rejected cookie
Ctx-->>User: Throw Error (Explicit failure)
end
end
Ctx-->>User: Done
User->>V3: NEW: cookies(urls?)
V3->>Ctx: cookies(urls)
Ctx->>Browser: Network.getAllCookies
Browser-->>Ctx: Protocol.Network.Cookie[]
Ctx->>Util: NEW: filterCookies(cookies, urls)
Note right of Util: Matches domain, path, and<br/>secure protocol requirements
Util-->>Ctx: Filtered Cookie[]
Ctx-->>User: Cookie[]
User->>V3: NEW: clearCookies(options?)
V3->>Ctx: clearCookies(options)
Ctx->>Ctx: cookies()
alt Selective Clear (options provided)
loop Each Cookie
Ctx->>Util: NEW: cookieMatchesFilter(cookie, options)
Util-->>Ctx: boolean
opt Match Found
Ctx->>Browser: CHANGED: Network.deleteCookies
end
end
else Clear All
Ctx->>Browser: Network.deleteCookies (All)
end
Ctx-->>User: Done
Note over User, Browser: Storage Persistence Flow
User->>Ctx: NEW: storageState()
Ctx->>Ctx: cookies()
Ctx-->>User: { cookies: Cookie[] }
User->>Ctx: NEW: setStorageState(state)
Ctx->>Ctx: clearCookies()
Ctx->>Util: Filter expired cookies
Ctx->>Ctx: addCookies(validCookies)
Ctx-->>User: Context Restored
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Browser automation workflows frequently need to manage authentication state, persist sessions across runs, and handle cookie-based features. Currently, users have no direct API to read, write, or clear cookies in Stagehand, forcing workarounds through raw CDP commands or page-level JavaScript injection.
What Changed
Cookie Management APIs
Added cookie management methods that mirror the familiar Playwright BrowserContext API:
On
contextinstance:context.cookies(urls?)— Get all browser cookies, optionally filtered by URL(s)context.addCookies(cookies)— Set one or more cookies in the browser contextcontext.clearCookies(options?)— Clear all cookies or selectively by name/domain/path (supports RegExp)Types Added
Cookie— Cookie object returned by the browserCookieParam— Parameters for setting a cookie (supportsurlORdomain+path)ClearCookieOptions— Filter options for selective cookie clearingTest Plan
Cookie Management
context.cookies()returns all cookies when no URLs providedcontext.cookies(url)filters cookies by single URLcontext.cookies([url1, url2])filters cookies by multiple URLscontext.addCookies([...])successfully sets cookiescontext.addCookies()validates cookie params (requires url OR domain+path)context.addCookies()rejectssameSite: "None"withoutsecure: truecontext.addCookies()throws on browser rejection (checks CDP success flag)context.clearCookies()clears all cookies atomically via single CDP callcontext.clearCookies({ name: "session" })clears by exact namecontext.clearCookies({ domain: /\.example\.com/ })clears by regex