IIIF Publication Preflight avatar

IIIF Publication Preflight

Pricing

$0.05 / useful iiif report

Go to Apify Store
IIIF Publication Preflight

IIIF Publication Preflight

Experimental bounded IIIF Presentation 3 image-resource and metadata diagnostics attributed to canvases.

Pricing

$0.05 / useful iiif report

Rating

0.0

(0)

Developer

L3Digital

L3Digital

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

4 hours ago

Last modified

Categories

Share

Get an experimental dependency report for one IIIF Presentation 3 Manifest with embedded annotation pages. The report joins HTTP, CORS and limited Image API metadata observations to the affected canvases. Use it to locate missing or restricted image dependencies and metadata problems before investigating them in a viewer. It does not check image pixels, viewer behavior or full IIIF conformance.

Use from an AI agent through MCP

Add this URL to a client that supports remote HTTP MCP, then authorize with your own Apify account using the Apify MCP setup guide:

https://mcp.apify.com/?tools=l3digital/iiif-publication-preflight

This configuration selects the Actor directly. Availability still depends on Apify account and Actor eligibility. Call l3digital/iiif-publication-preflight with the example input below; this page's pricing and input restrictions apply.

When using call-actor, its response contains run status and storage IDs. If the run is still active, check that run with get-actor-run. After success, retrieve the report with get-dataset-items using the returned dataset ID (defaultDatasetId in the run API). These retrieval tools load with the Actor. Retrieve the existing result instead of starting another run, which can incur another report charge. Inspect coverage, resource access, robots and diagnostics before using the observations.

Input

Submit one public HTTPS manifest URL. Optionally supply the HTTPS origin of your viewer to observe credentialless CORS responses for that origin.

For a public reference example, use:

{
"manifestUrl": "https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json",
"viewerOrigin": "https://example.org"
}

This example uses the IIIF Cookbook's rights recipe, credited to Glen Robson, IIIF Technical Coordinator, under CC BY-SA 3.0. A hosted owner check of this reference produced complete coverage for three resources, with four HTTP attempts including robots, allowed CORS for the supplied origin and valid ImageService3 metadata. These are reference observations, not institutional coverage, visual validation or IIIF endorsement. Future responses can change. A complete useful report from this example qualifies for the $0.05 charge described below; it is not a free hosted demo.

manifestUrl must be caller-authorized public HTTPS without credentials, query, fragment or a custom port. viewerOrigin is optional and must be an HTTPS origin without an application path. Runtime validation rejects unsafe DNS answers and checks robots before each resource/redirect. No cookies, credentials or environment proxy settings are sent. DNS resolution failure is inconclusive (dns_unresolved); private or mixed DNS answers are refused. Origin robots policies and acquisition failures are cached for one report, preserving the first diagnosis without repeated failed attempts. Requests identify as IIIFPublicationPreflight. Robots groups match case-folded prefixes of the product token before any /version; suffix/version substrings do not override wildcard policy. Robots decoding accepts a leading UTF-8 BOM and refuses invalid UTF-8. Empty Allow/Disallow directives end a group's user-agent list. This intentionally corrects earlier handling that could merge an empty wildcard Disallow group with the following unrelated bot's deny rules; those unrelated rules no longer apply to this Actor. Both group orders preserve the bot-specific policy. Applicable Crawl-delay or Request-rate declarations make a source unsupported for acquisition: this bounded Actor has no pacing scheduler. It conservatively refuses protected requests for any declared value, including zero, empty or malformed values. These extensions are not mandatory RFC 9309 directives; this refusal honors the Actor's stronger source-policy contract. Only the selected most-specific groups, including ties, impose this restriction; unrelated bot groups and overridden wildcard groups do not. Robots reads are still permitted. The report is partial, with resource robots: unknown, access: refused and robots_pacing_unsupported in diagnostics; the refused source's manifest or dependency is not contacted. Cached origins and redirect destinations receive the same check. These partial reports do not charge a report event. Use only sources you are authorized to inspect; public availability and robots permission do not grant reuse rights. Confirm the source's terms and your intended use before submitting a manifest. The reference example's license does not grant permission to inspect or reuse material from other sources.

Output and interpretation

The Actor writes one default dataset row and the same JSON to the default key-value store's OUTPUT record. Open either output after the run to read the report. Resources are deduplicated by URL and method; each retains source-order canvasIds. Images receive HEAD only. Root manifests, service info.json and robots receive bounded GET. HTTP 200 proves neither decodable image content nor correct tiles, pixels or viewer behavior. Image API metadata checks only the documented subset: object, identifier, type/protocol/profile and positive integer dimensions. Canvas and image dimensions may legitimately differ.

