Skip to main content

W3C Export API

Export annotations in W3C Web Annotation format for interoperability and data portability.

Overview

Cluster stores annotations in W3C Web Annotation format internally. The Export API provides:

  • Complete JSON-LD — Valid W3C Web Annotation documents
  • Annotation Collections — Groups of related annotations
  • Annotation Pages — Paginated annotation lists
  • Research Extensions — Optional Cluster-specific metadata

Export Formats

Single Annotation

GET /api/annotations/:id/export
Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"

Response:

{
"@context": [
"http://www.w3.org/ns/anno.jsonld",
"https://cluster.research/ns/research.jsonld"
],
"id": "urn:uuid:a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "Annotation",
"motivation": ["highlighting", "tagging"],
"created": "2025-01-03T14:30:00Z",
"modified": "2025-01-03T15:00:00Z",
"creator": {
"id": "https://company.sharepoint.com/users/jsmith",
"type": "Person",
"name": "Jane Smith",
"email": "jsmith@company.com"
},
"generator": {
"id": "https://cluster.research",
"type": "Software",
"name": "Cluster",
"homepage": "https://github.com/cluster-research-solutions/cluster"
},
"body": [
{
"type": "SpecificResource",
"source": "https://cluster.research/taxonomies/main#pain-point",
"purpose": "tagging"
}
],
"target": {
"source": "https://company.sharepoint.com/sites/research/interviews/p05-transcript.txt",
"selector": [
{
"type": "TextQuoteSelector",
"exact": "I had no idea what to do after I created my account.",
"prefix": "the signup was fine but ",
"suffix": " I ended up just closing"
},
{
"type": "TextPositionSelector",
"start": 2847,
"end": 2934
}
]
},
"research:study": "urn:uuid:study-id",
"research:participant": "P05"
}

Annotation Collection

Export a study's annotations as a W3C Annotation Collection:

GET /api/studies/:id/export
Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"

Response:

{
"@context": "http://www.w3.org/ns/anno.jsonld",
"id": "https://cluster.yourcompany.com/api/studies/uuid/export",
"type": "AnnotationCollection",
"label": "Onboarding Research Study 2025",
"total": 247,
"first": {
"id": "https://cluster.yourcompany.com/api/studies/uuid/export?page=0",
"type": "AnnotationPage",
"startIndex": 0,
"items": [
{ ... },
{ ... }
]
},
"last": "https://cluster.yourcompany.com/api/studies/uuid/export?page=12"
}

Annotation Page

Paginated annotation results:

GET /api/studies/:id/export?page=2

Response:

{
"@context": "http://www.w3.org/ns/anno.jsonld",
"id": "https://cluster.yourcompany.com/api/studies/uuid/export?page=2",
"type": "AnnotationPage",
"partOf": {
"id": "https://cluster.yourcompany.com/api/studies/uuid/export",
"total": 247
},
"startIndex": 40,
"next": "https://cluster.yourcompany.com/api/studies/uuid/export?page=3",
"prev": "https://cluster.yourcompany.com/api/studies/uuid/export?page=1",
"items": [
{ ... },
{ ... }
]
}

Cluster Export

Export a cluster (affinity group) as an Annotation Collection:

GET /api/clusters/:id/export
Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"

Response:

{
"@context": [
"http://www.w3.org/ns/anno.jsonld",
"https://cluster.research/ns/research.jsonld"
],
"id": "urn:uuid:cluster-id",
"type": ["AnnotationCollection", "research:AffinityGroup"],
"label": "Onboarding Confusion",
"total": 12,
"first": {
"type": "AnnotationPage",
"items": [
{ ... }
]
}
}

Insights Export

Export insights with evidence links:

GET /api/insights/:id/export
Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"

Response:

