Rust Client
The Evomi Rust Client provides a production-ready, async interface to Evomi’s API with full type safety and idiomatic Rust patterns.
Installation
Add to your Cargo.toml:
[dependencies]
evomi-client = "0.1.2"
tokio = { version = "1", features = ["full"] }Quick Start
use evomi_client::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize with API key (or set EVOMI_API_KEY env var)
let client = Client::new("your-api-key", None, None)?;
// Scrape a URL
let result = client.scrape("https://example.com", None).await?;
println!("{:?}", result);
Ok(())
}Authentication
Set your API key via environment variable:
export EVOMI_API_KEY="your-api-key"Or pass it directly:
let client = Client::new("your-api-key", None, None)?;Custom base URL (for testing):
let client = Client::new("your-api-key", Some("https://custom.evomi.com".to_string()), None)?;Scraping Operations
scrape(url, options)
Scrape a single URL with configurable options.
use evomi_client::{Client, ScrapeOptions};
let result = client.scrape("https://example.com", Some(ScrapeOptions {
mode: Some("auto".to_string()),
content: Some("markdown".to_string()),
device: Some("windows".to_string()),
proxy_type: Some("residential".to_string()),
proxy_country: Some("US".to_string()),
proxy_session_id: Some("abc123".to_string()),
wait_until: Some("domcontentloaded".to_string()),
ai_enhance: Some(true),
ai_prompt: Some("Extract product data".to_string()),
ai_source: Some("markdown".to_string()),
js_instructions: Some(vec![serde_json::json!({"click": ".load-more"})]),
execute_js: Some("window.scrollTo(0, document.body.scrollHeight)".to_string()),
wait_seconds: Some(2),
screenshot: Some(false),
pdf: Some(false),
excluded_tags: Some(vec!["nav".to_string(), "footer".to_string()]),
excluded_selectors: Some(vec![".ads".to_string()]),
block_resources: Some(vec!["image".to_string(), "stylesheet".to_string()]),
capture_headers: Some(true),
async_mode: Some(false),
config_id: Some("cfg_abc123".to_string()),
scheme_id: Some("sch_abc123".to_string()),
extract_scheme: Some(vec![serde_json::json!({"label": "title", "type": "content", "selector": "h1"})]),
storage_id: Some("stor_abc123".to_string()),
use_default_storage: Some(false),
webhook: None,
..Default::default()
})).await?;| Field | Type | Default | Description |
|---|---|---|---|
mode |
Option<String> |
"auto" |
Scraping mode: "request", "browser", "auto" |
content |
Option<String> |
"markdown" |
Output format: "html", "markdown", "screenshot", "pdf" |
device |
Option<String> |
"windows" |
Device type: "windows", "macos", "android" |
proxy_type |
Option<String> |
"residential" |
Proxy type: "datacenter", "residential" |
proxy_country |
Option<String> |
"US" |
Two-letter country code |
proxy_session_id |
Option<String> |
— | Proxy session ID (6-8 chars) |
wait_until |
Option<String> |
"domcontentloaded" |
Wait condition |
ai_enhance |
Option<bool> |
false |
Enable AI extraction |
ai_prompt |
Option<String> |
— | Prompt for AI extraction |
ai_source |
Option<String> |
— | AI source |
ai_force_json |
Option<bool> |
true |
Force AI response to JSON |
js_instructions |
Option<Vec<Value>> |
— | JS actions |
execute_js |
Option<String> |
— | Raw JavaScript to execute |
wait_seconds |
Option<u32> |
0 |
Seconds to wait after page load |
screenshot |
Option<bool> |
false |
Capture screenshot |
pdf |
Option<bool> |
false |
Capture PDF |
excluded_tags |
Option<Vec<String>> |
— | HTML tags to remove |
excluded_selectors |
Option<Vec<String>> |
— | CSS selectors to remove |
block_resources |
Option<Vec<String>> |
— | Resource types to block |
additional_headers |
Option<HashMap<String, String>> |
— | Extra HTTP headers |
capture_headers |
Option<bool> |
false |
Capture response headers |
network_capture |
Option<Vec<Value>> |
— | Network capture filters |
async_mode |
Option<bool> |
false |
Return immediately with task ID |
config_id |
Option<String> |
— | Saved config ID |
scheme_id |
Option<String> |
— | Saved extraction schema ID |
extract_scheme |
Option<Vec<Value>> |
— | Inline extraction schema |
storage_id |
Option<String> |
— | Storage config ID |
use_default_storage |
Option<bool> |
false |
Use default storage |
delivery |
Option<String> |
"json" |
Response format: "raw" or "json" |
include_content |
Option<bool> |
true |
Include content in response |
webhook |
Option<WebhookConfig> |
— | Webhook configuration |
crawl(domain, options)
Crawl a website to discover and scrape multiple pages.
use evomi_client::CrawlOptions;
let result = client.crawl("example.com", Some(CrawlOptions {
max_urls: Some(100),
depth: Some(2),
url_pattern: Some("/blog/.*".to_string()),
scraper_config: Some(serde_json::json!({"mode": "browser", "output": "markdown"})),
async_mode: Some(false),
webhook: None,
})).await?;| Field | Type | Default | Description |
|---|---|---|---|
max_urls |
Option<u32> |
100 |
Maximum URLs to crawl |
depth |
Option<u32> |
2 |
Crawl depth |
url_pattern |
Option<String> |
— | Regex pattern to filter URLs |
scraper_config |
Option<Value> |
— | Config for scraping each page |
async_mode |
Option<bool> |
false |
Return immediately with task ID |
map_website(domain, options)
Discover URLs from a website via sitemaps, CommonCrawl, or crawling.
use evomi_client::MapOptions;
let result = client.map_website("example.com", Some(MapOptions {
sources: Some(vec!["sitemap".to_string(), "commoncrawl".to_string()]),
max_urls: Some(500),
url_pattern: Some("/products/.*".to_string()),
check_if_live: Some(false),
depth: Some(1),
async_mode: Some(false),
webhook: None,
})).await?;| Field | Type | Default | Description |
|---|---|---|---|
sources |
Option<Vec<String>> |
["sitemap", "commoncrawl"] |
Discovery sources |
max_urls |
Option<u32> |
500 |
Maximum URLs to discover |
url_pattern |
Option<String> |
— | Regex pattern to filter URLs |
check_if_live |
Option<bool> |
false |
Check if URLs are live |
depth |
Option<u32> |
1 |
Crawl depth if using crawl source |
async_mode |
Option<bool> |
false |
Return immediately with task ID |
search_domains(query, options)
Find domains by searching the web.
use evomi_client::SearchOptions;
// Single query
let result = client.search_domains("e-commerce platforms", Some(SearchOptions {
max_urls: Some(20),
region: Some("us-en".to_string()),
webhook: None,
})).await?;
// Multiple queries (up to 10)
let result = client.search_domains(
vec!["web scraping tools".to_string(), "data extraction".to_string()],
Some(SearchOptions { max_urls: Some(20), ..Default::default() })
).await?;| Field | Type | Default | Description |
|---|---|---|---|
max_urls |
Option<u32> |
20 |
Max domains per query (max: 100) |
region |
Option<String> |
"us-en" |
Region for results |
agent_request(message)
Send a natural language request to the AI agent.
let result = client.agent_request("Scrape example.com and extract all product prices").await?;get_task_status(task_id, task_type)
Check the status of an async task.
let result = client.get_task_status("abc123", "scrape").await?;
// task_type: "scrape" | "crawl" | "map" | "config_generate" | "schema"
Config Management
Save and reuse scrape configurations.
list_configs(options)
use evomi_client::ListOptions;
let configs = client.list_configs(Some(ListOptions {
page: Some(1),
per_page: Some(20),
sort_by: Some("created_at".to_string()),
sort_order: Some("desc".to_string()),
})).await?;create_config(name, config)
let config = client.create_config("Product Scraper", serde_json::json!({
"mode": "browser",
"output": "markdown"
})).await?;get_config(config_id)
let config = client.get_config("cfg_abc123").await?;update_config(config_id, name, config)
let config = client.update_config("cfg_abc123", Some("New Name"), Some(serde_json::json!({
"mode": "request"
}))).await?;delete_config(config_id)
let result = client.delete_config("cfg_abc123").await?;generate_config(name, prompt)
Generate a scrape config from natural language using AI.
let config = client.generate_config(
"Amazon Scraper",
"Scrape product title and price from Amazon product pages"
).await?;Schema Management
Define reusable structured data extraction schemas.
list_schemas(options)
let schemas = client.list_schemas(Some(ListOptions {
page: Some(1),
per_page: Some(20),
sort_by: Some("created_at".to_string()),
sort_order: Some("desc".to_string()),
})).await?;create_schema(name, config, options)
use evomi_client::CreateSchemaOptions;
let schema = client.create_schema("Product Schema", serde_json::json!({
"url": "https://example.com/product",
"extract_scheme": [
{"label": "title", "type": "content", "selector": "h1"},
{"label": "price", "type": "content", "selector": ".price"}
]
}), Some(CreateSchemaOptions {
test: Some(true),
fix: Some(false),
extract_prompt: None,
})).await?;get_schema(scheme_id)
let schema = client.get_schema("sch_abc123").await?;update_schema(scheme_id, name, config, options)
let schema = client.update_schema("sch_abc123", "Updated Schema", serde_json::json!({
"url": "...",
"extract_scheme": [...]
}), Some(CreateSchemaOptions {
test: Some(true),
..Default::default()
})).await?;delete_schema(scheme_id)
let result = client.delete_schema("sch_abc123").await?;get_schema_status(scheme_id)
let status = client.get_schema_status("sch_abc123").await?;Schedule Management
Run scrape configs on a recurring schedule.
list_schedules(options, active_only)
let schedules = client.list_schedules(Some(ListOptions {
page: Some(1),
per_page: Some(20),
..Default::default()
}), Some(false)).await?;create_schedule(name, config_id, interval_minutes, options)
use evomi_client::CreateScheduleOptions;
let schedule = client.create_schedule(
"Daily Price Check",
"cfg_abc123",
1440, // Daily (in minutes)
Some(CreateScheduleOptions {
start_time: Some("09:00".to_string()),
stop_on_error: Some(true),
webhook: None,
})
).await?;get_schedule(schedule_id)
let schedule = client.get_schedule("sched_abc123").await?;update_schedule(schedule_id, name, config_id, interval_minutes, stop_on_error)
let schedule = client.update_schedule(
"sched_abc123",
Some("New Name"),
None,
Some(720),
None
).await?;delete_schedule(schedule_id)
let result = client.delete_schedule("sched_abc123").await?;toggle_schedule(schedule_id)
let result = client.toggle_schedule("sched_abc123").await?;list_schedule_runs(schedule_id, page, per_page)
let runs = client.list_schedule_runs("sched_abc123", Some(1), Some(20)).await?;Storage Management
Connect cloud storage to automatically save scrape results.
list_storage_configs()
let configs = client.list_storage_configs().await?;create_storage_config(name, storage_type, config, options)
use evomi_client::CreateStorageOptions;
// S3-compatible storage
let storage = client.create_storage_config(
"My S3",
"s3_compatible",
serde_json::json!({
"bucket": "my-bucket",
"region": "us-east-1",
"access_key": "...",
"secret_key": "..."
}),
Some(CreateStorageOptions {
set_as_default: Some(true),
})
).await?;
// Google Cloud Storage
let storage = client.create_storage_config(
"My GCS",
"gcs",
serde_json::json!({
"bucket": "my-bucket",
"credentials_json": "..."
}),
None
).await?;
// Azure Blob Storage
let storage = client.create_storage_config(
"My Azure",
"azure_blob",
serde_json::json!({
"container": "my-container",
"connection_string": "..."
}),
None
).await?;update_storage_config(storage_id, name, config, set_as_default)
let storage = client.update_storage_config(
"stor_abc123",
Some("Renamed Storage"),
None,
Some(true)
).await?;delete_storage_config(storage_id)
let result = client.delete_storage_config("stor_abc123").await?;Public API
Access proxy credentials and related data.
get_public_api()
Access the Evomi Public API to get proxy credentials and related data.
let data = client.get_public_api().await?;
// Returns proxy credentials and product information
get_proxy_data()
Get detailed information about your proxy products.
let data = client.get_proxy_data().await?;
// Returns: {"products": {"rp": {...}, "sdc": {...}, "mp": {...}}, ...}
get_targeting_options()
Get available targeting parameters for different proxy types.
let options = client.get_targeting_options().await?;get_scraper_data()
Get information about your Scraper API access.
let data = client.get_scraper_data().await?;get_browser_data()
Get information about your Browser API access.
let data = client.get_browser_data().await?;rotate_session(session_id, product)
Force an IP address change for an existing proxy session.
let result = client.rotate_session("abc12345", "rp").await?;
// product: "rpc", "rp", "sdc", "mp"
generate_proxies(product, options)
Generate proxy strings with specific targeting parameters.
use evomi_client::GenerateProxiesOptions;
let proxies = client.generate_proxies("rp", Some(GenerateProxiesOptions {
countries: Some("US,GB,DE".to_string()),
city: Some("New York".to_string()),
session: Some("sticky".to_string()),
amount: Some(10),
protocol: Some("http".to_string()),
lifetime: Some(30),
adblock: Some(true),
..Default::default()
})).await?;
// Returns plain text, one proxy per line
Account Info
get_account_info()
let info = client.get_account_info().await?;
println!("{:?}", info.get("credits_remaining"));Webhooks
Webhooks allow you to receive notifications when scraping operations complete, fail, or start. Supports Discord, Slack, and custom endpoints.
WebhookConfig
use evomi_client::WebhookConfig;
// Discord webhook
let webhook = WebhookConfig::new("https://discord.com/api/webhooks/...")
.webhook_type("discord")
.events(vec!["completed".to_string(), "failed".to_string()]);
// Custom webhook with HMAC signature
let webhook = WebhookConfig::new("https://your-server.com/webhook")
.webhook_type("custom")
.events(vec!["completed".to_string()])
.secret("your-secret-key");Using Webhooks with Scrape
let webhook = WebhookConfig::new("https://discord.com/api/webhooks/...")
.webhook_type("discord")
.events(vec!["completed".to_string(), "failed".to_string()]);
let result = client.scrape("https://example.com", Some(ScrapeOptions {
mode: Some("browser".to_string()),
webhook: Some(webhook),
..Default::default()
})).await?;Using Webhooks with Schedules
let webhook = WebhookConfig::new("https://hooks.slack.com/services/...")
.webhook_type("slack")
.events(vec!["completed".to_string()]);
let schedule = client.create_schedule(
"Daily Monitor",
"cfg_abc123",
1440,
Some(CreateScheduleOptions {
webhook: Some(webhook),
..Default::default()
})
).await?;Proxy String Builder
Evomi provides a proxy network you can use with any HTTP client. Build proxy strings for reqwest or any other library:
Automatic Proxy Configuration
use evomi_client::types::{ProxyType, ProxyProtocol, ProxyBuildOptions};
// Build a proxy string for US residential proxy
let proxy_string = client.build_proxy_string(
ProxyType::Residential,
Some(ProxyBuildOptions::new()
.country("US")
.session("abc12345")
.protocol(ProxyProtocol::Http))
).await?;
println!("{}", proxy_string);
// Output: http://user:[email protected]:1000
Manual Proxy Configuration
use evomi_client::proxy::ProxyConfig;
use evomi_client::types::{ProxyType, ProxyProtocol, ResidentialMode};
let config = ProxyConfig::new()
.proxy_type(ProxyType::Residential)
.protocol(ProxyProtocol::Http)
.country("US")
.city("New York")
.credentials("username", "password");
let proxy_string = config.build_proxy_string();Proxy Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
proxy_type |
ProxyType | Residential |
Type: Residential, Datacenter, Mobile |
protocol |
ProxyProtocol | Http |
Protocol: Http, Https, Socks5 |
country |
String | — | Two-letter ISO country code (e.g., “US”, “DE”) |
city |
String | — | City name (spaces replaced with dots) |
region |
String | — | State/region name |
continent |
String | — | Continent: africa, asia, europe, north.america, oceania, south.america |
isp |
String | — | ISP shortcode (e.g., “att”, “comcast”) |
session |
String | — | Sticky session ID (6-10 alphanumeric chars) |
hardsession |
String | — | Hard session ID (6-10 alphanumeric chars) |
lifetime |
u32 | — | Session duration in minutes (max 120) |
mode |
ResidentialMode | — | Residential mode: Speed, Quality |
Expert Settings
| Parameter | Type | Default | Description |
|---|---|---|---|
latency |
u32 | — | Max latency in ms |
fraudscore |
u32 | — | Max fraud score |
device |
String | — | Device type: “windows”, “unix”, “apple” |
activesince |
u32 | — | Min connection minutes |
asn |
String | — | ASN filter |
zip |
String | — | Zipcode targeting |
http3 |
bool | false |
Enable HTTP3/QUIC |
localdns |
bool | false |
Local DNS resolution |
udp |
bool | false |
UDP support (Enterprise only) |
extended |
bool | false |
Extended pool (cannot combine with other expert filters) |
Proxy Endpoints & Ports
| Type | HTTP | HTTPS | SOCKS5 |
|---|---|---|---|
| Residential | rp.evomi.com:1000 |
rp.evomi.com:1001 |
rp.evomi.com:1002 |
| Datacenter | dcp.evomi.com:2000 |
dcp.evomi.com:2001 |
dcp.evomi.com:2002 |
| Mobile | mp.evomi.com:3000 |
mp.evomi.com:3001 |
mp.evomi.com:3002 |
Proxy String Format
{protocol}://{username}:{password}_{params}@{endpoint}:{port}Example: http://user:[email protected]:1000
Proxy Types
| Type | Endpoint | Use Case |
|---|---|---|
| Residential | rp.evomi.com:1000 |
Human-like browsing, anti-bot bypass |
| Datacenter | dcp.evomi.com:2000 |
Fast, high-volume requests |
| Mobile | mp.evomi.com:3000 |
Highest trust, mobile-specific targets |
Error Handling
use evomi_client::Error;
match client.scrape("https://example.com", None).await {
Ok(result) => println!("{:?}", result),
Err(Error::MissingApiKey) => eprintln!("API key not set"),
Err(Error::HttpError(e)) => eprintln!("HTTP error: {}", e),
Err(Error::JsonError(e)) => eprintln!("JSON error: {}", e),
Err(Error::ApiError(msg)) => eprintln!("API error: {}", msg),
Err(e) => eprintln!("Other error: {}", e),
}Credits & Pricing
All operations consume credits:
| Operation | Cost |
|---|---|
| Base request | 1 credit |
| Browser mode | 5x multiplier |
| Residential proxy | 2x multiplier |
| AI enhancement | +30 credits |
| Screenshot/PDF | +1 credit each |
Credit usage is returned in the result:
println!("{:?}", result.get("_credits_used"));
println!("{:?}", result.get("_credits_remaining"));Requirements
- Rust 1.70+
- Tokio runtime
Resources
| Resource | Link |
|---|---|
| crates.io Package | crates.io/crates/evomi-client |
| Evomi Website | evomi.com |
| API Documentation | docs.evomi.com |
Benefits
- Async/Await — Built on Tokio for async operations
- Full API Coverage — All Evomi endpoints supported
- Type Safe — Strong typing with idiomatic Rust patterns
- Builder Pattern — Ergonomic configuration with builder methods