# Custom page settings

A custom page set replaces the error responses of a [workload](/en/documentation/platform/workloads/) with pages of your own. It holds one page per HTTP status code, and each page fetches its content from a [connector](/en/documentation/platform/connectors/), keeps it in cache for its own time, and can answer with a different status code. A workload uses a set only when you assign the set in the workload's deployment, in `strategy.attributes.custom_page`. For the deployment fields, refer to [Workload settings](/en/documentation/platform/workloads/settings/#deployment).

---

## Interfaces

Three interfaces write a custom page set, and the deployment of a workload assigns it. The tables on this page name the Console control and the API field of each setting.

| Interface                                                                    | Create                                                                             | Read, update, delete                                                                                                             |
| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| [Azion Console](https://console.azion.com/)                                  | The **Custom Pages** menu at `/custom-pages`, then the **Create Custom Page** page | The **Edit Custom Page** page                                                                                                    |
| [Azion API v4](https://api.azion.com/v4#/operations/GetWorkspaceCustomPages) | `POST /v4/workspace/custom_pages`                                                  | `GET`, `PUT`, `PATCH`, and `DELETE /v4/workspace/custom_pages/{custom_page_id}`; `GET /v4/workspace/custom_pages` lists the sets |
| Azion CLI                                                                    | `azion create custom-pages --file`                                                 | `azion describe custom-pages --custom-page-id` and `azion list custom-pages`                                                     |

The CLI reads every field of the set from the JSON file of `--file`. To assign a set, select it in the **Custom Page** field of the workload's **Deployment Settings** section, send its ID in `strategy.attributes.custom_page`, or pass `--custom-page` to `azion create workload-deployment`. A deployment without a set reads `"custom_page": null`.

Azion does not guarantee when an assigned set starts to serve. A change to a workload's deployment takes several minutes to reach Azion's distributed infrastructure, and requests can receive the previous or the updated configuration while it spreads.

On API v4, **Custom Pages** takes the place of Error Responses, the error page settings of an API v3 application. Each v3 field has a v4 counterpart:

| Error Responses field, API v3 | Custom Pages field, API v4                            |
| ----------------------------- | ----------------------------------------------------- |
| Status Code                   | **Page Code**, `code`                                 |
| Error Caching TTL             | **Response TTL**, `ttl`                               |
| URI                           | **Page Path (URI)**, `uri`                            |
| Custom Status Code            | **Response Custom Status Code**, `custom_status_code` |

The two models locate the page file differently. A v3 URI is appended to the application's domain and fetched from the origin named in Set Origin. A v4 `uri` is fetched from the connector of the page. For an application that still runs on API v3, refer to [Error Responses](/en/documentation/platform/workloads/custom-pages/error-responses/).

---

## Custom page set fields

A custom page set is a named list of pages. The API requires `name` and `pages`, and the other fields are read-only, except `active`. In the Console, the **Create Custom Page** page reads: "Create custom pages to handle errors and cache TTL based on the HTTP status code received from the Connectors."

| Console control      | API field         | Type                  | Values                                                    | Default              |
| -------------------- | ----------------- | --------------------- | --------------------------------------------------------- | -------------------- |
| none                 | `id`              | integer               | assigned by Azion, read-only                              | none                 |
| **Name**             | `name`            | string                | 1 to 255 characters                                       | required, no default |
| **Active**           | `active`          | boolean               | `true`, `false`                                           | `true`               |
| **Page Codes** table | `pages`           | array of page objects | at least one page, each described in Page fields          | required, no default |
| none                 | `last_editor`     | string                | the email of the last user who changed the set, read-only | none                 |
| none                 | `last_modified`   | string, date-time     | read-only                                                 | none                 |
| none                 | `created_at`      | string, date-time     | read-only                                                 | none                 |
| none                 | `product_version` | string                | read-only                                                 | `1.0`                |

The help text of **Name** reads "Give a unique and descriptive name to identify the custom page." The **Page Codes** table lists one row per page, with the columns **Page Status Code**, **Page Path (URI)**, **Custom Status Code**, and **Response TTL**. A set with no page is refused, in the API and in the Console.

---

## Page fields

Each entry of `pages` binds one status code to one page. The page names the connector that holds the content, the path of the content on that connector, the time Azion keeps it in cache, and an optional status code for the response. In the Console, these fields sit in the **Status Configuration** and **Response Details** sections of a page.

| Console control                 | API field                            | Type               | Values                                                         | Default              |
| ------------------------------- | ------------------------------------ | ------------------ | -------------------------------------------------------------- | -------------------- |
| **Page Code**                   | `code`                               | string             | `default` or one of the codes in Status codes, such as `"404"` | required, no default |
| *Page Connector*                | `page.type`                          | string             | `page_connector`                                               | `page_connector`     |
| **Connector**                   | `page.attributes.connector`          | integer            | the ID of a connector                                          | required, no default |
| **Response TTL**                | `page.attributes.ttl`                | integer, seconds   | 0 to 31,536,000                                                | `0`                  |
| **Page Path (URI)**             | `page.attributes.uri`                | string, or `null`  | 1 to 250 characters                                            | none                 |
| **Response Custom Status Code** | `page.attributes.custom_status_code` | integer, or `null` | 100 to 599                                                     | none                 |

A page acts on the status code Azion receives from the connector of the application. When that code has a page in the set, the visitor receives the page's content in place, with no redirect, and the content can be cached. The Console offers two page types, *Page Connector* and *Page Default*. With *Page Default*, the Console shows the **Content Type** and **Response** fields instead of the connector fields, and the API has no documented shape for that type.

`page.attributes.uri` is the path from which the page's connector delivers the content. For example, with the path `/myerrors/505.html` and a connector whose address is `myconnector.azion.com`, Azion fetches and delivers the content from `myconnector.azion.com/myerrors/505.html`.

`page.attributes.ttl` sets how many seconds the error page stays in cache before Azion refreshes it. An error page is often static and rarely changes, so Azion recommends a high value, which reduces the processing your origin does. For the expiration settings of an application's own cache, refer to [Cache settings](/en/documentation/platform/applications/cache/cache-settings/#browser-cache).

`page.attributes.custom_status_code` is the status code the visitor receives instead of the original one. For example, a page with `code` set to `"403"` and `custom_status_code` set to `404` answers a `403` from the connector with a `404`.

---

## Status codes

The `code` field takes 22 HTTP status codes: 16 client errors (4xx) and six server errors (5xx). It also accepts `default`, which the Console lists as *Default*. For a code with no page of its own, the **Page Codes** help text reads: "Codes tagged Azion serve the default Azion page; setting a custom page for one of them replaces it." The table describes what each code means when the connector returns it.

| `code` | Status                          | What the connector response means                                                                                                                                                                                                                                                                                      |
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Bad Request                     | The request has invalid parameters or lacks required ones.                                                                                                                                                                                                                                                             |
| `401`  | Unauthorized                    | The request lacks the authentication header the server requires.                                                                                                                                                                                                                                                       |
| `403`  | Forbidden                       | The user has no permission to run the operation.                                                                                                                                                                                                                                                                       |
| `404`  | Not Found                       | The requested resource does not exist.                                                                                                                                                                                                                                                                                 |
| `405`  | Method Not Allowed              | The request method cannot be applied to the URL.                                                                                                                                                                                                                                                                       |
| `406`  | Not Acceptable                  | The request has no `Accept` header, or the header asks for a format or version the server does not support.                                                                                                                                                                                                            |
| `408`  | Request Timeout                 | The request arrives more slowly than the server is prepared to wait, so the server wants to close the connection. Some browsers, such as Chrome, Firefox 27+, and IE9, open connections in advance to speed up navigation, which makes this response common, and some servers close the connection without sending it. |
| `409`  | Conflict                        | The request conflicts with the server's state, such as a request that creates a record that already exists.                                                                                                                                                                                                            |
| `410`  | Gone                            | The content was deleted from the server permanently, with no redirect address, so caches and links to it should be removed. The HTTP specification describes it for limited promotional services, and an API should not use it to say which resources were removed.                                                    |
| `411`  | Length Required                 | The server requires a `Content-Length` header, and the request has none.                                                                                                                                                                                                                                               |
| `414`  | URI Too Long                    | The requested URI is longer than the server accepts.                                                                                                                                                                                                                                                                   |
| `415`  | Unsupported Media Type          | The server does not support the media format of the request data, so it rejects the request.                                                                                                                                                                                                                           |
| `416`  | Range Not Satisfiable           | The server cannot fill the value of the `Range` header, usually because it falls outside the data of the target URI.                                                                                                                                                                                                   |
| `426`  | Upgrade Required                | The server refuses the request on the current protocol and accepts it after the client changes protocol. Its `Upgrade` header names the protocols it requires.                                                                                                                                                         |
| `429`  | Too Many Requests               | The request exceeded an operation limit and was refused for a time. The client must wait before it tries again.                                                                                                                                                                                                        |
| `431`  | Request Header Fields Too Large | The request headers are too long, or the request sends too many cookies.                                                                                                                                                                                                                                               |
| `500`  | Internal Server Error           | An unexpected fault occurred while the server processed the request.                                                                                                                                                                                                                                                   |
| `501`  | Not Implemented                 | The server does not support the request method. Servers must support `GET` and `HEAD`, so they do not return this code for those two methods.                                                                                                                                                                          |
| `502`  | Bad Gateway                     | The server, acting as a gateway, received an invalid response while it handled the request.                                                                                                                                                                                                                            |
| `503`  | Service Unavailable             | The server is not ready to handle the request, often because it is overloaded or under maintenance. The code marks a temporary condition: the response should explain the problem, carry a `Retry-After` header with the estimated recovery time, and is not normally cached.                                          |
| `504`  | Gateway Timeout                 | The server, acting as a gateway, did not receive a response in time.                                                                                                                                                                                                                                                   |
| `505`  | HTTP Version Not Supported      | The server does not support the HTTP version of the request.                                                                                                                                                                                                                                                           |

---

## Request body

The JSON body below creates a set with one page. It replaces a `404` from the connector with the document the connector serves at `/html`, and answers with status `404`. The same body works for `POST /v4/workspace/custom_pages` and for the file of `azion create custom-pages --file`:

```json
{"name": "my-custom-pages", "active": true, "pages": [
  {"code": "404", "page": {"type": "page_connector", "attributes": {"connector": <connector-id>, "ttl": 0, "uri": "/html", "custom_status_code": 404}}}
]}
```

Send it with the CLI, with the body saved as `cp.json`:

```bash
azion create custom-pages --file cp.json
```

The command prints the ID of the new set:

```text
Created Custom Page with ID <custom-page-id>
```

`azion list custom-pages --details` lists the set:

```text
ID   NAME                  ACTIVE  LAST EDITOR             LAST MODIFIED                         
<custom-page-id>  my-custom-pages  true    <your-email>  2026-01-01 12:00:00.000000 +0000 UTC  
```

`azion describe custom-pages --custom-page-id <custom-page-id> --format json` returns the set as the API stores it, with every page attribute as sent:

```json
{
 "active": true,
 "created_at": "2026-01-01T12:00:00.00000Z",
 "id": <custom-page-id>,
 "is_versioned": false,
 "last_editor": "<your-email>",
 "last_modified": "2026-01-01T12:00:00.000000Z",
 "name": "my-custom-pages",
 "pages": [
  {
   "code": "404",
   "page": {
    "attributes": {
     "connector": <connector-id>,
     "custom_status_code": 404,
     "ttl": 0,
     "uri": "/html"
    },
    "type": "page_connector"
   }
  }
 ],
 "product_version": "1.0",
 "version": null,
 "version_id": null,
 "version_state": null
}
```

The set serves only after a workload's deployment names it. The CLI assigns it when it creates the deployment:

```bash
azion create workload-deployment \
  --workload-id <workload-id> \
  --name my-deployment \
  --application-id <application-id> \
  --custom-page <custom-page-id> \
  --strategy-type default \
  --active true \
  --current true
```

The command prints the ID of the new deployment:

```text
Created Workload Deployment with ID <deployment-id>
```

After the deployment propagates, a request whose connector answers `404` receives the page's content in place. The response keeps status `404`, from `custom_status_code`, and carries no `Location` header, so the client is not redirected:

```bash
curl -s -D - https://<workload-domain>/status/404
```

The response starts with the status line and the document from the connector's `/html` path:

```text
HTTP/2 404 
content-type: text/html; charset=utf-8

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
      <h1>Herman Melville - Moby-Dick</h1>
```

---

## Errors

The API refuses a set with an empty `pages` list, and the Console refuses to save one. The CLI prints the API message inside `Error: Failed to create Custom Page: [...]`, followed by `Check your settings and try again. If the error persists, contact Azion support`.

| Message                                       | Cause                                                     | What to do                               |
| --------------------------------------------- | --------------------------------------------------------- | ---------------------------------------- |
| `Ensure this field has at least 1 elements.`  | The request sends `"pages": []`.                          | Add at least one page to `pages`.        |
| `You must have at least one custom page code` | The Console form has no page in the **Page Codes** table. | Add a page code before you save the set. |

---

## Related resources

- [Custom Pages quickstart](/en/documentation/platform/workloads/custom-pages/quickstart.md): Create a custom page set, assign it in a workload's deployment, and see a page replace an error.
- [Workload settings](/en/documentation/platform/workloads/settings.md): Every field of a workload and of the deployment that assigns its application, firewall, and custom page set.
- [Error Responses](/en/documentation/platform/workloads/custom-pages/error-responses.md): The error page settings of an API v3 application, for accounts that still run on API v3.
- [How Workloads works](/en/documentation/platform/workloads/how-it-works.md): The path a request follows from a domain through the workload to its application and connector.
