Contentful Python SDK
The Contentful Python SDK (`contentful.py`) is an actively maintained client library for the Contentful Content Delivery API (CDA). It enables Python applications to programmatically retrieve published content from Contentful spaces. Key features include content retrieval, synchronization, localization support, link resolution, and built-in rate-limiting recovery. The current stable version is 2.5.0.
Common errors
-
contentful.errors.UnauthorizedError: The authorization token was invalid.
cause The provided `SPACE_ID` or `ACCESS_TOKEN` is incorrect, revoked, or does not have permissions for the requested action.fixVerify that your `CONTENTFUL_SPACE_ID` and `CONTENTFUL_ACCESS_TOKEN` environment variables (or direct parameters to `Client`) exactly match the credentials from your Contentful space. Ensure the token is for the Content Delivery API (CDA) if accessing published content. -
contentful.errors.RateLimitExceededError: Rate limit exceeded. Too many requests.
cause Your application has made too many requests to the Contentful API within a short timeframe, exceeding the allowed rate limit.fixReview your application's API call patterns. Implement or improve caching mechanisms for Contentful data, especially for content that doesn't change frequently. Leverage the SDK's built-in retry logic but avoid aggressive polling. -
contentful.errors.EntryNotFoundError: The requested resource or endpoint could not be found.
cause The `entry_id`, `content_type` ID, or other query parameters used to fetch content do not correspond to an existing resource in your Contentful space.fixDouble-check the IDs and query parameters you are using against your Contentful space's content model and entries. Ensure the content is published if you are using the Delivery API. -
TypeError: Object of type Link is not JSON serializable
cause Prior to `contentful>=2.5.0`, direct `json.dumps(entry.raw)` or similar serialization of `entry.raw` could fail if `entry.raw` contained unresolved `Entry` or `Link` objects.fixUpgrade to `contentful>=2.5.0` which fixed this issue. If upgrading is not possible, manually process `entry.raw` to extract only primitive types or use `entry.fields()` to access coerced field values. -
AttributeError: 'Link' object has no attribute 'fields'
cause You are attempting to access fields (e.g., `entry.fields.author.fields.name`) on a linked entry that has not been resolved (fetched with `include` parameter). By default, linked entries are returned as `Link` objects, not full `Entry` objects.fixWhen querying for an entry that has linked references, use the `include` parameter to specify the depth of link resolution. For example: `client.entry('my_entry_id', {'include': 2})`. The value of `include` should be greater than 0, up to a maximum of 10.
Warnings
- breaking Version 2.0.0 introduced breaking changes to the internal caching mechanism. The `__CACHE__` object type changed from `list` to `dict`, and the `ContentTypeCache.get` method now requires a `space_id` argument (e.g., `ContentTypeCache.get(space_id, content_type_id)`).
- breaking Starting with version 2.3.0, support for legacy Python versions was removed, requiring Python >= 3.9. Additionally, the project moved from `setup.py` and `requirements.txt` to `pyproject.toml` and PDM for dependency management.
- gotcha This `contentful.py` SDK (for Content Delivery API) replaced an older, unofficial Python CDA SDK found at `https://github.com/contentful-labs/contentful.py`. Migrating from the older SDK requires code changes.
- gotcha Incorrect `SPACE_ID` or `ACCESS_TOKEN` will result in `contentful.errors.UnauthorizedError`. This is a common setup mistake.
- gotcha Contentful's API has rate limits. While the SDK includes built-in retry mechanisms, frequent or unoptimized queries can still lead to `contentful.errors.RateLimitExceededError`.
Install
-
pip install contentful
Imports
- Client
import contentful; client = contentful.client.Client(...)
from contentful import Client
Quickstart
import os
from contentful import Client
SPACE_ID = os.environ.get('CONTENTFUL_SPACE_ID', 'cfexampleapi') # Use example space for quick demo if not set
ACCESS_TOKEN = os.environ.get('CONTENTFUL_ACCESS_TOKEN', 'b4c0n73n7fu1') # Use example token for quick demo if not set
if not SPACE_ID or not ACCESS_TOKEN:
print("Please set CONTENTFUL_SPACE_ID and CONTENTFUL_ACCESS_TOKEN environment variables.")
else:
try:
client = Client(SPACE_ID, ACCESS_TOKEN)
entries = client.entries({'content_type': 'cat', 'limit': 1})
if entries:
first_cat = entries[0]
print(f"Found entry: {first_cat.sys['id']}")
print(f"Name: {getattr(first_cat, 'name', 'N/A')}")
if getattr(first_cat, 'image', None):
print(f"Image URL: {first_cat.image.url()}")
else:
print("No entries found for content type 'cat'.")
except Exception as e:
print(f"An error occurred: {e}")