spider_client/browser.rs
1//! Browser automation via the `spider-browser` crate.
2//!
3//! Re-exports the [`spider_browser`] public types and provides a
4//! [`Spider::browser`](crate::Spider::browser) constructor that creates a
5//! [`SpiderBrowser`] pre-configured with the client's API key. The browser
6//! connects to Spider's pre-warmed browser fleet over WebSocket (CDP/BiDi)
7//! and supports deterministic page control as well as AI-powered
8//! automation (act, observe, extract, agent).
9
10use crate::Spider;
11
12pub use spider_browser::ai::agent::{Agent, AgentOptions, AgentResult};
13pub use spider_browser::ai::llm_provider::{LLMConfig, LLMProviderKind};
14pub use spider_browser::ai::observe::ObserveResult;
15pub use spider_browser::{SpiderBrowser, SpiderBrowserOptions, SpiderPage};
16
17/// Options for a [`SpiderBrowser`] created via [`Spider::browser`].
18///
19/// The API key is injected from the [`Spider`] client, so it does not need
20/// to be set here. Use the chainable `with_*` methods to configure the
21/// browser:
22///
23/// ```rust,no_run
24/// use spider_client::{BrowserOptions, Spider};
25///
26/// let spider = Spider::new(Some("myspiderapikey".into())).expect("API key must be provided");
27/// let options = BrowserOptions::new()
28/// .with_browser("chrome")
29/// .with_stealth(2)
30/// .with_country("US");
31/// let browser = spider.browser(Some(options));
32/// ```
33#[derive(Debug, Clone)]
34pub struct BrowserOptions(SpiderBrowserOptions);
35
36impl Default for BrowserOptions {
37 fn default() -> Self {
38 Self(SpiderBrowserOptions::new(String::new()))
39 }
40}
41
42impl BrowserOptions {
43 /// Create a new set of browser options with defaults.
44 pub fn new() -> Self {
45 Self::default()
46 }
47
48 /// Set the browser type (e.g. "chrome", "firefox", "auto").
49 pub fn with_browser(mut self, browser: impl Into<String>) -> Self {
50 self.0.browser = Some(browser.into());
51 self
52 }
53
54 /// Override the default WebSocket server URL.
55 pub fn with_server_url(mut self, url: impl Into<String>) -> Self {
56 self.0.server_url = Some(url.into());
57 self
58 }
59
60 /// Set the initial stealth level (1-3, 0 = auto-escalate).
61 pub fn with_stealth(mut self, level: u32) -> Self {
62 self.0.stealth = Some(level);
63 self
64 }
65
66 /// Set the LLM configuration for AI-powered actions.
67 pub fn with_llm(mut self, config: LLMConfig) -> Self {
68 self.0.llm = Some(config);
69 self
70 }
71
72 /// Set the captcha handling mode ("off", "detect", "solve").
73 pub fn with_captcha(mut self, mode: impl Into<String>) -> Self {
74 self.0.captcha = Some(mode.into());
75 self
76 }
77
78 /// Set the country code for geo-located proxies (e.g. "US", "GB").
79 pub fn with_country(mut self, country: impl Into<String>) -> Self {
80 self.0.country = Some(country.into());
81 self
82 }
83
84 /// Set a custom proxy URL (e.g. "http://user:pass@proxy:8080").
85 pub fn with_proxy_url(mut self, proxy_url: impl Into<String>) -> Self {
86 self.0.proxy_url = Some(proxy_url.into());
87 self
88 }
89
90 /// Enable or disable screencast recording.
91 pub fn with_record(mut self, record: bool) -> Self {
92 self.0.record = Some(record);
93 self
94 }
95
96 /// Set the browser mode ("scraping" or "cua").
97 pub fn with_mode(mut self, mode: impl Into<String>) -> Self {
98 self.0.mode = Some(mode.into());
99 self
100 }
101}
102
103impl Spider {
104 /// Create a new [`SpiderBrowser`] instance using this client's API key.
105 /// The returned browser must be initialized with `init()` before use.
106 ///
107 /// ```rust,no_run
108 /// use spider_client::{BrowserOptions, Spider};
109 ///
110 /// # #[ignore]
111 /// #[tokio::main]
112 /// async fn main() {
113 /// let spider = Spider::new(Some("myspiderapikey".into())).expect("API key must be provided");
114 ///
115 /// let mut browser = spider.browser(Some(BrowserOptions::new().with_browser("chrome")));
116 /// browser.init().await.expect("Failed to connect to the browser fleet");
117 ///
118 /// browser.page().goto("https://example.com").await.expect("Failed to navigate");
119 /// let html = browser.page().content(1_000, 0).await.expect("Failed to get the page content");
120 /// println!("{}", html);
121 ///
122 /// browser.close();
123 /// }
124 /// ```
125 pub fn browser(&self, options: Option<BrowserOptions>) -> SpiderBrowser {
126 let mut opts = options.unwrap_or_default().0;
127 opts.api_key = self.api_key.clone();
128 SpiderBrowser::new(opts)
129 }
130}