How to Export Content Metadata from Contentful
Contentful stores structured content with rich metadata. Here's how to extract your entries and assets into a spreadsheet for quality assessment.
Contentful does not export directly to CSV or Excel. The platform's native export format is JSON. However, getting to CSV is straightforward: use the built-in Web App export or CLI to get JSON, then convert to CSV with a short script. For targeted exports, the Content Management API gives you full control over which content types and fields to include.
Contentful Web App Export
Contentful's Web App includes a built-in export feature that downloads all content entries and assets from a space as a JSON file. You can then convert it to CSV.
import json, csv
with open("contentful-export.json") as f:
data = json.load(f)
# Export entries (content items)
with open("contentful_entries.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow([
"ID", "Content Type", "Created", "Updated",
"Published Version", "Locale", "Fields Summary"
])
for entry in data.get("entries", []):
sys = entry.get("sys", {})
fields = entry.get("fields", {})
field_summary = "; ".join(
f"{k}: {str(v.get('en-US', v))[:80]}"
for k, v in fields.items()
)
writer.writerow([
sys.get("id", ""),
sys.get("contentType", {}).get("sys", {}).get("id", ""),
sys.get("createdAt", ""),
sys.get("updatedAt", ""),
sys.get("publishedVersion", ""),
"en-US",
field_summary,
])
# Export assets (media files)
with open("contentful_assets.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow([
"ID", "Title", "Description", "File Name",
"Content Type", "Size", "URL", "Created", "Updated"
])
for asset in data.get("assets", []):
sys = asset.get("sys", {})
fields = asset.get("fields", {})
file_info = fields.get("file", {}).get("en-US", {})
writer.writerow([
sys.get("id", ""),
fields.get("title", {}).get("en-US", ""),
fields.get("description", {}).get("en-US", ""),
file_info.get("fileName", ""),
file_info.get("contentType", ""),
file_info.get("details", {}).get("size", ""),
file_info.get("url", ""),
sys.get("createdAt", ""),
sys.get("updatedAt", ""),
])
print("Exported entries and assets to CSV")Contentful CLI
The Contentful CLI provides a powerful space export command that exports all content from a space to a JSON file. It handles pagination, rate limiting, and large spaces automatically.
npm install -g contentful-clicontentful login. This opens a browser for authentication.# Export entire space (entries, assets, content types)
contentful space export \
--space-id YOUR_SPACE_ID \
--environment-id master \
--content-file contentful-export.json
# Export only specific content type
contentful space export \
--space-id YOUR_SPACE_ID \
--content-type blogPost \
--content-file blog_posts.json
# The exported JSON can be converted to CSV using the
# Python script from Method 1 above.--content-type. For very large spaces, you can also use --skip-content-model to exclude the content type definitions, or --skip-roles to skip user roles.Content Management API (CMA)
The Contentful CMA gives you the most granular control. Query specific content types, filter by field values, select specific fields, and handle pagination. This is the best approach when you need a targeted export of specific content.
pip install contentful-managementimport contentful_management
import csv
client = contentful_management.Client("YOUR_CMA_TOKEN")
space = client.spaces().find("YOUR_SPACE_ID")
environment = space.environments().find("master")
# List all entries of a specific content type
entries = []
skip = 0
limit = 100
while True:
batch = environment.entries().all({
"content_type": "blogPost", # Change to your content type
"limit": limit,
"skip": skip,
})
entries.extend(batch)
if len(batch) < limit:
break
skip += limit
with open("contentful_metadata.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow([
"ID", "Title", "Slug", "Status",
"Created", "Updated", "Published At"
])
for entry in entries:
writer.writerow([
entry.id,
entry.fields().get("title", ""),
entry.fields().get("slug", ""),
"published" if entry.is_published else "draft",
entry.sys.get("created_at", ""),
entry.sys.get("updated_at", ""),
entry.sys.get("published_at", ""),
])
# List all assets
assets = []
skip = 0
while True:
batch = environment.assets().all({"limit": limit, "skip": skip})
assets.extend(batch)
if len(batch) < limit:
break
skip += limit
with open("contentful_assets.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow([
"ID", "Title", "Description", "File Name",
"Content Type", "Size", "Created", "Updated"
])
for asset in assets:
file_info = asset.fields().get("file", {})
writer.writerow([
asset.id,
asset.fields().get("title", ""),
asset.fields().get("description", ""),
file_info.get("fileName", "") if file_info else "",
file_info.get("contentType", "") if file_info else "",
file_info.get("details", {}).get("size", "") if file_info else "",
asset.sys.get("created_at", ""),
asset.sys.get("updated_at", ""),
])
print(f"Exported {len(entries)} entries and {len(assets)} assets")What metadata fields can you export?
| Field | Web App Export | CLI Export | CMA API |
|---|---|---|---|
| Entry ID | ✓ | ✓ | ✓ |
| Content type | ✓ | ✓ | ✓ |
| All custom fields | ✓ | ✓ | ✓ |
| Created date | ✓ | ✓ | ✓ |
| Updated date | ✓ | ✓ | ✓ |
| Published version | ✓ | ✓ | ✓ |
| Publication status | ✕ | ✕ | ✓ |
| Locale / translations | ✓ | ✓ | ✓ |
| Asset title | ✓ | ✓ | ✓ |
| Asset file name | ✓ | ✓ | ✓ |
| Asset MIME type | ✓ | ✓ | ✓ |
| Asset file size | ✓ | ✓ | ✓ |
| Asset dimensions | ✓ | ✓ | ✓ |
| Asset URL | ✓ | ✓ | ✓ |
| Tags | ✓ | ✓ | ✓ |
| Content type schema | ✓ | ✓ | Separate call |
- JSON-first platform: Contentful exports are JSON, not CSV. You will always need a conversion step. The scripts above handle this for common use cases.
- Linked entries: Contentful content models use references (links) between entries. The export includes reference IDs but not the resolved content. To include linked content, you need to resolve references in your conversion script.
- Locales: Multi-locale spaces include field values for each locale. The JSON structure nests field values under locale keys (e.g.,
en-US). Decide whether your CSV should include all locales or just the default.
You have your metadata export.
Now score it.
Upload your CSV or Excel file to MQS and get a structural metadata health score out of 100 with dimension breakdowns and actionable diagnostics.