---
title: "Save or clear workspace custom CSS"
method: PATCH
path: "/api/v3/workspaces/{workspaceId}/custom-css"
tags: ["V3 Workspaces"]
---

# Save or clear workspace custom CSS

`PATCH /api/v3/workspaces/{workspaceId}/custom-css`

## Request

- Base URL: `https://app.formbricks.com`
- URL: `https://app.formbricks.com/api/v3/workspaces/{workspaceId}/custom-css`
- Auth: one of:
  - API key in cookie `next-auth.session-token`
  - API key in header `x-api-key`
  - HTTP bearer

Saves or clears the workspace's shared survey CSS. `customCss` replaces both fields; `null` clears all of it. The source is processed by the same processor every save path uses: constructs it removes come back as top-level `warnings`, and CSS it rejects is a **422** that leaves the saved CSS in effect. The replaced value becomes `previous`, the one recoverable revision — restore it by sending its source back. Unchanged source writes nothing.

Workspace CSS reaches every survey in the workspace, so writing it is narrower than writing a survey: **organization owners and managers** for signed-in users (session or OAuth), and a **`manage`** grant on this workspace for API keys — a Read & write grant is refused with **403**. On Formbricks Cloud, adding or editing needs the Scale plan (**403** `custom_css_plan_required`); clearing never does. Successful changes refresh the cached configuration the SDKs receive (they pick it up on their next configuration fetch). Saves that add or edit CSS count against a custom CSS budget of 60 per minute per user or API key, shared with custom CSS validation and with survey writes that add or edit custom CSS; beyond it they return **429**. Re-saving the same CSS and clearing it are never counted.

## Path parameters

- `workspaceId` string, cuid2, required

## Request body

- PatchWorkspaceCustomCssRequest
  - `customCss` CustomCssInput, required: Custom CSS **source** as a caller writes it (ENG-3641). Both keys are required. `light` is base CSS that applies in both appearances; `dark` adds overrides on top of it when the survey renders dark. `null`, an empty string or whitespace means "no CSS" for that field. Source only: compiled output and the processor version are computed by the server on every write, and a request that supplies either is rejected. The combined source is limited to 100 000 UTF-8 bytes for a workspace and 20 000 for a survey; larger CSS is a **422** with error code `source_too_large`.
    - `light` string, nullable, required: Base CSS, applied in light and dark appearance.
    - `dark` string, nullable, required: Additional CSS applied only in dark appearance.

## Response `200`

Workspace custom CSS saved (or unchanged)

- object
  - `data` WorkspaceCustomCssResource, required: A workspace's shared survey CSS (ENG-3641): editable source for authorized readers, never compiled output. It applies to every survey in the workspace, beneath each survey's own CSS.
    - `workspaceId` string, required
    - `customCss` CustomCssInput, required: Custom CSS **source** as a caller writes it (ENG-3641). Both keys are required. `light` is base CSS that applies in both appearances; `dark` adds overrides on top of it when the survey renders dark. `null`, an empty string or whitespace means "no CSS" for that field. Source only: compiled output and the processor version are computed by the server on every write, and a request that supplies either is rejected. The combined source is limited to 100 000 UTF-8 bytes for a workspace and 20 000 for a survey; larger CSS is a **422** with error code `source_too_large`.
      - `light` string, nullable, required: Base CSS, applied in light and dark appearance.
      - `dark` string, nullable, required: Additional CSS applied only in dark appearance.
    - `previous` CustomCssInput, required: Custom CSS **source** as a caller writes it (ENG-3641). Both keys are required. `light` is base CSS that applies in both appearances; `dark` adds overrides on top of it when the survey renders dark. `null`, an empty string or whitespace means "no CSS" for that field. Source only: compiled output and the processor version are computed by the server on every write, and a request that supplies either is rejected. The combined source is limited to 100 000 UTF-8 bytes for a workspace and 20 000 for a survey; larger CSS is a **422** with error code `source_too_large`.
      - `light` string, nullable, required: Base CSS, applied in light and dark appearance.
      - `dark` string, nullable, required: Additional CSS applied only in dark appearance.
    - `status` 'ok' | 'stale' | 'withheld', required: `stale`: compiled by an older processor and delivered by recompiling its source. `withheld`: the source no longer passes the current processor, so respondents receive none of it until it is fixed and saved again.
    - `errors` CustomCssError[]: Present only when `status` is `withheld`.
      - `code` 'syntax_error' | 'source_too_large' | 'output_too_large' | 'limit_exceeded' | 'processing_failed', required
      - `scope` 'workspace' | 'survey', required
      - `appearance` 'light' | 'dark' | 'null', nullable, required
      - `line` integer, nullable, required
      - `column` integer, nullable, required
      - `reason` string, required
    - `canEdit` boolean, required: Whether this caller may PATCH it: organization owners and managers for signed-in users, a `manage` grant on this workspace for API keys.
    - `planAllowed` boolean, required: Whether the organization's plan allows additions and edits (Scale on Formbricks Cloud; every self-hosted plan). Removing CSS is always allowed.
  - `warnings` CustomCssWarning[]: Processing warnings for this write: constructs the processor removed. Additive, returned beside `data` (never inside it, so `data` can be sent back unchanged); present only when the write processed custom CSS.
    - `code` 'import_removed' | 'font_face_removed' | 'external_resource_removed' | 'unsupported_at_rule_removed' | 'unsafe_property_removed' | 'unsafe_value_removed' | 'fixed_position_removed' | 'unsafe_selector_removed' | 'unknown_property' | 'invalid_value', required
    - `scope` 'workspace' | 'survey', required
    - `appearance` 'light' | 'dark' | 'null', nullable, required: Source field the issue is in; `null` when it concerns the scope as a whole.
    - `line` integer, nullable, required: 1-based line in that field's source; `null` when there is no single location.
    - `column` integer, nullable, required
    - `reason` string, required

## Other responses

- `400`: Bad Request — malformed body, a missing `customCss` key or a missing `light` / `dark` key, an unsupported field (including `compiled` or `processorVersion`), or a field that is neither a string nor null. Every offending field is itemized in `invalid_params`. CSS over the size budget is a **422** `source_too_large`.
- `401`: Not authenticated (no valid session or API key).
- `403`: Forbidden — no access to the workspace (404 not used; avoids existence leak), a principal that may not write workspace CSS (`code: forbidden`), or an addition or edit on an organization without the Scale plan (`code: custom_css_plan_required`).
- `422`: Unprocessable Content — the CSS could not be processed (a syntax error, the 100 000-byte workspace budget, a complexity limit). `invalid_params` names `customCss.light` / `customCss.dark`; `details.errors` carries the processor's located errors. Nothing was saved.
- `429`: Rate limit exceeded.
- `500`: Internal Server Error.

## Changes

- **2026-10-28** `84820a01e550`: 18 warning
  - added the new `chart_in_use` enum value to the `code` response property for the response status `400`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `401`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `403`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `422`
  - …14 more
- **2026-10-27** `aad5dc1d8236`: 12 warning
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `400`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `401`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `403`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `422`
  - …8 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/formbricks/apis/formbricks-api-v3/changes/api/v3/workspaces/:workspaceId/custom-css/patch.md)

---

[API](https://skmtc.dev/formbricks/apis/formbricks-api-v3.md) - [All operations](https://skmtc.dev/formbricks/apis/formbricks-api-v3/llms.txt) - [OpenAPI document](https://skmtc.dev/formbricks/apis/formbricks-api-v3/revisions/25335c959a13?raw)
