Turn web pages into structured data and change events — extract, search, crawl, monitor, and get webhook notifications when pages change.
Project description
FlyPython SDK
The Python-first web runtime for agents.
Search, extract, crawl, monitor, and interact with any website. Structured data ready for LLMs.
Installation
pip install flypython
CLI
export FLYPYTHON_API_KEY=fp_your_key_here
flypython monitor https://example.com/pricing \
--schema '{"price":"number"}' \
--schedule '0 */6 * * *'
flypython extract https://example.com --schema '{"title":"string"}'
flypython search "competitor pricing changes" --limit 5
flypython tasks --status active
For async support:
pip install flypython[async]
Quick Start
import flypython
# Set your API key
export FLYPYTHON_API_KEY=fp_your_key_here
# Extract structured data from any URL
result = flypython.extract(
url="https://example.com/product",
schema={"title": "string", "price": "number", "rating": "number"}
)
print(result.data)
# { "title": "...", "price": 29.99, "rating": 4.5 }
# Search the web
results = flypython.search("best mechanical keyboards 2025")
for r in results:
print(r.title, r.url, r.snippet)
# Crawl multiple pages
result = flypython.crawl(
url="https://example.com",
max_pages=10,
schema={"title": "string", "description": "string"}
)
# Capture a screenshot
screenshot = flypython.screenshot("https://example.com")
print(screenshot.screenshot.image_url)
# Monitor a page for changes
task = flypython.monitor(
url="https://example.com/price",
schema={"price": "number"},
webhook="https://myapp.com/webhooks/price",
schedule="0 */6 * * *" # Every 6 hours
)
print(task.id)
Client Usage
Sync Client
from flypython import FlyPythonClient
client = FlyPythonClient(api_key="fp_your_key_here")
# Extract
result = client.extract(url="https://example.com", schema={"title": "string"})
# Search
results = client.search("python tutorials")
# Crawl
result = client.crawl(url="https://example.com", max_pages=5)
# Screenshot
screenshot = client.screenshot("https://example.com")
# Browser actions + extraction in one session
result = client.interact(
url="https://example.com/product",
actions=[{"type": "wait", "ms": 1000}],
extract={"price": ".price"}
)
# AI-assisted selector suggestion
suggestion = client.suggest_template(
"Watch this product page for price and stock changes",
url="https://example.com/product"
)
# Status history
history = client.get_status_history(task_id="task-uuid", limit=30)
# API keys
keys = client.list_api_keys()
new_key = client.create_api_key(
name="Production Key",
scopes=["tasks:read", "tasks:write", "extract:run"],
usage_limit=10000,
ip_whitelist="203.0.113.0/24"
)
client.revoke_api_key("key-uuid")
Async Client
import asyncio
from flypython import AsyncFlyPythonClient
async def main():
async with AsyncFlyPythonClient(api_key="fp_your_key_here") as client:
result = await client.extract(url="https://example.com")
print(result.data)
tasks = await client.list_tasks()
for t in tasks:
print(t.name, t.status)
task = await client.monitor(
url="https://competitor.com/pricing",
schema={"price": "number"},
notify={"slack": "https://hooks.slack.com/services/..."},
)
print(task.id)
asyncio.run(main())
Media Download
Download images and videos during extraction:
# Get image URL only (default)
result = flypython.extract(
url="https://example.com/product",
schema={"image": "image_url"}
)
print(result.data["image"]) # "https://example.com/product.jpg"
# Download image as base64
result = flypython.extract(
url="https://example.com/product",
schema={"image": "image_url"},
download_images=True
)
print(result.data["image"]["data"]) # base64 string
print(result.data["image"]["mime_type"]) # "image/jpeg"
# Save media files to disk
result = flypython.extract_with_media(
url="https://example.com/product",
schema={"image": "image_url"},
download_images=True,
save_media=True,
output_dir="./downloads"
)
# Saved 1 media files to ./downloads
Task Management
Full CRUD for monitor tasks:
# Create a task
task = flypython.create_task(
name="Competitor Price Monitor",
target_url="https://competitor.com/product",
mode="monitor",
selectors={"price": ".price", "title": "h1"},
schedule_cron="0 */6 * * *",
destinations=[{"type": "webhook", "config": {"url": "https://hooks.example.com/flypython"}}],
)
# List all tasks
tasks = flypython.list_tasks(status="active")
# Get a specific task
task = flypython.get_task(task.id)
# Update task
flypython.update_task(task.id, status="paused")
# Run immediately
run = flypython.run_task(task.id)
# Inspect or export a run
run_detail = flypython.get_run(run["run_id"])
rows = flypython.get_run_data(run["run_id"])
csv_text = flypython.export_run(run["run_id"], format="csv")
# Delete task
flypython.delete_task(task.id)
Change Detection (Diffs)
# List all detected changes
diffs = flypython.list_diffs(change_type="price_drop", limit=10)
for d in diffs.diffs:
print(d.summary, d.confidence)
# Get specific diff detail
diff = flypython.get_diff("diff-uuid")
print(diff.field_changes)
# Compare two snapshots locally (no API call)
diff = flypython.compare_snapshots(before={"price": "100"}, after={"price": "90"})
print(diff.change_type) # "price_change"
Snapshots
# List snapshots for a task
snapshots = flypython.list_snapshots(task_id="task-uuid", limit=5)
# Get the most recent snapshot
latest = flypython.get_latest_snapshot(task_id="task-uuid")
print(latest.extracted_json)
Billing
# Check balance
balance = flypython.get_balance()
print(balance.balance_display) # "$5.00"
print(balance.free_calls_remaining) # 95
# Check usage
usage = flypython.get_usage()
print(usage.estimated_cost_display)
# List transactions
transactions = flypython.list_transactions(limit=10)
# Get pricing
options = flypython.get_top_up_options()
for p in options.pricing:
print(p.operation, p.display)
Alerts
# List alerts
alerts = flypython.list_alerts(limit=20)
for a in alerts:
print(a.task_name, a.alert_type, a.severity)
# Acknowledge an alert
flypython.acknowledge_alert("alert-uuid")
Templates
# List official templates
templates = flypython.list_templates()
# Include community templates
templates = flypython.list_templates(include_community=True)
# Get a specific template
template = flypython.get_template("amazon-product")
print(template.selectors)
# Create a community template
template = flypython.create_template(
id="generic-price",
name="Generic Price",
selectors={"price": ".price", "title": "h1"},
sample_url="https://example.com/product"
)
# Admin-only approval, and owner/admin delete
flypython.approve_template("generic-price")
flypython.delete_template("generic-price")
Browser Interaction and Selector Suggestions
# Browser Rendering supports wait, click, type, scroll, select, and extraction.
result = flypython.interact(
url="https://example.com/product",
actions=[{"type": "wait", "ms": 1000}],
extract={"price": ".price", "stock": ".stock"}
)
suggestion = flypython.suggest_template(
"Monitor this product page for price and stock",
url="https://example.com/product"
)
print(suggestion["suggested_selectors"])
API Keys, Status, and Account Data
keys = flypython.list_api_keys()
new_key = flypython.create_api_key(
name="CI",
scopes=["tasks:read", "tasks:write", "extract:run"],
usage_limit=10000,
)
flypython.revoke_api_key(new_key["id"])
history = flypython.get_status_history(task_id="task-uuid", limit=30)
print(history.days)
exported = flypython.export_account_data()
# Guarded because this disables the user and active API keys.
flypython.delete_account(confirm=True)
Webhook Verification
FlyPython signs webhooks with an X-FlyPython-Signature: t=<timestamp>,v1=<hex>
header. The digest is HMAC-SHA256(secret, "<timestamp>.<raw_body>") over the
exact raw request bytes. Verify it with:
from flypython import verify_webhook
signature = request.headers.get("X-FlyPython-Signature", "")
is_valid = verify_webhook(
payload=request.body, # raw bytes, exactly as received
signature=signature, # "t=1700000000,v1=abc123..."
secret="whsec_your_webhook_secret",
tolerance=300, # max signature age in seconds; 0 skips the check
)
Both FlyPythonClient.verify_webhook and AsyncFlyPythonClient.verify_webhook
share this signature. Pass tolerance=0 to disable the replay/freshness check.
Error Handling
API errors raise subclasses of flypython.FlyPythonError. Each error carries
status_code and detail (the server's {"detail": "..."} message), and the
sync and async clients raise the same classes:
| Exception | HTTP status | Notes |
|---|---|---|
AuthenticationError |
401 | Bad credentials, or API-key auth on a dashboard-only endpoint |
InsufficientBalanceError |
402 | Prepaid balance too low for the call |
RateLimitError |
429 | retry_after holds the Retry-After seconds (or None) |
ValidationError |
400 | Request failed server-side validation |
NotFoundError |
404 | Resource does not exist |
ServerError |
5xx | Server-side failure |
FlyPythonError |
any other | Base class — catch it to handle every API error |
import flypython
from flypython import InsufficientBalanceError, RateLimitError
try:
result = flypython.extract(url="https://example.com")
except InsufficientBalanceError as e:
print("Please top up:", e.detail)
except RateLimitError as e:
print("Rate limited, retry in", e.retry_after, "seconds")
Retries
Both clients retry 429 and 5xx responses, up to max_retries extra
attempts (default 2, i.e. 3 attempts total; 0 disables retries). On 429
the server's Retry-After header is honored (capped at 30 seconds); otherwise
exponential backoff (0.5 * 2**n seconds plus jitter) is used.
from flypython import FlyPythonClient, AsyncFlyPythonClient
client = FlyPythonClient(api_key="fp_...", max_retries=4)
async_client = AsyncFlyPythonClient(api_key="fp_...", max_retries=0)
top_up and convert_credits are never retried, so a payment-style
operation is never submitted twice.
Dashboard-JWT-Only Methods
The following methods call endpoints that only accept a dashboard session
JWT. The backend rejects API-key auth on them with 401
(AuthenticationError) — this is by design. Use them with a session token
from the dashboard, not an fp_... API key:
- Workspaces:
list_workspaces,list_workspace_members,invite_member,remove_member - API keys:
list_api_keys,create_api_key,revoke_api_key - Account / GDPR:
export_account_data,delete_account - Billing:
top_up,convert_credits
API Reference
Core Functions
| Function | Description |
|---|---|
extract(url, schema, ...) |
Extract structured data from a URL |
extract_with_media(url, ...) |
Extract and save media files |
search(query, limit, format) |
Search the web |
crawl(url, max_pages, ...) |
Crawl multiple pages |
screenshot(url, ...) |
Capture webpage screenshot |
interact(url, actions, extract, wait_for, timeout) |
Load a rendered page and extract fields |
suggest_template(description, url) |
Suggest monitor selectors |
health() / ready() |
Check API health/readiness |
monitor(url, schema, template, notify, webhook, slack_webhook, email, webhook_secret, schedule, name) |
Create a monitoring task (shorthand) |
Task Management
| Function | Description |
|---|---|
create_task(name, target_url, ...) |
Create a monitor task |
list_tasks(status, limit) |
List tasks |
get_task(task_id) |
Get task by ID |
update_task(task_id, **fields) |
Update task |
delete_task(task_id) |
Delete task |
run_task(task_id) |
Trigger execution |
reset_task(task_id) |
Reset paused task |
list_task_runs(task_id, limit) |
List execution history |
get_run(run_id) |
Get run detail |
get_run_data(run_id) |
Get extracted run rows |
export_run(run_id, format) |
Export run data as JSON or CSV text |
Diffs & Snapshots
| Function | Description |
|---|---|
list_diffs(task_id, change_type, ...) |
List detected changes |
get_diff(diff_id) |
Get diff details |
compare_snapshots(before, after) |
Local snapshot comparison |
list_snapshots(task_id, limit) |
List snapshots |
get_latest_snapshot(task_id) |
Get most recent snapshot |
Billing & Alerts
| Function | Description |
|---|---|
get_balance() |
Get prepaid balance |
get_usage() |
Get monthly usage |
list_transactions(limit) |
List transactions |
get_subscription() |
Get plan status |
get_top_up_options() |
Get pricing info |
convert_credits(credits) |
Convert credits to balance |
list_alerts(task_id, limit) |
List alerts |
acknowledge_alert(alert_id) |
Acknowledge alert |
API Keys & Status History
| Function | Description |
|---|---|
list_api_keys() |
List API keys |
create_api_key(name, scopes, usage_limit, ip_whitelist) |
Create API key |
revoke_api_key(key_id) |
Revoke API key |
get_status_history(task_id, url, from_time, to_time, limit) |
Daily aggregated run history |
export_account_data() |
Export current user's account data |
delete_account(confirm=True) |
Schedule account deletion |
Templates & Delivery
| Function | Description |
|---|---|
list_templates(category, include_community) |
List templates |
get_template(template_id) |
Get template |
create_template(id, name, selectors, ...) |
Create community template |
approve_template(template_id) |
Approve community template (admin) |
delete_template(template_id) |
Delete community template |
list_delivery_logs(task_id, ...) |
List delivery logs |
retry_delivery(log_id) |
Retry failed delivery |
Utilities
| Function | Description |
|---|---|
verify_webhook(payload, signature, secret) |
Verify HMAC signature |
REST API
The SDK uses the FlyPython REST API under the hood. You can also call the API directly:
curl -X POST https://api.flypython.com/v1/extract \
-H "Authorization: Bearer fp_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"schema": {"title": "string"}
}'
See API Documentation for more details.
Requirements
- Python 3.9+
requests>=2.28.0pydantic>=2.0.0httpx>=0.25.0(for async client)
Testing
cd sdk
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
pytest
License
MIT
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flypython-0.3.1.tar.gz.
File metadata
- Download URL: flypython-0.3.1.tar.gz
- Upload date:
- Size: 42.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dfba8f43380553f12a48baeb2aaa21a815b1d6e84f7bb7ee4fc39f2fe80e144
|
|
| MD5 |
5d50112168685c1561cf92eb2a26ae5c
|
|
| BLAKE2b-256 |
b7a2a98d2ca60670b0919c7fa4d5a09ba24c96447df87fa44fe1dc3b7ea68aaa
|
File details
Details for the file flypython-0.3.1-py3-none-any.whl.
File metadata
- Download URL: flypython-0.3.1-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ebe2a8fc2555d8f512869f88f88c4aca8dabcdc3263cf2e5bf6ea2e0e329981
|
|
| MD5 |
6a8d82b0ccb9f631b73209b18b4511b5
|
|
| BLAKE2b-256 |
59e34769a84fc5487b24c733e4f9bde9303a16a5963cf44e115bc419d024cca8
|