Integrations / Ruby SDK

Ruby SDK

Create sessions, interact with pages, and extract structured data.

Installation #

Install the gem from RubyGems:

gem install browserbeam

Or add it to your Gemfile:

gem "browserbeam"

Then run:

bundle install
Requires Ruby 3.0+. The SDK uses Faraday for HTTP requests — it is installed automatically as a dependency.

Quick Start #

Create a client, open a session, and interact with a page:

require "browserbeam"

client = Browserbeam::Client.new(api_key: "bb_your_key")

session = client.sessions.create(url: "https://example.com")
session.click(text: "More information")
result = session.extract(title: "string", paragraphs: ["string"])
puts result.extraction
session.close

Configuration #

Pass options when you create the client:

client = Browserbeam::Client.new(
  api_key: "bb_your_key",       # or set BROWSERBEAM_API_KEY env var
  base_url: "https://api.browserbeam.com",  # default
  timeout: 120                  # request timeout in seconds, default 120
)
Option Default Description
api_key ENV["BROWSERBEAM_API_KEY"] Your API key. The param takes priority over the env var.
base_url https://api.browserbeam.com API base URL.
timeout 120 HTTP request timeout in seconds.
If you omit api_key, the SDK reads BROWSERBEAM_API_KEY from the environment. If neither is set, it raises an ArgumentError.

Creating Sessions #

Call client.sessions.create to launch a browser session. It returns a Session object you use for all subsequent actions.

session = client.sessions.create(
  url: "https://example.com",
  viewport: { width: 1280, height: 720 },
  locale: "en-US",
  timezone: "America/New_York",
  user_agent: "MyBot/1.0",
  proxy: { kind: "residential", country: "us" },
  block_resources: ["image", "font"],
  auto_dismiss_blockers: true,
  cookies: [{ name: "session", value: "abc123", domain: ".example.com" }],
  idempotency_key: "unique-request-id"
)

puts session.page.title
Parameter Type Description
url String URL to navigate to after launch.
viewport Hash { width:, height: } — browser viewport size.
locale String Browser locale, e.g. "en-US".
timezone String IANA timezone, e.g. "America/New_York".
user_agent String Custom user-agent string.
proxy Hash | String Managed proxy { kind: "datacenter"|"residential", country: "us"|"auto" } or BYO proxy URL. Default: datacenter, auto.
block_resources Array Resource types to block, e.g. ["image", "font"].
auto_dismiss_blockers Boolean Auto-dismiss cookie banners and overlays.
cookies Array Cookies to set before navigation.
idempotency_key String Prevents duplicate session creation.

Session Methods #

Every method below sends a step to the browser and returns the updated session envelope.

Method Description
goto(url)Navigate to a URL.
observeGet page content and interactive elements. Supports mode: "full" for all page sections.
clickClick an element by ref, text, or label.
typeType text character by character.
selectSelect a dropdown option.
checkToggle a checkbox.
fillSet the value of an input field; target by ref, text, or label.
fill_formFill multiple form fields at once.
extractExtract structured data matching a schema.
screenshotTake a screenshot of the page.
scroll_collectScroll the page and collect content.
scrollScroll the page or to an element.
waitWait for time, selector, text, or JS expression.
uploadUpload files to a file input.
pdfGenerate a PDF of the page.
execute_jsRun JavaScript in the browser.
closeClose the browser session.

goto(url) #

Navigate the browser to a new URL.

session.goto("https://example.com/about")

# Wait for a CSS selector or JS expression
session.goto("https://example.com", wait_for: ".loaded", wait_timeout: 5000)
session.goto("https://example.com", wait_until: "document.readyState === 'complete'")

observe #

Read the page content and discover interactive elements. Use scope to limit to a CSS container. Switch to HTML format when you need tag/class names. Use mode: "full" to get content from all page sections (nav, aside, footer, etc.) organized by region. The first observe auto-includes a section map showing available page regions.

