IIIF Collections
As introduced on the IIIF Presentation API support page, Collections come in two flavours:
- Storage Collections act as containers — like folders, organising the storage of IIIF resources within the platform, in an arbitrary hierarchy. A Storage Collection doesn’t have a rich stored JSON representation, and its
itemsproperty is always generated by the platform from what the collection actually contains. - IIIF Collections are stored JSON documents — IIIF Presentation 3.0 Collections that can carry anything valid IIIF can carry, whose
itemsyou edit yourself, referencing any Manifests or Collections whether the platform manages them or not.
This page describes both, along with ordering, paging and search. The URL forms, the X-IIIF-CS-Show-Extras header, write semantics and error conventions shared by all IIIF resources are described once, on the parent page.
Customer 99 is used as an example throughout.
The Storage Collection
Section titled “The Storage Collection”Both the API view and the public view of a Storage Collection are valid IIIF Collections as defined by the IIIF Presentation API 3.0. But there are obvious differences between the resource you operate on via the API, and the resource served to the public. Here is the API view of a Storage Collection containing five children — two public Storage Collections, one non-public Storage Collection, a IIIF Collection and a Manifest:
{ "@context": [ "http://tbc.org/iiif-repository/1/context.json", "http://iiif.io/api/presentation/3/context.json" ], "id": "https://iiif.dlcs.example/99/collections/d44eeb7a", "type": "Collection", "slug": "manuscripts", "parent": "https://iiif.dlcs.example/99/collections/root", "publicId": "https://iiif.dlcs.example/99/manuscripts", "flatId": "d44eeb7a", "behavior": [ "storage-collection", "public-iiif" ], "label": {"en": ["Manuscripts"]}, "created": "2026-09-09T13:31:01Z", "createdBy": "Admin", "modified": "2026-09-09T13:31:01Z", "modifiedBy": null, "totals": { "childStorageCollections": 3, "childIIIFCollections": 1, "childManifests": 1 }, "totalItems": 5, "view": { "@id": "https://iiif.dlcs.example/99/collections/d44eeb7a?page=1&pageSize=100", "@type": "PartialCollectionView", "page": 1, "pageSize": 100, "totalPages": 1 }, "partOf": [ { "id": "https://iiif.dlcs.example/99/collections/root", "type": "Collection", "label": {"en": ["IIIF Home"]} } ], "seeAlso": [ { "id": "https://iiif.dlcs.example/99/manuscripts", "type": "Collection", "profile": "public-iiif", "label": {"en": ["Manuscripts"]} }, { "id": "https://iiif.dlcs.example/99/manuscripts", "type": "Collection", "profile": "api-hierarchical", "label": {"en": ["Manuscripts"]} } ], "items": [ { "id": "https://iiif.dlcs.example/99/collections/wvdx22gecu7e", "type": "Collection", "label": {"en": ["14th Century"]}, "behavior": ["public-iiif", "storage-collection"] }, { "id": "https://iiif.dlcs.example/99/collections/mfstw2c3fyty", "type": "Collection", "label": {"en": ["15th Century"]}, "behavior": ["public-iiif", "storage-collection"] }, { "id": "https://iiif.dlcs.example/99/collections/nrbew3hg67dz", "type": "Collection", "label": {"en": ["Working files"]}, "behavior": ["storage-collection"] }, { "id": "https://iiif.dlcs.example/99/collections/pqcfx4jh78ea", "type": "Collection", "label": {"en": ["Highlights"]}, "behavior": ["public-iiif"] }, { "id": "https://iiif.dlcs.example/99/manifests/gb799m5z", "type": "Manifest", "label": {"en": ["MS 125"]} } ]}IIIF behaviors
Section titled “IIIF behaviors”The API Storage Collection has one or two additional behavior property values:
- The
storage-collectionbehavior identifies the Collection as a Storage Collection rather than a regular IIIF Collection. This means you can only edit itslabelproperty (a language map), and itsslugandparent. You cannot edit theitemsproperty via HTTP operations on JSON, only by adding or deleting child Manifests or Collections with PUTs and POSTs. Theitemsproperty is only ever generated by the server; you cannot supply it for a Storage Collection. - The
public-iiifbehavior indicates that a public request for this resource will be served. If the Storage Collection does not have this behavior, it won’t be visible to the public and its public URL returns HTTP 404. You may not wish for purely organisational containers in your IIIF repository to be available to the public as (potentially huge) IIIF Collections.
Notice the behavior values on the entries in items above: you can tell the three kinds of child apart — Storage Collections, IIIF Collections (no storage-collection behavior) and Manifests (no behavior at all).
Navigation properties
Section titled “Navigation properties”The API Storage Collection has properties that govern the resource’s location in the hierarchy, and therefore the public URL of the Collection — slug, parent and publicId, as introduced on the parent page. The hierarchical URL is composed of path elements provided by the resource’s slug, its parent’s slug, and so on up to the root.
For Storage Collections, IIIF Collections and Manifests returned by the platform with Show-Extras:
parentis always the flat form, not the hierarchical form.publicIdshows what URL the public version of this resource is available on, which is also the value ofidthat appears in that resource when viewed publicly.partOfcarries the parent as a standard IIIF reference, so IIIF-aware clients can navigate upwards.
For resources supplied to the platform by POST and PUT:
parentmay be the hierarchical form or the flat form.publicIdis not settable; it is read-only, and ignored if supplied.
Counts and modification metadata
Section titled “Counts and modification metadata”The totals property summarises what the collection contains — the three counts of immediate children, by kind. Note that totals and totalItems count all children, including non-public ones. (totalItems and view provide paging, described in the next section.)
The API view also carries modification metadata: created, createdBy, modified and modifiedBy.
seeAlso links
Section titled “seeAlso links”The API Storage Collection has one or two seeAlso links: one with profile api-hierarchical pointing at the hierarchical form of the API version, and — only if the Storage Collection has the public-iiif behavior — one with profile public-iiif pointing at the canonical public equivalent. In the default configuration both point at the same hierarchical URL, but they are distinct in meaning.
The public view
Section titled “The public view”The public view of the same Storage Collection is a plain IIIF Presentation 3.0 Collection — just @context, id, type, label and items:
{ "@context": "http://iiif.io/api/presentation/3/context.json", "id": "https://iiif.dlcs.example/99/manuscripts", "type": "Collection", "label": {"en": ["Manuscripts"]}, "items": [ { "id": "https://iiif.dlcs.example/99/manuscripts/14th-century", "type": "Collection", "label": {"en": ["14th Century"]} }, { "id": "https://iiif.dlcs.example/99/manuscripts/15th-century", "type": "Collection", "label": {"en": ["15th Century"]} }, { "id": "https://iiif.dlcs.example/99/manuscripts/highlights", "type": "Collection", "label": {"en": ["Highlights"]} }, { "id": "https://iiif.dlcs.example/99/manuscripts/ms-125", "type": "Manifest", "label": {"en": ["MS 125"]} } ]}Note the differences from the API view: the ids are hierarchical public URLs, and the non-public “Working files” child is simply absent — the public view lists only children that are themselves public. It is navigable by any client (an IIIF browser) that understands a IIIF Collection.
The root
Section titled “The root”Every customer starts with a root Storage Collection that cannot be deleted (attempting to returns 400, “Cannot delete a root collection”). Its public hierarchical form is https://iiif.dlcs.example/99 and its flat form is https://iiif.dlcs.example/99/collections/root. In every other respect it behaves as any other Storage Collection.
Ordering and paging
Section titled “Ordering and paging”The API Storage Collection has totalItems and view properties, which work the same way as paging resources in the rest of the API (documented in Hydra Collections). Pass page and pageSize as query parameters; view describes where you are, with first, previous, next and last links as appropriate:
{ "totalItems": 5, "view": { "@id": "https://iiif.dlcs.example/99/collections/d44eeb7a?page=1&pageSize=2", "@type": "PartialCollectionView", "page": 1, "pageSize": 2, "totalPages": 3, "next": "https://iiif.dlcs.example/99/collections/d44eeb7a?page=2&pageSize=2", "last": "https://iiif.dlcs.example/99/collections/d44eeb7a?page=3&pageSize=2" }}The default page size is 100. A normal IIIF Collection has no paging features — it is intended for human interaction as a single resource, so should not be arbitrarily large. But we need paging for Storage Collections on the API view, to allow them to be used as containers and still ensure a good user experience in any interfaces built on them.
By default, the items of a Storage Collection are ordered by creation date, ascending. You can change this with the orderBy or orderByDescending query parameter, with one of three fields:
created— the defaultslug— alphabetical by URL path elementid— by flat identifier
Any other field name is silently ignored, leaving the default order. The ordering parameter is carried through into the view paging links, so you can page through a large collection in a stable order:
GET /99/collections/d44eeb7a?orderBy=slug&pageSize=100GET /99/collections/d44eeb7a?orderByDescending=createdCreating, updating and deleting
Section titled “Creating, updating and deleting”The write semantics — credentials plus the Show-Extras header, the If-Match rules, and the Operations table — are described on the parent page. For Collections specifically:
Creating with a minted identifier
Section titled “Creating with a minted identifier”If your public IIIF resources use the hierarchical scheme, you may not have any need to assign your own flat identifiers — an example might be a IIIF Manifest Editor that only presents a folder-and-file model to its users, where it would be inconvenient to have to mint identifiers yourself. POST the new Collection to the flat container URL and the platform assigns the identity, returning it in the Location header:
POST /99/collectionsHost: iiif.dlcs.example{ "type": "Collection", "behavior": ["storage-collection", "public-iiif"], "label": {"en": ["My first Storage Collection"]}, "slug": "my-first-storage-collection", "parent": "https://iiif.dlcs.example/99/collections/root"}Returns 201 Created, with the API view of the new Collection in the body and its minted flat URL in the Location header.
Creating with your own identifier
Section titled “Creating with your own identifier”PUT the same body to the flat URL you want the resource to have:
PUT /99/collections/my-flat-identifierHost: iiif.dlcs.exampleThere is no Location header on a PUT response — you chose the URL. To create a Collection inside another one, use exactly the same operations with the parent set to the containing Collection (in either of its URL forms) — and the same goes for every level of the hierarchy.
Notes that apply to both forms of create:
- The
storage-collectionbehavior tells the platform that you are creating a Storage Collection and not a regular IIIF Collection. - An
itemsproperty supplied for a Storage Collection is ignored —itemsis always generated by the platform. - Another resource with the same
slugunder the sameparentreturns409 Conflict. - If all you have is the public hierarchical URL (e.g., you didn’t record the returned
Location), you can always obtain the flat URL by requesting the hierarchical URL with the Show-Extras header and following the redirect — or from theseeAlsoof any API view.
Updating, moving and renaming
Section titled “Updating, moving and renaming”Updates are whole-resource PUTs with If-Match. For a Storage Collection you can change its label, its behavior (to publish or unpublish it), and its position in the hierarchy:
- changing
slugrenames the Collection; - changing
parentmoves it.
Changing either will change the public URL of the Collection — and the public URLs of all child and descendant resources, Collections and Manifests, below it in the hierarchy. The old URLs return 404; the flat URLs of every affected resource are unchanged. This is how you move a resource.
Deleting
Section titled “Deleting”DELETE the flat URL with If-Match. A Collection that still has children cannot be deleted — 400 Bad Request, “Cannot delete a collection with child items” (…/errors/DeleteResourceErrorType/CollectionNotEmpty) — delete the children first, or move them. The root Collection cannot be deleted at all.
IIIF Collections
Section titled “IIIF Collections”So far the examples have been Storage Collections — containers to organise content. But you can also create IIIF Collections: stored JSON documents with, potentially, no platform dependencies at all. A IIIF Collection can use summary, metadata, provider, homepage, thumbnail and any other standard IIIF properties — all supported in a IIIF Collection but not in a Storage Collection — and its items are yours to edit, referencing any Manifests or Collections, on this platform or anywhere on the web.
Create one exactly as in the previous section — PUT to a flat URL of your choice, or POST to /99/collections for a minted one — with the mandatory parent and slug, the public-iiif behavior, and without the storage-collection behavior:
{ "type": "Collection", "behavior": ["public-iiif"], "label": {"en": ["Selected letters"]}, "summary": {"en": ["A IIIF Collection with ordinary IIIF properties"]}, "metadata": [{"label": {"en": ["Curator"]}, "value": {"en": ["The docs team"]}}], "slug": "selected-letters", "parent": "https://iiif.dlcs.example/99/collections/d44eeb7a", "items": [ { "id": "https://iiif.wellcomecollection.org/presentation/b29000798", "type": "Collection", "label": {"en": ["An external IIIF Collection"]} }, { "id": "https://example.org/iiif/manifest.json", "type": "Manifest", "label": {"en": ["An external manifest"]} } ]}The public view is your document, served at its public URL — the same JSON apart from the platform-controlled id. The API view adds the extension @context and the same navigation and modification properties as a Storage Collection (slug, parent, publicId, flatId, partOf, created, createdBy, modified, modifiedBy). It does not have the view and totalItems properties — only Storage Collections are paged.
Containment vs content
Section titled “Containment vs content”A IIIF Collection’s items are content, not containment: listing a Manifest in a IIIF Collection doesn’t move or contain that Manifest, it just references it. In the file-system analogy, a IIIF Collection is a file, not a directory: only Storage Collections can act as a parent. Attempting to create a resource whose parent is a IIIF Collection returns 409 Conflict, “The parent must be a storage collection”.
So a IIIF Collection lives in the hierarchy (it has a parent and a slug, and appears in its parent Storage Collection’s generated items), but nothing lives inside it except by reference.
Searching your collections
Section titled “Searching your collections”You can search across your resources by label:
GET /99/collections/root/search?label=manuscriptsHost: iiif.dlcs.exampleX-IIIF-CS-Show-Extras: AllAuthorization: <(credentials here)>Search is an API feature, not a public one — it requires credentials and the Show-Extras header, and it searches all your resources, including non-public ones. It is currently available on the root Storage Collection only; the search path under any other collection returns 404. The root’s API view advertises the service:
"service": [ { "id": "https://iiif.dlcs.example/99/collections/root/search", "type": "IIIFCS-Search", "profile": "level0" }]The response is a synthetic IIIF Collection — generated for the request, not stored, so it has no slug, parent or ETag. Its items are the matches, which can be Storage Collections, IIIF Collections and Manifests alike, identified by their flat URLs; seeAlso links back to the collection searched:
{ "@context": [ "http://tbc.org/iiif-repository/1/context.json", "http://iiif.io/api/presentation/3/context.json" ], "id": "https://iiif.dlcs.example/99/collections/root/search", "type": "Collection", "label": {"en": ["Search results for 'manuscripts' in 'root'"]}, "totalItems": 1, "view": { "@id": "https://iiif.dlcs.example/99/collections/root/search?page=1&pageSize=100", "@type": "PartialCollectionView", "page": 1, "pageSize": 100, "totalPages": 1 }, "seeAlso": [ { "id": "https://iiif.dlcs.example/99/collections/root", "type": "Collection", "label": {"en": ["IIIF Home"]} } ], "items": [ { "id": "https://iiif.dlcs.example/99/collections/d44eeb7a", "type": "Collection", "label": {"en": ["14th Century Manuscripts"]}, "behavior": ["public-iiif", "storage-collection"] } ]}The query parameters:
label={terms}— matches against resource labels. At least one term must be 3 characters or more; a shorter query returns400 Bad Request(…/errors/ModifyCollectionType/InvalidSearchQuery, “At least one search term must be 3 characters or more”).pageandpageSize— paging, exactly as on Storage Collections.orderBy/orderByDescending—id,slugorcreated, exactly as on Storage Collections.