Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with TYPO3

To integrate Replit with TYPO3, install and configure TYPO3's RESTful API extension (typo3/cms-headless or EXT:headless), generate an API token in TYPO3's backend, store it in Replit Secrets (lock icon 🔒) as TYPO3_API_TOKEN, and call the TYPO3 REST API with a Bearer auth header. TYPO3 is the dominant enterprise CMS in Germany and Central Europe, widely used in government and healthcare.

What you'll learn

  • How to install and configure a TYPO3 headless API extension for REST access
  • How to authenticate Replit requests to TYPO3 with Bearer token or API key headers
  • How to fetch TYPO3 page content, content elements, and page tree from Node.js and Python
  • How TYPO3's content element model differs from WordPress posts or Ghost articles
  • When to use TYPO3's headless mode versus direct database integration
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read25 minutesCMSMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with TYPO3, install and configure TYPO3's RESTful API extension (typo3/cms-headless or EXT:headless), generate an API token in TYPO3's backend, store it in Replit Secrets (lock icon 🔒) as TYPO3_API_TOKEN, and call the TYPO3 REST API with a Bearer auth header. TYPO3 is the dominant enterprise CMS in Germany and Central Europe, widely used in government and healthcare.

TYPO3 REST API Integration from Replit

TYPO3 is the enterprise CMS of choice across German-speaking Europe and beyond — it powers a significant share of German government websites, healthcare portals, university sites, and large corporate web presences. For developers building integrations with TYPO3-powered organizations, programmatic access to TYPO3 content is a common requirement. Unlike WordPress or Ghost, TYPO3 does not ship with a REST API in its core — you need to install a headless extension.

The most widely used TYPO3 headless extension is EXT:headless (packaged as wirl-pl/headless on Packagist), which exposes TYPO3 page content as structured JSON. Another option is EXT:rest-api which provides a configurable REST API. The extension choice affects the API structure your Replit integration will work with. Organizations running TYPO3 for public-facing content often prefer EXT:headless for its clean JSON output; those using TYPO3 as a data platform may use the REST API extension.

TYPO3's content model is different from other CMS platforms. Content lives in a page tree structure — pages contain content elements (text, images, files, forms), and pages are organized in a hierarchical tree. The headless API exposes this structure as JSON, with page content as arrays of typed content elements. Understanding this model is essential for correctly interpreting the API responses your Replit integration receives.

Integration method

Standard API Integration

TYPO3 does not include a REST API in its core installation — you must install a headless extension such as EXT:headless (wirl-pl/headless) or EXT:rest (typo3-rest-api). The extension exposes page content, content elements, and page tree as JSON API endpoints. Your Replit server stores API credentials in Replit Secrets and makes authenticated HTTP requests to the TYPO3 API to read and manage content.

Prerequisites

  • A Replit account with a Node.js or Python Repl ready
  • A TYPO3 installation (version 11.5 LTS or 12.x recommended) with admin access
  • A TYPO3 headless extension installed (EXT:headless via Composer: wirl-pl/headless)
  • A configured API endpoint URL and authentication credentials for your TYPO3 setup

Step-by-step guide

1

Install and Configure a TYPO3 Headless Extension

Log into your TYPO3 server via SSH or your hosting control panel. TYPO3 extensions are installed via Composer. Install the EXT:headless extension by running: composer require wirl-pl/headless. Then activate it in TYPO3's Extension Manager (Admin Tools → Extensions). Alternatively, if your TYPO3 installation uses the TYPO3 Extension Repository (TER), search for 'headless' in the Extensions module and install EXT:headless from there. After installation, create a Site Configuration that includes headless settings. In TYPO3's Sites module (Configuration → Sites), edit your site and add the headless API base path — typically /api/. This makes page content available at /api/{pageUid} or /api/?id={pageUid}. For authentication, EXT:headless supports API key authentication. Create an API key in the TYPO3 Backend by navigating to System → API Keys (or the equivalent module provided by the headless extension). Note your API key and the header format — typically X-Auth-Token or Authorization: Bearer. For TYPO3's built-in REST API (without a headless extension), some older configurations use the core TYPO3 API which accepts user credentials via HTTP Basic Auth. Check your TYPO3 version's documentation for the exact API endpoint structure. If you do not have direct server access and cannot install extensions, contact your TYPO3 administrator to request headless API access and ask for the API base URL and authentication credentials.

