11# Stagehand Ruby API library
22
3+ <!-- x-stagehand-custom-start -->
4+ <div id =" toc " align =" center " style =" margin-bottom : 0 ;" >
5+ <ul style =" list-style : none ; margin : 0 ; padding : 0 ;" >
6+ <a href="https://stagehand.dev">
7+ <picture>
8+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_logo.png" />
9+ <img alt="Stagehand" src="https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_logo.png" width="200" style="margin-right: 30px;" />
10+ </picture>
11+ </a>
12+ </ul >
13+ </div >
14+ <p align =" center " >
15+ <strong >The AI Browser Automation Framework</strong ><br >
16+ <a href =" https://docs.stagehand.dev/v3/sdk/ruby " >Read the Docs</a >
17+ </p >
18+
19+ <p align =" center " >
20+ <a href =" https://github.com/browserbase/stagehand/tree/main?tab=MIT-1-ov-file#MIT-1-ov-file " >
21+ <picture>
22+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_license.svg" />
23+ <img alt="MIT License" src="https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_license.svg" />
24+ </picture>
25+ </a >
26+ <a href =" https://stagehand.dev/discord " >
27+ <picture>
28+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_discord.svg" />
29+ <img alt="Discord Community" src="https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_discord.svg" />
30+ </picture>
31+ </a >
32+ </p >
33+
34+ <p align =" center " >
35+ <a href="https://trendshift.io/repositories/12122" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12122" alt="browserbase%2Fstagehand | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
36+ </p >
37+
38+ <p align =" center " >
39+ If you're looking for other languages, you can find them
40+ <a href =" https://docs.stagehand.dev/v3/first-steps/introduction " > here</a >
41+ </p >
42+
43+ <div align =" center " style =" display : flex ; align-items : center ; justify-content : center ; gap : 4px ; margin-bottom : 0 ;" >
44+ <b >Vibe code</b >
45+ <span style =" font-size : 1.05em ;" > Stagehand with </span >
46+ <a href =" https://director.ai " style =" display : flex ; align-items : center ;" >
47+ <span>Director</span>
48+ </a >
49+ <span > </span >
50+ <picture >
51+ <img alt="Director" src="https://raw.githubusercontent.com/browserbase/stagehand/main/media/director_icon.svg" width="25" />
52+ </picture >
53+ </div >
54+ <!-- x-stagehand-custom-end -->
55+
356The Stagehand Ruby library provides convenient access to the Stagehand REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [ see below] ( https://github.com/browserbase/stagehand-ruby#Sorbet ) for usage with Sorbet. The standard library's ` net/http ` is used as the HTTP transport, with connection pooling via the ` connection_pool ` gem.
457
558It is generated with [ Stainless] ( https://www.stainless.com/ ) .
@@ -24,165 +77,119 @@ gem "stagehand", :git => "git://github.com/browserbase/stagehand-ruby.git"
2477
2578## Usage
2679
80+ This mirrors ` examples/remote_browser_playwright_example.rb ` .
81+
2782``` ruby
2883require " bundler/setup"
2984require " stagehand"
3085
31- # Create a new Stagehand client with your credentials
86+ require_relative " examples/env"
87+ ExampleEnv .load!
88+
89+ require " playwright"
90+
3291client = Stagehand ::Client .new (
33- browserbase_api_key: ENV [" BROWSERBASE_API_KEY" ], # defaults to ENV["BROWSERBASE_API_KEY"]
34- browserbase_project_id: ENV [" BROWSERBASE_PROJECT_ID" ], # defaults to ENV["BROWSERBASE_PROJECT_ID"]
35- model_api_key: ENV [" MODEL_API_KEY" ] # defaults to ENV["MODEL_API_KEY"]
92+ browserbase_api_key: ENV [" BROWSERBASE_API_KEY" ],
93+ browserbase_project_id: ENV [" BROWSERBASE_PROJECT_ID" ],
94+ model_api_key: ENV [" MODEL_API_KEY" ],
95+ server: " remote"
3696)
3797
38- # Start a new browser session
3998start_response = client.sessions.start(
40- model_name: " openai/gpt-5-nano"
99+ model_name: " anthropic/claude-sonnet-4-6" ,
100+ browser: { type: :browserbase }
41101)
42- puts " Session started: #{ start_response.data.session_id } "
43102
44103session_id = start_response.data.session_id
104+ cdp_url = start_response.data.cdp_url
105+ raise " No CDP URL returned for this session." if cdp_url.to_s.empty?
45106
46- # Navigate to a webpage
47- client.sessions.navigate(
48- session_id,
49- url: " https://news.ycombinator.com"
50- )
51- puts " Navigated to Hacker News"
107+ Playwright .create(playwright_cli_executable_path: " ./node_modules/.bin/playwright" ) do |playwright |
108+ browser = playwright.chromium.connect_over_cdp(cdp_url)
109+ context = browser.contexts.first || browser.new_context
110+ page = context.pages.first || context.new_page
52111
53- # Use Observe to find possible actions on the page
54- observe_response = client.sessions.observe(
55- session_id,
56- instruction: " find the link to view comments for the top post"
57- )
58-
59- actions = observe_response.data.result
60- puts " Found #{ actions.length } possible actions"
112+ client.sessions.navigate(session_id, url: " https://news.ycombinator.com" )
113+ page.wait_for_load_state(state: " domcontentloaded" )
61114
62- # Take the first action returned by Observe
63- action = actions.first
64- puts " Acting on: #{ action.description } "
115+ observe_stream = client.sessions.observe_streaming(
116+ session_id,
117+ instruction: " find the link to view comments for the top post"
118+ )
119+ observe_stream.each { |_event | }
65120
66- # Pass the structured action to Act
67- # Convert the observe result to a hash and ensure method is set to "click"
68- act_response = client.sessions.act(
69- session_id,
70- input: action.to_h.merge(method: " click" )
71- )
72- puts " Act completed: #{ act_response.data.result[:message ] } "
73-
74- # Extract data from the page
75- # We're now on the comments page, so extract the top comment text
76- extract_response = client.sessions.extract(
77- session_id,
78- instruction: " extract the text of the top comment on this page" ,
79- schema: {
80- type: " object" ,
81- properties: {
82- comment_text: {
83- type: " string" ,
84- description: " The text content of the top comment"
121+ act_stream = client.sessions.act_streaming(
122+ session_id,
123+ input: " Click the comments link for the top post"
124+ )
125+ act_stream.each { |_event | }
126+
127+ extract_stream = client.sessions.extract_streaming(
128+ session_id,
129+ instruction: " extract the text of the top comment on this page" ,
130+ schema: {
131+ type: " object" ,
132+ properties: {
133+ commentText: {type: " string" },
134+ author: {type: " string" }
85135 },
86- author: {
87- type: " string" ,
88- description: " The username of the comment author"
89- }
136+ required: [" commentText" ]
137+ }
138+ )
139+ extract_stream.each { |_event | }
140+
141+ execute_stream = client.sessions.execute_streaming(
142+ session_id,
143+ execute_options: {
144+ instruction: " Click the 'Learn more' link if available" ,
145+ max_steps: 3
90146 },
91- required: [" comment_text" ]
92- }
93- )
94- puts " Extracted data: #{ extract_response.data.result } "
95-
96- # Get the author from the extracted data
97- extracted_data = extract_response.data.result
98- author = extracted_data[:author ]
99- puts " Looking up profile for author: #{ author } "
100-
101- # Use the Agent to find the author's profile
102- # Execute runs an autonomous agent that can navigate and interact with pages
103- execute_response = client.sessions.execute(
104- session_id,
105- execute_options: {
106- instruction: " Find any personal website, GitHub, LinkedIn, or other best profile URL for the Hacker News user '#{ author } '. " \
107- " Click on their username to go to their profile page and look for any links they have shared." ,
108- max_steps: 15
109- },
110- agent_config: {
111- model: Stagehand ::ModelConfig ::ModelConfigObject .new (
112- model_name: " openai/gpt-5-nano" ,
113- api_key: ENV [" MODEL_API_KEY" ]
114- ),
115- cua: false
116- }
117- )
118- puts " Agent completed: #{ execute_response.data.result[:message ] } "
119- puts " Agent success: #{ execute_response.data.result[:success ] } "
120- puts " Agent actions taken: #{ execute_response.data.result[:actions ]&.length || 0 } "
147+ agent_config: {
148+ model: Stagehand ::ModelConfig .new (
149+ model_name: " anthropic/claude-sonnet-4-6" ,
150+ api_key: ENV [" MODEL_API_KEY" ]
151+ ),
152+ cua: false
153+ }
154+ )
155+ execute_stream.each { |_event | }
156+ end
121157
122- # End the session to cleanup browser resources
123158client.sessions.end_(session_id)
124- puts " Session ended"
125159```
126160
127- ### Running the Examples
161+ ## Running the Example
128162
129- Install dependencies, set credentials, and run the scripts below.
163+ Set your environment variables (from ` examples/.env.example ` ):
130164
131- ``` bash
132- # Install the gem dependencies
133- bundle install
134- ```
135-
136- Remote browser example:
165+ - ` STAGEHAND_API_URL `
166+ - ` MODEL_API_KEY `
167+ - ` BROWSERBASE_API_KEY `
168+ - ` BROWSERBASE_PROJECT_ID `
137169
138170``` bash
139171cp examples/.env.example examples/.env
140172# Edit examples/.env with your credentials.
141- bundle exec ruby examples/remote_browser_example.rb
142173```
143174
144175The examples load ` examples/.env ` automatically.
145176
146- Local mode example (embedded server, local Chrome/Chromium):
147-
148- ``` bash
149- cp examples/.env.example examples/.env
150- # Edit examples/.env with your credentials.
151- bundle exec ruby examples/local_browser_example.rb
152- ```
153-
154- Playwright local example (SSE streaming):
177+ Examples and dependencies:
155178
156- ``` bash
157- gem install playwright-ruby-client
158- npm install playwright
159- ./node_modules/.bin/ playwright install chromium
160- export MODEL_API_KEY= " your-openai-api-key "
161- bundle exec ruby examples/local_playwright_example .rb
179+ - ` examples/remote_browser_example.rb ` : stagehand only
180+ - ` examples/local_browser_example.rb ` : stagehand only
181+ - ` examples/remote_browser_playwright_example.rb ` : ` playwright-ruby-client ` + Playwright browsers
182+ - ` examples/local_browser_playwright_example.rb ` : ` playwright-ruby-client ` + Playwright browsers
183+ - ` examples/local_playwright_example.rb ` : ` playwright-ruby-client ` + Playwright browsers
184+ - ` examples/local_watir_example .rb ` : ` watir `
162185
163- bundle exec ruby examples/local_browser_playwright_example.rb
164- ```
165-
166- Playwright remote example:
186+ Install dependencies for the example you want to run, then execute it:
167187
168188``` bash
169- gem install playwright-ruby-client
170- npm install playwright
171- ./node_modules/.bin/playwright install chromium
172- export BROWSERBASE_API_KEY=" your-browserbase-api-key"
173- export BROWSERBASE_PROJECT_ID=" your-browserbase-project-id"
174- export MODEL_API_KEY=" your-openai-api-key"
189+ bundle install
175190bundle exec ruby examples/remote_browser_playwright_example.rb
176191```
177192
178- Watir local example:
179-
180- ``` bash
181- gem install watir
182- export MODEL_API_KEY=" your-openai-api-key"
183- bundle exec ruby examples/local_watir_example.rb
184- ```
185-
186193### Streaming
187194
188195We provide support for streaming responses using Server-Sent Events (SSE).
@@ -204,7 +211,7 @@ When the library is unable to connect to the API, or if the API returns a non-su
204211
205212``` ruby
206213begin
207- session = stagehand.sessions.start(model_name: " openai/gpt-5-nano " )
214+ session = stagehand.sessions.start(model_name: " anthropic/claude-sonnet-4-6 " )
208215rescue Stagehand ::Errors ::APIConnectionError => e
209216 puts (" The server could not be reached" )
210217 puts (e.cause) # an underlying Exception, likely raised within `net/http`
@@ -247,7 +254,7 @@ stagehand = Stagehand::Client.new(
247254)
248255
249256# Or, configure per-request:
250- stagehand.sessions.start(model_name: " openai/gpt-5-nano " , request_options: {max_retries: 5 })
257+ stagehand.sessions.start(model_name: " anthropic/claude-sonnet-4-6 " , request_options: {max_retries: 5 })
251258```
252259
253260### Timeouts
@@ -261,7 +268,7 @@ stagehand = Stagehand::Client.new(
261268)
262269
263270# Or, configure per-request:
264- stagehand.sessions.start(model_name: " openai/gpt-5-nano " , request_options: {timeout: 5 })
271+ stagehand.sessions.start(model_name: " anthropic/claude-sonnet-4-6 " , request_options: {timeout: 5 })
265272```
266273
267274On timeout, ` Stagehand::Errors::APITimeoutError ` is raised.
@@ -293,7 +300,7 @@ Note: the `extra_` parameters of the same name overrides the documented paramete
293300``` ruby
294301response =
295302 stagehand.sessions.start(
296- model_name: " openai/gpt-5-nano " ,
303+ model_name: " anthropic/claude-sonnet-4-6 " ,
297304 request_options: {
298305 extra_query: {my_query_parameter: value},
299306 extra_body: {my_body_parameter: value},
0 commit comments