{
"@context": [
"http://www.w3.org/ns/anno.jsonld",
"https://cluster.research/ns/research.jsonld"
],
"id": "urn:uuid:insight-id",
"type": ["Annotation", "research:Insight"],
"motivation": "describing",
"body": {
"type": "TextualBody",
"value": "Users experience critical confusion immediately after account creation, with 4 of 6 participants unable to identify their next action.",
"format": "text/markdown",
"purpose": "describing"
},
"target": [
"urn:uuid:annotation-1",
"urn:uuid:annotation-2",
"urn:uuid:annotation-3",
"urn:uuid:annotation-4"
],
"research:confidence": "high",
"research:impact": "critical",
"research:recommendation": "Add onboarding checklist to post-signup dashboard"
}

Bulk Export

Export all annotations for a study:

GET /api/studies/:id/export/bulk
Accept: application/ld+json

Returns a JSON array of all annotations (no pagination):

[
{ "@context": [...], "type": "Annotation", ... },
{ "@context": [...], "type": "Annotation", ... }
]
Large Exports

For studies with >1000 annotations, use paginated export instead.

Export Options

Include/Exclude Fields

GET /api/studies/:id/export?include=body,target&exclude=creator
ParameterDescription
includeOnly include these fields
excludeExclude these fields

Filter by Date

GET /api/studies/:id/export?from=2025-01-01&to=2025-01-31

Filter by Motivation

GET /api/studies/:id/export?motivation=highlighting,tagging

Exclude Research Extensions

For pure W3C compliance (without Cluster extensions):

GET /api/studies/:id/export?pure=true

This removes research:* properties and uses only the W3C context.

Download as File

JSON-LD File

GET /api/studies/:id/export/download
Accept: application/ld+json

Response Headers:

Content-Type: application/ld+json
Content-Disposition: attachment; filename="study-name-annotations.jsonld"

ZIP Archive

Export with separate files per annotation:

GET /api/studies/:id/export/download?format=zip

ZIP Structure:

study-name-annotations/
├── collection.jsonld
├── annotations/
│ ├── a1b2c3d4.jsonld
│ ├── b2c3d4e5.jsonld
│ └── ...
├── clusters/
│ ├── cluster-1.jsonld
│ └── ...
└── insights/
├── insight-1.jsonld
└── ...

Validation

Validate export against W3C schemas:

POST /api/validate
Content-Type: application/ld+json

Request Body:

{
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"target": "https://example.com/page"
}

Response:

{
"valid": true,
"warnings": [],
"errors": []
}

Validation Errors

{
"valid": false,
"errors": [
{
"path": "target",
"message": "Target must have a source or be a string URI",
"spec": "https://www.w3.org/TR/annotation-model/#targets"
}
]
}

JSON-LD Context

W3C Context

http://www.w3.org/ns/anno.jsonld

Cluster Research Context

https://cluster.research/ns/research.jsonld

Research Context Definition:

{
"@context": {
"research": "https://cluster.research/ns/research#",

"Study": "research:Study",
"Insight": "research:Insight",
"AffinityGroup": "research:AffinityGroup",

"study": {"@id": "research:study", "@type": "@id"},
"participant": "research:participant",
"session": "research:session",
"confidence": "research:confidence",
"impact": "research:impact",
"recommendation": "research:recommendation"
}
}

Import

Import W3C annotations from other tools:

POST /api/annotations/import
Content-Type: application/ld+json

Request Body:

{
"annotations": [
{
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"target": "https://example.com/document",
"body": {
"type": "TextualBody",
"value": "Imported annotation"
}
}
],
"options": {
"studyId": "uuid",
"mapSources": {
"https://old-system.com/files/": "https://company.sharepoint.com/sites/research/"
}
}
}

Response:

{
"imported": 15,
"skipped": 2,
"errors": [
{
"index": 7,
"error": "Invalid selector type"
}
]
}

Interoperability

Cluster exports are compatible with:

ToolFormatNotes
HypothesisW3C JSON-LDDirect import
RecogitoW3C JSON-LDDirect import
CATMAW3C JSON-LDMay need source mapping
DovetailCustomRequires transformation

Next Steps