Skip to main content

manifest-api

Stop guessing selectors. Manifest tells your agent what's clickable, fillable, and submittable on any page.

Python SDK for the Manifest API — extracts structured action manifests from web pages so AI agents know what they can do, not just what's on screen.

Raw browser access Content extraction Manifest
Gives agents a browser ✓ ✗ ✓
Returns page content ✓ ✓ ✓
Returns available actions ✗ ✗ ✓
Required fields, input types ✗ ✗ ✓
Survives UI redesigns ✗ ✓ ✓

Install

pip install manifest-api

Quickstart

Sync

from manifest_api import ManifestClient

client = ManifestClient(api_key="your-key")  # or set MANIFEST_API_KEY env var
manifest = client.get("https://example.com")

print(manifest.current_page_state)
print(manifest.actions)

# Convenience helpers
action = manifest.action("submit-form")
inputs = manifest.actions_of_type("input")
required = manifest.required_actions

# Cheap structural-change check (no LLM call, never cached)
fp = client.fingerprint("https://example.com")
print(fp.fingerprint)

Async

import asyncio
from manifest_api import AsyncManifestClient

async def main():
    async with AsyncManifestClient(api_key="your-key") as client:
        manifest = await client.get("https://example.com")
        print(manifest.current_page_state)

asyncio.run(main())

LangChain

pip install "manifest-api[langchain]"
from manifest_api.integrations.langchain import create_manifest_tool

tool = create_manifest_tool()  # reads MANIFEST_API_KEY from env
# or: create_manifest_tool(api_key="...")

# use with an agent, e.g.:
from langchain.agents import create_agent
agent = create_agent(model=..., tools=[tool])

create_manifest_tool wraps AsyncManifestClient as a get_manifest(url) StructuredTool — the API key is bound at creation time, so the LLM never sees it.

All methods

# Both ManifestClient and AsyncManifestClient expose:
manifest = client.get("https://example.com")          # POST /manifest → Manifest
manifest = client.get("https://example.com", country="US")  # POST /manifest → Manifest, Accept-Language: en-US,en;q=0.9
fp       = client.fingerprint("https://example.com")  # POST /fingerprint → Fingerprint
health   = client.health()                             # GET  /health → dict
valid    = client.session_valid()                      # GET  /session-status → bool

Manifest helpers

manifest.action("id")              # → Action | None
manifest.actions_of_type("input")  # → list[Action]
manifest.required_actions          # → list[Action]
manifest.blocked_actions([...])    # → list[Action], see "Action dependencies" below
manifest.fingerprint               # → str | None, same hash `fingerprint()` returns

Fingerprint

fingerprint(url) runs the same page-render + extraction pipeline as get(url) but skips the LLM translation step, returning just a stable hash of the page's interactive surface (Fingerprint.fingerprint). Useful for cheaply polling whether a page's action surface has changed since your last get() call, without paying for another manifest generation. Every Manifest also carries this same hash on manifest.fingerprint, so you can compare it against a later fingerprint() call directly.

fp = client.fingerprint("https://example.com")
print(fp.url, fp.fingerprint)

Geo/locale

manifest = client.get("https://example.com", country="US")  # ISO 3166-1 alpha-2
print(manifest.requested_country, manifest.served_locale, manifest.locale_mismatch)

country sets the scan's Accept-Language header to steer server-side geo/locale redirects (e.g. a store redirecting to a different country's pricing). This is a first attempt, not a guarantee — some sites geo-route on IP and ignore Accept-Language entirely, no proxy routing yet. Check manifest.locale_mismatch: True means a country was requested and the page actually captured (manifest.served_locale, best-effort from the URL) didn't match — an honest flag, not corrected pricing/currency data.

Action dependencies

Some actions are disabled until others are completed (e.g. a submit button gated on required fields). Action.requires lists the ids of actions that must be completed first; blocked_actions() filters a manifest down to actions not yet unblocked by a given set of completed ids:

completed = ["email-input"]
still_blocked = manifest.blocked_actions(completed)  # actions still waiting on something

requires is inferred by the LLM translation step from DOM signals (disabled attributes, aria-disabled, form field proximity) — it's best-effort, not a guaranteed-accurate dependency graph, and won't capture custom JS validation logic.

Action types

button · input · textarea · select · checkbox · radio · other

Locators

Each action may carry a locator with css, role, and name — enough to find and act on the underlying element without guessing a selector yourself. It's best-effort: locator is None if no element on the page plausibly matched the action.

Prefer role/name over css where possible — they hold up better across redesigns, since css can be a brittle positional fallback when the element has no id or name attribute.

action = manifest.action("continue")
if action.locator and action.locator.css:
    page.click(action.locator.css)

Error handling

from manifest_api import AuthenticationError, RateLimitError, APIError

try:
    manifest = client.get("https://example.com")
except AuthenticationError:
    print("Check your API key")
except RateLimitError:
    print("Slow down — rate limit hit")
except APIError as e:
    print(f"Server error {e.status_code}")

Docs

https://omfang.io/manifest-docs

Metadata

Release files for manifest-api 0.3.0

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

Source distribution (sdist)

Source distribution for manifest-api 0.3.0
File Size Uploaded
manifest_api-0.3.0.tar.gz 9.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for manifest-api 0.3.0
File Interpreter ABI Platform
manifest_api-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.1 kB

Release files / manifest_api-0.3.0.tar.gz

Download URL manifest_api-0.3.0.tar.gz
Size 9.5 kB
Tags Source
SHA-256 checksum
How to use checksums
fde93635c0403fc9e24dca30cf3e9d41db8e6764373844f7c8a4a7bdecd0e211
BLAKE2b-256 checksum
How to use checksums
833f763203b3d37c1101b6884e544187433acc90053f2c45deeeda3e6bcad931
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.1

Release files / manifest_api-0.3.0-py3-none-any.whl

Download URL manifest_api-0.3.0-py3-none-any.whl
Size 8.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74767f1cece8de6387d72ce39518d87d53dc0a27b39946ef3b6505c3f54c1b83
BLAKE2b-256 checksum
How to use checksums
96f61677979ba78c6128a31e70c7b1bf1157be6518af09e748d58f10d20b910e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.1

Release history Release notifications | RSS feed

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

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