---
title: "Update SEO settings"
method: PUT
path: "/api/apps/{app_id}/seo/settings"
---

# Update SEO settings

`PUT /api/apps/{app_id}/seo/settings`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Saves SEO settings for the app and returns the settings as they now stand.

This is a partial update. Keys you leave out of `settings` keep their saved values. The same is true one level deeper for `pages`. A page absent from your `pages` object keeps its existing overrides, and within a page you do include, any field you leave out keeps its saved value. For example, sending only a page's `title` changes that field alone. Its `description` and every other page stay as they were.

You can't remove a page or a page override through this endpoint. An empty `pages` object changes nothing, and a `null` page entry is rejected. To stop a page overriding a tag, send an empty string as that field's value instead.

Saving itself is immediate. The live site is served from a separate copy, which is updated right after, but that update isn't guaranteed to happen in the same moment and can lag. A successful call means the settings are stored, not that the live site has caught up, so confirm with [Get SEO settings](/api-reference/get-seo-settings) rather than treating the published pages as proof.

<Warning>The response includes fields beyond the ones documented here. Don't rely on undocumented response fields, as they can change at any time. Send only the fields documented here. Other request fields are not supported and their behavior can change.</Warning>

## Path parameters

- `app_id` string, required — ID of the app whose SEO settings you want.

## Request body

- object
  - `settings` object, required — The settings to save. Send only the keys you want to change.
    - `seo_disabled` boolean — Whether you run your own SEO. When `true`, Base44 stops injecting titles, descriptions, Open Graph and Twitter tags, canonical URLs, JSON-LD and prerender snapshots, and serves your own `public/robots.txt` when you ship one. Defaults to `false` while the key is absent. This does not add a `noindex` tag, and a login-gated or private app stays unindexed whatever you set here.
    - `platform_meta_injection_enabled` boolean — Whether Base44 injects the title, description, Open Graph and Twitter tag block. Set it to `false` when your deployed `index.html` already carries a complete set. Narrower than `seo_disabled`, which also turns off canonical URLs, JSON-LD and snapshots. Defaults to `true` while the key is absent.
    - `platform_jsonld_injection_enabled` boolean — Whether Base44 injects its own WebSite, Organization, BreadcrumbList and FAQPage JSON-LD. Set it to `false` when your app ships its own structured data. Defaults to `true` while the key is absent.
    - `robots_txt_enabled` boolean — Whether Base44 generates `/robots.txt`. When `false`, your deployed `public/robots.txt` is served instead, and the path returns 404 when you ship none. Defaults to `true` while the key is absent.
    - `sitemap_xml_enabled` boolean — Whether Base44 generates `/sitemap.xml`. When `false`, your deployed `public/sitemap.xml` is served instead, and the path returns 404 when you ship none. Defaults to `true` while the key is absent.
    - `llms_txt_enabled` boolean — Whether Base44 serves a generated `/llms.txt` describing the app to AI crawlers. Defaults to `false` while the key is absent.
    - `ai_crawlers_enabled` boolean — Whether known AI crawlers are allowed in the generated `robots.txt`. Defaults to `true` while the key is absent.
    - `synthesized_breadcrumb_enabled` boolean — Whether Base44 builds a BreadcrumbList for each request path at render time. Set it to `false` to serve the saved `breadcrumb_schema` instead, which is what keeps a hand-written breadcrumb intact. Defaults to `true` while the key is absent.
    - `canonical_url` string, nullable — Base URL Base44 builds canonical tags from. The app's own published URL is used while the key is absent.
    - `content_query_params` string[] — Query-string parameter names whose values serve distinct content, such as `article` for `/guides?article=slug`. Naming one opts its URL variants into prerender warming, which otherwise only covers paths. Send at most 25 names, counted before the list is cleaned up, and match each name's casing exactly. Names are trimmed, and blank or repeated entries are dropped, so the list you read back can be shorter than the one you sent. Defaults to an empty list, meaning no query variants are warmed.
    - `custom_json_ld` object[], nullable — Extra JSON-LD entries Base44 injects alongside its own. Each entry needs a `json_ld_template` key holding the markup object to inject, matching the shape [Preview JSON-LD](/api-reference/preview-json-ld) returns. The key is absent while you have added none.
    - `website_schema` object, nullable — Saved WebSite JSON-LD object. The key is absent while none is saved.
    - `organization_schema` object, nullable — Saved Organization JSON-LD object. The key is absent while none is saved.
    - `breadcrumb_schema` object, nullable — Saved BreadcrumbList JSON-LD object. It is served only while `synthesized_breadcrumb_enabled` is `false`. The key is absent while none is saved.
    - `faq_schema` object, nullable — Saved FAQPage JSON-LD object. The key is absent while none is saved.
    - `pages` object — Per-page tag overrides, keyed by the page's component name as it appears in the app's code. The key is absent while no page overrides anything.

