Skip to main content

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}