result = session.observe(scope: "main", format: "markdown")
puts result.page.markdown.content

result.page.interactive_elements.each do |el|
  puts "#{el.ref} — #{el.tag} — #{el.label}"
end

# Page map is auto-included on first observe
result.page.map.each do |entry|
  puts "#{entry.section}: #{entry.hint}"
end

# Re-request the map on subsequent calls
session.observe(include_page_map: true)

# Get content from all page sections
full = session.observe(mode: "full", max_text_length: 20_000)
puts full.page.markdown.content
# ## [nav]
# Home · Docs · Pricing
# ## [main]
# ...article content...
# ## [aside]
# Related posts · ...
Parameter Type Description
scope String CSS selector to scope observation to a page section.
format String "markdown" (default) or "html".
mode String "main" (default) returns main content only. "full" returns all page sections organized by region headers.
include_page_map Boolean Include a section map with hints. Auto-included on first observe; set true to request again.
include_links Boolean Include links in the markdown output.
max_text_length Integer Max content length in chars (default: 12000, or 20000 for mode "full").

click #

Click an element. Target by ref (from observe), visible text, or label.

# By ref from observe results
session.click(ref: "a7")

# By visible text
session.click(text: "Sign in")

# By label (for buttons, links, inputs)
session.click(label: "Submit")

fill #

Set the value of an input field. Target by ref, text, or label. Clears existing content first.

# By ref
session.fill("hello@example.com", ref: "input3")

# By label
session.fill("hello@example.com", label: "Email")

# By visible text
session.fill("hello@example.com", text: "Email")

fill_form #

Fill multiple form fields in a single step. Optionally submit the form.

session.fill_form([
  { label: "Email", value: "hello@example.com" },
  { label: "Password", value: "s3cret" }
], submit: true)

extract #

Extract structured data from the page. Define a schema using Ruby keyword arguments.

# Mix CSS, JS, and AI selectors in a single extraction
result = session.extract(
  products: [{
    "_parent": ".product-card",
    "_limit": 3,
    "name": "h2 >> text",                          # CSS selector
    "price": ".price >> text",                     # CSS selector
    "url": "a >> href",                            # CSS attribute
    "rating": "ai >> the star rating out of 5",    # AI selector
    "in_stock": "js >> el.querySelector('.stock')?.textContent.includes('In stock')",  # JS selector
  }]
)

result.extraction["products"].each do |product|
  puts "#{product['name']}: #{product['price']} (#{product['rating']})"
end

Three selector types work together in the same schema:

  • CSS"h2 >> text", "a >> href", ".price >> text"
  • AI"ai >> the star rating" — resolves to a CSS selector via AI, cached after first call
  • JS"js >> expression" — runs JavaScript against each matched element

screenshot #

Capture a screenshot. The image is returned as base64 in media.

result = session.screenshot(full_page: true)

# Save to file
require "base64"
File.write("page.png", Base64.decode64(result.media.first.data))

scroll_collect #

Scroll through the page and collect all content. Useful for infinite-scroll pages.

result = session.scroll_collect(max_scrolls: 10)
puts result.page.markdown.content

close #

Close the browser session and release resources.

session.close
Sessions expire automatically after the configured timeout, but closing them explicitly frees resources immediately and stops credit consumption.

type #

Type text character by character. Useful for inputs with autocomplete or client-side filtering. Target by ref, text, or label.

session.type("search query", ref: "input5", delay: 50)
session.type("hello", label: "Search")

select #

Select a dropdown option by value. Target the select element by ref, text, or label.

session.select("us", label: "Country")

check #

Toggle a checkbox or radio button. Target by ref, text, or label.

session.check(label: "I agree to the terms")
session.check(ref: "cb3", checked: false)

scroll #

Scroll the page or scroll an element into view. Target by ref, text, or label.

session.scroll(to: "bottom")
session.scroll(direction: "down", amount: 500)
session.scroll(text: "Footer section")

wait #

