{"id":35690926,"url":"https://github.com/browserbase/stagehand-ruby","last_synced_at":"2026-02-26T01:18:16.641Z","repository":{"id":329012504,"uuid":"1108325182","full_name":"browserbase/stagehand-ruby","owner":"browserbase","description":"Official Stagehand AI Browser Automation SDK for Ruby users. Built by Browserbase.com","archived":false,"fork":false,"pushed_at":"2026-02-17T18:53:32.000Z","size":536,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-18T00:00:08.205Z","etag":null,"topics":["ai","browser-automation","browserbase","ruby","sdk","stagehand"],"latest_commit_sha":null,"homepage":"https://docs.stagehand.dev/v3/sdk/ruby","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/browserbase.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-02T10:08:51.000Z","updated_at":"2026-02-11T07:37:40.000Z","dependencies_parsed_at":"2026-02-07T09:08:55.273Z","dependency_job_id":null,"html_url":"https://github.com/browserbase/stagehand-ruby","commit_stats":null,"previous_names":["browserbase/stagehand-ruby"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/browserbase/stagehand-ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browserbase%2Fstagehand-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browserbase%2Fstagehand-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browserbase%2Fstagehand-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browserbase%2Fstagehand-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/browserbase","download_url":"https://codeload.github.com/browserbase/stagehand-ruby/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browserbase%2Fstagehand-ruby/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29566366,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T00:47:08.760Z","status":"online","status_checked_at":"2026-02-18T02:00:09.468Z","response_time":162,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","browser-automation","browserbase","ruby","sdk","stagehand"],"created_at":"2026-01-05T23:13:18.162Z","updated_at":"2026-02-26T01:18:16.634Z","avatar_url":"https://github.com/browserbase.png","language":"Ruby","readme":"# Stagehand Ruby API library\n\n\u003c!-- x-stagehand-custom-start --\u003e\n\u003cdiv id=\"toc\" align=\"center\" style=\"margin-bottom: 0;\"\u003e\n  \u003cul style=\"list-style: none; margin: 0; padding: 0;\"\u003e\n    \u003ca href=\"https://stagehand.dev\"\u003e\n      \u003cpicture\u003e\n        \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_logo.png\" /\u003e\n        \u003cimg alt=\"Stagehand\" src=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_logo.png\" width=\"200\" style=\"margin-right: 30px;\" /\u003e\n      \u003c/picture\u003e\n    \u003c/a\u003e\n  \u003c/ul\u003e\n\u003c/div\u003e\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eThe AI Browser Automation Framework\u003c/strong\u003e\u003cbr\u003e\n  \u003ca href=\"https://docs.stagehand.dev/v3/sdk/ruby\"\u003eRead the Docs\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/browserbase/stagehand/tree/main?tab=MIT-1-ov-file#MIT-1-ov-file\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_license.svg\" /\u003e\n      \u003cimg alt=\"MIT License\" src=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_license.svg\" /\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://stagehand.dev/discord\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/dark_discord.svg\" /\u003e\n      \u003cimg alt=\"Discord Community\" src=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/light_discord.svg\" /\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://trendshift.io/repositories/12122\" target=\"_blank\"\u003e\u003cimg src=\"https://trendshift.io/api/badge/repositories/12122\" alt=\"browserbase%2Fstagehand | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nIf you're looking for other languages, you can find them\n\u003ca href=\"https://docs.stagehand.dev/v3/first-steps/introduction\"\u003e here\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\" style=\"display: flex; align-items: center; justify-content: center; gap: 4px; margin-bottom: 0;\"\u003e\n  \u003cb\u003eVibe code\u003c/b\u003e\n  \u003cspan style=\"font-size: 1.05em;\"\u003e Stagehand with \u003c/span\u003e\n  \u003ca href=\"https://director.ai\" style=\"display: flex; align-items: center;\"\u003e\n    \u003cspan\u003eDirector\u003c/span\u003e\n  \u003c/a\u003e\n  \u003cspan\u003e \u003c/span\u003e\n  \u003cpicture\u003e\n    \u003cimg alt=\"Director\" src=\"https://raw.githubusercontent.com/browserbase/stagehand/main/media/director_icon.svg\" width=\"25\" /\u003e\n  \u003c/picture\u003e\n\u003c/div\u003e\n\u003c!-- x-stagehand-custom-end --\u003e\n\nThe Stagehand Ruby library provides convenient access to the Stagehand REST API from any Ruby 3.2.0+ application. It ships with comprehensive types \u0026 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.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## Documentation\n\nDocumentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/stagehand).\n\nThe REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev).\n\n## Installation\n\nTo use this gem, install via Bundler by adding the following to your application's `Gemfile`:\n\n\u003c!-- x-release-please-start-version --\u003e\n\n```ruby\ngem \"stagehand\", :git =\u003e \"git://github.com/browserbase/stagehand-ruby.git\"\n```\n\n\u003c!-- x-release-please-end --\u003e\n\n## Usage\n\nThis mirrors `examples/remote_browser_playwright_example.rb`.\n\n```ruby\nrequire \"bundler/setup\"\nrequire \"stagehand\"\n\nrequire_relative \"examples/env\"\nExampleEnv.load!\n\nrequire \"playwright\"\n\nclient = Stagehand::Client.new(\n  browserbase_api_key: ENV[\"BROWSERBASE_API_KEY\"],\n  browserbase_project_id: ENV[\"BROWSERBASE_PROJECT_ID\"],\n  model_api_key: ENV[\"MODEL_API_KEY\"],\n  server: \"remote\"\n)\n\nstart_response = client.sessions.start(\n  model_name: \"anthropic/claude-sonnet-4-6\",\n  browser: { type: :browserbase }\n)\n\nsession_id = start_response.data.session_id\ncdp_url = start_response.data.cdp_url\nraise \"No CDP URL returned for this session.\" if cdp_url.to_s.empty?\n\nPlaywright.create(playwright_cli_executable_path: \"./node_modules/.bin/playwright\") do |playwright|\n  browser = playwright.chromium.connect_over_cdp(cdp_url)\n  context = browser.contexts.first || browser.new_context\n  page = context.pages.first || context.new_page\n\n  client.sessions.navigate(session_id, url: \"https://news.ycombinator.com\")\n  page.wait_for_load_state(state: \"domcontentloaded\")\n\n  observe_stream = client.sessions.observe_streaming(\n    session_id,\n    instruction: \"find the link to view comments for the top post\"\n  )\n  observe_stream.each { |_event| }\n\n  act_stream = client.sessions.act_streaming(\n    session_id,\n    input: \"Click the comments link for the top post\"\n  )\n  act_stream.each { |_event| }\n\n  extract_stream = client.sessions.extract_streaming(\n    session_id,\n    instruction: \"extract the text of the top comment on this page\",\n    schema: {\n      type: \"object\",\n      properties: {\n        commentText: {type: \"string\"},\n        author: {type: \"string\"}\n      },\n      required: [\"commentText\"]\n    }\n  )\n  extract_stream.each { |_event| }\n\n  execute_stream = client.sessions.execute_streaming(\n    session_id,\n    execute_options: {\n      instruction: \"Click the 'Learn more' link if available\",\n      max_steps: 3\n    },\n    agent_config: {\n      model: Stagehand::ModelConfig.new(\n        model_name: \"anthropic/claude-opus-4-6\",\n        api_key: ENV[\"MODEL_API_KEY\"]\n      ),\n      cua: false\n    }\n  )\n  execute_stream.each { |_event| }\nend\n\nclient.sessions.end_(session_id)\n```\n\n## Running the Example\n\nSet your environment variables (from `examples/.env.example`):\n\n- `STAGEHAND_API_URL`\n- `MODEL_API_KEY`\n- `BROWSERBASE_API_KEY`\n- `BROWSERBASE_PROJECT_ID`\n\n```bash\ncp examples/.env.example examples/.env\n# Edit examples/.env with your credentials.\n```\n\nThe examples load `examples/.env` automatically.\n\nExamples and dependencies:\n\n- `examples/remote_browser_example.rb`: stagehand only\n- `examples/local_browser_example.rb`: stagehand only\n- `examples/remote_browser_playwright_example.rb`: `playwright-ruby-client` + Playwright browsers\n- `examples/local_browser_playwright_example.rb`: `playwright-ruby-client` + Playwright browsers\n- `examples/local_playwright_example.rb`: `playwright-ruby-client` + Playwright browsers\n- `examples/local_watir_example.rb`: `watir`\n\nInstall dependencies for the example you want to run, then execute it:\n\n```bash\nbundle install\nbundle exec ruby examples/remote_browser_playwright_example.rb\n```\n\n### Streaming\n\nWe provide support for streaming responses using Server-Sent Events (SSE).\n\n```ruby\nstream = stagehand.sessions.act_streaming(\n  \"00000000-your-session-id-000000000000\",\n  input: \"click the first link on the page\"\n)\n\nstream.each do |session|\n  puts(session.data)\nend\n```\n\n### Handling errors\n\nWhen the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `Stagehand::Errors::APIError` will be thrown:\n\n```ruby\nbegin\n  session = stagehand.sessions.start(model_name: \"anthropic/claude-sonnet-4-6\")\nrescue Stagehand::Errors::APIConnectionError =\u003e e\n  puts(\"The server could not be reached\")\n  puts(e.cause)  # an underlying Exception, likely raised within `net/http`\nrescue Stagehand::Errors::RateLimitError =\u003e e\n  puts(\"A 429 status code was received; we should back off a bit.\")\nrescue Stagehand::Errors::APIStatusError =\u003e e\n  puts(\"Another non-200-range status code was received\")\n  puts(e.status)\nend\n```\n\nError codes are as follows:\n\n| Cause            | Error Type                 |\n| ---------------- | -------------------------- |\n| HTTP 400         | `BadRequestError`          |\n| HTTP 401         | `AuthenticationError`      |\n| HTTP 403         | `PermissionDeniedError`    |\n| HTTP 404         | `NotFoundError`            |\n| HTTP 409         | `ConflictError`            |\n| HTTP 422         | `UnprocessableEntityError` |\n| HTTP 429         | `RateLimitError`           |\n| HTTP \u003e= 500      | `InternalServerError`      |\n| Other HTTP error | `APIStatusError`           |\n| Timeout          | `APITimeoutError`          |\n| Network error    | `APIConnectionError`       |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\n\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, \u003e=500 Internal errors, and timeouts will all be retried by default.\n\nYou can use the `max_retries` option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nstagehand = Stagehand::Client.new(\n  max_retries: 0 # default is 2\n)\n\n# Or, configure per-request:\nstagehand.sessions.start(model_name: \"anthropic/claude-sonnet-4-6\", request_options: {max_retries: 5})\n```\n\n### Timeouts\n\nBy default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nstagehand = Stagehand::Client.new(\n  timeout: nil # default is 60\n)\n\n# Or, configure per-request:\nstagehand.sessions.start(model_name: \"anthropic/claude-sonnet-4-6\", request_options: {timeout: 5})\n```\n\nOn timeout, `Stagehand::Errors::APITimeoutError` is raised.\n\nNote that requests that time out are retried by default.\n\n## Advanced concepts\n\n### BaseModel\n\nAll parameter and response objects inherit from `Stagehand::Internal::Type::BaseModel`, which provides several conveniences, including:\n\n1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj =\u003e {prop: prop}` or pattern-matching syntax.\n\n2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.\n\n3. Both instances and the classes themselves can be pretty-printed.\n\n4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.\n\n### Making custom or undocumented requests\n\n#### Undocumented properties\n\nYou can send undocumented parameters to any endpoint, and read undocumented response properties, like so:\n\nNote: the `extra_` parameters of the same name overrides the documented parameters.\n\n```ruby\nresponse =\n  stagehand.sessions.start(\n    model_name: \"anthropic/claude-sonnet-4-6\",\n    request_options: {\n      extra_query: {my_query_parameter: value},\n      extra_body: {my_body_parameter: value},\n      extra_headers: {\"my-header\": value}\n    }\n  )\n\nputs(response[:my_undocumented_property])\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:\n\n```ruby\nresponse = client.request(\n  method: :post,\n  path: '/undocumented/endpoint',\n  query: {\"dog\": \"woof\"},\n  headers: {\"useful-header\": \"interesting-value\"},\n  body: {\"hello\": \"world\"}\n)\n```\n\n### Concurrency \u0026 connection pooling\n\nThe `Stagehand::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.\n\nEach instance of `Stagehand::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.\n\nWhen all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.\n\nUnless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.\n\n## Sorbet\n\nThis library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.\n\nYou can provide typesafe request parameters like so:\n\n```ruby\nstagehand.sessions.act(\"00000000-your-session-id-000000000000\", input: \"click the first link on the page\")\n```\n\nOr, equivalently:\n\n```ruby\n# Hashes work, but are not typesafe:\nstagehand.sessions.act(\"00000000-your-session-id-000000000000\", input: \"click the first link on the page\")\n\n# You can also splat a full Params class:\nparams = Stagehand::SessionActParams.new(input: \"click the first link on the page\")\nstagehand.sessions.act(\"00000000-your-session-id-000000000000\", **params)\n```\n\n### Enums\n\nSince this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide \"tagged symbols\" instead, which is always a primitive at runtime:\n\n```ruby\n# :true\nputs(Stagehand::SessionActParams::XStreamResponse::TRUE)\n\n# Revealed type: `T.all(Stagehand::SessionActParams::XStreamResponse, Symbol)`\nT.reveal_type(Stagehand::SessionActParams::XStreamResponse::TRUE)\n```\n\nEnum parameters have a \"relaxed\" type, so you can either pass in enum constants or their literal value:\n\n```ruby\n# Using the enum constants preserves the tagged type information:\nstagehand.sessions.act(\n  x_stream_response: Stagehand::SessionActParams::XStreamResponse::TRUE,\n  # …\n)\n\n# Literal values are also permissible:\nstagehand.sessions.act(\n  x_stream_response: :true,\n  # …\n)\n```\n\n## Versioning\n\nThis package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time.\n\nThis package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes.\n\n## Requirements\n\nRuby 3.2.0 or higher.\n\n## Contributing\n\nSee [the contributing documentation](https://github.com/browserbase/stagehand-ruby/tree/main/CONTRIBUTING.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowserbase%2Fstagehand-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrowserbase%2Fstagehand-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowserbase%2Fstagehand-ruby/lists"}