Installation
Get your API key from app.spidra.io under Settings > API Keys.
Store it as an environment variable. Never hardcode it.
Getting started
spidra, client, or whatever fits your codebase — the method names stay the same.
If you’re inside an existing async context (FastAPI, asyncio, Jupyter notebook), use
AsyncSpidra instead and await the calls. The method signatures are identical.Scraping
The scraper accepts up to three URLs per request and processes them in parallel. You can pass a URL string directly, or aScrapeParams object for full control.
The simplest call:
start_scrape() returns a job ID immediately. You can then call get_scrape() whenever you’re ready to check:
queued → waiting → active → completed (or failed).
Scrape parameters
Enforcing an exact output shape
Without a schema the AI extracts what it finds. With a schema, missing fields come back asNone rather than guessed values, which matters when the output feeds a database or a typed pipeline downstream:
Enforcing shape with Pydantic
If you already model your data with Pydantic, skip the JSON Schema entirely — pass the model itself (class or instance) and the SDK converts it for you:batch_scrape() and crawl() (applied per page). Pydantic stays optional — install it with pip install spidra[pydantic] only if you use this. Both v2 and v1 models are supported.
Scraping geo-restricted content
Some sites serve different prices or content depending on where you’re browsing from. Setuse_proxy=True and a proxy_country code to route through a residential IP in that country:
us, gb, de, fr, jp, au, ca, br, in, nl, and 40+ more. Use "global" or "eu" for regional routing without pinning to a specific country.
Scraping pages behind a login
If the page requires a session, pass your cookies as a raw header string. The easiest way to get this is to log in through your browser, open devtools, and copy theCookie header from any authenticated request:
Browser actions
Sometimes you need to interact with the page before extraction — dismiss a cookie banner, type into a search box, scroll to load lazy content. Pass anactions list inside the ScrapeUrl and they run in order before the AI sees the page:
selector you can pass a CSS selector or XPath. If you’d rather describe the element in plain English, use value and Spidra will locate it with AI.
Controlling how long scrape() waits
By defaultscrape() polls every 3 seconds and waits until the job finishes, however long that takes. If you’d rather cap the wait, pass a timeout in seconds — when it fires, SpidraTimeoutError is raised and the job keeps running server-side, so you can check it later with get_scrape() or cancel it:
batch_scrape() and crawl().
Batch scraping
When you have a list of URLs to process, batch is the right tool. You can submit up to 50 URLs in a single request and they all run in parallel.pending → running → completed (or failed).
If you don’t want to wait for the whole thing to finish, use start_batch_scrape() and get_batch_scrape() separately:
Retrying failures and cancelling
Crawling
Crawling is different from scraping. You give it a starting URL and it discovers and processes pages on its own, following links according to your instructions. Good for indexing a docs site, monitoring a competitor’s blog, or building a structured dataset from an entire section of a site.crawl_instruction tells the crawler which links to follow. transform_instruction tells the AI what to extract from each page. By default the call waits until the crawl finishes — pass timeout=<seconds> to bound the wait (the job keeps running server-side if it fires).
Raw content mode
Omit bothtransform_instruction and schema to get the raw page content without any AI processing. Each page’s data field contains the plain markdown of that page — no token credits are charged:
Structured output with schema
When you need every page to return the same fields in the same format, useschema. The AI returns JSON matching it exactly for every page:
Scoped crawling with path filters
Useinclude_paths and exclude_paths to keep crawls focused on the content you actually need. Both accept glob-style patterns:
Crawl parameters
Submitting without waiting
Just like scraping, you can fire-and-forget withstart_crawl() and poll with get_crawl():
Cancelling a crawl
Cancel a queued or running job at any time. Pages already processed are kept:Downloading the raw HTML and Markdown
Once a crawl completes,crawl_pages() returns signed download URLs for the raw HTML and Markdown of every page. These links expire after one hour:
Re-extracting with a different prompt
If you crawled a site and want to pull out different information, you don’t have to re-crawl.crawl_extract() runs a new AI pass over the already-crawled content and charges only transformation credits:
Browsing your crawl history
Watching jobs (streaming results)
A 50-page crawl can take a while. Instead of waiting for the whole thing,watch_crawl() yields each page the moment it’s crawled — perfect for writing results to a database as they arrive or updating a progress bar:
watch_batch() yields each item as it finishes (completed or failed):
AsyncSpidra these are async generators — same names, just async for. Every page/item is yielded exactly once, including ones that finished before you started watching, and page content is only re-fetched when the crawl actually makes progress, so watching stays cheap. The loop ends when the job completes or is cancelled, raises SpidraJobFailedError if it fails, and breaking out early never cancels the job — use cancel_crawl() for that.
Logs
Every scrape request your API key makes gets logged automatically. You can filter by status, URL, date range, or where it came from:Usage statistics
Check how many requests and credits your account has used over a given period:Retries and reliability
You don’t have to write retry loops. Transient failures — network blips, 502/503/504 gateway errors — are retried automatically with exponential backoff, so a single hiccup never fails your call. Both knobs are configurable:Retry-After hint, the SDK honors it instead of its own backoff.
Error handling
Every API error is mapped to a typed exception class, so you can catch exactly what you care about and let the rest bubble up:
All exceptions expose
.status (the HTTP status code, or 0 for non-HTTP errors like job failures and timeouts) and .message. API errors also carry .code (a machine-readable identifier like SERVICE_BUSY) and .details (the raw error body).
Verifying webhooks
Crawl jobs can pushcrawl.page, crawl.completed, and crawl.failed events to your webhook_url. Spidra signs each delivery with HMAC-SHA256 in the X-Spidra-Signature header, and the SDK ships a helper so you never accept a forged event:
Ruby
Official Ruby SDK — pure stdlib, no external dependencies. Works in Rails, Sinatra, and scripts.
Elixir
Official Elixir SDK — idiomatic pattern matching, OTP-ready, works with Phoenix and plain Mix projects.