## Response `200`

The settings as they stand after the merge.

- SEOSettingsResponse — An app's SEO settings.
  - `result` SEOSettingsResource, required — An app's saved SEO settings.
    - `seo_disabled` boolean — Whether you run your own SEO. When `true`, Base44 stops injecting titles, descriptions, Open Graph and Twitter tags, canonical URLs, JSON-LD and prerender snapshots, and serves your own `public/robots.txt` when you ship one. Defaults to `false` while the key is absent. This does not add a `noindex` tag, and a login-gated or private app stays unindexed whatever you set here.
    - `platform_meta_injection_enabled` boolean — Whether Base44 injects the title, description, Open Graph and Twitter tag block. Set it to `false` when your deployed `index.html` already carries a complete set. Narrower than `seo_disabled`, which also turns off canonical URLs, JSON-LD and snapshots. Defaults to `true` while the key is absent.
    - `platform_jsonld_injection_enabled` boolean — Whether Base44 injects its own WebSite, Organization, BreadcrumbList and FAQPage JSON-LD. Set it to `false` when your app ships its own structured data. Defaults to `true` while the key is absent.
    - `robots_txt_enabled` boolean — Whether Base44 generates `/robots.txt`. When `false`, your deployed `public/robots.txt` is served instead, and the path returns 404 when you ship none. Defaults to `true` while the key is absent.
    - `sitemap_xml_enabled` boolean — Whether Base44 generates `/sitemap.xml`. When `false`, your deployed `public/sitemap.xml` is served instead, and the path returns 404 when you ship none. Defaults to `true` while the key is absent.
    - `llms_txt_enabled` boolean — Whether Base44 serves a generated `/llms.txt` describing the app to AI crawlers. Defaults to `false` while the key is absent.
    - `ai_crawlers_enabled` boolean — Whether known AI crawlers are allowed in the generated `robots.txt`. Defaults to `true` while the key is absent.
    - `synthesized_breadcrumb_enabled` boolean — Whether Base44 builds a BreadcrumbList for each request path at render time. Set it to `false` to serve the saved `breadcrumb_schema` instead, which is what keeps a hand-written breadcrumb intact. Defaults to `true` while the key is absent.
    - `canonical_url` string, nullable — Base URL Base44 builds canonical tags from. The app's own published URL is used while the key is absent.
    - `content_query_params` string[] — Query-string parameter names whose values serve distinct content, such as `article` for `/guides?article=slug`. Naming one opts its URL variants into prerender warming, which otherwise only covers paths. Send at most 25 names, counted before the list is cleaned up, and match each name's casing exactly. Names are trimmed, and blank or repeated entries are dropped, so the list you read back can be shorter than the one you sent. Defaults to an empty list, meaning no query variants are warmed.
    - `custom_json_ld` object[], nullable — Extra JSON-LD entries Base44 injects alongside its own. Each entry needs a `json_ld_template` key holding the markup object to inject, matching the shape [Preview JSON-LD](/api-reference/preview-json-ld) returns. The key is absent while you have added none.
    - `website_schema` object, nullable — Saved WebSite JSON-LD object. The key is absent while none is saved.
    - `organization_schema` object, nullable — Saved Organization JSON-LD object. The key is absent while none is saved.
    - `breadcrumb_schema` object, nullable — Saved BreadcrumbList JSON-LD object. It is served only while `synthesized_breadcrumb_enabled` is `false`. The key is absent while none is saved.
    - `faq_schema` object, nullable — Saved FAQPage JSON-LD object. The key is absent while none is saved.
    - `pages` object — Per-page tag overrides, keyed by the page's component name as it appears in the app's code. The key is absent while no page overrides anything.

## Other responses

- `401` — Missing or invalid credentials.
- `403` — You don't have access to this app, you used a workspace API key, or you used a read-only personal access token. These endpoints accept a user's credentials only, and none of them accept a read-only credential, including the ones that only read.
- `404` — App not found.
- `422` — The body is missing, `settings` is missing or not an object, a value doesn't match its field's type, `og_image` exceeds 2048 characters or isn't a valid `https://` URL with a host, `content_query_params` has more than 25 entries, or an entry in `custom_json_ld` isn't a JSON object.
- `429` — Rate limit exceeded. The base limit is 30 requests per minute, shared with the app's other SEO endpoints. See [Rate limits](/developers/references/apps-api/get-started/rate-limits) for the multiplier your plan gets.

## Changes

- **2026-09-18** `f70e515893d2` — 1 breaking
  - removed the media type `application/json` for the response with the status `422`

[Change history](https://skmtc.dev/base44/apis/base44-app-management-api/changes/api/apps/:app_id/seo/settings/put.md)

---

[API](https://skmtc.dev/base44/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/base44/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/base44/apis/base44-app-management-api/revisions/cf164639a9bf?raw)
