Class: Firecrawl::Client
- Inherits:
-
Object
- Object
- Firecrawl::Client
- Defined in:
- lib/firecrawl/client.rb
Overview
Client for the Firecrawl v2 API.
Constant Summary collapse
- DEFAULT_API_URL =
"https://api.firecrawl.dev"- DEFAULT_TIMEOUT =
seconds
300- DEFAULT_MAX_RETRIES =
3- DEFAULT_BACKOFF_FACTOR =
0.5- DEFAULT_POLL_INTERVAL =
seconds
2- DEFAULT_JOB_TIMEOUT =
seconds
300
Class Method Summary collapse
-
.from_env ⇒ Client
Creates a client from the FIRECRAWL_API_KEY environment variable.
Instance Method Summary collapse
-
#agent(options, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::AgentStatusResponse
Runs an agent task and waits for completion (auto-polling).
-
#batch_scrape(urls, options = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::BatchScrapeJob
Batch-scrapes URLs and waits for completion (auto-polling).
-
#cancel_agent(job_id) ⇒ Hash
Cancels a running agent task.
-
#cancel_batch_scrape(job_id) ⇒ Hash
Cancels a running batch scrape job.
-
#cancel_crawl(job_id) ⇒ Hash
Cancels a running crawl job.
-
#crawl(url, options = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::CrawlJob
Crawls a website and waits for completion (auto-polling).
-
#create_monitor(name:, schedule:, targets:, webhook: nil, notification: nil, retention_days: nil, goal: nil, judge_enabled: nil) ⇒ Object
MONITOR ================================================================.
- #delete_monitor(monitor_id) ⇒ Object
-
#get_agent_snapshot(job_id, snapshot_id) ⇒ Models::AgentSnapshotResponse
Gets a snapshot of an agent task.
-
#get_agent_status(job_id) ⇒ Models::AgentStatusResponse
Gets the status of an agent task.
-
#get_agent_trace(job_id, live_view: false) ⇒ Models::AgentTraceResponse
Gets the trace of an agent task.
-
#get_batch_scrape_status(job_id) ⇒ Models::BatchScrapeJob
Gets the status and results of a batch scrape job.
-
#get_concurrency ⇒ Models::ConcurrencyCheck
Gets current concurrency usage.
-
#get_crawl_errors(job_id) ⇒ Hash
Gets errors from a crawl job.
-
#get_crawl_status(job_id) ⇒ Models::CrawlJob
Gets the status and results of a crawl job.
-
#get_credit_usage ⇒ Models::CreditUsage
Gets current credit usage.
- #get_monitor(monitor_id) ⇒ Object
- #get_monitor_check(monitor_id, check_id, limit: nil, skip: nil, status: nil, auto_paginate: true) ⇒ Object
-
#initialize(api_key: nil, api_url: nil, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, backoff_factor: DEFAULT_BACKOFF_FACTOR) ⇒ Client
constructor
Creates a new Firecrawl client.
-
#inspect_paper(paper_id) ⇒ Hash
Inspect paper metadata.
-
#interact(job_id, code, language: "node", timeout: nil) ⇒ Hash
Interacts with the scrape-bound browser session for a scrape job.
-
#list_agents(before: nil) ⇒ Models::AgentListResponse
Lists agent tasks, most recent first.
- #list_monitor_checks(monitor_id, limit: nil, offset: nil) ⇒ Object
- #list_monitors(limit: nil, offset: nil) ⇒ Object
-
#map(url, options = nil) ⇒ Models::MapData
Discovers URLs on a website.
-
#parse(file, options = nil) ⇒ Models::Document
Parses an uploaded file and returns the extracted document.
-
#read_paper(paper_id, query_text, options = {}) ⇒ Hash
Read a paper with query-guided passages.
-
#related_papers(paper_id, intent, options = {}) ⇒ Hash
Find papers related to a paper.
- #run_monitor(monitor_id) ⇒ Object
-
#scrape(url, options = nil) ⇒ Models::Document
Scrapes a single URL and returns the document.
-
#search(query, options = nil) ⇒ Models::SearchData
Performs a web search.
-
#search_github(query_text, options = {}) ⇒ Hash
deprecated
Deprecated.
Stops responding after 2026-11-03. Use the developer index at GET or POST /v2/search/developer, which this SDK does not wrap yet, so call it directly. It does not carry over the score breakdown or the web fallback results.
-
#search_papers(query, options = {}) ⇒ Hash
Search research papers.
-
#start_agent(options) ⇒ Models::AgentResponse
Starts an async agent task.
-
#start_batch_scrape(urls, options = nil) ⇒ Models::BatchScrapeResponse
Starts an async batch scrape job.
-
#start_crawl(url, options = nil) ⇒ Models::CrawlResponse
Starts an async crawl job and returns immediately.
-
#stop_interactive_browser(job_id) ⇒ Hash
Stops the interactive browser session for a scrape job.
- #update_monitor(monitor_id, **attrs) ⇒ Object
Constructor Details
#initialize(api_key: nil, api_url: nil, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, backoff_factor: DEFAULT_BACKOFF_FACTOR) ⇒ Client
Creates a new Firecrawl client.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/firecrawl/client.rb', line 34 def initialize( api_key: nil, api_url: nil, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, backoff_factor: DEFAULT_BACKOFF_FACTOR ) resolved_key = api_key || ENV["FIRECRAWL_API_KEY"] # A nil/empty key is allowed: scrape, search, and interact fall back to the # keyless free tier (rate-limited per IP). Other methods return 401 from the # API until a key is provided. resolved_key = nil if resolved_key.nil? || resolved_key.strip.empty? resolved_url = api_url || ENV["FIRECRAWL_API_URL"] || DEFAULT_API_URL unless resolved_url.match?(%r{\Ahttps?://}i) raise FirecrawlError, "API URL must be a fully qualified HTTP or HTTPS URL (got: #{resolved_url})." end @http = HttpClient.new( api_key: resolved_key, base_url: resolved_url, timeout: timeout, max_retries: max_retries, backoff_factor: backoff_factor ) end |
Class Method Details
.from_env ⇒ Client
Creates a client from the FIRECRAWL_API_KEY environment variable.
64 65 66 |
# File 'lib/firecrawl/client.rb', line 64 def self.from_env new end |
Instance Method Details
#agent(options, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::AgentStatusResponse
Runs an agent task and waits for completion (auto-polling).
490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/firecrawl/client.rb', line 490 def agent(, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) start = start_agent() raise FirecrawlError, "Agent start did not return a job ID" if start.id.nil? deadline = Time.now + timeout while Time.now < deadline status = get_agent_status(start.id) return status if status.done? sleep(poll_interval) end raise JobTimeoutError.new(start.id, timeout, "Agent") end |
#batch_scrape(urls, options = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::BatchScrapeJob
Batch-scrapes URLs and waits for completion (auto-polling).
308 309 310 311 |
# File 'lib/firecrawl/client.rb', line 308 def batch_scrape(urls, = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) start = start_batch_scrape(urls, ) poll_batch_scrape(start.id, poll_interval, timeout) end |
#cancel_agent(job_id) ⇒ Hash
Cancels a running agent task.
508 509 510 511 512 |
# File 'lib/firecrawl/client.rb', line 508 def cancel_agent(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? @http.delete("/v2/agent/#{job_id}") end |
#cancel_batch_scrape(job_id) ⇒ Hash
Cancels a running batch scrape job.
317 318 319 320 321 |
# File 'lib/firecrawl/client.rb', line 317 def cancel_batch_scrape(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? @http.delete("/v2/batch/scrape/#{job_id}") end |
#cancel_crawl(job_id) ⇒ Hash
Cancels a running crawl job.
243 244 245 246 247 |
# File 'lib/firecrawl/client.rb', line 243 def cancel_crawl(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? @http.delete("/v2/crawl/#{job_id}") end |
#crawl(url, options = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) ⇒ Models::CrawlJob
Crawls a website and waits for completion (auto-polling).
234 235 236 237 |
# File 'lib/firecrawl/client.rb', line 234 def crawl(url, = nil, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_JOB_TIMEOUT) start = start_crawl(url, ) poll_crawl(start.id, poll_interval, timeout) end |
#create_monitor(name:, schedule:, targets:, webhook: nil, notification: nil, retention_days: nil, goal: nil, judge_enabled: nil) ⇒ Object
================================================================
MONITOR
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/firecrawl/client.rb', line 346 def create_monitor(name:, schedule:, targets:, webhook: nil, notification: nil, retention_days: nil, goal: nil, judge_enabled: nil) body = { "name" => name, "schedule" => schedule, "targets" => targets, "webhook" => webhook, "notification" => notification, "retentionDays" => retention_days, "goal" => goal, "judgeEnabled" => judge_enabled, }.compact raw = @http.post("/v2/monitor", body) Models::Monitor.new(raw["data"] || raw) end |
#delete_monitor(monitor_id) ⇒ Object
392 393 394 395 396 |
# File 'lib/firecrawl/client.rb', line 392 def delete_monitor(monitor_id) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? @http.delete("/v2/monitor/#{monitor_id}")["success"] == true end |
#get_agent_snapshot(job_id, snapshot_id) ⇒ Models::AgentSnapshotResponse
Gets a snapshot of an agent task.
531 532 533 534 535 536 537 |
# File 'lib/firecrawl/client.rb', line 531 def get_agent_snapshot(job_id, snapshot_id) raise ArgumentError, "Job ID is required" if job_id.nil? raise ArgumentError, "Snapshot ID is required" if snapshot_id.nil? raw = @http.get("/v2/agent/#{job_id}/snapshots/#{snapshot_id}") Models::AgentSnapshotResponse.new(raw) end |
#get_agent_status(job_id) ⇒ Models::AgentStatusResponse
Gets the status of an agent task.
463 464 465 466 467 468 |
# File 'lib/firecrawl/client.rb', line 463 def get_agent_status(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? raw = @http.get("/v2/agent/#{job_id}") Models::AgentStatusResponse.new(raw) end |
#get_agent_trace(job_id, live_view: false) ⇒ Models::AgentTraceResponse
Gets the trace of an agent task.
519 520 521 522 523 524 |
# File 'lib/firecrawl/client.rb', line 519 def get_agent_trace(job_id, live_view: false) raise ArgumentError, "Job ID is required" if job_id.nil? raw = @http.get("/v2/agent/#{job_id}/trace#{query(liveView: live_view ? true : nil)}") Models::AgentTraceResponse.new(raw) end |
#get_batch_scrape_status(job_id) ⇒ Models::BatchScrapeJob
Gets the status and results of a batch scrape job.
294 295 296 297 298 299 |
# File 'lib/firecrawl/client.rb', line 294 def get_batch_scrape_status(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? raw = @http.get("/v2/batch/scrape/#{job_id}") Models::BatchScrapeJob.new(raw) end |
#get_concurrency ⇒ Models::ConcurrencyCheck
Gets current concurrency usage.
546 547 548 549 |
# File 'lib/firecrawl/client.rb', line 546 def get_concurrency raw = @http.get("/v2/concurrency-check") Models::ConcurrencyCheck.new(raw) end |
#get_crawl_errors(job_id) ⇒ Hash
Gets errors from a crawl job.
253 254 255 256 257 |
# File 'lib/firecrawl/client.rb', line 253 def get_crawl_errors(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? @http.get("/v2/crawl/#{job_id}/errors") end |
#get_crawl_status(job_id) ⇒ Models::CrawlJob
Gets the status and results of a crawl job.
220 221 222 223 224 225 |
# File 'lib/firecrawl/client.rb', line 220 def get_crawl_status(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? raw = @http.get("/v2/crawl/#{job_id}") Models::CrawlJob.new(raw) end |
#get_credit_usage ⇒ Models::CreditUsage
Gets current credit usage.
554 555 556 557 558 |
# File 'lib/firecrawl/client.rb', line 554 def get_credit_usage raw = @http.get("/v2/team/credit-usage") data = raw["data"] || raw Models::CreditUsage.new(data) end |
#get_monitor(monitor_id) ⇒ Object
367 368 369 370 371 372 |
# File 'lib/firecrawl/client.rb', line 367 def get_monitor(monitor_id) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? raw = @http.get("/v2/monitor/#{monitor_id}") Models::Monitor.new(raw["data"] || raw) end |
#get_monitor_check(monitor_id, check_id, limit: nil, skip: nil, status: nil, auto_paginate: true) ⇒ Object
412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/firecrawl/client.rb', line 412 def get_monitor_check(monitor_id, check_id, limit: nil, skip: nil, status: nil, auto_paginate: true) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? raise ArgumentError, "Check ID is required" if check_id.nil? params = query(limit: limit, skip: skip, status: status) raw = @http.get("/v2/monitor/#{monitor_id}/checks/#{check_id}#{params}") data = raw["data"] || raw data["next"] = raw["next"] if raw["next"] check = Models::MonitorCheckDetail.new(data) auto_paginate ? paginate_monitor_check(check) : check end |
#inspect_paper(paper_id) ⇒ Hash
Inspect paper metadata.
101 102 103 104 |
# File 'lib/firecrawl/client.rb', line 101 def inspect_paper(paper_id) raise ArgumentError, "Paper ID is required" if paper_id.nil? @http.get("/v2/search/research/papers/#{URI.encode_www_form_component(paper_id)}") end |
#interact(job_id, code, language: "node", timeout: nil) ⇒ Hash
Interacts with the scrape-bound browser session for a scrape job.
150 151 152 153 154 155 156 157 158 |
# File 'lib/firecrawl/client.rb', line 150 def interact(job_id, code, language: "node", timeout: nil) raise ArgumentError, "Job ID is required" if job_id.nil? raise ArgumentError, "Code is required" if code.nil? body = { "code" => code, "language" => language } body["timeout"] = timeout if timeout body["origin"] ||= "ruby-sdk@#{Firecrawl::VERSION}" @http.post("/v2/scrape/#{job_id}/interact", body) end |
#list_agents(before: nil) ⇒ Models::AgentListResponse
Lists agent tasks, most recent first.
Pages are fixed at 20 runs. To fetch the next page, pass the before value from the previous page's next URL. This method does not auto-paginate.
479 480 481 482 |
# File 'lib/firecrawl/client.rb', line 479 def list_agents(before: nil) raw = @http.get("/v2/agent#{query(before: before)}") Models::AgentListResponse.new(raw) end |
#list_monitor_checks(monitor_id, limit: nil, offset: nil) ⇒ Object
405 406 407 408 409 410 |
# File 'lib/firecrawl/client.rb', line 405 def list_monitor_checks(monitor_id, limit: nil, offset: nil) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? raw = @http.get("/v2/monitor/#{monitor_id}/checks#{query(limit: limit, offset: offset)}") (raw["data"] || []).map { |item| Models::MonitorCheck.new(item) } end |
#list_monitors(limit: nil, offset: nil) ⇒ Object
362 363 364 365 |
# File 'lib/firecrawl/client.rb', line 362 def list_monitors(limit: nil, offset: nil) raw = @http.get("/v2/monitor#{query(limit: limit, offset: offset)}") (raw["data"] || []).map { |item| Models::Monitor.new(item) } end |
#map(url, options = nil) ⇒ Models::MapData
Discovers URLs on a website.
332 333 334 335 336 337 338 339 340 |
# File 'lib/firecrawl/client.rb', line 332 def map(url, = nil) raise ArgumentError, "URL is required" if url.nil? body = { "url" => url } body.merge!(.to_h) if raw = @http.post("/v2/map", body) data = raw["data"] || raw Models::MapData.new(data) end |
#parse(file, options = nil) ⇒ Models::Document
Parses an uploaded file and returns the extracted document.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/firecrawl/client.rb', line 179 def parse(file, = nil) raise ArgumentError, "File is required" if file.nil? unless file.is_a?(Models::ParseFile) raise ArgumentError, "File must be a Firecrawl::Models::ParseFile" end = .nil? ? {} : .to_h raw = @http.post_multipart( "/v2/parse", fields: { "options" => JSON.generate() }, file_field: "file", filename: file.filename, content: file.content, content_type: file.content_type, ) data = raw["data"] || raw Models::Document.new(data) end |
#read_paper(paper_id, query_text, options = {}) ⇒ Hash
Read a paper with query-guided passages.
112 113 114 115 116 |
# File 'lib/firecrawl/client.rb', line 112 def read_paper(paper_id, query_text, = {}) raise ArgumentError, "Paper ID is required" if paper_id.nil? path = "/v2/search/research/papers/#{URI.encode_www_form_component(paper_id)}" @http.get("#{path}#{query(.merge("query" => query_text, "origin" => "ruby-sdk@#{Firecrawl::VERSION}"))}") end |
#related_papers(paper_id, intent, options = {}) ⇒ Hash
Find papers related to a paper.
124 125 126 127 128 |
# File 'lib/firecrawl/client.rb', line 124 def (paper_id, intent, = {}) raise ArgumentError, "Paper ID is required" if paper_id.nil? path = "/v2/search/research/papers/#{URI.encode_www_form_component(paper_id)}/similar" @http.get("#{path}#{query(.merge("intent" => intent, "origin" => "ruby-sdk@#{Firecrawl::VERSION}"))}") end |
#run_monitor(monitor_id) ⇒ Object
398 399 400 401 402 403 |
# File 'lib/firecrawl/client.rb', line 398 def run_monitor(monitor_id) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? raw = @http.post("/v2/monitor/#{monitor_id}/run", {}) Models::MonitorCheck.new(raw["data"] || raw) end |
#scrape(url, options = nil) ⇒ Models::Document
Scrapes a single URL and returns the document.
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/firecrawl/client.rb', line 77 def scrape(url, = nil) raise ArgumentError, "URL is required" if url.nil? body = { "url" => url } body.merge!(.to_h) if body["origin"] ||= "ruby-sdk@#{Firecrawl::VERSION}" raw = @http.post("/v2/scrape", body) data = raw["data"] || raw Models::Document.new(data) end |
#search(query, options = nil) ⇒ Models::SearchData
Performs a web search.
433 434 435 436 437 438 439 440 441 442 |
# File 'lib/firecrawl/client.rb', line 433 def search(query, = nil) raise ArgumentError, "Query is required" if query.nil? body = { "query" => query } body.merge!(.to_h) if body["origin"] ||= "ruby-sdk@#{Firecrawl::VERSION}" raw = @http.post("/v2/search", body) data = raw["data"] || raw Models::SearchData.new(data) end |
#search_github(query_text, options = {}) ⇒ Hash
Stops responding after 2026-11-03. Use the developer index at GET or POST /v2/search/developer, which this SDK does not wrap yet, so call it directly. It does not carry over the score breakdown or the web fallback results.
Search GitHub research content.
139 140 141 |
# File 'lib/firecrawl/client.rb', line 139 def search_github(query_text, = {}) @http.get("/v2/search/research/github#{query(.merge("query" => query_text, "origin" => "ruby-sdk@#{Firecrawl::VERSION}"))}") end |
#search_papers(query, options = {}) ⇒ Hash
Search research papers.
93 94 95 |
# File 'lib/firecrawl/client.rb', line 93 def search_papers(query, = {}) @http.get("/v2/search/research/papers#{query(.merge("query" => query, "origin" => "ruby-sdk@#{Firecrawl::VERSION}"))}") end |
#start_agent(options) ⇒ Models::AgentResponse
Starts an async agent task.
452 453 454 455 456 457 |
# File 'lib/firecrawl/client.rb', line 452 def start_agent() raise ArgumentError, "Agent options are required" if .nil? raw = @http.post("/v2/agent", .to_h) Models::AgentResponse.new(raw) end |
#start_batch_scrape(urls, options = nil) ⇒ Models::BatchScrapeResponse
Starts an async batch scrape job.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/firecrawl/client.rb', line 268 def start_batch_scrape(urls, = nil) raise ArgumentError, "URLs list is required" if urls.nil? body = { "urls" => urls } extra_headers = {} if opts_hash = .to_h # idempotencyKey goes as a header, not in body if .idempotency_key && !.idempotency_key.empty? extra_headers["x-idempotency-key"] = .idempotency_key end # Flatten nested scrape options to top level (API expects this) nested = opts_hash.delete("options") body.merge!(opts_hash) body.merge!(nested) if nested end raw = @http.post("/v2/batch/scrape", body, extra_headers: extra_headers) Models::BatchScrapeResponse.new(raw) end |
#start_crawl(url, options = nil) ⇒ Models::CrawlResponse
Starts an async crawl job and returns immediately.
207 208 209 210 211 212 213 214 |
# File 'lib/firecrawl/client.rb', line 207 def start_crawl(url, = nil) raise ArgumentError, "URL is required" if url.nil? body = { "url" => url } body.merge!(.to_h) if raw = @http.post("/v2/crawl", body) Models::CrawlResponse.new(raw) end |
#stop_interactive_browser(job_id) ⇒ Hash
Stops the interactive browser session for a scrape job.
164 165 166 167 168 |
# File 'lib/firecrawl/client.rb', line 164 def stop_interactive_browser(job_id) raise ArgumentError, "Job ID is required" if job_id.nil? @http.delete("/v2/scrape/#{job_id}/interact") end |
#update_monitor(monitor_id, **attrs) ⇒ Object
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/firecrawl/client.rb', line 374 def update_monitor(monitor_id, **attrs) raise ArgumentError, "Monitor ID is required" if monitor_id.nil? body = { "name" => attrs[:name], "status" => attrs[:status], "schedule" => attrs[:schedule], "webhook" => attrs[:webhook], "notification" => attrs[:notification], "targets" => attrs[:targets], "retentionDays" => attrs[:retention_days], "goal" => attrs[:goal], "judgeEnabled" => attrs[:judge_enabled], }.compact raw = @http.patch("/v2/monitor/#{monitor_id}", body) Models::Monitor.new(raw["data"] || raw) end |