Wait for a duration, CSS selector, visible text, or a JavaScript expression to become truthy.

session.wait(ms: 2000)
session.wait(selector: ".loaded", timeout: 10000)
session.wait(until: "document.querySelectorAll('.item').length > 5")

upload #

Upload files to a file input. Target by ref, text, or label.

session.upload(["https://example.com/file.pdf"], ref: "file1")
session.upload(["https://example.com/photo.jpg"], label: "Upload photo")

pdf #

Generate a PDF of the page. Supports format, landscape, background, scale, and margin options.

result = session.pdf(format: "A4", landscape: true, scale: 0.8,
  margin: { top: "1cm", bottom: "1cm" })
require "base64"
File.write("page.pdf", Base64.decode64(result.media.first.data))

execute_js #

Run JavaScript code in the browser. The result is stored in the extraction under the specified key.

result = session.execute_js("return document.title")
puts result.extraction["js_result"]

# With custom result key and timeout
result = session.execute_js("return document.querySelectorAll('a').length",
  result_key: "link_count", timeout: 5000)

Session Management #

List, inspect, and destroy sessions through the client.sessions namespace.

List sessions

result = client.sessions.list(status: "active", limit: 10)
result.sessions.each do |s|
  puts "#{s.session_id} — #{s.status} — #{s.started_at}"
end

# Pagination
if result.has_more
  next_page = client.sessions.list(after: result.next_cursor)
end

Get session info

info = client.sessions.get("ses_abc123")
puts info.status         # "active" | "closed" | "failed"
puts info.expires_at     # "2026-03-24T12:00:00Z"
if info.status == "failed"
  puts info.error_code, info.error_message
end

Destroy a session

client.sessions.destroy("ses_abc123")

Error Handling #

All errors inherit from Browserbeam::Error. Each error exposes message, code, status_code, context, and request_id.

Class HTTP When
AuthenticationError401Invalid or missing API key.
InvalidRequestError400Malformed request or invalid parameters.
SessionNotFoundError404Session does not exist or has expired.
RateLimitError429Too many requests. Check retry_after.
QuotaExceededError429Credit quota exhausted. Check retry_after.
EngineUnavailableError503Service temporarily unavailable. Check retry_after.
StepExecutionErrorvariesA step failed. Check step_index and action.
begin
  session = client.sessions.create(url: "https://example.com")
  session.click(ref: "missing")
  session.close
rescue Browserbeam::RateLimitError => e
  puts "Rate limited. Retry after #{e.retry_after}s"
rescue Browserbeam::SessionNotFoundError => e
  puts "Session gone: #{e.message}"
rescue Browserbeam::AuthenticationError => e
  puts "Bad API key: #{e.message}"
rescue Browserbeam::Error => e
  puts "Error [#{e.code}]: #{e.message}"
  puts "Request ID: #{e.request_id}"
end

Full Example #

Extract the top stories from Hacker News, search for a topic, and save a screenshot.

require "browserbeam"
require "base64"
require "json"

client = Browserbeam::Client.new

# Navigate to Hacker News
session = client.sessions.create(url: "https://news.ycombinator.com/")

# Extract top stories from the front page
result = session.extract(
  stories: [{ "_parent": ".titleline", "title": "a >> text", "url": "a >> href" }]
)
result.extraction["stories"].first(5).each do |story|
  puts "#{story['title']} — #{story['url']}"
end

# Fill the search form and submit
session.fill_form({ "q" => "browser automation" }, submit: true)

# Take a screenshot of search results
shot = session.screenshot(full_page: true)
File.write("hn-search.png", Base64.decode64(shot.media.first.data))

session.close

Source code on GitHub. Found an issue? Open a ticket.

API Reference

Give your AI agent a faster, leaner browser

Structured page data instead of raw HTML. Your agent processes less, decides faster, and costs less to run.

Stability detection built in
Fraction of the payload size
Diffs after every action
No credit card required. 5,000 free credits included.