typo3-install-commands.sh
1# Install EXT:headless via Composer on the TYPO3 server
2# (Run this on the TYPO3 server, not in Replit)
3composer require wirl-pl/headless
4
5# Flush TYPO3 caches after installation
6./vendor/bin/typo3 cache:flush

Pro tip: EXT:headless requires TypoScript configuration to define which content elements are exposed via the API. Add the headless TypoScript setup to your TYPO3 template. Ask your TYPO3 developer or check the EXT:headless documentation for the required TypoScript snippet.

Expected result: EXT:headless is installed and active. The TYPO3 site serves JSON responses at the /api/ path. An API key exists for authentication.

2

Store TYPO3 Credentials in Replit Secrets

Click the lock icon (🔒) in the left Replit sidebar to open the Secrets pane. Add the following secrets: TYPO3_API_TOKEN: your TYPO3 API key or Bearer token. TYPO3_BASE_URL: your TYPO3 site's base URL without trailing slash (e.g., https://yoursite.com). TYPO3_API_PATH: the API base path (e.g., /api or /json — depends on your headless extension configuration). The full API URL for a page request is typically: {TYPO3_BASE_URL}{TYPO3_API_PATH}?id={pageId} or {TYPO3_BASE_URL}{TYPO3_API_PATH}/{pageId}. Verify the exact format with your TYPO3 admin. For authentication, EXT:headless typically uses a custom header: X-Auth-Token: {apikey}. Some configurations use Authorization: Bearer {token}. Confirm the expected header name with your TYPO3 configuration. For TYPO3 instances using HTTP Basic Auth (common in older setups or staging environments), store TYPO3_USERNAME and TYPO3_PASSWORD instead of an API token.

check-typo3-secrets.js
1// check-typo3-secrets.js
2const required = ['TYPO3_API_TOKEN', 'TYPO3_BASE_URL', 'TYPO3_API_PATH'];
3for (const key of required) {
4 if (!process.env[key]) {
5 throw new Error(`Missing secret: ${key}. Set it in Replit Secrets (lock icon 🔒).`);
6 }
7}
8console.log('TYPO3 config OK.');
9console.log('Base URL:', process.env.TYPO3_BASE_URL);
10console.log('API path:', process.env.TYPO3_API_PATH);

Pro tip: Ask your TYPO3 administrator for the exact API authentication header name — EXT:headless versions differ in whether they use X-Auth-Token, Authorization: Bearer, or a custom header. Getting this wrong produces 401 errors that look identical regardless of which header format is wrong.

Expected result: TYPO3_API_TOKEN, TYPO3_BASE_URL, and TYPO3_API_PATH appear in Replit Secrets. The check script prints the URL and path without errors.

3

Fetch TYPO3 Page Content (Node.js)

Install required packages in the Shell tab: npm install axios express. TYPO3's headless API typically returns JSON responses where the page content is in a content object containing arrays of content elements organized by colPos (column position in TYPO3's backend layout). A typical EXT:headless response includes: page metadata (id, title, description, slug), seo data, and content as an object with colPos keys (colPos0, colPos1, etc.) — each containing an array of content elements. Each content element has a type (text, textpic, image, bullets, etc.), a uid, and type-specific data fields. Common TYPO3 content element types: text (headline + body text), textpic (text with image), image (images only), bullets (bullet list), header (headline only), menu (navigation menu), form (forms), and custom extension elements. For the page tree, EXT:headless provides an endpoint (varies by version) that returns the page hierarchy. Use this to discover available page UIDs and navigate the site structure programmatically. Error handling: TYPO3 headless APIs typically return HTTP 200 even for pages that do not exist, but with empty content arrays. Check if the response contains actual content rather than relying solely on HTTP status codes.

