Getting Started
Five-minute path from a fresh TYPO3 install to your first JSON response.
1. Install
composer require friendsoftypo3/headless
Composer is the recommended way. Classic mode still works but takes
manual steps: download the release, unpack it to
typo3conf/, then activate it in the Extension Manager.
2. Create a root page + site config
In the backend, create a new page at the root level (the site root). Then go to Site Management → Sites and add a site configuration pointing at that page.
Important
Serve the API from a dedicated URL like https://.
Paths on the main domain (https://) can lead to
unexpected behaviour.
3. Add the headless set and switch the site to JSON
Both switches live in the site configuration:
# config/sites/<identifier>/config.yaml
rootPageId: 1
base: https://api.example.com
dependencies:
- friendsoftypo3/headless
headless: 1 # 0 = NONE, 1 = FULL (always JSON), 2 = MIXED (Accept-driven)
In MIXED mode the first Accept header value must be exactly
application/ — Accept: application/ (the
axios/fetch default) or application/ renders HTML.
Do not add a root sys_template record — sites using sets don't need one, and its "Clear" flags would wipe the set TypoScript. Sites not using sets can select the equivalent statics in a root TypoScript record instead: "Headless", "Headless Legacy (4.x)" or "Headless - Mixed mode JSON response".
Headless 4.x ships sets too (TYPO3 v13): friendsoftypo3/ (full
response) and friendsoftypo3/. On TYPO3 v12 include the
headless static template in the root TypoScript record instead.
Set and mode variants are described in Configuration.
4. Drop a content element on the page
Add a Text element (or any standard CE) to the page. Save.
5. Fetch the page
curl https://api.example.com/
You should get something like:
{
"id": 1,
"slug": "/",
"seo": { "title": "Home" },
"breadcrumbs": [{ "title": "Home", "link": "/" }],
"content": {
"colPos0": [{ "id": 1, "type": "text", "content": { "bodytext": "…" } }]
}
}
See Reference: TypoScript helpers for what each field means and where to override it.
What next?
- Add a top-level field of your own: Adding fields via raw TypoScript.
- Put your SPA on a separate domain (so links in the response point at your frontend, not the API): Multi-Site & URL Configuration.
- Listen to a headless event (e.g. inject a signed CDN URL into every file payload): Events you can listen to.
- Stuck? FAQ → Troubleshooting.