---
title: "TypoScript cObjects"
manual: "Headless"
version: "main"
permalink: "https://docs.typo3.org/permalink/friendsoftypo3/headless:developer-cobjects@main"
source: "Developer/CObjects.rst"
rendered: "2026-10-14T09:29:03+00:00"
---

# TypoScript cObjects {#developer-cobjects}

EXT:headless registers a handful of new cObjects:

-   `JSON`
-   `CONTENT_JSON`
-   `BOOL`, `FLOAT`, `INT`

`BOOL`, `FLOAT` and `INT` take `value` and `value.` (stdWrap applied
to the value); every remaining top-level property is treated as stdWrap
configuration directly — `noIndex.field = no_index` works, there is no
`stdWrap.` sub-key like core `TEXT`. They return a real bool / float /
int and only work as fields *inside* a `JSON` cObject, not in generic
TypoScript.

## JSON {#json}

Builds a JSON object inline.

```typoscript
lib.meta = JSON
lib.meta {
  if.isTrue = 1
  fields {
    title = TEXT
    title {
      field = seo_title
      stdWrap.ifEmpty.cObject = TEXT
      stdWrap.ifEmpty.cObject {
        field = title
      }
    }
    robots {
      fields {
        noIndex = BOOL
        noIndex.field = no_index
      }
    }
    ogImage = TEXT
    ogImage {
      dataProcessing {
        10 = FriendsOfTYPO3\Headless\DataProcessing\FilesProcessor
        10 {
          as = media
          references.fieldName = og_image
          processingConfiguration {
            returnFlattenObject = 1
          }
        }
      }
    }
  }
  dataProcessing {
  }
  stdWrap {
  }
}
```

The JSON cObject understands these properties:

**\`if\`** — render the object only when the condition is met.

**\`fields\`** — array of child cObjects. Each field accepts:

-   `intval` / `floatval` / `boolval` — cast the result.
-   `ifEmptyReturnNull` — return `null` when the result is empty.
-   `ifEmptyUnsetKey` — drop the key when the result is empty.
-   `source` — nested field blocks only: output the block's `fields`
    result under a different key. Ignored on plain fields, and ignored
    when the block defines `dataProcessing` — that result is always
    stored under the block's own key.
-   `dataProcessing` — run data processors (see `lib.meta.ogImage`). A field
    whose cObject is `JSON` runs its processors itself, exactly once; its own
    `dataProcessingMerge`, `stdWrap` and `if` apply to the result.

**\`nullableFieldsIfEmpty\`** — comma list of field names to null out
when empty (bulk variant of `ifEmptyReturnNull`).

A field whose cObject is `USER_INT` (or whose output starts with an
`<!--INT_SCRIPT` placeholder) is wrapped in `HeadlessUserInt` markers,
so the uncacheable value is substituted into the JSON on output; with
`ifEmptyReturnNull = 1` the nullable marker variant is used.

**\`dataProcessing\`** — *replaces* the `fields` output: the processors
run and the value registered under the last `as` key of the object's own
processors becomes the object's content (e.g.
[MenuProcessor](https://docs.typo3.org/permalink/friendsoftypo3/headless:dataprocessors-menuprocessor@main)). An `as` on a
field's processor or on a nested processor is never used for this.
When no processor declares `as`, or none of the declared names was
registered, the last variable the processors registered is used, so a
processor's default name such as `files` or `menu` works without `as`.
Set `dataProcessingMerge` to keep both.

**\`dataProcessingMerge\`** — merge instead of replace. With
`dataProcessingMerge = 1` and `fields` present, the `fields` output is
kept and every processor result is added to it under the processor's
target (`as`) name; on a key collision the processor result wins.

```typoscript
lib.page = JSON
lib.page {
  dataProcessingMerge = 1
  fields {
    title = TEXT
    title.field = title
  }
  dataProcessing {
    10 = FriendsOfTYPO3\Headless\DataProcessing\MenuProcessor
    10.as = mainMenu
  }
}

# {"title":"…","mainMenu":[…]} instead of the menu replacing the title
```

The flag also works on a nested field block that defines both `fields`
and `dataProcessing`, and on a field rendered as `JSON`. Without the
flag — or without `fields` — the behaviour is unchanged: the processors
replace the whole object.

**\`stdWrap\`** — `stdWrap` applied to the already-encoded JSON string.

## CONTENT_JSON {#content-json}

Like core's `CONTENT`, but content elements are grouped by `colPos`
and JSON-encoded by default. All `CONTENT` options apply, plus four
JSON-specific extras:

**merge**

Run a second `CONTENT_JSON` query and merge the result into the
first — handy for the `slide` feature.

```typoscript
lib.content = CONTENT_JSON
lib.content {
  table = tt_content
  select {
    orderBy = sorting
    where = {#colPos} != 1
  }
  merge {
    table = tt_content
    select {
      orderBy = sorting
      where = {#colPos} = 1
    }
    slide = -1
  }
}
```

**doNotGroupByColPos**

`0` (default) groups by `colPos` — every rendered element must then
expose a `colPos` field, otherwise rendering throws a
`RuntimeException`. `1` returns a flat JSON array.

An empty result is encoded as `{}` with grouping enabled and as `[]`
with `doNotGroupByColPos = 1` — consumers must handle both types.

```typoscript
lib.content = CONTENT_JSON
lib.content {
  table = tt_content
  select {
    orderBy = sorting
    where = {#colPos} != 1
  }
  doNotGroupByColPos = 1
}
```

**sortByBackendLayout**

Order the `colPos` groups by the order of columns in the page's
backend layout instead of numerically.

**returnSingleRow**

Return the first matched element as a single object instead of an
array — for one-record queries. Only takes effect together with
`doNotGroupByColPos = 1`; with the default `colPos` grouping the flag
is silently ignored.

```typoscript
lib.header = CONTENT_JSON
lib.header {
  table = tt_content
  select {
    orderBy = sorting
    max = 1
  }
  doNotGroupByColPos = 1
  returnSingleRow = 1
}
```