typo3.js
1// typo3.js — TYPO3 Headless API integration for Node.js on Replit
2const axios = require('axios');
3const express = require('express');
4
5const app = express();
6app.use(express.json());
7
8const BASE_URL = process.env.TYPO3_BASE_URL;
9const API_PATH = process.env.TYPO3_API_PATH;
10const API_TOKEN = process.env.TYPO3_API_TOKEN;
11
12const typo3Api = axios.create({
13 baseURL: BASE_URL,
14 headers: {
15 'X-Auth-Token': API_TOKEN, // EXT:headless v3+ uses this header
16 // Some versions use: 'Authorization': `Bearer ${API_TOKEN}`
17 'Accept': 'application/json'
18 }
19});
20
21// Get page content by TYPO3 page UID
22app.get('/api/page/:pageId', async (req, res) => {
23 const pageId = parseInt(req.params.pageId);
24 if (!pageId) return res.status(400).json({ error: 'Valid page ID required' });
25
26 try {
27 // EXT:headless endpoint format — may vary by version
28 const response = await typo3Api.get(`${API_PATH}`, {
29 params: { id: pageId, type: 834 } // type=834 is EXT:headless JSON typeNum
30 });
31
32 const data = response.data;
33
34 // Extract page metadata and content elements
35 const page = {
36 id: data.page?.id || pageId,
37 title: data.page?.title,
38 description: data.page?.description,
39 slug: data.page?.slug,
40 seo: data.seo || {},
41 // colPos0 is the main content column in most TYPO3 layouts
42 content: data.content?.colPos0 || data.content?.main || []
43 };
44
45 res.json(page);
46 } catch (err) {
47 res.status(err.response?.status || 500).json({ error: err.message });
48 }
49});
50
51// Get site navigation / page tree
52app.get('/api/navigation', async (req, res) => {
53 const { rootPageId = 1, levels = 2 } = req.query;
54 try {
55 const response = await typo3Api.get(`${API_PATH}`, {
56 params: {
57 id: rootPageId,
58 type: 834,
59 tx_headless_request: JSON.stringify({ navigation: true, levels })
60 }
61 });
62 res.json({ navigation: response.data.navigation || [] });
63 } catch (err) {
64 res.status(err.response?.status || 500).json({ error: err.message });
65 }
66});
67
68// Get list of content elements from a page filtered by type
69app.get('/api/page/:pageId/content', async (req, res) => {
70 const { pageId } = req.params;
71 const { type: filterType } = req.query;
72 try {
73 const response = await typo3Api.get(`${API_PATH}`, {
74 params: { id: pageId, type: 834 }
75 });
76
77 const allContent = [
78 ...(response.data.content?.colPos0 || []),
79 ...(response.data.content?.colPos1 || [])
80 ];
81
82 const filtered = filterType
83 ? allContent.filter(el => el.type === filterType)
84 : allContent;
85
86 res.json({ pageId, content: filtered, count: filtered.length });
87 } catch (err) {
88 res.status(err.response?.status || 500).json({ error: err.message });
89 }
90});
91
92app.listen(3000, '0.0.0.0', () => console.log('TYPO3 headless server running on port 3000'));

Pro tip: The type=834 parameter in EXT:headless requests is the TYPO3 typeNum for JSON output. This is a TYPO3 convention — different output formats use different typeNum values. If 834 does not work, check the TypoScript configuration in your TYPO3 installation for the configured headless typeNum.

Expected result: GET /api/page/1 returns the TYPO3 homepage content as JSON with page metadata and content elements. GET /api/navigation returns the site's page tree.

4

Python Integration for TYPO3 API

For Python Replit projects, install requests and flask: pip install requests flask. The Python integration follows the same patterns — create a requests.Session with the TYPO3 auth header set, and call the API endpoints. For parsing TYPO3 content element responses, write a helper that traverses the colPos keys in the content object and flattens all elements into a single list. This simplifies content processing regardless of which column each element was placed in. For headless frontend rendering with Python, process content elements by type: text elements have header and bodytext fields, textpic elements have header, bodytext, and gallery (images) fields, and bullets elements have bodytext as HTML list markup. Transform each element type into the appropriate output for your rendering target. Deploy as Autoscale for web APIs that serve TYPO3 content to frontend clients. Use Reserved VM for background content sync jobs that periodically pull and cache TYPO3 content in a local database for fast serving.

