---
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 even though it is a `PUT`. Keys you leave out of `settings` keep their saved values, and `pages` merges twice over: a page you don't mention keeps its overrides, and a field you don't send on a page you do mention keeps its saved value. Sending one page's `title` therefore leaves that page's `description` and every other page untouched.

<Note>You can't remove a page or a page override here. Sending `pages: {}` changes nothing, and a `null` page entry is rejected with a 422. To stop a page overriding a tag, send an empty string as that field's value.</Note>

Saving is immediate, and the copy the live site serves is refreshed right after on a best-effort basis. A 200 means the settings are stored, so re-read them with [Get SEO settings](/api-reference/get-seo-settings) rather than treating the published pages as confirmation.

This endpoint is limited to 30 requests per minute per app, and that budget is shared with the app's other SEO endpoints.

<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 objects Base44 injects alongside its own. Every entry must be a JSON object. 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, wrapped in the field the endpoint returns them under.
  - `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 objects Base44 injects alongside its own. Every entry must be a JSON object. 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, or you used a workspace API key. These endpoints accept a user's credentials only.
- `404` — App not found.
- `422` — Validation Error
- `429` — Rate limit exceeded (30 requests per minute).

---

[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-service-production.skmtc.workers.dev/v1/apis/base44/base44-app-management-api/revisions/173e4e9c63c2/schema)
