bulkurlchecker
[PyPI version]
[Python versions]
[License: MIT]
Python client for the Bulk URL Checker API.
Skip the proxy-rotation, rate-limiter, soft-404 detector, and retry classifier you would otherwise spend two weeks building. Submit thousands of URLs, get status codes, redirect chains, and broken-link detection back as plain Python objects. Backed by a managed cloud service with residential proxies and per-domain throttling.
Install
5-line example
Get an API key at https://app.bulkurlchecker.com/dashboard/api-keys. First 300 URLs are free, no card required.
What you get back
Command-line usage
Install with the [cli] extra to get the bulkurlchecker command:
Output formats: csv (default), json, jsonl. Run bulkurlchecker check --help for the full flag list.
Larger jobs: submit and poll
check_urls() blocks for up to 15 minutes server-side. For lists where the wait would time out, use the two-step pattern:
Safe retries with idempotency_key
Pass an idempotency key on submit() or check_urls() to make retries safe under network failures. The server caches the response for 24 hours; a retry with the same key + same body returns the original result without creating a duplicate job.
Same idempotency_key + different urls returns 409 Conflict (raised as ValidationError) so client bugs that reuse a key against a new payload are caught loudly instead of silently mapping to the wrong cached response.
Receiving webhooks
When a job finishes, we POST to your registered endpoint with a signed payload. Verify the signature before trusting the body — anyone who knows your endpoint URL can otherwise send fake events.
Register endpoints + get secrets at https://app.bulkurlchecker.com/dashboard/webhooks (or via POST /api/v2/webhooks/endpoints).
verify_signature() enforces a 5-minute timestamp tolerance by default to defeat replays. Tune via tolerance_seconds=.
Error handling
All errors derive from BulkURLCheckerError. Catch specific subclasses when you want to branch on the failure mode:
Every error carries status_code, code (server's machine-readable string), request_id (for support), and details (when the server provides them).
Why use this instead of writing your own checker with httpx + asyncio?
Honest answer: for ≤500 URLs you don't need this. The standard requests/httpx toolchain handles it fine.
The wall hits at scale:
If you've already lost a weekend to httpx + proxy rotation, you know what we're talking about.
Pricing
- First month on us: 15,000 URL checks on the Starter plan, no credit card.
The first time an API or SDK integration runs successfully, the trial grows
to a month of Pro: 50,000 URL checks, once per account.
- After that: 300 URL checks a month are included on every account.
- Starter: $9/month or $90/year, 15,000 URLs/month
- Pro: $29/month or $290/year, 50,000 URLs/month
- Agency: $99/month or $990/year, 200,000 URLs/month
Scheduled checks, with email, Slack and webhook alerts, are included on every
plan. One-time credit packs start at $5 for 3,000 checks, and pack credits
roll over. Current prices: https://bulkurlchecker.com/#pricing
Links
Stability
The SDK follows semver. While we're at 0.x, breaking changes can land in minor releases (we'll always note them in CHANGELOG.md). Once we hit 1.0 you can pin major versions safely.
License
MIT. See LICENSE.