---
title: "Getting Started"
manual: "Headless"
version: "main"
permalink: "https://docs.typo3.org/permalink/friendsoftypo3/headless:quickstart@main"
source: "GettingStarted/Index.rst"
rendered: "2026-10-14T09:29:03+00:00"
---

# Getting Started {#quickstart}

Five-minute path from a fresh TYPO3 install to your first JSON response.

## 1\. Install {#1-install}

```bash
composer require friendsoftypo3/headless
```

Composer is the recommended way. Classic mode still works but takes
manual steps: download the release, unpack it to
`typo3conf/ext/headless`, then activate it in the Extension Manager.

## 2\. Create a root page + site config {#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://api.example.com`.
> Paths on the main domain (`https://example.com/api`) can lead to
> unexpected behaviour.

## 3\. Add the headless set and switch the site to JSON {#3-add-the-headless-set-and-switch-the-site-to-json}

Both switches live in the site configuration:

```yaml
# 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/json` — `Accept: application/json, text/plain, */*` (the
axios/fetch default) or `application/json; charset=utf-8` 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/headless` (full
response) and `friendsoftypo3/headless-mixed`. On TYPO3 v12 include the
`headless` static template in the root TypoScript record instead.

Set and mode variants are described in [Configuration](https://docs.typo3.org/permalink/friendsoftypo3/headless:configuration@main).

## 4\. Drop a content element on the page {#4-drop-a-content-element-on-the-page}

Add a *Text* element (or any standard CE) to the page. Save.

## 5\. Fetch the page {#5-fetch-the-page}

```bash
curl https://api.example.com/
```

You should get something like:

```json
{
  "id": 1,
  "slug": "/",
  "seo": { "title": "Home" },
  "breadcrumbs": [{ "title": "Home", "link": "/" }],
  "content": {
    "colPos0": [{ "id": 1, "type": "text", "content": { "bodytext": "…" } }]
  }
}
```

See [Reference: TypoScript helpers](https://docs.typo3.org/permalink/friendsoftypo3/headless:ref-typoscript@main) for what each field means and where to
override it.

## What next? {#what-next}

-   Add a top-level field of your own: [Adding fields via raw TypoScript](https://docs.typo3.org/permalink/friendsoftypo3/headless:developer-custom-typoscript@main).
-   Put your SPA on a separate domain (so links in the response point at
    your frontend, not the API): [Multi-Site & URL Configuration](https://docs.typo3.org/permalink/friendsoftypo3/headless:multisite@main).
-   Listen to a headless event (e.g. inject a signed CDN URL into every
    file payload): [Events you can listen to](https://docs.typo3.org/permalink/friendsoftypo3/headless:developer-events@main).
-   Stuck? [FAQ → Troubleshooting](https://docs.typo3.org/permalink/friendsoftypo3/headless:faq@main).