typo3_api.py
1# typo3_api.py TYPO3 Headless API for Python on Replit
2import os
3import requests
4from flask import Flask, request, jsonify
5
6BASE_URL = os.environ['TYPO3_BASE_URL']
7API_PATH = os.environ['TYPO3_API_PATH']
8API_TOKEN = os.environ['TYPO3_API_TOKEN']
9
10session = requests.Session()
11session.headers.update({
12 'X-Auth-Token': API_TOKEN,
13 'Accept': 'application/json'
14})
15
16app = Flask(__name__)
17
18def get_page_content(page_id: int) -> dict:
19 """Fetch TYPO3 page content by page UID."""
20 response = session.get(
21 f'{BASE_URL}{API_PATH}',
22 params={'id': page_id, 'type': 834}
23 )
24 response.raise_for_status()
25 return response.json()
26
27def extract_content_elements(data: dict) -> list:
28 """Flatten all colPos content elements from a TYPO3 page response."""
29 content = data.get('content', {})
30 elements = []
31 for col_key in sorted(content.keys()): # colPos0, colPos1, etc.
32 elements.extend(content[col_key])
33 return elements
34
35@app.route('/api/page/<int:page_id>')
36def get_page(page_id):
37 try:
38 data = get_page_content(page_id)
39 return jsonify({
40 'id': page_id,
41 'title': data.get('page', {}).get('title'),
42 'description': data.get('page', {}).get('description'),
43 'slug': data.get('page', {}).get('slug'),
44 'content': extract_content_elements(data),
45 'seo': data.get('seo', {})
46 })
47 except requests.HTTPError as e:
48 return jsonify({'error': str(e)}), e.response.status_code
49
50@app.route('/api/pages/crawl')
51def crawl_pages():
52 """Crawl multiple TYPO3 pages and return their titles."""
53 start = int(request.args.get('start', 1))
54 end = int(request.args.get('end', 20))
55 results = []
56 for pid in range(start, min(end + 1, start + 50)): # Max 50 pages per request
57 try:
58 data = get_page_content(pid)
59 page = data.get('page', {})
60 if page.get('title'): # Skip non-existent pages
61 results.append({'id': pid, 'title': page['title'], 'slug': page.get('slug')})
62 except Exception:
63 pass # Skip pages that return errors
64 return jsonify({'pages': results, 'count': len(results)})
65
66if __name__ == '__main__':
67 app.run(host='0.0.0.0', port=3000)

Pro tip: TYPO3 page UIDs are sequential integers starting from 1 but with gaps for deleted or hidden pages. When crawling the page tree programmatically, use the navigation/page tree endpoint if available rather than guessing numeric IDs.

Expected result: GET /api/page/1 returns the TYPO3 root page with its content elements. GET /api/pages/crawl returns titles and slugs for pages in the given ID range.

Common use cases

Headless TYPO3 Frontend

Use TYPO3 as a content management backend while serving the public frontend from a Replit application. Content editors work in TYPO3's familiar backend, and your Replit app fetches page content via the API to render it with a custom design — a modern React frontend, a mobile app backend, or an email newsletter generator.

Replit Prompt

Build an Express server that fetches TYPO3 page content for a given page UID, transforms the content elements array into HTML, and serves it as a custom-rendered page.

Copy this prompt to try it in Replit

Content Migration and Sync

Read content from TYPO3's API to migrate it to another platform or create backup exports. Parse TYPO3 content elements, extract text, headlines, images, and links, and transform them into the target format. Useful for organizations modernizing away from TYPO3.

Replit Prompt

Write a script that reads all TYPO3 pages and their content elements from the API, exports them to a JSON file with page hierarchy preserved, and generates a migration report.

Copy this prompt to try it in Replit

Content Monitoring and Reporting

Monitor TYPO3 page content for staleness, broken links, or content audit requirements. Crawl the TYPO3 page tree via the API, check last-modified dates, identify pages that have not been updated in N months, and generate compliance reports for content governance.

Replit Prompt

Create a content audit endpoint that fetches the TYPO3 page tree, identifies pages not modified in the last 6 months, and returns a report with page titles, UIDs, and last modification dates.

Copy this prompt to try it in Replit

Troubleshooting

HTTP 200 response but content array is empty

Cause: The page exists in TYPO3 but either has no published content elements, or the headless TypoScript is not configured to expose that page's content, or the requested page is hidden/restricted.

Solution: Log into TYPO3's backend and verify the page has published content elements in the correct column position. Check the TypoScript configuration to ensure the headless extension is configured to include content from that page's template. Verify the page is not hidden or restricted by access groups.

typescript
1// Log raw API response to understand structure
2const response = await typo3Api.get(`${API_PATH}`, { params: { id: pageId, type: 834 } });
3console.log('Raw response keys:', Object.keys(response.data));
4console.log('Content keys:', Object.keys(response.data.content || {}));