FieldMeaning
observedAtUTC report start time
coveragecomplete supported observations; partial omitted/unknown surfaces; unsupported root outside embedded P3 Manifest scope
resourcesURL, GET/HEAD method, roles, affected canvases, final URL, status, access, robots, CORS and metadata diagnostics
accessObserved 200 accessible, 404/410 missing, 401/403 restricted; rate limits, server errors, HEAD 405 and transport failures unknown; rejected acquisition hops refused
corsObservation for the supplied origin and actual GET/HEAD method, with no credentials; no universal browser compatibility claim
findingsExplicit unsupported, inconsistent or omitted surfaces; bounded code strings, with canvas IDs where available
omittedResources, omittedFindingsCounts of report omissions, making partial output explicit
requestCount, byteCountHTTP attempts including robots/redirects, and downloaded JSON/robots body bytes

coverage: complete means the supported observations were performed, not that every dependency is healthy. Missing (404/410) or restricted (401/403) image HEAD responses can be complete negative observations. A non-200 service info.json response leaves metadata unchecked and makes coverage partial.

Malformed/repeated CORS headers, wrong origins and invalid metadata are concrete observations. Restricted access is reported without retrying with credentials. refused can concern the resource, its redirect or a required robots hop; it does not establish that the original resource's address itself is unsafe. Collections, Presentation 2, remote annotation pages, nonpainting annotations, Choice/SpecificResource/non-image bodies, ambiguous targets and unsupported services remain explicit unchecked surfaces. The Actor does not fetch remote pages, perform migration, validate full IIIF conformance, decode images or run a viewer.

Reference output excerpt

This excerpt comes from the hosted reference check above. The complete report also contains the manifest and Image API metadata resources; those entries and other fields are omitted here for readability. complete describes coverage, while image content and full conformance remain unchecked.

{
"reportVersion": 1,
"coverage": "complete",
"resources": [
{
"url": "https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen/full/max/0/default.jpg",
"method": "HEAD",
"roles": [
"image"
],
"canvasIds": [
"https://iiif.io/api/cookbook/recipe/0008-rights/canvas/p1"
],
"status": 200,
"access": "accessible",
"robots": "allowed",
"cors": "allowed",
"imageContent": "unchecked"
}
],
"requestCount": 4,
"byteCount": 2711,
"fullConformance": "unchecked"
}

Bounds

The ceilings are 50 canvases, 100 URL/method resources including the manifest, 1,000 annotation traversal attempts, 128 HTTP attempts, 2 MiB downloaded metadata, 20 JSON nesting levels, 20,000 JSON value nodes, 45 seconds inside the worker, a 50-second process watchdog, three redirects per chain and 2,048-character URLs/identifiers. Raw ASCII path characters requiring encoding must already be percent-encoded; Unicode paths use UTF-8 percent encoding consistently with robots. The normalized URL must also fit 2,048 characters before robots work or DNS. Robots matching shares at most 100,000 work units per report, charging name and pattern characters plus wildcard-loop iterations. Policies are parsed once per origin. Over-limit policy remains unknown and protected acquisition is skipped. This deterministic work cap is not a measured CPU-time guarantee. One complex policy can exhaust the shared allowance and leave later resources, including other origins, unknown. Coverage on such hosts is unmeasured. Findings retain at most 100 entries and 100,000 UTF-8 bytes with explicit omitted counts. The JSON report is at most 750,000 UTF-8 bytes. Whole resource records are omitted when necessary; canvas attribution within retained records is never truncated. Policy and acquisition-budget failures produce partial observations when the worker returns. If the hard watchdog terminates the worker, or the isolated worker fails, the SDK run fails with a fixed error and persists no report. Partial recovery from a killed worker is not implemented.

Initial test pricing

The initial test price is $0.05 per useful report, billed as one report-produced event. There is no Actor startup or dataset charge. One event is requested only after both the default dataset row and KVS OUTPUT are successfully written, and only when coverage is complete with at least one image resource carrying nonempty canvasIds. Complete negative observations such as missing (404/410), restricted (401/403) images or invalid Image API metadata still qualify.

Partial, unsupported, empty and unattributed reports are persisted without this event. Invalid input, worker failure/timeout and failed output writes do not request a charge. Pay-per-event mode requires the configured event and available capacity before acquisition. If a charge request fails, the run fails after output has been persisted; whether the platform accepted that charge may be unknown. An unexpected provider charge count also fails visibly. There is no automatic charge retry, restart recovery or cross-run deduplication. Rerunning the same input can produce another billable report.

Local offline example

For developers with this repository, Python 3.13 and uv are required to use the pinned SDK and model contracts. From the repository root, run the closed synthetic example on the worker:

rexec --shell 'cd actors/iiif-publication-preflight && uv run --locked python -m iiif_publication_preflight.demo'

This command makes no network or platform calls and bypasses billing. It prints one JSON report with coverage: complete, three HTTP fixture attempts, and one missing image resource attributed to both https://museum.example/c1 and https://museum.example/c2. imageContent and fullConformance remain unchecked. These synthetic results do not establish customer usage, source permission or demand.

See PRODUCT.md and VALIDATION.md for development scope, test receipts and limitations. The package pins Apify 4.0.1 and Pydantic 2.11.9; the output schemas are generated from the report model.