Custom Contentful Apps (Extensions) Development
Contentful Apps are a mechanism for extending the editor interface through iframe applications mounted in fields, sidebars, or entire screens. This is not just UI widgets: through the Contentful App SDK, applications get access to Entry API, Space API, and can run App Actions — serverless functions executed in Contentful context.
Contentful App Architecture
Each application consists of two parts: frontend (React/Vue/Vanilla JS, hosted anywhere) and optional App Backend (AWS Lambda or any HTTP endpoint for App Actions and Events). Both are registered in App Definition via Contentful Management API or Web App.
App Definition
├── Locations: field, sidebar, entry-editor, page, home
├── Parameters: instance params (per-field) + installation params (per-space)
└── App Actions: serverless functions callable from UI or API
Typical scenarios:
- Custom field editor — e.g., color picker linked to design tokens from Figma
- Sidebar extension — SEO analysis panel reading Entry fields in real-time
- Page location — full-screen Asset Manager with Cloudinary integration
- App Actions — generating AI descriptions via OpenAI on Entry save
Field Extension Development
SDK initialization:
import { init, FieldExtensionSDK } from '@contentful/app-sdk';
init((sdk: FieldExtensionSDK) => {
// Read current field value
const value = sdk.field.getValue();
// Subscribe to external changes
sdk.field.onValueChanged((newValue) => {
setFieldValue(newValue);
});
// Update value
sdk.field.setValue({ color: '#ff5500', token: 'brand-primary' });
// Auto-resize iframe to content
sdk.window.startAutoResizer();
});
For React applications, @contentful/react-apps-toolkit is more convenient:
import { useSDK, useFieldValue } from '@contentful/react-apps-toolkit';
const ColorPickerField = () => {
const sdk = useSDK<FieldExtensionSDK>();
const [value, setValue] = useFieldValue<string>();
return (
<ColorPicker
value={value}
onChange={(color) => setValue(color.hex)}
tokens={sdk.parameters.installation.designTokens}
/>
);
};
App Actions (Server Logic)
App Actions allow running server code from Contentful interface without custom backend — Contentful proxies the call to registered endpoint:
// Register App Action in App Definition (via CMA)
// callType: "request" | "event"
// url: https://your-backend.com/actions/generate-seo
// Call from frontend application
const result = await sdk.cma.appAction.callById({
spaceId: sdk.ids.space,
environmentId: sdk.ids.environment,
appDefinitionId: sdk.ids.app,
appActionId: 'generate-seo',
parameters: {
entryId: sdk.ids.entry,
locale: sdk.locales.default,
},
});
On server side (Node.js/Express):
app.post('/actions/generate-seo', async (req, res) => {
// Verify Contentful signature
verifySignature(req.headers['x-contentful-signature'], req.body);
const { entryId, locale } = req.body.parameters;
const entry = await cma.entry.get({ entryId });
const seoData = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: buildSeoPrompt(entry, locale) }],
});
res.json({ result: { seoTitle: seoData.choices[0].message.content } });
});
Installation Parameters and Configuration
Installation parameters are set once when installing app in Space. They pass API keys, tokens, configs — without hardcoding in application:
// Application settings screen
const ConfigScreen = () => {
const sdk = useSDK<AppExtensionSDK>();
const [params, setParams] = useState(sdk.parameters.installation);
sdk.app.onConfigure(() => ({
parameters: params,
targetState: {
EditorInterface: {
// Auto-attach to Symbol type fields
controls: [{ fieldId: 'seoTitle', widgetId: sdk.ids.app }],
},
},
}));
};
Build and Deploy
Contentful provides CLI for local development and deployment:
# Create new application from template
npx create-contentful-app@latest my-app --template typescript
# Local development with tunnel
npm run start # runs on localhost:3000
contentful-app-scripts activate # temporarily registers localhost in App Definition
# Deploy to Contentful hosting (free for Apps)
npm run build
contentful-app-scripts upload # uploads dist/ to Contentful CDN
Timeline and Scope
| Extension type | Complexity | Development time |
|---|---|---|
| Simple field editor (picker, slider) | Low | 1–2 days |
| Sidebar with external API | Medium | 3–5 days |
| Page location (full screen) | High | 1–2 weeks |
| App Actions + server backend | High | 1–2 weeks |
| Full-featured application with config screen | High | 2–3 weeks |
When developing, always cover with tests using @contentful/app-sdk mock objects and set up CI for automatic deployment via contentful-app-scripts upload.







