Install & Compatibility
Where this runs
tested against v2.5.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.657s · 22.3MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 2.2s · import 0.583s · 23MB
20MB installed
● package 20MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
Client
✓ from contentful import Client
✗ import contentful; client = contentful.client.Client(...)
The Client class is typically imported directly from the top-level 'contentful' package, not from the internal 'contentful.client' module.
This quickstart initializes the Contentful client using environment variables for credentials and fetches the first entry of content type 'cat'. Ensure you have `CONTENTFUL_SPACE_ID` and `CONTENTFUL_ACCESS_TOKEN` set, or it will fall back to a public example space.
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}")
Debug
Known issues
breakingVersion 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)`).fixReview any direct interactions with `ContentTypeCache` or internal SDK caching logic and update to use the new `space_id` parameter where applicable. Most users interacting only via the main `Client` should not be affected.
affects: >=2.0.0
breakingStarting 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.fixEnsure your project runs on Python 3.9 or newer. If you were relying on `setup.py` for direct installation or `requirements.txt` for dependencies, these are no longer present in the source repository. Use `pip install contentful` as usual, or PDM if managing the project development directly.
affects: >=2.3.0
gotchaThis `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.fixFor new projects, always use `pip install contentful`. For existing projects using the old SDK, refer to the official documentation and migration guides for `contentful.py` as the API surface is different.
affects: All versions (when migrating from old SDK)
gotchaIncorrect `SPACE_ID` or `ACCESS_TOKEN` will result in `contentful.errors.UnauthorizedError`. This is a common setup mistake.fixAlways double-check that your `SPACE_ID` and `ACCESS_TOKEN` are correct for your Contentful space and the API you intend to use (Delivery API vs. Preview API). Ensure they are properly loaded from environment variables or a secure configuration.
affects: All versions
gotchaContentful's API has rate limits. While the SDK includes built-in retry mechanisms, frequent or unoptimized queries can still lead to `contentful.errors.RateLimitExceededError`.fixImplement client-side caching strategies for Contentful data, especially for frequently accessed content. Review application logic to minimize redundant API calls. The SDK will automatically retry, but persistent abuse will still fail.
affects: All versions
Errors
Common errors & fixes
contentful.errors.UnauthorizedError: The authorization token was invalid.
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.
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.
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
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'
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. Upgrade
Version history
2.5.0latest on PyPI · released Aug 29, 2025
Audit
Dependencies
requestsrequiredHTTP client for API communication.
python-dateutilrequiredDate and time utilities, especially for parsing API date formats.