Skip to main content

spn-client

A hardened Python client for archive.org's availability API and Save Page Now (SPN2) — the pieces that are easy to get wrong when you actually run this against archive.org at any volume:

  • Process-wide rate pacing with a circuit breaker. archive.org throttles per IP, not per thread or per endpoint. A naive per-thread backoff (or none at all) looks fine in testing and then silently stops archiving anything the first time it's run concurrently or against a busy queue.
  • Both submission modes. Anonymous GET /save/<url> (capture runs inline, answer comes back as a redirect) and S3-key-authenticated POST /save (capture is queued, answer comes back as a job_id you poll for).
  • An explicit outcome vocabulary. submitted is not archived. This library only ever reports archived: True alongside a real snapshot URL that came back from archive.org — never as a synonym for "we asked."
  • Staleness checking, so callers can skip re-archiving a URL that already has a recent-enough snapshot.
  • Submissions are paced and breaker-protected too, at archive.org's own documented capture-endpoint limits (7/min authenticated, 3/min anonymous) — not just the availability check.
  • Categorized capture failures. archive.org's SPN2 API documents ~30 specific error codes; check_job_status() sorts each into "permanent" (retrying won't help), "transient" (worth trying again), or "quota_exhausted" (back off the whole run, not just this URL) via categorize_job_error().
  • The rest of the documented capture options, exposed as optional keyword arguments on submit(): screenshots, outlink availability, skipping the first-capture check, JS render timeout, login credentials for pages behind a form, a cookie for the target page, a custom capture User-Agent, and delayed Wayback availability.
  • A default timeout that matches archive.org's own documented capture ceiling (2 minutes) rather than an arbitrary short one, so a slow-but-legitimate anonymous capture doesn't get reported as failed when archive.org would have finished it given more time.

Every non-obvious piece of behavior in client.py is a documented response to a specific, dated, measured incident against the real archive.org API — not a guess.

Install

pip install spn-client

Usage

import spn_client

result = spn_client.check("https://example.com/some-page")
if result["archived"] is False or result.get("snapshot_stale"):
    submission = spn_client.submit(
        "https://example.com/some-page",
        access_key=ACCESS_KEY,   # optional — omit for anonymous, lower-rate submission
        secret_key=SECRET_KEY,
    )
    if submission["job_id"]:
        # authenticated path: poll for the real outcome
        status = spn_client.check_job_status(
            submission["job_id"], access_key=ACCESS_KEY, secret_key=SECRET_KEY
        )

Call spn_client.reset_rate_limit_state() once at the start of each independent run/process if you're running this as a long-lived worker — the pacing/breaker state is process-wide and intentionally does not reset itself, so a breaker tripped by one run would otherwise silently degrade the next.

Handling a failed capture

status = spn_client.check_job_status(job_id, access_key=ACCESS_KEY, secret_key=SECRET_KEY)
if status["state"] == "failed":
    category = status["retry_category"]  # "permanent" / "transient" / "quota_exhausted" / None
    if category == "quota_exhausted":
        ...  # stop submitting new URLs this run, not just this one
    elif category != "permanent":
        ...  # worth another attempt later (also covers the unknown/None case)

Optional capture options

spn_client.submit(
    url,
    access_key=ACCESS_KEY, secret_key=SECRET_KEY,
    capture_screenshot=True,       # -> status["screenshot_url"] once the job succeeds
    outlinks_availability=True,    # -> status["outlinks"]
    skip_first_archive=True,
    js_behavior_timeout=15,        # seconds, 0-30 (archive.org's default is 5)
    target_username="user", target_password="pass",  # pages behind a login form
    capture_cookie="session=abc123",  # a cookie sent to the *target page*, not archive.org
    use_user_agent="MyBot/1.0",       # what archive.org's capture bot presents to the target site
    delay_wb_availability=True,       # capture is visible in Wayback ~12h later instead of immediately
)

Cookie-based session auth to archive.org itself (the alternative to an S3 key pair) is not supported — this client only authenticates with S3 keys, which archive.org's own docs call "highly preferable" anyway. Don't confuse that with capture_cookie above, which is unrelated: a cookie sent to whatever page you're asking archive.org to capture, not to archive.org.

What this doesn't do

This is the archive.org client only — it has no opinion about:

  • What staleness policy is right for your use case (stale_days is always a caller-supplied parameter)
  • How you track which URLs you've already archived (that's a caller-side ledger/cache concern)
  • Batch-loop concerns like a progress heartbeat or a wall-clock budget across many submissions — those depend on your own operational needs

License

MIT

Metadata

Release files for spn-client 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spn-client 0.3.1
File Size Uploaded
spn_client-0.3.1.tar.gz 41.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for spn-client 0.3.1
File Interpreter ABI Platform
spn_client-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 69.7 kB

Release files / spn_client-0.3.1.tar.gz

Download URL spn_client-0.3.1.tar.gz
Size 41.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2d6d9d32770a9555d455bb068838b201d74fb311fb55a4047746cded7f6aa89b
BLAKE2b-256 checksum
How to use checksums
7a7f0997dbbad78b677b028d7bb197a12c787af220260f96f7393205d11770e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / spn_client-0.3.1-py3-none-any.whl

Download URL spn_client-0.3.1-py3-none-any.whl
Size 27.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b541abedddafce06a73370f9625dd69da121a2265ed851617d029e6abcec006b
BLAKE2b-256 checksum
How to use checksums
d332913f1a238e4ac241fa80b326754039b2e865e72569c3399105a3a8fa3e15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page