EXT:redirects 

Install EXT:redirects (composer require typo3/cms-redirects) and the standard redirect manager works as usual. EXT:headless then automatically swaps the relevant frontend middlewares so a matched redirect surfaces to a headless frontend as JSON rather than a 30x response — no feature flag required.

The replaced middlewares are:

  • typo3/cms-frontend/base-redirect-resolverFriendsOfTYPO3HeadlessMiddlewareSiteBaseRedirectResolver
  • typo3/cms-frontend/shortcut-and-mountpoint-redirectFriendsOfTYPO3HeadlessMiddlewareShortcutAndMountPointRedirect

Matched redirects from the redirect manager are turned into JSON by the headless/RedirectWasHit event listener (see below) — the core redirecthandler middleware stays in place.

Requests for the headless page-content type (?type=834) bypass shortcut and mount-point redirect handling entirely and are resolved downstream instead.

JSON response shape 

A matched redirect produces:

{
  "redirectUrl": "https://example.com/new-target",
  "statusCode": 301
}
Copied!

redirectUrl is run through UrlUtility::prepareRelativeUrlIfPossible(), so internal targets come back as relative paths (/new-target) when they land on the same frontend host.

The HTTP response itself is always 200statusCode tells the frontend which redirect to perform, and the frontend must apply the usual method semantics itself (301/302 may switch to GET, 307/308 preserve the request method). Its value depends on the source:

  • redirect-manager records: the record's configured target status code;
  • shortcut/mount-point and site-base redirects: the HTTP code the core middleware would have sent (typically 307).

Customising the redirect 

The JSON envelope is built by FriendsOfTYPO3HeadlessEventListenerHeadlessRedirectResponseListener, which listens to the core TYPO3CMSRedirectsEventRedirectWasHitEvent (identifier headless/RedirectWasHit). Register your own listener for the same event after it and replace the response:

final readonly class TagRedirectsForAnalytics
{
    public function __invoke(RedirectWasHitEvent $event): void
    {
        $response = $event->getResponse();
        if (!$response instanceof JsonResponse) {
            return;
        }

        $payload = json_decode((string)$response->getBody(), true);
        $payload['redirectUrl'] .= '?utm_source=redirect';
        $event->setResponse(new JsonResponse($payload));
    }
}
Copied!
# Configuration/Services.yaml
services:
  Vendor\MyExt\EventListener\TagRedirectsForAnalytics:
    tags:
      - name: event.listener
        identifier: 'myext/redirect/analytics'
        after: 'headless/RedirectWasHit'
Copied!

Page targets carrying Extbase plugin parameters in the typolink additionalParams segment are rebuilt through the site router by FriendsOfTYPO3HeadlessRedirectsTargetUrlResolver (the core RedirectService drops that segment unless "keep query parameters" is enabled). Override or extend that service via Services.yaml when you need different target URL resolution.

Short URLs & QR codes (5.x) 

The "Short URLs" and "QR Codes" backend modules of EXT:redirects show source URLs on the TYPO3 host — useless when the public site lives on the frontend domain. With headless, both modules (and the QR-code/short-URL fields in redirect records) resolve source URLs against the site's frontendBase instead, so copied links and scanned codes land on the public frontend. No configuration needed beyond frontendBase; resolution logic can be replaced by overriding FriendsOfTYPO3HeadlessRedirectsSourceUrlResolver via Services.yaml.