401 Unauthorized or 403 Forbidden despite correct credentials

Cause: The API token header name is wrong — EXT:headless versions use different header names. Or the token was generated for a different site configuration in TYPO3.

Solution: Check your EXT:headless version number and verify the correct auth header format in the extension documentation. Try both X-Auth-Token and Authorization: Bearer formats. Verify the token is configured for the correct TYPO3 site (if TYPO3 hosts multiple sites).

typescript
1// Try both auth header formats
2const response = await axios.get(url, {
3 headers: { 'X-Auth-Token': token } // EXT:headless v3+
4 // headers: { 'Authorization': `Bearer ${token}` } // alternative
5});

typeNum 834 returns HTML instead of JSON

Cause: The EXT:headless TypoScript is not configured in the TYPO3 template, or the typeNum for JSON output in this installation is different from 834.

Solution: Contact your TYPO3 administrator to verify the headless extension is configured and the correct typeNum is set. The typeNum can be anything — check the TypoScript configuration for 'typeNum' and 'lib.headless' entries to find the correct value.

CORS error when calling TYPO3 API from browser-side JavaScript

Cause: TYPO3 does not add CORS headers by default. Cross-origin requests to TYPO3 must be proxied through your Replit server.

Solution: Always call the TYPO3 API from your Replit server-side code, not from browser JavaScript. Your browser calls your Replit Express/Flask endpoint, which calls TYPO3 internally. This server-side proxy avoids CORS and keeps API credentials server-side.

Best practices

  • Store TYPO3_API_TOKEN, TYPO3_BASE_URL, and TYPO3_API_PATH in Replit Secrets (lock icon 🔒) — never expose credentials in code
  • Verify the correct API authentication header name with your TYPO3 admin — EXT:headless versions differ on whether to use X-Auth-Token or Authorization: Bearer
  • Always make TYPO3 API calls from your Replit server, not from browser JavaScript, to avoid CORS issues and keep credentials server-side
  • Cache TYPO3 page content in your Replit server's memory or database — TYPO3 editorial content changes infrequently, so caching reduces load on the TYPO3 server
  • Handle the case where content arrays are empty — TYPO3 returns HTTP 200 for pages with no content, so check the content length explicitly
  • Use the page tree / navigation endpoint to discover page UIDs programmatically rather than hardcoding them
  • Deploy as Autoscale for APIs serving TYPO3 content to frontends; use Reserved VM for background content sync and caching jobs
  • When processing TYPO3 content elements, handle each type explicitly — text, textpic, and image elements have different field structures

Alternatives

Frequently asked questions

How do I connect Replit to TYPO3?

Install a TYPO3 headless extension like EXT:headless (wirl-pl/headless) on your TYPO3 server, configure it to expose content as JSON, generate API credentials, store them in Replit Secrets as TYPO3_API_TOKEN and TYPO3_BASE_URL, and call the TYPO3 API from your Replit server with the appropriate authentication header.

Does TYPO3 have a REST API?

Not in core. TYPO3's REST API requires a third-party extension such as EXT:headless (for headless CMS JSON output) or EXT:rest-api (for full REST CRUD). Once the extension is installed and configured, the API is accessible at a configurable path with authentication support.

What is the difference between TYPO3 and WordPress?

TYPO3 is the dominant enterprise CMS in German-speaking Europe, with strong multilingual content management, granular permissions, and enterprise scalability baked in. WordPress is a general-purpose CMS with a larger global ecosystem and simpler setup. TYPO3's API requires extension installation; WordPress has a built-in REST API in core.

What is typeNum 834 in TYPO3?

typeNum is a TYPO3 TypoScript concept that maps URL parameters to different output formats. EXT:headless registers typeNum 834 to return JSON content instead of HTML. When you add type=834 to a TYPO3 URL, the headless extension intercepts the request and returns structured JSON instead of the regular HTML page. The typeNum value can be customized per installation.

What deployment type should I use on Replit for TYPO3 integrations?

Use Autoscale for APIs that serve TYPO3 content to frontend clients on demand. Since TYPO3 editorial content changes infrequently, a caching layer in your Replit server significantly reduces load. Use Reserved VM for background content sync jobs that periodically pull and index TYPO3 content into a faster database for your application.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.