Skip to content
IIIF & Image Interoperability

A good IIIF manifest is valid Presentation API 3.0 JSON with stable URIs, language-tagged labels, a single rights URI, descriptive metadata that matches your catalogue, and a canvas order that mirrors the physical object. Build them by generating from your catalogue rather than hand-editing at scale, and validate every one. Below is the checklist I apply across a whole collection so results stay consistent and defensible.

What goes into a minimal valid manifest?

The smallest useful v3 manifest declares its context, a stable id, a language-mapped label, and at least one canvas whose annotation paints an Image API resource:

json
{
  "@context": "http://iiif.io/api/presentation/3/context.json",
  "id": "https://example.org/iiif/ms-12/manifest.json",
  "type": "Manifest",
  "label": { "en": ["Book of Hours, MS 12"] },
  "items": [{
    "id": "https://example.org/iiif/ms-12/canvas/1",
    "type": "Canvas",
    "height": 6000, "width": 4000,
    "items": [{
      "id": "https://example.org/iiif/ms-12/page/1",
      "type": "AnnotationPage",
      "items": [{
        "id": "https://example.org/iiif/ms-12/annotation/1",
        "type": "Annotation",
        "motivation": "painting",
        "target": "https://example.org/iiif/ms-12/canvas/1",
        "body": {
          "id": "https://images.example.org/iiif/3/ms-12-f1r/full/max/0/default.jpg",
          "type": "Image", "format": "image/jpeg",
          "height": 6000, "width": 4000,
          "service": [{
            "id": "https://images.example.org/iiif/3/ms-12-f1r",
            "type": "ImageService3", "profile": "level2"
          }]
        }
      }]
    }]
  }]
}

Note the canvas dimensions match the image, and the painting annotation targets the canvas.

Why should every label be a language map?

In Presentation 3.0 the value of label, summary, and each metadata entry is an object keyed by a BCP-47 language tag, like { "en": ["..."], "la": ["..."] }. Use "none" only for values with no linguistic content, such as a shelfmark. Plain strings are a v2 habit that fails v3 validation and strips multilingual viewers of the ability to choose a language.

How should you handle rights and attribution?

Keep them separate and machine-actionable:

  • rights: exactly one URI, e.g. http://creativecommons.org/licenses/by/4.0/ or a rightsstatements.org URI.
  • requiredStatement: the human-readable attribution a viewer must display, as a labelled language map.
json
"rights": "http://rightsstatements.org/vocab/InC/1.0/",
"requiredStatement": {
  "label": { "en": ["Attribution"] },
  "value": { "en": ["Held by Example Library. Reproduced with permission."] }
}

Should you hand-write or generate manifests?

Author one or two by hand to internalise the model, then generate the rest. For Python, the iiif-prezi3 library builds objects programmatically and serialises valid JSON, so you map catalogue rows to canvases in a loop instead of copy-pasting brackets. Generation gives you one source of truth and consistent structure across thousands of objects, which is the entire point of a defensible collection.

How do you order canvases and add structure?

Canvas order in items must follow the reading order of the physical object: recto then verso, cover to cover. For finding aids inside an object, add a structures array of Ranges that name chapters, sections, or illuminations. A reader navigating your manuscript should see the same sequence and divisions a curator would describe in a catalogue record.

What is the pre-publish quality checklist?

  • [ ] @context present and correct for v3.
  • [ ] Every id is a resolvable HTTPS URI, not a relative path.
  • [ ] All labels/summaries/metadata are language maps.
  • [ ] Each canvas height/width matches its painted image.
  • [ ] A single rights URI; attribution in requiredStatement.
  • [ ] Canvas order matches physical sequence.
  • [ ] Passes the official Presentation API validator with zero errors.
  • [ ] Manifest URL is permanent and will not change.

Key Takeaways

  • Use Presentation API 3.0 for all new manifests.
  • Every label, summary and metadata value must be a BCP-47 language map.
  • Canvas dimensions must match the painted Image API resource.
  • Put one licence URI in rights; human attribution goes in requiredStatement.
  • Generate manifests from your catalogue for consistency; hand-author only to learn.
  • Validate every manifest and treat its URL as a permanent identifier.

Frequently Asked Questions

What version of the Presentation API should new manifests use?

Use Presentation API 3.0 for new work. It cleaned up the data model, made language maps explicit, and unified annotations on the Web Annotation model. Only fall back to 2.1 if a critical downstream viewer cannot read v3.

Why must every value be a language map in v3?

In Presentation 3.0, label, summary and metadata values are objects keyed by BCP-47 language tags. This makes multilingual content unambiguous and lets viewers pick the right language for the user.

Should I generate manifests by hand or with a tool?

Hand-write one or two to learn the model, then generate at scale from your catalogue with a script or a library such as iiif-prezi3. Manual authoring across a whole collection invites inconsistency and typos.

What is the rights field for?

The rights property holds a single URI to a licence or rights statement, typically a Creative Commons or rightsstatements.org URI. Human-readable terms go in requiredStatement instead.

How do I make a manifest validate?

Run it through the official IIIF Presentation API validator and resolve every error before publishing. Common failures are missing @context, non-URI ids, and metadata values that are plain strings instead of language maps.

Do manifest URLs need to be stable?

Yes. A manifest URL is what people cite, embed and annotate against. Treat it as a permanent identifier; breaking it breaks every link, viewer embed and annotation that referenced it.