---
title: Cloudflare for Platforms
description: Cloudflare for Platforms is used by leading platforms big and small to:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Cloudflare for Platforms

Build a platform where your customers can deploy code, each with their own subdomain or custom domain.

Cloudflare for Platforms is used by leading platforms big and small to:

* Build application development platforms tailored to specific domains, like ecommerce storefronts or mobile apps
* Power AI coding platforms that let anyone build and deploy software
* Customize product behavior by allowing any user to write a short code snippet
* Offer every customer their own isolated database
* Provide each customer with their own subdomain

---

## Deploy your own platform

Get a working platform running in minutes. Choose a template based on what you are building:

### Platform Starter Kit

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/main/worker-publisher-template)

An example of a platform where users can deploy code at scale. Each snippet becomes its own isolated Worker, served at `example.com/{app-name}`. Deploying this starter kit automatically configures Workers for Platforms with routing handled for you.

[ View demo ](https://worker-publisher-template.templates.workers.dev/) [ View on GitHub ](https://github.com/cloudflare/templates/tree/main/worker-publisher-template) 

### AI vibe coding platform

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/vibesdk)

Build an [AI vibe coding platform](https://developers.cloudflare.com/reference-architecture/diagrams/ai/ai-vibe-coding-platform/) where users describe what they want and AI generates and deploys working applications. Best for: AI-powered app builders, code generation tools, or internal platforms that empower teams to build applications & prototypes.

[VibeSDK ↗](https://github.com/cloudflare/vibesdk) handles AI code generation, code execution in secure sandboxes, live previews, and deployment at scale.

[ View demo ](https://build.cloudflare.dev/) [ View on GitHub ](https://github.com/cloudflare/vibesdk) 

---

## Features

* **Isolation and multitenancy** — Each of your customers runs code in their own Worker, a [secure and isolated sandbox](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/worker-isolation/).
* **Programmable routing, ingress, egress, and limits** — You write code that dispatches requests to your customers' code, and can control [ingress](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/), [egress](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers/), and set [per-customer limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/).
* **Databases and storage** — You can provide [databases, object storage, and more](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) to your customers as APIs they can call directly, without API tokens, keys, or external dependencies.
* **Custom domains and subdomains** — You [call an API](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) to create custom subdomains or configure custom domains for each of your customers.

To learn how these components work together, refer to [How Workers for Platforms works](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}}]}
```

---

---
title: Workers for Platforms
description: Workers for Platforms lets you run untrusted code written by your customers, or by AI, in a secure hosted sandbox. Each customer runs code in their own Worker, a secure and isolated environment.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Workers for Platforms

Build a multi-tenant platform that runs untrusted code in secure, isolated sandboxes.

Workers for Platforms lets you run untrusted code written by your customers, or by AI, in a secure hosted sandbox. Each customer runs code in their own Worker, a secure and isolated environment.

## When to use Workers for Platforms

Use Workers for Platforms when you need to:

* **Run untrusted code at scale** \- Execute code written by your customers or generated by AI in a secure sandbox, with the ability to deploy an unlimited number of applications.
* **Build multi-tenant platforms** \- Give each customer their own isolated compute environment with complete separation between tenants.
* **Extend Cloudflare's developer platform to your customers** \- Use [bindings](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) to give each customer access to KV stores, D1 databases, R2 storage, and more. Your customers get the same powerful tools, managed through your platform.
* **Give each application its own domain** \- Host applications under a subdomain of your domain (for example, `customer-name.myplatform.com`) or integrate with [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) to allow customers to use their own domains.

## Features

Workers for Platforms provides tools to manage and control your customers' code:

* **[Custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/)** \- Set per-customer limits on CPU time and subrequests.
* **[Observability](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/observability/)** \- Collect logs and metrics across all user Workers in your namespace. Export to third-party platforms like Datadog, Splunk, and Grafana.
* **[Tags](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/tags/)** \- Organize, search, and filter user Workers by custom tags like customer ID, plan type, or environment.

---

## Reference architectures

Explore reference architectures that use Workers for Platforms:

[Programmable PlatformsWorkers for Platforms provide secure, scalable, cost-effective infrastructure for programmable platforms with global reach.](https://developers.cloudflare.com/reference-architecture/diagrams/serverless/programmable-platforms/)[AI Vibe Coding PlatformCloudflare's low-latency, fully serverless compute platform, Workers offers powerful capabilities to enable A/B testing using a server-side implementation.](https://developers.cloudflare.com/reference-architecture/diagrams/ai/ai-vibe-coding-platform/)

---

## Get started

[Get started](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/get-started/) 

Set up a dispatch namespace, dynamic dispatch Worker, and user Worker.

[How Workers for Platforms works](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/) 

Understand the architecture: dispatch namespaces, dynamic dispatch Workers, user Workers, and outbound Workers.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}}]}
```

---

---
title: Bindings
description: When you deploy User Workers through Workers for Platforms, you can attach bindings to give them access to resources like KV namespaces, D1 databases, R2 buckets, and more. This enables your end customers to build more powerful applications without you having to build the infrastructure components yourself.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

### Tags

[ Bindings ](https://developers.cloudflare.com/search/?tags=Bindings) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/bindings.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Bindings

When you deploy User Workers through Workers for Platforms, you can attach [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/) to give them access to resources like [KV namespaces](https://developers.cloudflare.com/kv/), [D1 databases](https://developers.cloudflare.com/d1/), [R2 buckets](https://developers.cloudflare.com/r2/), and more. This enables your end customers to build more powerful applications without you having to build the infrastructure components yourself.

With bindings, each of your users can have their own:

* [KV namespace](https://developers.cloudflare.com/kv/) that they can use to store and retrieve data
* [R2 bucket](https://developers.cloudflare.com/r2/) that they can use to store files and assets
* [Analytics Engine](https://developers.cloudflare.com/analytics/analytics-engine/) dataset that they can use to collect observability data
* [Durable Objects](https://developers.cloudflare.com/durable-objects/) class that they can use for stateful coordination

#### Resource isolation

Each User Worker can only access the bindings that are explicitly attached to it. For complete isolation, you can create and attach a unique resource (like a D1 database or KV namespace) to every User Worker.

![Resource Isolation Model](https://developers.cloudflare.com/_astro/programmable-platforms-5.B2yd7IjV_Z1IMWex.svg "Resource Isolation Model")

Resource Isolation Model

## Adding a KV Namespace to a User Worker

This example walks through how to create a [KV namespace](https://developers.cloudflare.com/kv/) and attach it to a User Worker. The same process can be used to attach to other [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/).

### 1\. Create a KV namespace

Create a KV namespace using the [Cloudflare API](https://developers.cloudflare.com/api/resources/kv/subresources/namespaces/methods/bulk%5Fupdate/).

### 2\. Attach the KV namespace to the User Worker

Use the [Upload User Worker API](https://developers.cloudflare.com/api/resources/workers%5Ffor%5Fplatforms/subresources/dispatch/subresources/namespaces/subresources/scripts/methods/update/) to attach the KV namespace binding to the Worker. You can do this when you're first uploading the Worker script or when updating an existing Worker.

Note

When using the API to upload scripts, bindings must be specified in the `metadata` object of your multipart upload request. You cannot upload the Wrangler configuration file as a module to configure the bindings. For more details about multipart uploads, see [Multipart upload metadata](https://developers.cloudflare.com/workers/configuration/multipart-upload-metadata/).

##### Example API request

Terminal window

```

curl -X PUT \

  "https://api.cloudflare.com/client/v4/accounts/<account-id>/workers/dispatch/namespaces/<your-namespace>/scripts/<script-name>" \

  -H "Content-Type: multipart/form-data" \

  -H "Authorization: Bearer <api-token>" \

  -F 'metadata={

    "main_module": "worker.js",

    "bindings": [

      {

        "type": "kv_namespace",

        "name": "USER_KV",

        "namespace_id": "<your-namespace-id>"

      }

    ]

  }' \

  -F 'worker.js=@/path/to/worker.js'


```

Now, the User Worker has can access the `USER_KV` binding through the `env` argument using `env.USER_DATA.get()`, `env.USER_DATA.put()`, and other KV methods.

Note: If you plan to add new bindings to the Worker, use the `keep_bindings` parameter to ensure existing bindings are preserved while adding new ones.

Terminal window

```

curl -X PUT \

  "https://api.cloudflare.com/client/v4/accounts/<account-id>/workers/dispatch/namespaces/<your-namespace>/scripts/<script-name>" \

  -H "Content-Type: multipart/form-data" \

  -H "Authorization: Bearer <api-token>" \

  -F 'metadata={

    "bindings": [

      {

        "type": "r2_bucket",

        "name": "STORAGE",

        "bucket_name": "<your-bucket-name>"

      }

    ],

    "keep_bindings": ["kv_namespace"]

  }'


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/","name":"Bindings"}}]}
```

---

---
title: Custom limits
description: Custom limits allow you to programmatically enforce limits on your customers' Workers' resource usage. You can set limits for the maximum CPU time and number of subrequests per invocation. If a user Worker hits either of these limits, the user Worker will immediately throw an exception.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom limits

Custom limits allow you to programmatically enforce limits on your customers' Workers' resource usage. You can set limits for the maximum CPU time and number of subrequests per invocation. If a user Worker hits either of these limits, the user Worker will immediately throw an exception.

## Set Custom limits

Custom limits can be set in the dynamic dispatch Worker:

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      // parse the URL, read the subdomain

      let workerName = new URL(request.url).host.split(".")[0];

      let userWorker = env.dispatcher.get(

        workerName,

        {},

        {

          // set limits

          limits: { cpuMs: 10, subRequests: 5 },

        },

      );

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        // we tried to get a worker that doesn't exist in our dispatch namespace

        return new Response("", { status: 404 });

      }

      return new Response(e.message, { status: 500 });

    }

  },

};


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/","name":"Custom limits"}}]}
```

---

---
title: Dynamic dispatch Worker
description: A dynamic dispatch Worker is a specialized routing Worker that directs incoming requests to the appropriate user Workers in your dispatch namespace. Instead of using Workers Routes, dispatch Workers let you programmatically control request routing through code.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Dynamic dispatch Worker

A [dynamic dispatch Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/#dynamic-dispatch-worker) is a specialized routing Worker that directs incoming requests to the appropriate user Workers in your dispatch namespace. Instead of using [Workers Routes](https://developers.cloudflare.com/workers/configuration/routing/routes/), dispatch Workers let you programmatically control request routing through code.

![Figure 1: Workers for Platforms: Main Flow](https://developers.cloudflare.com/_astro/programmable-platforms-1.BCCEhzLr_2d88FE.svg) 

Note

You can also create a dispatch Worker from the Cloudflare dashboard. Go to **Workers for Platforms**, select your namespace, and click **Create** \> **Dispatch Worker**. The dashboard provides templates for path-based and subdomain-based routing.

#### Why use a dynamic dispatch Worker?

* **Scale**: Route requests to millions of hostnames to different Workers, without defining [Workers Routes](https://developers.cloudflare.com/workers/configuration/routing/routes/) configuration for each one
* **Custom routing logic**: Write code to determine exactly how requests should be routed. For example:  
   * Store hostname-to-Worker mappings in [Workers KV](https://developers.cloudflare.com/kv/) and look them up dynamically  
   * Route requests based on subdomain, path, headers, or other request properties  
   * Use [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) attached to [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) for routing decisions
* **Add platform functionality**: Build additional features at the routing layer:  
   * Run authentication checks before requests reach user Workers  
   * Remove or add headers or metadata from incoming requests  
   * Attach useful context like user IDs or account information  
   * Transform requests or responses as needed

### Configure the dispatch namespace binding

To allow your dynamic dispatch Worker to dynamically route requests to Workers in a namespace, you need to configure a dispatch namespace [binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/). This binding enables your dynamic dispatch Worker to call any user Worker within that namespace using `env.dispatcher.get()`.

* [  wrangler.jsonc ](#tab-panel-3378)
* [  wrangler.toml ](#tab-panel-3379)

```

{

  "dispatch_namespaces": [

    {

      "binding": "DISPATCHER",

      "namespace": "my-dispatch-namespace"

    }

  ]

}


```

```

[[dispatch_namespaces]]

binding = "DISPATCHER"

namespace = "my-dispatch-namespace"


```

Once the binding is configured, your dynamic dispatch Worker can route requests to any Worker in the namespace. Below are common routing patterns you can implement in your dispatcher.

### Routing examples

![Figure 2: Workers for Platforms: Main Flow](https://developers.cloudflare.com/_astro/programmable-platforms-2.DGAT6ZDR_Z19nioR.svg) 

#### KV-Based Routing

Store the routing mappings in [Workers KV](https://developers.cloudflare.com/kv/). This allows you to modify your routing logic without requiring you to change or redeploy the dynamic dispatch Worker.

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      const url = new URL(request.url);


      // Use hostname, path, or any combination as the routing key

      const routingKey = url.hostname;


      // Lookup user Worker name from KV store

      const userWorkerName = await env.USER_ROUTING.get(routingKey);


      if (!userWorkerName) {

        return new Response("Route not configured", { status: 404 });

      }


      // Optional: Cache the KV lookup result

      const userWorker = env.DISPATCHER.get(userWorkerName);

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        return new Response("", { status: 404 });

      }

      return new Response(e.message, { status: 500 });

    }

  },

};


```

#### Subdomain-Based Routing

Route subdomains to the corresponding Worker. For example, `my-customer.example.com` will route to the Worker named `my-customer` in the dispatch namespace.

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      // Extract user Worker name from subdomain

      // Example: customer1.example.com -> customer1

      const url = new URL(request.url);

      const userWorkerName = url.hostname.split(".")[0];


      // Get user Worker from dispatch namespace

      const userWorker = env.DISPATCHER.get(userWorkerName);

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        // User Worker doesn't exist in dispatch namespace

        return new Response("", { status: 404 });

      }

      // Could be any other exception from fetch() or from the dispatched Worker

      return new Response(e.message, { status: 500 });

    }

  },

};


```

#### Path-Based routing

Route URL paths to the corresponding Worker. For example, `example.com/customer-1` will route to the Worker named `customer-1` in the dispatch namespace.

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      const url = new URL(request.url);

      const pathParts = url.pathname.split("/").filter(Boolean);


      if (pathParts.length === 0) {

        return new Response("Invalid path", { status: 400 });

      }


      // example.com/customer-1 -> routes to 'customer-1' worker

      const userWorkerName = pathParts[0];


      const userWorker = env.DISPATCHER.get(userWorkerName);

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        return new Response("", { status: 404 });

      }

      return new Response(e.message, { status: 500 });

    }

  },

};


```

### Enforce custom limits

Use [custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/) to control how much CPU time a given user Worker can use, or how many subrequests it can make. You can set different limits based on customer plan type or other criteria.

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      const url = new URL(request.url);

      const userWorkerName = url.hostname.split(".")[0];


      // Look up customer plan from your database or KV

      const customerPlan = await env.CUSTOMERS.get(userWorkerName);


      // Set limits based on plan type

      const plans = {

        enterprise: { cpuMs: 50, subRequests: 50 },

        pro: { cpuMs: 20, subRequests: 20 },

        free: { cpuMs: 10, subRequests: 5 },

      };

      const limits = plans[customerPlan] || plans.free;


      const userWorker = env.DISPATCHER.get(userWorkerName, {}, { limits });

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        return new Response("", { status: 404 });

      }

      if (e.message.includes("CPU time limit")) {

        // Track limit violations with Analytics Engine

        env.ANALYTICS.writeDataPoint({

          indexes: [userWorkerName],

          blobs: ["cpu_limit_exceeded"],

        });

        return new Response("CPU limit exceeded", { status: 429 });

      }

      return new Response(e.message, { status: 500 });

    }

  },

};


```

For more details on available limits, refer to [Custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/).

To track limit violations and other metrics across user Workers, use [Workers Analytics Engine](https://developers.cloudflare.com/analytics/analytics-engine/). For detailed logging and debugging, configure a [Tail Worker](https://developers.cloudflare.com/workers/observability/logs/tail-workers/) to capture events from your dispatch Worker.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/","name":"Dynamic dispatch Worker"}}]}
```

---

---
title: Hostname routing
description: Learn how to route requests to the dispatch worker.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/hostname-routing.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Hostname routing

You can use [dynamic dispatch](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/) Workers to route millions of vanity domains or subdomains to Workers without hitting traditional [route limits](https://developers.cloudflare.com/workers/platform/limits/#routes-and-domains). These hostnames can be subdomains under your managed domain (e.g. `customer1.saas.com`) or vanity domains controlled by your end customers (e.g. `mystore.com`), which can be managed through [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/).

## (Recommended) Wildcard route with a dispatch Worker

Configure a wildcard [Route](https://developers.cloudflare.com/workers/configuration/routing/routes/) (`*/*`) on your SaaS domain (the domain where you configure custom hostnames) to point to your dynamic dispatch Worker. This allows you to:

* **Support both subdomains and vanity domains**: Handle `customer1.myplatform.com` (subdomain) and `shop.customer.com` (custom hostname) with the same routing logic.
* **Avoid route limits**: Instead of creating individual routes for every domain, which can cause you to hit [Routes limits](https://developers.cloudflare.com/workers/platform/limits/#routes-and-domains), you can handle the routing logic in code and proxy millions of domains to individual Workers.
* **Programmatically control routing logic**: Write custom code to route requests based on hostname, [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/), path, or any other properties.

Note

This will route all traffic inbound to the domain to the dispatch Worker.

If you'd like to exclude certain hostnames from routing to the dispatch Worker, you can either:

* Add routes without a Worker specification to opt certain hostnames or paths from being executed by the dispatcher Worker (for example, for `saas.com`, `api.saas.com`, etc)
* Use a [dedicated domain](https://developers.cloudflare.com/dns/zone-setups/subdomain-setup/) (for example, `customers.saas.com`) for custom hostname and dispatch worker management to keep the rest of the traffic for that domain separate.

### Setup

To set up hostname routing with a wildcard route:

1. **Configure custom hostnames**: Set up your domain and custom hostnames using [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/)
2. **Set the fallback origin**: Set up a [fallback origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#1-create-fallback-origin), this is where all custom hostnames will be routed to. If you’d like to route them to separate origins, you can use a [custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/). Requests will route through the Worker before reaching the origin. If the Worker is the origin then place a dummy DNS record for the fallback origin (e.g., `A 192.0.2.0`).
3. **Configure DNS**: Point DNS records (subdomains or custom hostname) via [CNAME record to the saas domain](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record). If your customers need to proxy their apex hostname (e.g. `example.com`) and cannot use CNAME records, check out [Apex Proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/).
4. **Create wildcard route**: Add a `*/*` route on your platform domain (e.g. saas.com) and associate it with your dispatch Worker.
5. **Implement dispatch logic**: Add logic to your dispatch Worker to route based on hostname, lookup mappings stored in [Workers KV](https://developers.cloudflare.com/kv/), or use [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) attached to custom hostnames.

Note

If you plan to route requests based on custom metadata, you'll need to create subdomains (e.g. `customer1.saas.com`) as custom hostnames. This is because DNS records do not support custom metadata.

#### Example dispatch Worker

JavaScript

```

export default {

  async fetch(request, env) {

    const hostname = new URL(request.url).hostname;


    // Get custom hostname metadata for routing decisions

    const hostnameData = await env.KV.get(`hostname:${hostname}`, {

      type: "json",

    });


    if (!hostnameData?.workerName) {

      return new Response("Hostname not configured", { status: 404 });

    }


    // Route to the appropriate user Worker

    const userWorker = env.DISPATCHER.get(hostnameData.workerName);

    return await userWorker.fetch(request);

  },

};


```

## Subdomain routing

If you're only looking to route subdomain records (e.g. `customer1.saas.com`), you can use a more specific route (`*.saas.com/*`) to route requests to your dispatch Worker.

### Setup

To set up subdomain routing:

1. Create an orange-clouded wildcard DNS record: `*.saas.com` that points to the origin. If the Worker is the origin then you can use a dummy DNS value (for example, `A 192.0.2.0`).
2. Set wildcard route: `*.saas.com/*` pointing to your dispatch Worker
3. Add logic to the dispatch Worker to route subdomain requests to the right Worker.

#### Example subdomain dispatch Worker

JavaScript

```

export default {

  async fetch(request, env) {

    const url = new URL(request.url);

    const subdomain = url.hostname.split(".")[0];


    // Route based on subdomain

    if (subdomain && subdomain !== "saas") {

      const userWorker = env.DISPATCHER.get(subdomain);

      return await userWorker.fetch(request);

    }


    return new Response("Invalid subdomain", { status: 400 });

  },

};


```

### O2O Behavior

When your customers are also using Cloudflare and point their custom domain to your SaaS domain via CNAME (for example, `mystore.com` → `saas.com`), Worker routing behavior depends on whether the customer's DNS record is proxied (orange cloud) or DNS-only (grey cloud). Learn more about [O2O setups](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/#with-o2o)

This can cause inconsistent behavior when using specific hostname routes:

* If you're routing based on the CNAME target (`saas.com`), the custom hostname's DNS record must be orange-clouded for the Worker to be invoked.
* If you're routing based on the custom hostname (`mystore.com`), the customer's record must be grey-clouded for the Worker to be invoked.

Since you may not have control over your customer's DNS proxy settings, we recommend using `*/*` wildcard route to ensure routing logic always works as expected, regardless of how DNS is configured.

#### Worker invocation across route configurations and proxy modes

The table below shows when Workers are invoked based on your route pattern and the customer's DNS proxy settings:

| Route Pattern         | Custom Hostname (Orange Cloud) | Custom Hostname (Grey Cloud) |
| --------------------- | ------------------------------ | ---------------------------- |
| \*/\* (Recommended)   | ✅                              | ✅                            |
| Target hostname route | ✅                              | ❌                            |
| Custom hostname route | ❌                              | ✅                            |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/hostname-routing/","name":"Hostname routing"}}]}
```

---

---
title: Observability
description: Workers for Platforms provides you with logs and analytics that can be used to share data with end users.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/observability.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Observability

Workers for Platforms provides you with logs and analytics that can be used to share data with end users.

## Logs

Learn how to access logs with Workers for Platforms.

### Workers Trace Events Logpush

Workers Trace Events logpush is used to get raw Workers execution logs. Refer to [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) for more information.

Logpush can be enabled for an entire dispatch namespace or a single user Worker. To capture logs for all of the user Workers in a dispatch namespace:

1. Create a [Logpush job](https://developers.cloudflare.com/workers/observability/logs/logpush/#create-a-logpush-job).
2. Enable [logging](https://developers.cloudflare.com/workers/observability/logs/logpush/#enable-logging-on-your-worker) on your dispatch Worker.

Enabling logging on your dispatch Worker collects logs for both the dispatch Worker and for any user Workers in the dispatch namespace. Logs are automatically collected for all new Workers added to a dispatch namespace. To enable logging for an individual user Worker rather than an entire dispatch namespace, skip step 1 and complete step 2 on your user Worker.

All logs are forwarded to the Logpush job that you have setup for your account. Logpush filters can be used on the `Outcome` or `Script Name` field to include or exclude specific values or send logs to different destinations.

### Tail Workers

A [Tail Worker](https://developers.cloudflare.com/workers/observability/logs/tail-workers/) receives information about the execution of other Workers (known as producer Workers), such as HTTP statuses, data passed to `console.log()` or uncaught exceptions.

Use [Tail Workers](https://developers.cloudflare.com/workers/observability/logs/tail-workers/) instead of Logpush if you want granular control over formatting before logs are sent to their destination to receive [diagnostics channel events](https://developers.cloudflare.com/workers/runtime-apis/nodejs/diagnostics-channel), or if you want logs delivered in real-time.

Adding a Tail Worker to your dispatch Worker collects logs for both the dispatch Worker and for any user Workers in the dispatch namespace. Logs are automatically collected for all new Workers added to a dispatch namespace. To enable logging for an individual user Worker rather than an entire dispatch namespace, add the [Tail Worker configuration](https://developers.cloudflare.com/workers/observability/logs/tail-workers/#configure-tail-workers) directly to the user Worker.

## Analytics

There are two ways for you to review your Workers for Platforms analytics.

### Workers Analytics Engine

[Workers Analytics Engine](https://developers.cloudflare.com/analytics/analytics-engine/) can be used with Workers for Platforms to provide analytics to end users. It can be used to expose events relating to a Workers invocation or custom user-defined events. Platforms can write/query events by script tag to get aggregates over a user’s usage.

### GraphQL Analytics API

Use Cloudflare’s [GraphQL Analytics API](https://developers.cloudflare.com/analytics/graphql-api) to get metrics relating to your Dispatch Namespaces. Use the `dispatchNamespaceName` dimension in the `workersInvocationsAdaptive` node to query usage by namespace.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/observability/","name":"Observability"}}]}
```

---

---
title: Outbound Workers
description: Outbound Workers sit between your customer's Workers and the public Internet. They give you visibility into all outgoing fetch() requests from user Workers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Outbound Workers

Outbound Workers sit between your customer's Workers and the public Internet. They give you visibility into all outgoing `fetch()` requests from user Workers.

![Outbound Workers diagram information](https://developers.cloudflare.com/_astro/outbound-worker-diagram.BSvN4KG0_YJsgi.webp) 

## General Use Cases

Outbound Workers can be used to:

* Log all subrequests to identify malicious domains or usage patterns.
* Create, allow, or block lists for hostnames requested by user Workers.
* Configure authentication to your APIs behind the scenes (without end developers needing to set credentials).

Note

When an Outbound Worker is enabled, your customer's Worker will no longer be able to use the [connect() API](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/#connect)to create outbound TCP Sockets. This is to ensure all outbound communication goes through the Outbound Worker's `fetch` method.

## Use Outbound Workers

To use Outbound Workers:

1. Create a Worker intended to serve as your Outbound Worker.
2. Outbound Worker can be specified as an optional parameter in the [dispatch namespaces](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/) binding in a project's [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/). Optionally, to pass data from your dynamic dispatch Worker to the Outbound Worker, the variable names can be specified under **parameters**.

Make sure that you have `wrangler@3.3.0` or later [installed](https://developers.cloudflare.com/workers/wrangler/install-and-update/).

* [  wrangler.jsonc ](#tab-panel-3380)
* [  wrangler.toml ](#tab-panel-3381)

```

{

  "dispatch_namespaces": [

    {

      "binding": "dispatcher",

      "namespace": "<NAMESPACE_NAME>",

      "outbound": {

        "service": "<SERVICE_NAME>",

        "parameters": [

          "params_object"

        ]

      }

    }

  ]

}


```

```

[[dispatch_namespaces]]

binding = "dispatcher"

namespace = "<NAMESPACE_NAME>"


  [dispatch_namespaces.outbound]

  service = "<SERVICE_NAME>"

  parameters = [ "params_object" ]


```

1. Edit your dynamic dispatch Worker to call the Outbound Worker and declare variables to pass on `dispatcher.get()`.

JavaScript

```

export default {

  async fetch(request, env) {

    try {

      // parse the URL, read the subdomain

      let workerName = new URL(request.url).host.split(".")[0];


      let context_from_dispatcher = {

        customer_name: workerName,

        url: request.url,

      };


      let userWorker = env.dispatcher.get(

        workerName,

        {},

        {

          // outbound arguments. object name must match parameters in the binding

          outbound: {

            params_object: context_from_dispatcher,

          },

        },

      );

      return await userWorker.fetch(request);

    } catch (e) {

      if (e.message.startsWith("Worker not found")) {

        // we tried to get a worker that doesn't exist in our dispatch namespace

        return new Response("", { status: 404 });

      }

      return new Response(e.message, { status: 500 });

    }

  },

};


```

1. The Outbound Worker will now be invoked on any `fetch()` requests from a user Worker. The user Worker will trigger a [FetchEvent](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/) on the Outbound Worker. The variables declared in the binding can be accessed in the Outbound Worker through `env.<VAR_NAME>`.

The following is an example of an Outbound Worker that logs the fetch request from user Worker and creates a JWT if the fetch request matches `api.example.com`.

JavaScript

```

export default {

  // this event is fired when the dispatched Workers make a subrequest

  async fetch(request, env, ctx) {

    // env contains the values we set in `dispatcher.get()`

    const customer_name = env.customer_name;

    const original_url = env.url;


    // log the request

    ctx.waitUntil(

      fetch("https://logs.example.com", {

        method: "POST",

        body: JSON.stringify({

          customer_name,

          original_url,

        }),

      }),

    );


    const url = new URL(original_url);

    if (url.host === "api.example.com") {

      // pre-auth requests to our API

      const jwt = make_jwt_for_customer(customer_name);


      let headers = new Headers(request.headers);

      headers.set("Authorization", `Bearer ${jwt}`);


      // clone the request to set new headers using existing body

      let new_request = new Request(request, { headers });


      return fetch(new_request);

    }


    return fetch(request);

  },

};


```

Note

Outbound Workers do not intercept fetch requests made from [Durable Objects](https://developers.cloudflare.com/durable-objects/) or [mTLS certificate bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/mtls/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers/","name":"Outbound Workers"}}]}
```

---

---
title: Static assets
description: Host static assets on Cloudflare's global network and deliver faster load times worldwide with Workers for Platforms.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/static-assets.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Static assets

Workers for Platforms lets you deploy front-end applications at scale. By hosting static assets on Cloudflare's global network, you can deliver faster load times worldwide and eliminate the need for external infrastructure. You can also combine these static assets with dynamic logic in Cloudflare Workers, providing a full-stack experience for your customers.

### What you can build

#### Static sites

Host and serve HTML, CSS, JavaScript, and media files directly from Cloudflare's network, ensuring fast loading times worldwide. This is ideal for blogs, landing pages, and documentation sites.

#### Full-stack applications

Combine asset hosting with Cloudflare Workers to power dynamic, interactive applications. Store and retrieve data using Cloudflare KV, D1, and R2 Storage, allowing you to serve both front-end assets and backend logic from a single Worker.

### Benefits

#### Global caching for faster performance

Cloudflare automatically caches static assets at data centers worldwide, reducing latency and improving load times by up to 2x for users everywhere.

#### Scalability without infrastructure management

Your applications scale automatically to handle high traffic without requiring you to provision or manage infrastructure. Cloudflare dynamically adjusts to demand in real time.

#### Unified deployment for static and dynamic content

Deploy front-end assets alongside server-side logic, all within Cloudflare Workers. This eliminates the need for a separate hosting provider and ensures a streamlined deployment process.

---

## Deploy static assets to User Workers

It is common that, as the Platform, you will be responsible for uploading static assets on behalf of your end users. This often looks like this:

1. Your user uploads files (HTML, CSS, images) through your interface.
2. Your platform interacts with the Workers for Platforms APIs to attach the static assets to the User Worker script.

Once you receive the static files from your users (for a new or updated site), complete the following steps to attach the files to the corresponding User Worker:

1. Create an Upload Session
2. Upload file contents
3. Deploy/Update the Worker

After these steps are completed, the User Worker's static assets will be live on the Cloudflare's global network.

### 1\. Create an Upload Session

Before sending any file data, you need to tell Cloudflare which files you intend to upload. That list of files is called a manifest. Each item in the manifest includes:

* A file path (for example, `"/index.html"` or `"/assets/logo.png"`)
* A hash (32-hex characters) representing the file contents
* The file size in bytes

Asset Isolation Considerations

Static assets uploaded to Workers for Platforms are associated with the namespace rather than with individual User Worker. If multiple User Workers exist under the same namespace, assets with identical hashes may be shared across them. **JWTs should therefore only be shared with trusted platform services and should never be distributed to end-users.**

If strict isolation of assets is required, we recommend either salting with a random value each time, or incorporating an end-user identifier (for example, account ID or Worker script ID) within the hashing process, to ensure uniqueness. For example, `hash = slice(sha256(accountID + fileContents), 32)`.

#### Example manifest (JSON)

```

{

  "/index.html": {

    "hash": "08f1dfda4574284ab3c21666d1ee8c7d4",

    "size": 1234

  },

  "/styles.css": {

    "hash": "36b8be012ee77df5f269b11b975611d3",

    "size": 5678

  }

}


```

To start the upload process, send a POST request to the Create Assets Upload Session [API endpoint](https://developers.cloudflare.com/api/resources/workers%5Ffor%5Fplatforms/subresources/dispatch/subresources/namespaces/subresources/scripts/subresources/asset%5Fupload/methods/create/).

Terminal window

```

POST /accounts/{account_id}/workers/dispatch/namespaces/{namespace}/scripts/{script_name}/assets-upload-session


```

Path Parameters:

* `namespace`: Name of the Workers for Platforms dispatch namespace
* `script_name`: Name of the User Worker

In the request body, include a JSON object listing each file path along with its hash and size. This helps Cloudflare identify which files you intend to upload and allows Cloudflare to check if any of them are already stored.

#### Sample request

Terminal window

```

curl -X POST \

  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME/assets-upload-session" \

  -H "Content-Type: application/json" \

  -H "Authorization: Bearer $API_TOKEN" \

  --data '{

    "manifest": {

      "/index.html": {

        "hash": "08f1dfda4574284ab3c21666d1ee8c7d4",

        "size": 1234

      },

      "/styles.css": {

        "hash": "36b8be012ee77df5f269b11b975611d3",

        "size": 5678

      }

    }

  }'


```

#### Generating the hash

You can compute a SHA-256 digest of the file contents, then truncate or otherwise represent it consistently as a 32-hex-character string. Make sure to do it the same way each time so Cloudflare can reliably match files across uploads.

#### API Response

If all the files are already stored on Cloudflare, the response will only return the JWT token. If new or updated files are needed, the response will return:

* `jwt`: An upload token (valid for 1 hour) which will be used in the API request to upload the file contents (Step 2).
* `buckets`: An array of file-hash groups indicating which files to upload together. Files that have been recently uploaded will not appear in buckets, since Cloudflare already has them.

Note

This step alone does not store files on Cloudflare. You must upload the actual file data in the next step.

### 2\. Upload File Contents

If the response to the Upload Session API returns `buckets`, that means you have new or changed files that need to be uploaded to Cloudflare.

Use the [Workers Assets Upload API](https://developers.cloudflare.com/api/resources/workers/subresources/assets/subresources/upload/) to transmit the raw file bytes in base64-encoded format for any missing or changed files. Once uploaded, Cloudflare will store these files so they can then be attached to a User Worker.

Warning

Asset uniqueness is determined by the provided hash and are associated globally to their namespace rather than with each specific User Worker. If an asset has already been uploaded for that namespace earlier, Cloudflare will automatically omit sending this asset hash back in the `buckets` response to save you from re-uploading the same thing twice. This means that an asset can be shared between multiple User Workers if it shares the same hash unless you **explicitly make the hash unique**. If you require full isolation between assets across User Workers, incorporate a unique identifier within your asset hashing process (either salting it with something entirely random each time, or by including the end-user account ID or their Worker name to retain per-customer re-use).

#### API Request Authentication

Unlike most Cloudflare API calls that use an account-wide API token in the Authorization header, uploading file contents requires using the short-lived JWT token returned in the `jwt` field of the `assets-upload-session` response.

Include it as a Bearer token in the header:

Terminal window

```

Authorization: Bearer <upload-session-token>


```

This token is valid for one hour and must be supplied for each upload request to the Workers Assets Upload API.

#### File fields (multipart/form-data)

You must send the files as multipart/form-data with base64-encoded content:

* Field name: The file hash (for example, `36b8be012ee77df5f269b11b975611d3`)
* Field value: A Base64-encoded string of the file's raw bytes

#### Example: Uploading multiple files within a single bucket

If your Upload Session response listed a single "bucket" containing two file hashes:

```

"buckets": [

  [

    "08f1dfda4574284ab3c21666d1ee8c7d4",

    "36b8be012ee77df5f269b11b975611d3"

  ]

]


```

You can upload both files in one request, each as a form-data field:

Terminal window

```

curl -X POST \

  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/assets/upload?base64=true" \

  -H "Authorization: Bearer <upload-session-token>" \

  -F "08f1dfda4574284ab3c21666d1ee8c7d4=<BASE64_OF_INDEX_HTML>" \

  -F "36b8be012ee77df5f269b11b975611d3=<BASE64_OF_STYLES_CSS>"


```

* `<upload-session-token>` is the token from step 1's assets-upload-session response
* `<BASE64_OF_INDEX_HTML>` is the Base64-encoded content of index.html
* `<BASE64_OF_STYLES_CSS>` is the Base64-encoded content of styles.css

If you have multiple buckets (for example, `[["hashA"], ["hashB"], ["hashC"]]`), you might need to repeat this process for each bucket, making one request per bucket group.

Once every file in the manifest has been uploaded, a status code of `201` will be returned, with the `jwt` field present. This JWT is a final "completion" token which can be used to create a deployment of a Worker with this set of assets. This completion token is valid for 1 hour.

```

{

  "success": true,

  "errors": [],

  "messages": [],

  "result": {

    "jwt": "<completion-token>"

  }

}


```

`<completion-token>` indicates that Cloudflare has successfully received and stored the file contents specified by your manifest. You will use this `<completion-token>` in Step 3 to finalize the attachment of these files to the Worker.

### 3\. Deploy the User Worker with static assets

Now that Cloudflare has all the files it needs (from the previous upload steps), you must attach them to the User Worker by making a PUT request to the [Upload User Worker API](https://developers.cloudflare.com/api/resources/workers%5Ffor%5Fplatforms/subresources/dispatch/subresources/namespaces/subresources/scripts/methods/update/). This final step links the static assets to the User Worker using the completion token you received after uploading file contents.

You can also specify any optional settings under the `assets.config` field to customize how your files are served (for example, to handle trailing slashes in HTML paths).

#### API request example

Terminal window

```

curl -X PUT \

  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME" \

  -H "Content-Type: multipart/form-data" \

  -H "Authorization: Bearer $API_TOKEN" \

  -F 'metadata={

    "main_module": "index.js",

    "assets": {

      "jwt": "<completion-token>",

      "config": {

        "html_handling": "auto-trailing-slash"

      }

    },

    "compatibility_date": "2025-01-24"

  };type=application/json' \

  -F 'index.js=@/path/to/index.js;type=application/javascript'


```

* The `"jwt": "<completion-token>"` links the newly uploaded files to the Worker
* Including "html\_handling" (or other fields under "config") is optional and can customize how static files are served
* If the user's Worker code has not changed, you can omit the code file or re-upload the same index.js

Once this PUT request succeeds, the files are served on the User Worker. Requests routed to that Worker will serve the new or updated static assets.

---

## Deploying static assets with Wrangler

If you prefer a CLI-based approach and your platform setup allows direct publishing, you can use Wrangler to deploy both your Worker code and static assets. Wrangler bundles and uploads static assets (from a specified directory) along with your Worker script, so you can manage everything in one place.

Create or update your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/) to specify where Wrangler should look for static files:

* [  wrangler.jsonc ](#tab-panel-3382)
* [  wrangler.toml ](#tab-panel-3383)

```

{

  "$schema": "./node_modules/wrangler/config-schema.json",

  "name": "my-static-site",

  "main": "./src/index.js",

  // Set this to today's date

  "compatibility_date": "2026-04-03",

  "assets": {

    "directory": "./public",

    "binding": "ASSETS",

  },

}


```

```

"$schema" = "./node_modules/wrangler/config-schema.json"

name = "my-static-site"

main = "./src/index.js"

# Set this to today's date

compatibility_date = "2026-04-03"


[assets]

directory = "./public"

binding = "ASSETS"


```

* `directory`: The local folder containing your static files (for example, `./public`).
* `binding`: The binding name used to reference these assets within your Worker code.

### 1\. Organize your files

Place your static files (HTML, CSS, images, etc.) in the specified directory (in this example, `./public`). Wrangler will detect and bundle these files when you publish your Worker.

If you need to reference these files in your Worker script to serve them dynamically, you can use the `ASSETS` binding like this:

JavaScript

```

export default {

  async fetch(request, env, ctx) {

    return env.ASSETS.fetch(request);

  },

};


```

### 2\. Deploy the User Worker with the static assets

Run Wrangler to publish both your Worker code and the static assets:

Terminal window

```

npx wrangler deploy --name <USER_WORKER_NAME> --dispatch-namespace <NAMESPACE_NAME>


```

Wrangler will automatically detect your static files, bundle them, and upload them to Cloudflare along with your Worker code.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/static-assets/","name":"Static assets"}}]}
```

---

---
title: Tags
description: Use tags to organize, search, and filter user Workers at scale. Tag Workers based on customer ID, plan type, project ID, or environment. After you tag user Workers, you can perform bulk operations like deleting all Workers for a specific customer.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/configuration/tags.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Tags

Use tags to organize, search, and filter user Workers at scale. Tag Workers based on customer ID, plan type, project ID, or environment. After you tag user Workers, you can perform bulk operations like deleting all Workers for a specific customer.

Note

You can set a maximum of eight tags per script. Avoid special characters like `,` and `&` when naming your tag.

## Add tags via dashboard

1. Go to **Workers for Platforms** in the Cloudflare dashboard and select your namespace.
2. Select a user Worker from the list.
3. Go to **Settings** \> **Tags**.
4. Add your tags (for example, `customer-123`, `pro-plan`, `production`).
5. Select **Save**.

You can also search and filter Workers by tags in the namespace view.

## Tags API reference

For complete API documentation, refer to [Workers for Platforms API](https://developers.cloudflare.com/api/resources/workers%5Ffor%5Fplatforms/subresources/dispatch/subresources/namespaces/subresources/scripts/subresources/tags/).

### Get script tags

Fetch all tags for a Worker script.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Tail Read`
* `Workers Scripts Write`
* `Workers Scripts Read`

Get Script Tags

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts/$SCRIPT_NAME/tags" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

### Set script tags

Replace all tags on a Worker script. Existing tags not in the request are removed.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Scripts Write`

Put Script Tags

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts/$SCRIPT_NAME/tags" \

  --request PUT \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

### Add a single tag

Add one tag to a Worker script without affecting existing tags.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Scripts Write`

Put Script Tag

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts/$SCRIPT_NAME/tags/$TAG" \

  --request PUT \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

### Delete a single tag

Remove one tag from a Worker script.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Scripts Write`

Delete Script Tag

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts/$SCRIPT_NAME/tags/$TAG" \

  --request DELETE \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

### Filter Workers by tag

List all Workers that match a tag filter. Use `tag:yes` to include or `tag:no` to exclude.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Tail Read`
* `Workers Scripts Write`
* `Workers Scripts Read`

List Scripts in Namespace

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts?tags=production%3Ayes" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

### Delete Workers by tag

Delete all Workers matching a tag filter. Use this to bulk delete Workers when a customer leaves your platform.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Workers Scripts Write`

Delete Scripts in Namespace

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$DISPATCH_NAMESPACE/scripts?tags=customer-123%3Ayes" \

  --request DELETE \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/","name":"Configuration"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/configuration/tags/","name":"Tags"}}]}
```

---

---
title: Get started
description: Get started with Workers for Platforms by deploying a starter kit to your account.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Get started

Get started with Workers for Platforms by deploying a starter kit to your account.

## Deploy a platform

Deploy the [Platform Starter Kit ↗](https://github.com/cloudflare/templates/tree/main/worker-publisher-template) to your Cloudflare account. This creates a complete Workers for Platforms setup with one click.

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/main/worker-publisher-template)

After deployment completes, open your Worker URL. You now have a platform where you can deploy code snippets.

### Try it out

1. Enter a script name, for example `my-worker`.
2. Write or paste Worker code in the editor.
3. Click **Deploy Worker**.

Once deployed, visit `/<script-name>` on your Worker URL to run your code. For example, if you named your script `my-worker`, go to `https://<your-worker>.<subdomain>.workers.dev/my-worker`.

Each script you deploy becomes its own isolated Worker. The platform calls the Cloudflare API to create the Worker and the dispatch Worker routes requests to it based on the URL path.

## Understand how it works

The template you deployed contains three components that work together:

### Dispatch namespace

A dispatch namespace is a collection of user Workers. Think of it as a container that holds all the Workers your platform deploys on behalf of your customers.

When you deployed the template, it created a dispatch namespace automatically. You can view it in the Cloudflare dashboard under **Workers for Platforms**.

### Dispatch Worker

The dispatch Worker receives incoming requests and routes them to the correct user Worker. It uses a [binding](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) to access the dispatch namespace.

JavaScript

```

export default {

  async fetch(request, env) {

    // Get the user Worker name from the URL path

    const url = new URL(request.url);

    const workerName = url.pathname.split("/")[1];


    // Fetch the user Worker from the dispatch namespace

    const userWorker = env.DISPATCHER.get(workerName);


    // Forward the request to the user Worker

    return userWorker.fetch(request);

  },

};


```

The `env.DISPATCHER.get()` method retrieves a user Worker by name from the dispatch namespace.

### User Workers

User Workers contain the code your customers write and deploy. They run in isolated environments with no access to other customers' data or code.

In the template, user Workers are deployed programmatically through the API. In production, your platform would call the Cloudflare API or SDK to deploy user Workers when your customers save their code.

## Build your platform

Now that you understand how the components work together, customize the template for your use case:

* [Dynamic dispatch](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/) — Route requests by subdomain or hostname
* [Hostname routing](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/hostname-routing/) — Let customers use [custom domains](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) with their applications
* [Bindings](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) — Give each customer access to their own [database](https://developers.cloudflare.com/d1/), [key-value store](https://developers.cloudflare.com/kv/), or [object storage](https://developers.cloudflare.com/r2/)
* [Outbound Workers](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers/) — Configure egress policies on outgoing requests from customer code
* [Custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/) — Set CPU time and subrequest limits per customer
* [API examples](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/platform-examples/) — Examples for deploying and managing customer code programmatically

## Build an AI vibe coding platform

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/vibesdk)

Build an [AI vibe coding platform](https://developers.cloudflare.com/reference-architecture/diagrams/ai/ai-vibe-coding-platform/) where users describe what they want and AI generates and deploys applications.

With [VibeSDK ↗](https://github.com/cloudflare/vibesdk), Cloudflare's open source vibe coding platform, you can get started with an example that handles AI code generation, code execution in secure sandboxes, live previews, and deployment at scale.

[ View demo ](https://build.cloudflare.dev) [ View on GitHub ](https://github.com/cloudflare/vibesdk) 

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/get-started/","name":"Get started"}}]}
```

---

---
title: How Workers for Platforms works
description: If you are familiar with Workers, Workers for Platforms introduces four key components: dispatch namespaces, dynamic dispatch Workers, user Workers, and optionally outbound Workers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# How Workers for Platforms works

## Architecture

If you are familiar with [Workers](https://developers.cloudflare.com/workers/), Workers for Platforms introduces four key components: dispatch namespaces, dynamic dispatch Workers, user Workers, and optionally outbound Workers.

![Workers for Platforms architecture](https://developers.cloudflare.com/_astro/programmable-platforms-1.BCCEhzLr_2d88FE.svg) 

### Dispatch namespace

A dispatch namespace is a container that holds all of your customers' Workers. Your platform takes the code your customers write, and then makes an API request to deploy that code as a user Worker to a namespace — for example `staging` or `production`. Compared to [Workers](https://developers.cloudflare.com/workers/), this provides:

* **Unlimited number of Workers** \- No per-account script limits apply to Workers in a namespace
* **Isolation by default** \- Each user Worker in a namespace runs in [untrusted mode](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/worker-isolation/) — user Workers never share a cache even when running on the same Cloudflare zone, and cannot access the `request.cf` object
* **Dynamic invocation** \- Your dynamic dispatch Worker can call any Worker in the namespace using `env.DISPATCHER.get("worker-name")`

Best practice

All your customers' Workers should live in a single namespace (for example, `production`). Do not create a namespace per customer.

If you need to test changes safely, create a separate `staging` namespace.

### Dynamic dispatch Worker

A dynamic dispatch Worker is the entry point for all requests to your platform. Your dynamic dispatch Worker:

* **Routes requests** \- Determines which customer Worker should handle each request based on hostname, path, headers, or any other criteria
* **Runs platform logic** \- Executes authentication, rate limiting, or request validation before customer code runs
* **Sets per-customer limits** \- Enforces [custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/) on CPU time and subrequests based on plan type
* **Sanitizes responses** \- Modifies or filters responses from customer Workers

The dynamic dispatch Worker uses a [dispatch namespace binding](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/) to invoke user Workers:

JavaScript

```

export default {

  async fetch(request, env) {

    // Determine which customer Worker to call

    const customerName = new URL(request.url).hostname.split(".")[0];


    // Get and invoke the customer's Worker

    const userWorker = env.DISPATCHER.get(customerName);

    return userWorker.fetch(request);

  },

};


```

### User Workers

User Workers contain code written by your customers. Your customer sends their code to your platform, and then you make an API request to deploy a user Worker on their behalf. User Workers are deployed to a dispatch namespace and invoked by your dynamic dispatch Worker. You can provide user Workers with [bindings](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) to access KV, D1, R2, and other Cloudflare resources.

![Deployment and management flow](https://developers.cloudflare.com/_astro/programmable-platforms-6.BfYznbr5_2d88FE.svg) 

### Outbound Worker (optional)

An [outbound Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers/) intercepts [fetch()](https://developers.cloudflare.com/workers/runtime-apis/fetch/) requests made by user Workers. Use it to:

* **Control egress** \- Block or allow external API calls from customer code
* **Log requests** \- Track what external services customers are calling
* **Modify requests** \- Add authentication headers or transform requests before they leave your platform
![Outbound Worker egress control pattern](https://developers.cloudflare.com/_astro/programmable-platforms-3.C-LkeZtS_Z19nioR.svg) 

### Request lifecycle

1. A request arrives at your dynamic dispatch Worker (for example, `customer-a.example.com/api`)
2. Your dynamic dispatch Worker determines which user Worker should handle the request
3. The dynamic dispatch Worker calls `env.DISPATCHER.get("customer-a")` to get the user Worker
4. The user Worker executes. If it makes external `fetch()` calls and an outbound Worker is configured, those requests pass through the outbound Worker first.
5. The user Worker returns a response
6. Your dynamic dispatch Worker can optionally modify the response before returning it

---

## Workers for Platforms versus Service bindings

Both Workers for Platforms and [Service bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) enable Worker-to-Worker communication. Use Service bindings when you know exactly which Workers need to communicate. Use Workers for Platforms when user Workers are uploaded dynamically by your customers.

You can use both simultaneously - your dynamic dispatch Worker can use Service bindings to call internal services while also dispatching to user Workers in a namespace.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/","name":"How Workers for Platforms works"}}]}
```

---

---
title: Platform Starter Kit
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/platform-templates/platform-starter-kit.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Platform Starter Kit

**Last reviewed:**  3 months ago 

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/platform-templates/","name":"Platform templates"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/platform-templates/platform-starter-kit/","name":"Platform Starter Kit"}}]}
```

---

---
title: Deploy an AI vibe coding platform
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/platform-templates/vibesdk.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Deploy an AI vibe coding platform

**Last reviewed:**  3 months ago 

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/platform-templates/","name":"Platform templates"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/platform-templates/vibesdk/","name":"Deploy an AI vibe coding platform"}}]}
```

---

---
title: Limits
description: Cloudflare provides an unlimited number of scripts for Workers for Platforms customers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/reference/limits.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Limits

## Script limits

Cloudflare provides an unlimited number of scripts for Workers for Platforms customers.

## `cf` object

The [cf object](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties) contains Cloudflare-specific properties of a request. This field is not accessible in [user Workers](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/#user-workers) by default because some fields in this object are sensitive and can be used to manipulate Cloudflare features (for example, `cacheKey`, `resolveOverride`, `scrapeShield`.)

To access the `cf` object, you need to enable [trusted mode](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/worker-isolation/#trusted-mode) for your namespace. Only enable this if you control all Worker code in the namespace.

## Durable Object namespace limits

Workers for Platforms do not have a limit for the number of Durable Object namespaces.

## Cache API

For isolation, `caches.default` is disabled for namespaced scripts. To learn more about the cache, refer to [How the cache Works](https://developers.cloudflare.com/workers/reference/how-the-cache-works/).

## ​Tags

You can set a maximum of eight tags per script. Avoid special characters like `,` and `&` when naming your tag.

Need a higher limit?

To request an adjustment to a limit, complete the [Limit Increase Request Form ↗](https://forms.gle/ukpeZVLWLnKeixDu7). If the limit can be increased, Cloudflare will contact you with next steps.

## Gradual Deployments

[Gradual Deployments](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/gradual-deployments/) is not supported yet for user Workers. Changes made to user Workers create a new version that deployed all-at-once to 100% of traffic.

## API Rate Limits

| Type                              | Limit                               |
| --------------------------------- | ----------------------------------- |
| Client API per user/account token | 1200/5 minutes                      |
| Client API per IP                 | 200/second                          |
| GraphQL                           | Varies by query cost. Max 320/5 min |
| User API token quota              | 50                                  |
| Account API token quota           | 500                                 |

Note

The global rate limit for the Cloudflare API is 1,200 requests per five minute period per user, and applies cumulatively regardless of whether the request is made via the dashboard, API key, or API token.

If you exceed this limit, all API calls for the next five minutes will be blocked, receiving a `HTTP 429 - Too Many Requests` response.

Some specific API calls have their own limits and are documented separately, such as the following:

* [Cache Purge APIs](https://developers.cloudflare.com/cache/how-to/purge-cache/#availability-and-limits)
* [GraphQL APIs](https://developers.cloudflare.com/analytics/graphql-api/limits/)
* [Rulesets APIs](https://developers.cloudflare.com/ruleset-engine/rulesets-api/#limits)
* [Lists API](https://developers.cloudflare.com/waf/tools/lists/lists-api/#rate-limiting-for-lists-api-requests)
* [Gateway Lists API](https://developers.cloudflare.com/cloudflare-one/reusable-components/lists/#api-rate-limit)

Enterprise customers can also [contact Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) to raise the Client API per user, GraphQL, or API token limits to a higher value.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/limits/","name":"Limits"}}]}
```

---

---
title: Local development
description: Test changes to your dynamic dispatch Worker by running the dynamic dispatch Worker locally but connecting it to user Workers that have been deployed to Cloudflare.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/reference/local-development.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Local development

Test changes to your [dynamic dispatch Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/#dynamic-dispatch-worker) by running the dynamic dispatch Worker locally but connecting it to user Workers that have been deployed to Cloudflare.

Note

Consider using a staging namespace to test changes safely before deploying to production.

This is helpful when:

* **Testing routing changes** and validating that updates continue to work with deployed User Workers
* **Adding new middleware** like authentication, rate limiting, or logging to the dynamic dispatch Worker
* **Debugging issues** in the dynamic dispatcher that may be impacting deployed User Workers

### How to use remote dispatch namespaces

In the dynamic dispatch Worker's Wrangler file, configure the [dispatch namespace binding](https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms) to connect to the remote namespace by setting [remote = true](https://developers.cloudflare.com/workers/development-testing/#remote-bindings):

* [  wrangler.jsonc ](#tab-panel-3384)
* [  wrangler.toml ](#tab-panel-3385)

```

{

  "dispatch_namespaces": [

    {

      "binding": "DISPATCH_NAMESPACE",

      "namespace": "production",

      "remote": true

    }

  ]

}


```

```

[[dispatch_namespaces]]

binding = "DISPATCH_NAMESPACE"

namespace = "production"

remote = true


```

This tells your dispatch Worker that's running locally to connect to the remote `production` namespace. When you run `wrangler dev`, your Dispatch Worker will route requests to the User Workers deployed in that namespace.

For more information about remote bindings during local development, refer to [remote bindings documentation](https://developers.cloudflare.com/workers/development-testing/#remote-bindings).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/local-development/","name":"Local development"}}]}
```

---

---
title: Multipart upload metadata
description: If you're using the Workers Script Upload API or Version Upload API directly, multipart/form-data uploads require you to specify a metadata part. This metadata defines the Worker's configuration in JSON format, analogue to the wrangler.toml file.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/workers/configuration/multipart-upload-metadata.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Multipart upload metadata

Note

There is a new API for uploading Workers. Refer to [these docs](https://developers.cloudflare.com/workers/platform/infrastructure-as-code#cloudflare-rest-api) for more information.

If you're using the [Workers Script Upload API](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/) or [Version Upload API](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/versions/methods/create/) directly, `multipart/form-data` uploads require you to specify a `metadata` part. This metadata defines the Worker's configuration in JSON format, analogue to the [wrangler.toml file](https://developers.cloudflare.com/workers/wrangler/configuration/).

## Sample `metadata`

```

{

  "main_module": "main.js",

  "bindings": [

    {

      "type": "plain_text",

      "name": "MESSAGE",

      "text": "Hello, world!"

    }

  ],

  "compatibility_date": "2021-09-14"

}


```

Note

See examples of metadata being used with the Workers Script Upload API [here](https://developers.cloudflare.com/workers/platform/infrastructure-as-code#cloudflare-rest-api).

## Attributes

The following attributes are configurable at the top-level.

Note

At a minimum, the `main_module` key is required to upload a Worker.

* `main_module` ` string ` required  
   * The part name that contains the module entry point of the Worker that will be executed. For example, `main.js`.
* `assets` ` object ` optional  
   * [Asset](https://developers.cloudflare.com/workers/static-assets/) configuration for a Worker.  
   * `config` ` object ` optional  
         * [html\_handling](https://developers.cloudflare.com/workers/static-assets/routing/advanced/html-handling/) determines the redirects and rewrites of requests for HTML content.  
         * [not\_found\_handling](https://developers.cloudflare.com/workers/static-assets/#routing-behavior) determines the response when a request does not match a static asset.  
   * `jwt` field provides a token authorizing assets to be attached to a Worker.
* `keep_assets` ` boolean ` optional  
   * Specifies whether assets should be retained from a previously uploaded Worker version; used in lieu of providing a completion token.
* `bindings` array\[object\] optional  
   * [Bindings](#bindings) to expose in the Worker.
* `placement` ` object ` optional  
   * [Smart placement](https://developers.cloudflare.com/workers/configuration/placement/) object for the Worker.  
   * `mode` field only supports `smart` for automatic placement.
* `compatibility_date` ` string ` optional  
   * [Compatibility Date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/#setting-compatibility-date) indicating targeted support in the Workers runtime. Backwards incompatible fixes to the runtime following this date will not affect this Worker. Highly recommended to set a `compatibility_date`, otherwise if on upload via the API, it defaults to the oldest compatibility date before any flags took effect (2021-11-02).
* `compatibility_flags` array\[string\] optional  
   * [Compatibility Flags](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#setting-compatibility-flags) that enable or disable certain features in the Workers runtime. Used to enable upcoming features or opt in or out of specific changes not included in a `compatibility_date`.

## Additional attributes: [Workers Script Upload API](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/)

For [immediately deployed uploads](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/#upload-a-new-version-and-deploy-it-immediately), the following **additional** attributes are configurable at the top-level.

Note

Except for `annotations`, these attributes are **not available** for version uploads.

* `migrations` array\[object\] optional  
   * [Durable Objects migrations](https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/) to apply.
* `logpush` ` boolean ` optional  
   * Whether [Logpush](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/hostname-analytics/#logpush) is turned on for the Worker.
* `tail_consumers` array\[object\] optional  
   * [Tail Workers](https://developers.cloudflare.com/workers/observability/logs/tail-workers/) that will consume logs from the attached Worker.
* `tags` array\[string\] optional  
   * List of strings to use as tags for this Worker.
* `annotations` ` object ` optional  
   * Annotations object for the Worker version created by this upload. Also available on the [Version Upload API](#additional-attributes-version-upload-api).  
   * `workers/message` specifies a custom message for the version.  
   * `workers/tag` specifies a custom identifier for the version.

## Additional attributes: [Version Upload API](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/versions/methods/create/)

For [version uploads](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/#upload-a-new-version-to-be-gradually-deployed-or-deployed-at-a-later-time), the following **additional** attributes are configurable at the top-level.

* `annotations` ` object ` optional  
   * Annotations object specific to the Worker version.  
   * `workers/message` specifies a custom message for the version.  
   * `workers/tag` specifies a custom identifier for the version.  
   * `workers/alias` specifies a custom alias for this version.

## Bindings

Workers can interact with resources on the Cloudflare Developer Platform using [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/). Refer to the JSON example below that shows how to add bindings in the `metadata` part.

```

{

  "bindings": [

    {

      "type": "ai",

      "name": "<VARIABLE_NAME>"

    },

    {

      "type": "analytics_engine",

      "name": "<VARIABLE_NAME>",

      "dataset": "<DATASET>"

    },

    {

      "type": "assets",

      "name": "<VARIABLE_NAME>"

    },

    {

      "type": "browser_rendering",

      "name": "<VARIABLE_NAME>"

    },

    {

      "type": "d1",

      "name": "<VARIABLE_NAME>",

      "id": "<D1_ID>"

    },

    {

      "type": "durable_object_namespace",

      "name": "<VARIABLE_NAME>",

      "class_name": "<DO_CLASS_NAME>"

    },

    {

      "type": "hyperdrive",

      "name": "<VARIABLE_NAME>",

      "id": "<HYPERDRIVE_ID>"

    },

    {

      "type": "kv_namespace",

      "name": "<VARIABLE_NAME>",

      "namespace_id": "<KV_ID>"

    },

    {

      "type": "mtls_certificate",

      "name": "<VARIABLE_NAME>",

      "certificate_id": "<MTLS_CERTIFICATE_ID>"

    },

    {

      "type": "plain_text",

      "name": "<VARIABLE_NAME>",

      "text": "<VARIABLE_VALUE>"

    },

    {

      "type": "queue",

      "name": "<VARIABLE_NAME>",

      "queue_name": "<QUEUE_NAME>"

    },

    {

      "type": "r2_bucket",

      "name": "<VARIABLE_NAME>",

      "bucket_name": "<R2_BUCKET_NAME>"

    },

    {

      "type": "secret_text",

      "name": "<VARIABLE_NAME>",

      "text": "<SECRET_VALUE>"

    },

    {

      "type": "service",

      "name": "<VARIABLE_NAME>",

      "service": "<SERVICE_NAME>",

      "environment": "production"

    },

    {

      "type": "vectorize",

      "name": "<VARIABLE_NAME>",

      "index_name": "<INDEX_NAME>"

    },

    {

      "type": "version_metadata",

      "name": "<VARIABLE_NAME>"

    }

  ]

}


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/workers/","name":"Workers"}},{"@type":"ListItem","position":3,"item":{"@id":"/workers/configuration/","name":"Configuration"}},{"@type":"ListItem","position":4,"item":{"@id":"/workers/configuration/multipart-upload-metadata/","name":"Multipart upload metadata"}}]}
```

---

---
title: API examples
description: REST API and TypeScript SDK examples for deploying Workers programmatically.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/reference/platform-examples.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# API examples

The following examples show how to use Cloudflare's REST API and TypeScript SDK to deploy and manage Workers programmatically.

### Prerequisites

Before using these examples, you need:

* Your **Account ID** \- Found in the Cloudflare dashboard URL or API settings
* A **dispatch namespace** \- Created via the [dashboard](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/get-started/)
* An **API token** with Workers permissions - Create one at [API Tokens ↗](https://dash.cloudflare.com/profile/api-tokens)

For SDK examples, install the Cloudflare SDK:

Terminal window

```

npm install cloudflare


```

### Deploy a user Worker

Upload a Worker script to your dispatch namespace. This is the primary operation your platform performs when customers deploy code.

* [ REST API ](#tab-panel-3386)
* [ TypeScript SDK ](#tab-panel-3387)

Terminal window

```

# First, create the worker script file

cat > worker.mjs << 'EOF'

export default {

  async fetch(request, env, ctx) {

    return new Response("Hello from user Worker!");

  },

};

EOF


# Deploy using multipart form (required for ES modules)

curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME" \

  -H "Authorization: Bearer $API_TOKEN" \

  -F 'metadata={"main_module": "worker.mjs"};type=application/json' \

  -F 'worker.mjs=@worker.mjs;type=application/javascript+module'


```

TypeScript

```

import Cloudflare from "cloudflare";


const client = new Cloudflare({

  apiToken: process.env.API_TOKEN,

});


async function deployUserWorker(

  accountId: string,

  namespace: string,

  scriptName: string,

  scriptContent: string,

) {

  const scriptFile = new File([scriptContent], `${scriptName}.mjs`, {

    type: "application/javascript+module",

  });


  const result =

    await client.workersForPlatforms.dispatch.namespaces.scripts.update(

      namespace,

      scriptName,

      {

        account_id: accountId,

        metadata: {

          main_module: `${scriptName}.mjs`,

        },

        files: [scriptFile],

      },

    );


  return result;

}


// Usage

await deployUserWorker(

  "your-account-id",

  "production",

  "customer-123",

  `export default {

  async fetch(request, env, ctx) {

    return new Response("Hello from customer 123!");

  },

};`,

);


```

### Deploy with bindings and tags

Use [bindings](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) to give each user Worker its own resources like a KV store or database. Use [tags](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/tags/) to organize Workers by customer ID, project ID, or plan type for bulk operations.

The following example shows how to deploy a Worker with its own KV namespace and tags attached:

* [ REST API ](#tab-panel-3388)
* [ TypeScript SDK ](#tab-panel-3389)

Terminal window

```

curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME" \

  -H "Authorization: Bearer $API_TOKEN" \

  -F 'metadata={"main_module": "worker.mjs", "bindings": [{"type": "kv_namespace", "name": "MY_KV", "namespace_id": "your-kv-namespace-id"}], "tags": ["customer-123", "production", "pro-plan"], "compatibility_date": "2024-01-01"};type=application/json' \

  -F 'worker.mjs=@worker.mjs;type=application/javascript+module'


```

TypeScript

```

import Cloudflare from "cloudflare";


const client = new Cloudflare({

  apiToken: process.env.API_TOKEN,

});


async function deployWorkerWithBindingsAndTags(

  accountId: string,

  namespace: string,

  scriptName: string,

  scriptContent: string,

  kvNamespaceId: string,

  tags: string[],

) {

  const scriptFile = new File([scriptContent], `${scriptName}.mjs`, {

    type: "application/javascript+module",

  });


  const result =

    await client.workersForPlatforms.dispatch.namespaces.scripts.update(

      namespace,

      scriptName,

      {

        account_id: accountId,

        metadata: {

          main_module: `${scriptName}.mjs`,

          compatibility_date: "2024-01-01",

          bindings: [

            {

              type: "kv_namespace",

              name: "MY_KV",

              namespace_id: kvNamespaceId,

            },

          ],

          tags: tags, // e.g., ["customer-123", "production", "pro-plan"]

        },

        files: [scriptFile],

      },

    );


  return result;

}


// Usage

const scriptContent = `export default {

  async fetch(request, env, ctx) {

    const value = await env.MY_KV.get("key") || "default";

    return new Response(value);

  },

};`;


await deployWorkerWithBindingsAndTags(

  "your-account-id",

  "production",

  "customer-123-app",

  scriptContent,

  "kv-namespace-id",

  ["customer-123", "production", "pro-plan"],

);


```

For more information, refer to [Bindings](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/bindings/) and [Tags](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/tags/).

### Deploy a Worker with static assets

Deploy a Worker that serves static files (HTML, CSS, JavaScript, images). This is a three-step process:

1. Create an upload session with a manifest of files
2. Upload the asset files
3. Deploy the Worker with the assets binding

For more details on static assets configuration and options, refer to [Static assets](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/static-assets/).

* [ REST API ](#tab-panel-3390)
* [ TypeScript SDK ](#tab-panel-3391)

**Step 1: Create upload session**

Terminal window

```

curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME/assets-upload-session" \

  -H "Authorization: Bearer $API_TOKEN" \

  -H "Content-Type: application/json" \

  -d '{

    "manifest": {

      "/index.html": {

        "hash": "<sha256-hash-first-16-bytes-hex>",

        "size": 1234

      },

      "/styles.css": {

        "hash": "<sha256-hash-first-16-bytes-hex>",

        "size": 567

      }

    }

  }'


```

The response includes a `jwt` token and `buckets` array indicating which files need uploading.

**Step 2: Upload assets**

Terminal window

```

curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/assets/upload?base64=true" \

  -H "Authorization: Bearer $JWT_FROM_STEP_1" \

  -F '<hash1>=<base64-encoded-content>' \

  -F '<hash2>=<base64-encoded-content>'


```

**Step 3: Deploy Worker with assets**

Terminal window

```

curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME" \

  -H "Authorization: Bearer $API_TOKEN" \

  -F 'metadata={"main_module": "worker.mjs", "assets": {"jwt": "<completion-token>"}, "bindings": [{"type": "assets", "name": "ASSETS"}]};type=application/json' \

  -F 'worker.mjs=export default { async fetch(request, env) { return env.ASSETS.fetch(request); } };type=application/javascript+module'


```

TypeScript

```

interface AssetFile {

  path: string; // e.g., "/index.html"

  content: string; // base64 encoded content

  size: number; // file size in bytes

}


async function hashContent(base64Content: string): Promise<string> {

  const binaryString = atob(base64Content);

  const bytes = new Uint8Array(binaryString.length);

  for (let i = 0; i < binaryString.length; i++) {

    bytes[i] = binaryString.charCodeAt(i);

  }

  const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);

  const hashArray = Array.from(new Uint8Array(hashBuffer));

  // Use first 16 bytes (32 hex chars) per API requirement

  return hashArray

    .slice(0, 16)

    .map((b) => b.toString(16).padStart(2, "0"))

    .join("");

}


async function deployWorkerWithAssets(

  accountId: string,

  namespace: string,

  scriptName: string,

  assets: AssetFile[],

) {

  const apiToken = process.env.API_TOKEN;

  const baseUrl = `https://api.cloudflare.com/client/v4/accounts/${accountId}/workers`;


  // Step 1: Build manifest

  const manifest: Record<string, { hash: string; size: number }> = {};

  const hashToAsset = new Map<string, AssetFile>();


  for (const asset of assets) {

    const hash = await hashContent(asset.content);

    const path = asset.path.startsWith("/") ? asset.path : "/" + asset.path;

    manifest[path] = { hash, size: asset.size };

    hashToAsset.set(hash, asset);

  }


  // Step 2: Create upload session

  const sessionResponse = await fetch(

    `${baseUrl}/dispatch/namespaces/${namespace}/scripts/${scriptName}/assets-upload-session`,

    {

      method: "POST",

      headers: {

        Authorization: `Bearer ${apiToken}`,

        "Content-Type": "application/json",

      },

      body: JSON.stringify({ manifest }),

    },

  );


  const sessionData = (await sessionResponse.json()) as {

    success: boolean;

    result?: { jwt: string; buckets?: string[][] };

  };


  if (!sessionData.success || !sessionData.result) {

    throw new Error("Failed to create upload session");

  }


  let completionToken = sessionData.result.jwt;

  const buckets = sessionData.result.buckets;


  // Step 3: Upload assets in buckets

  if (buckets && buckets.length > 0) {

    for (const bucket of buckets) {

      const formData = new FormData();

      for (const hash of bucket) {

        const asset = hashToAsset.get(hash);

        if (asset) {

          formData.append(hash, asset.content);

        }

      }


      const uploadResponse = await fetch(

        `${baseUrl}/assets/upload?base64=true`,

        {

          method: "POST",

          headers: { Authorization: `Bearer ${completionToken}` },

          body: formData,

        },

      );


      const uploadData = (await uploadResponse.json()) as {

        success: boolean;

        result?: { jwt?: string };

      };


      if (uploadData.result?.jwt) {

        completionToken = uploadData.result.jwt;

      }

    }

  }


  // Step 4: Deploy worker with assets binding

  const workerCode = `

export default {

  async fetch(request, env) {

    return env.ASSETS.fetch(request);

  }

};`;


  const deployFormData = new FormData();

  const metadata = {

    main_module: `${scriptName}.mjs`,

    assets: { jwt: completionToken },

    bindings: [{ type: "assets", name: "ASSETS" }],

  };


  deployFormData.append(

    "metadata",

    new Blob([JSON.stringify(metadata)], { type: "application/json" }),

  );

  deployFormData.append(

    `${scriptName}.mjs`,

    new Blob([workerCode], { type: "application/javascript+module" }),

  );


  const deployResponse = await fetch(

    `${baseUrl}/dispatch/namespaces/${namespace}/scripts/${scriptName}`,

    {

      method: "PUT",

      headers: { Authorization: `Bearer ${apiToken}` },

      body: deployFormData,

    },

  );


  return deployResponse.json();

}


// Usage

await deployWorkerWithAssets("your-account-id", "production", "customer-site", [

  {

    path: "/index.html",

    content: btoa("<html><body>Hello World</body></html>"),

    size: 37,

  },

  {

    path: "/styles.css",

    content: btoa("body { font-family: sans-serif; }"),

    size: 33,

  },

]);


```

### List Workers in a namespace

Retrieve all user Workers deployed to a namespace.

* [ REST API ](#tab-panel-3392)
* [ TypeScript SDK ](#tab-panel-3393)

Terminal window

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts" \

  -H "Authorization: Bearer $API_TOKEN"


```

TypeScript

```

async function listWorkers(accountId: string, namespace: string) {

  const response = await fetch(

    `https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/dispatch/namespaces/${namespace}/scripts`,

    {

      headers: {

        Authorization: `Bearer ${process.env.API_TOKEN}`,

      },

    },

  );


  const data = (await response.json()) as {

    success: boolean;

    result: Array<{ id: string; tags?: string[] }>;

  };


  return data.result;

}


// Usage

const workers = await listWorkers("your-account-id", "production");

console.log(workers);


```

### Delete Workers by tag

Delete all Workers matching a tag filter. This is useful when a customer deletes their account and you need to remove all their Workers at once.

* [ REST API ](#tab-panel-3394)
* [ TypeScript SDK ](#tab-panel-3395)

Delete all Workers tagged with `customer-123`:

Terminal window

```

curl -X DELETE "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts?tags=customer-123:yes" \

  -H "Authorization: Bearer $API_TOKEN"


```

TypeScript

```

async function deleteWorkersByTag(

  accountId: string,

  namespace: string,

  tag: string,

) {

  const response = await fetch(

    `https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/dispatch/namespaces/${namespace}/scripts?tags=${tag}:yes`,

    {

      method: "DELETE",

      headers: {

        Authorization: `Bearer ${process.env.API_TOKEN}`,

      },

    },

  );


  return response.json();

}


// Usage: Delete all Workers for a customer

await deleteWorkersByTag("your-account-id", "production", "customer-123");


```

### Delete a single Worker

Delete a specific Worker by name.

* [ REST API ](#tab-panel-3396)
* [ TypeScript SDK ](#tab-panel-3397)

Terminal window

```

curl -X DELETE "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/dispatch/namespaces/$NAMESPACE_NAME/scripts/$SCRIPT_NAME" \

  -H "Authorization: Bearer $API_TOKEN"


```

TypeScript

```

import Cloudflare from "cloudflare";


const client = new Cloudflare({

  apiToken: process.env.API_TOKEN,

});


async function deleteWorker(

  accountId: string,

  namespace: string,

  scriptName: string,

) {

  const result =

    await client.workersForPlatforms.dispatch.namespaces.scripts.delete(

      namespace,

      scriptName,

      { account_id: accountId },

    );


  return result;

}


// Usage

await deleteWorker("your-account-id", "production", "customer-123");


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/platform-examples/","name":"API examples"}}]}
```

---

---
title: Pricing
description: The Workers for Platforms Paid plan is $25 monthly. Workers for Platforms can be purchased through the Cloudflare dashboard.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/reference/pricing.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Pricing

The Workers for Platforms Paid plan is **$25 monthly**. Workers for Platforms can be purchased through the [Cloudflare dashboard ↗](https://dash.cloudflare.com/?to=/:account/workers-for-platforms).

Workers for Platforms comes with the following usage allotments and overage pricing.

| Requests1 2                                                           | Duration                        | CPU time2                                                                                                                                                                                                                                                                                                                                                                             | Scripts                                   |
| --------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| 20 million requests included per month  +$0.30 per additional million | No charge or limit for duration | 60 million CPU milliseconds included per month +$0.02 per additional million CPU milliseconds Max of 30 seconds of CPU time per invocation  Max of 15 minutes of CPU time per [Cron Trigger](https://developers.cloudflare.com/workers/configuration/cron-triggers/) or [Queue Consumer](https://developers.cloudflare.com/queues/configuration/javascript-apis/#consumer) invocation | 1000 scripts +$0.02 per additional script |

1 Inbound requests to your Worker. Cloudflare does not bill for [subrequests](https://developers.cloudflare.com/workers/platform/limits/#subrequests) you make from your Worker.   
2 Workers for Platforms only charges for 1 request across the chain of [dispatch Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/#dynamic-dispatch-worker) \-> [user Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/#user-workers) \-> [outbound Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/outbound-workers/). CPU time is charged across these Workers.

## Example pricing:

A Workers for Platforms project that serves 100 million requests per month, uses an average of 10 milliseconds (ms) of CPU time per request and uses 1200 scripts would have the following estimated costs:

| Monthly Costs    | Formula |                                                                                                             |
| ---------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| **Subscription** | $25.00  |                                                                                                             |
| **Requests**     | $24.00  | (100,000,000 requests - 20,000,000 included requests) / 1,000,000 \* $0.30                                  |
| **CPU time**     | $18.80  | ((10 ms of CPU time per request \* 100,000,000 requests) - 60,000,000 included CPU ms) / 1,000,000 \* $0.02 |
| **Scripts**      | $4.00   | (1200 scripts - 1000 included scripts) \* $0.02                                                             |
| **Total**        | $71.80  |                                                                                                             |

Custom limits

Set [custom limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/) for user Workers to get control over your Cloudflare bill, prevent accidental runaway bills or denial-of-wallet attacks. Configure the maximum amount of CPU time that can be used per invocation by [defining custom limits in your dispatch Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/custom-limits/#set-custom-limits).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/pricing/","name":"Pricing"}}]}
```

---

---
title: Worker Isolation
description: By default, Workers inside of a dispatch namespace are considered &#34;untrusted.&#34; This provides the strongest isolation between Workers and is best in cases where your customers have control over the code that's being deployed.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/reference/worker-isolation.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Worker Isolation

### Untrusted Mode (Default)

By default, Workers inside of a dispatch namespace are considered "untrusted." This provides the strongest isolation between Workers and is best in cases where your customers have control over the code that's being deployed.

In untrusted mode:

* The [request.cf](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties) object is not available in Workers (see [limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/limits/#cf-object) for more information)
* Each Worker has an isolated cache, when using the [Cache API](https://developers.cloudflare.com/workers/runtime-apis/cache/) or when making subrequests using `fetch()`, which egress via [Cloudflare's cache](https://developers.cloudflare.com/cache/)
* [caches.default](https://developers.cloudflare.com/workers/reference/how-the-cache-works/#cache-api) is disabled for all Workers in the namespace

This mode ensures complete isolation between customer Workers, preventing any potential cross-tenant data access.

### Trusted Mode

If you control the Worker code and want to disable isolation mode, you can configure the namespace as "trusted". This is useful when building internal platforms where your company controls all Worker code.

In trusted mode:

* The [request.cf](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties) object becomes available, providing access to request metadata
* All Workers in the namespace share the same cache space when using the Cache API

Note

In trusted mode, Workers can potentially access cached responses from other Workers in the namespace. Only enable this if you control all Worker code or have appropriate cache key isolation strategies.

To convert a namespace from untrusted to trusted:

Terminal window

```

curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/workers/dispatch/namespaces/{namespace_name}" \

  -H "Authorization: Bearer {api_token}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "{namespace_name}",

    "trusted_workers": true

  }'


```

If you enable trusted mode for a namespace that already has deployed Workers, you'll need to redeploy those Workers for the `request.cf` object to become available. Any new Workers you deploy after enabling trusted mode will automatically have access to it.

### Maintaining cache isolation in trusted mode

If you need access to `request.cf` but want to maintain cache isolation between customers, use customer-specific [cache keys](https://developers.cloudflare.com/workers/examples/cache-using-fetch/#custom-cache-keys) or the [Cache API](https://developers.cloudflare.com/workers/examples/cache-api/) with isolated keys.

## Related Resources

* [Platform Limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/limits) \- Understanding script and API limits
* [Cache API Documentation](https://developers.cloudflare.com/workers/runtime-apis/cache/) \- Learn about cache behavior in Workers
* [Request cf object](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestcf) \- Details on the cf object properties

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/reference/worker-isolation/","name":"Worker Isolation"}}]}
```

---

---
title: WFP REST API
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/workers-for-platforms/wfp-api.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# WFP REST API

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/","name":"Workers for Platforms"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/workers-for-platforms/wfp-api/","name":"WFP REST API"}}]}
```

---

---
title: Cloudflare for SaaS
description: Cloudflare for SaaS allows you to extend the security and performance benefits of Cloudflare's network to your customers via their own custom or vanity domains.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Cloudflare for SaaS

Cloudflare for SaaS allows you to extend the security and performance benefits of Cloudflare's network to your customers via their own custom or vanity domains.

  
As a SaaS provider, you may want to support subdomains under your own zone in addition to letting your customers use their own domain names with your services. For example, a customer may want to use their vanity domain `app.customer.com` to point to an application hosted on your Cloudflare zone `service.saas.com`. Cloudflare for SaaS allows you to increase security, performance, and reliability of your customers' domains.

Note

Enterprise customers can preview this product as a [non-contract service](https://developers.cloudflare.com/billing/preview-services/), which provides full access, free of metered usage fees, limits, and certain other restrictions.

## Benefits

When you use Cloudflare for SaaS, it helps you to:

* Provide custom domain support.
* Keep your customers' traffic encrypted.
* Keep your customers online.
* Facilitate fast load times of your customers' domains.
* Gain insight through traffic analytics.

## Limitations

If your customers already have their applications on Cloudflare, they cannot control some Cloudflare features for hostnames managed by your Custom Hostnames configuration, including:

* Argo
* Early Hints
* Client-side security (formerly known as Page Shield)
* Spectrum
* Wildcard DNS

## How it works

As the SaaS provider, you can extend Cloudflare's products to customer-owned custom domains by adding them to your zone [as custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/). Through a suite of easy-to-use products, Cloudflare for SaaS routes traffic from custom hostnames to an origin, set up on your domain. Cloudflare for SaaS is highly customizable. Three possible configurations are shown below.

### Standard Cloudflare for SaaS configuration:

Custom hostnames are routed to a default origin server called fallback origin. This configuration is available on all plans.

![Standard case](https://developers.cloudflare.com/_astro/Standard.DlPYrpsG_Z1aQodp.webp) 

### Cloudflare for SaaS with Apex Proxying:

This allows you to support apex domains even if your customers are using a DNS provider that does not allow a CNAME at the apex. This is available as an add-on for Enterprise plans. For more details, refer to [Apex Proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/).

![Advanced case](https://developers.cloudflare.com/_astro/Advanced.BaQXgT8v_Z1DP3hz.webp) 

### Cloudflare for SaaS with BYOIP:

This allows you to support apex domains even if your customers are using a DNS provider that does not allow a CNAME at the apex. Also, you can point to your own IPs if you want to bring an IP range to Cloudflare (instead of Cloudflare provided IPs). This is available as an add-on for Enterprise plans.

![Pro Case](https://developers.cloudflare.com/_astro/Pro.DTAC_nZK_Z23M1FF.webp) 

## Availability

Cloudflare for SaaS is bundled with non-Enterprise plans and available as an add-on for Enterprise plans. For more details, refer to [Plans](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

## Next steps

[ Get started ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) [ Learn more ](https://blog.cloudflare.com/introducing-ssl-for-saas/) 

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}}]}
```

---

---
title: API reference
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/api-reference.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# API reference

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/api-reference/","name":"API reference"}}]}
```

---

---
title: Design guide
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/design-guide.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Design guide

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/design-guide/","name":"Design guide"}}]}
```

---

---
title: Custom hostnames
description: Cloudflare for SaaS allows you, as a SaaS provider, to extend the benefits of Cloudflare products to custom domains by adding them to your zone as custom hostnames. We support adding hostnames that are a subdomain of your zone (for example, sub.serviceprovider.com) and vanity domains (for example, customer.com) to your SaaS zone.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom hostnames

Cloudflare for SaaS allows you, as a SaaS provider, to extend the benefits of Cloudflare products to custom domains by adding them to your zone as custom hostnames. We support adding hostnames that are a subdomain of your zone (for example, `sub.serviceprovider.com`) and vanity domains (for example, `customer.com`) to your SaaS zone.

## Resources

* [ Create custom hostnames ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/)
* [ Hostname validation ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/)
* [ Move hostnames ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/migrating-custom-hostnames/)
* [ Remove custom hostnames ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames/)
* [ Custom metadata ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}}]}
```

---

---
title: Create custom hostnames
description: Learn how to create custom hostnames.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Create custom hostnames

There are several required steps before a custom hostname can become active. For more details, refer to our [Get started guide](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/).

Zone name restriction

Do not configure a custom hostname which matches the zone name. For example, if your SaaS zone is `example.com`, do not create a custom hostname named `example.com`.

To create a custom hostname:

* [ Dashboard ](#tab-panel-3358)
* [ API ](#tab-panel-3359)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select **Add Custom Hostname**.
3. Add your customer's hostname `app.customer.com` and set the relevant options, including:  
   * The [minimum TLS version](https://developers.cloudflare.com/ssl/reference/protocols/).  
   * Defining whether you want to use a certificate provided by Cloudflare or [upload a custom certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/).  
   * Selecting the [certificate authority (CA)](https://developers.cloudflare.com/ssl/reference/certificate-authorities/) that will issue the certificate.  
   * Choosing the [validation method](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).  
   * Whether you want to **Enable wildcard**, which adds a `*.<custom-hostname>` SAN to the custom hostname certificate. For more details, refer to [Hostname priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority).  
   * Choosing a value for [Custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/).
4. Select **Add Custom Hostname**.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

1. To create a custom hostname using the API, use the [Create Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) endpoint.  
   * You can leave the `certificate_authority` parameter empty to set it to "default CA". With this option, Cloudflare checks the CAA records before requesting the certificates, which helps ensure the certificates can be issued from the CA.
2. For the newly created custom hostname, the `POST` response may not return the DCV validation token `validation_records`. It is recommended to make a second [GET command](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/list/) (with a delay) to retrieve these details.

The response contains the complete definition of the new custom hostname.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

For each custom hostname, Cloudflare issues two certificates bundled in chains that maximize browser compatibility (unless you [upload custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/)).

The primary certificate uses a `P-256` key, is `SHA-2/ECDSA` signed, and will be presented to browsers that support elliptic curve cryptography (ECC). The secondary or fallback certificate uses an `RSA 2048-bit` key, is `SHA-2/RSA` signed, and will be presented to browsers that do not support ECC.

## Hostnames over 64 characters

The Common Name (CN) restriction establishes a limit of 64 characters ([RFC 5280 ↗](https://www.rfc-editor.org/rfc/rfc5280.html)). If you have a hostname that exceeds this length, you can set `cloudflare_branding` to `true` when creating your custom hostnames [via API](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/).

```

"ssl": {

    "cloudflare_branding": true

  }


```

Cloudflare branding means that `sni.cloudflaressl.com` will be added as the certificate Common Name (CN) and the long hostname will be included as a part of the Subject Alternative Name (SAN).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/","name":"Create custom hostnames"}}]}
```

---

---
title: Custom metadata
description: Configure per-hostname settings such as URL rewriting and custom headers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom metadata

You may wish to configure per-hostname (customer) settings beyond the scale of Rules or Rate Limiting.

To do this, you will first need to reach out to your account team to enable access to Custom Metadata. After configuring custom metadata, you can use it in the following ways:

* Read the metadata JSON from [Cloudflare Workers](https://developers.cloudflare.com/workers/) (requires access to Workers) to define per-hostname behavior.
* Use custom metadata values in [rule expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/) of different Cloudflare security products to define the rule scope.

Note

Only certain customers have access to this feature. For more details, see the [Plans page](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

---

## Examples

* Per-customer URL rewriting — for example, customers 1-10,000 fetch assets from server A, 10,001-20,000 from server B, etc.
* Adding custom headers — for example, `X-Customer-ID: $number` based on the metadata you provided
* Setting HTTP Strict Transport Security (“HSTS”) headers on a per-customer basis

Please speak with your Solutions Engineer to discuss additional logic and requirements.

## Submitting custom metadata

You may add custom metadata to Cloudflare via the Custom Hostnames API. This data can be added via a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) to the specific hostname ID to set metadata for that hostname, for example:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "ssl": {

        "method": "http",

        "type": "dv"

    },

    "custom_metadata": {

        "customer_id": "12345",

        "redirect_to_https": true,

        "security_tag": "low"

    }

  }'


```

Changes to metadata will propagate across Cloudflare's edge within 30 seconds.

---

## Accessing custom metadata from a Cloudflare Worker

The metadata object will be accessible on each request using the `request.cf.hostMetadata` property. You can then read the data, and customize any behavior on it using the Worker.

In the example below we will use the user\_id in the Worker that was submitted using the API call above `"custom_metadata":{"customer_id":"12345","redirect_to_https": true,"security_tag":"low"}`, and set a request header to send the `customer_id` to the origin:

* [  JavaScript ](#tab-panel-3360)
* [  TypeScript ](#tab-panel-3361)

JavaScript

```

export default {

  /**

   * Fetch and add a X-Customer-Id header to the origin based on hostname

   * @param {Request} request

   */

  async fetch(request, env, ctx) {

    const customer_id = request.cf.hostMetadata.customer_id;

    const newHeaders = new Headers(request.headers);

    newHeaders.append("X-Customer-Id", customer_id);


    const init = {

      headers: newHeaders,

      method: request.method,

    };

    return fetch(request.url, init);

  },

};


```

TypeScript

```

export default {

  /**

   * Fetch and add a X-Customer-Id header to the origin based on hostname

   * @param {Request} request

   */

  async fetch(request, env, ctx): Promise<Response> {

    const customer_id = request.cf.hostMetadata.customer_id;

    const newHeaders = new Headers(request.headers);

    newHeaders.append("X-Customer-Id", customer_id);


    const init = {

      headers: newHeaders,

      method: request.method,

    };

    return fetch(request.url, init);

  },

} satisfies ExportedHandler<Env>;


```

## Accessing custom metadata in a rule expression

Use the [cf.hostname.metadata](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/reference/cf.hostname.metadata/) field to access the metadata object in rule expressions. To obtain the different values from the JSON object, use the [lookup\_json\_string](https://developers.cloudflare.com/ruleset-engine/rules-language/functions/#lookup%5Fjson%5Fstring) function.

The following rule expression defines that there will be a rule match if the `security_tag` value in custom metadata contains the value `low`:

```

lookup_json_string(cf.hostname.metadata, "security_tag") eq "low"


```

---

## Best practices

* Ensure that the JSON schema used is fixed: changes to the schema without corresponding Cloudflare Workers changes will potentially break websites, or fall back to any defined “default” behavior
* Prefer a flat JSON structure
* Use string keys in snake\_case (rather than camelCase or PascalCase)
* Use proper booleans (true/false rather than `true` or `1` or `0`)
* Use numbers to represent integers instead of strings (`1` or `2` instead of `"1"` or `"2"`)
* Define fallback behaviour in the non-presence of metadata
* Define fallback behaviour if a key or value in the metadata are unknown

General guidance is to follow [Google's JSON Style guide ↗](https://google.github.io/styleguide/jsoncstyleguide.xml) where appropriate.

---

## Limitations

There are some limitations to the metadata that can be provided to Cloudflare:

* It must be valid JSON.
* Any origin resolution — for example, directing requests for a given hostname to a specific backend — must be provided as a hostname that exists within Cloudflare's DNS (even for non-authoritative setups). Providing an IP address directly will cause requests to error.
* The total payload must not exceed 4 KB.
* It requires a Cloudflare Worker that knows how to process the schema and trigger logic based on the contents.

Note

Be careful when modifying the schema. Adding, removing, or changing keys and possible values may cause the Cloudflare Worker to either ignore the data or return an error for requests that trigger it.

### Terraform support

[Terraform](https://developers.cloudflare.com/terraform/) only allows maps of a single type, so Cloudflare's Terraform support for custom metadata for custom hostnames is limited to string keys and values.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/","name":"Custom metadata"}}]}
```

---

---
title: Hostname validation
description: Before Cloudflare can proxy traffic through a custom hostname, we need to verify your customer's ownership of that hostname.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Hostname validation

Before Cloudflare can proxy traffic through a custom hostname, we need to verify your customer's ownership of that hostname.

Note

If a custom hostname is already on Cloudflare, using the [pre-validation methods](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation/) will not shift the traffic to the SaaS zone. That will only happen once the [DNS target](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record) of the custom hostnames changes to point to the SaaS zone.

## Options

If minimizing downtime is more important to you, refer to our [pre-validation methods](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation/).

If ease of use for your customers is more important, review our [real-time validation methods](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/).

## Limitations

Custom hostnames using another CDN are not compatible with Cloudflare for SaaS. Since Cloudflare must be able to validate your customer's ownership of the hostname you add, if their usage of another CDN obfuscates their DNS records, hostname validation will fail.

## Related resources

* [ Pre-validation ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation/)
* [ Real-time validation ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/)
* [ Backoff schedule ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/backoff-schedule/)
* [ Validation status ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/validation-status/)
* [ Error codes ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/error-codes/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}}]}
```

---

---
title: Backoff schedule
description: After you create a custom hostname, Cloudflare has to validate that hostname.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/backoff-schedule.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Backoff schedule

After you create a custom hostname, Cloudflare has to [validate that hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/).

Attempts to validate a Custom Hostname are distributed over seven days (a total of 75 retries). At the end of this schedule, if the validation is unsuccessful, the custom hostname will be deleted. The function that determines the next check varies based on the number of attempts:

* For the first 10 attempts:

```

now() + min((floor(60 * pow(1.05, retry_attempt)) * INTERVAL '1 second'), INTERVAL '4 hours')


```

* For the remaining 65 attempts:

```

now() + min((floor(60 * pow(1.15, retry_attempt)) * INTERVAL '1 second'), INTERVAL '4 hours')


```

The first 10 checks complete within 20 minutes and most checks complete in the first four hours. The check back off is capped to a maximum of four hours to avoid exponential growth. The back off behavior causes larger gaps between check intervals towards the end of the back off schedule:

| Retry Attempt | In Seconds | In Minutes | In Hours |
| ------------- | ---------- | ---------- | -------- |
| 0             | 60         | 1          | 0.016667 |
| 1             | 63         | 1.05       | 0.0175   |
| 2             | 66         | 1.1        | 0.018333 |
| 3             | 69         | 1.15       | 0.019167 |
| 4             | 72         | 1.2        | 0.02     |
| 5             | 76         | 1.266667   | 0.021111 |
| 6             | 80         | 1.333333   | 0.022222 |
| 7             | 84         | 1.4        | 0.023333 |
| 8             | 88         | 1.466667   | 0.024444 |
| 9             | 93         | 1.55       | 0.025833 |
| 10            | 242        | 4.033333   | 0.067222 |
| 11            | 279        | 4.65       | 0.0775   |
| 12            | 321        | 5.35       | 0.089167 |
| 13            | 369        | 6.15       | 0.1025   |
| 14            | 424        | 7.066667   | 0.117778 |
| 15            | 488        | 8.133333   | 0.135556 |
| 16            | 561        | 9.35       | 0.155833 |
| 17            | 645        | 10.75      | 0.179167 |
| 18            | 742        | 12.366667  | 0.206111 |
| 19            | 853        | 14.216667  | 0.236944 |
| 20            | 981        | 16.35      | 0.2725   |
| 21            | 1129       | 18.816667  | 0.313611 |
| 22            | 1298       | 21.633333  | 0.360556 |
| 23            | 1493       | 24.883333  | 0.414722 |
| 24            | 1717       | 28.616667  | 0.476944 |
| 25            | 1975       | 32.916667  | 0.548611 |
| 26            | 2271       | 37.85      | 0.630833 |
| 27            | 2612       | 43.533333  | 0.725556 |
| 28            | 3003       | 50.05      | 0.834167 |
| 29            | 3454       | 57.566667  | 0.959444 |
| 30            | 3972       | 66.2       | 1.103333 |
| 31            | 4568       | 76.133333  | 1.268889 |
| 32            | 5253       | 87.55      | 1.459167 |
| 33            | 6041       | 100.683333 | 1.678056 |
| 34            | 6948       | 115.8      | 1.93     |
| 35            | 7990       | 133.166667 | 2.219444 |
| 36            | 9189       | 153.15     | 2.5525   |
| 37            | 10567      | 176.116667 | 2.935278 |
| 38            | 12152      | 202.533333 | 3.375556 |
| 39            | 13975      | 232.916667 | 3.881944 |
| 40            | 14400      | 240        | 4        |
| 41            | 14400      | 240        | 4        |
| 42            | 14400      | 240        | 4        |
| 43            | 14400      | 240        | 4        |
| 44            | 14400      | 240        | 4        |
| 45            | 14400      | 240        | 4        |
| 46            | 14400      | 240        | 4        |
| 47            | 14400      | 240        | 4        |
| 48            | 14400      | 240        | 4        |
| 49            | 14400      | 240        | 4        |
| 50            | 14400      | 240        | 4        |
| 51            | 14400      | 240        | 4        |
| 52            | 14400      | 240        | 4        |
| 53            | 14400      | 240        | 4        |
| 54            | 14400      | 240        | 4        |
| 55            | 14400      | 240        | 4        |
| 56            | 14400      | 240        | 4        |
| 57            | 14400      | 240        | 4        |
| 58            | 14400      | 240        | 4        |
| 59            | 14400      | 240        | 4        |
| 60            | 14400      | 240        | 4        |
| 61            | 14400      | 240        | 4        |
| 62            | 14400      | 240        | 4        |
| 63            | 14400      | 240        | 4        |
| 64            | 14400      | 240        | 4        |
| 65            | 14400      | 240        | 4        |
| 66            | 14400      | 240        | 4        |
| 67            | 14400      | 240        | 4        |
| 68            | 14400      | 240        | 4        |
| 69            | 14400      | 240        | 4        |
| 70            | 14400      | 240        | 4        |
| 71            | 14400      | 240        | 4        |
| 72            | 14400      | 240        | 4        |
| 73            | 14400      | 240        | 4        |
| 74            | 14400      | 240        | 4        |
| 75            | 14400      | 240        | 4        |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/backoff-schedule/","name":"Backoff schedule"}}]}
```

---

---
title: Error codes
description: When you validate a custom hostname, you might encounter the following error codes.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/error-codes.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Error codes

When you [validate a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/), you might encounter the following error codes.

| Error                                                                                                                   | Cause                                                                                                                                                                                                                                    |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Zone does not have a fallback origin set.                                                                               | Fallback is not active.                                                                                                                                                                                                                  |
| Fallback origin is in a status of initializing, pending\_deployment, pending\_deletion, or deleted.                     | Fallback is not active.                                                                                                                                                                                                                  |
| Custom hostname does not CNAME to this zone.                                                                            | Zone does not have [apex proxying entitlement](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/) and custom hostname does not CNAME to zone.                        |
| None of the A or AAAA records are owned by this account and the pre-generated ownership validation token was not found. | Account has [apex proxying enabled](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/) but the custom hostname failed the hostname validation check on the A record. |
| This account and the pre-generated ownership validation token was not found.                                            | Hostname does not CNAME to zone or none of the A/AAAA records match reserved IPs for zone.                                                                                                                                               |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/error-codes/","name":"Error codes"}}]}
```

---

---
title: Pre-validation
description: Pre-validation methods help verify domain ownership before your customer's traffic is proxying through Cloudflare.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Pre-validation

Pre-validation methods help verify domain ownership before your customer's traffic is proxying through Cloudflare.

## Use when

Use pre-validation methods when your customers cannot tolerate any downtime, which often occurs with production domains.

The downside is that these methods require an additional setup step for your customers. Especially if you already need them to add something to their domain for [certificate validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/), pre-validation might make their onboarding more complicated.

If your customers can tolerate a bit of downtime and you want their setup to be simpler, review our [real-time validation methods](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/).

## How to

### TXT records

TXT validation is when your customer adds a `TXT` record to their authoritative DNS to verify domain ownership.

Note

If your customer cannot update their authoritative DNS, you could also use [HTTP validation](#http-tokens).

To set up `TXT` validation:

1. When you [create a custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/), save the `ownership_verification` information.  
```  
{  
"result": [  
    {  
    "id": "3537a672-e4d8-4d89-aab9-26cb622918a1",  
    "hostname": "app.example.com",  
    // ...  
    "status": "pending",  
    "verification_errors": ["custom hostname does not CNAME to this zone."],  
    "ownership_verification": {  
        "type": "txt",  
        "name": "_cf-custom-hostname.app.example.com",  
        "value": "0e2d5a7f-1548-4f27-8c05-b577cb14f4ec"  
    },  
    "created_at": "2020-03-04T19:04:02.705068Z"  
    }  
]  
}  
```
2. Have your customer add a `TXT` record with that `name` and `value` at their authoritative DNS provider.
3. After a few minutes, you will see the hostname status become **Active** in the UI.
4. Once you activate the custom hostname, your customer can remove the `TXT` record.

### HTTP tokens

HTTP validation is when you or your customer places an HTTP token on their origin server to verify domain ownership.

To set up HTTP validation:

When you [create a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates/) using the API, Cloudflare provides an HTTP `ownership_verification` record in the response.

To get and use the `ownership_verification` record:

1. Make an API call to [create a Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/).
2. In the response, copy the `http_url` and `http_body` from the `ownership_verification_http` object:  
Example response (truncated)  
```  
{  
  "result": [  
    {  
      "id": "24c8c68e-bec2-49b6-868e-f06373780630",  
      "hostname": "app.example.com",  
      // ...  
      "ownership_verification_http": {  
          "http_url": "http://app.example.com/.well-known/cf-custom-hostname-challenge/24c8c68e-bec2-49b6-868e-f06373780630",  
          "http_body": "48b409f6-c886-406b-8cbc-0fbf59983555"  
      },  
      "created_at": "2020-03-04T20:06:04.117122Z"  
    }  
  ]  
}  
```
3. Have your customer place the `http_url` and `http_body` on their origin web server.  
Example response (truncated)  
```  
location "/.well-known/cf-custom-hostname-challenge/24c8c68e-bec2-49b6-868e-f06373780630" {  
    return 200 "48b409f6-c886-406b-8cbc-0fbf59983555\n";  
}  
```  
Cloudflare will access this token by sending `GET` requests to the `http_url` using `User-Agent: Cloudflare Custom Hostname Verification`.  
Note  
If you can serve these tokens on behalf of your customers, you can simplify their overall setup.
4. After a few minutes, you will see the hostname status become **Active** in the UI.
5. Once the hostname is active, your customer can remove the token from their origin server.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation/","name":"Pre-validation"}}]}
```

---

---
title: Real-time validation
description: When you use a real-time validation method, Cloudflare verifies your customer's hostname when your customers adds their DNS routing record to their authoritative DNS.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Real-time validation

When you use a real-time validation method, Cloudflare verifies your customer's hostname when your customers adds their [DNS routing record](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record) to their authoritative DNS.

## Use when

Real-time validation methods put less burden on your customers because it does not require any additional actions.

However, it may cause some downtime since Cloudflare takes a few seconds to iterate over DNS records. This downtime also can increase - due to the increasing [validation backoff schedule](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/backoff-schedule/) \- if your customer takes additional time to add their DNS routing record.

To minimize this downtime, you can continually send no-change [PATCH requests](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) for the specific custom hostname until it validates (which resets the validation backoff schedule).

To avoid any chance of downtime, use a [pre-validation method](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/pre-validation/)

## How to

Real-time validation occurs automatically when your customer adds their [DNS routing record](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record).

The exact record depends on your Cloudflare for SaaS setup.

### Normal setup (CNAME target)

Most customers will have a `CNAME` target, which requires their customers to create a `CNAME` record similar to:

```

mystore.com CNAME customers.saasprovider.com


```

### Apex proxying

With [apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/), SaaS customers need to create an `A` record for their hostname that points to the IP prefix allocated to the SaaS provider's account.

```

example.com.  60  IN  A   192.0.2.1


```

Note

For [BYOIP](https://developers.cloudflare.com/byoip/) customers, Cloudflare automatically enables the Apex Proxy Access feature on your BYOIP block, which allows Custom Hostnames to be activated via [Apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/#apex-proxying) when Authoritative DNS for a customer's hostname targets any IP addresses in your BYOIP block.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/","name":"Real-time validation"}}]}
```

---

---
title: Validation status
description: When you validate a custom hostname, that hostname can be in several different statuses.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/validation-status.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Validation status

When you [validate a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/), that hostname can be in several different statuses.

| Status              | Description                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pending             | Custom hostname is pending hostname validation.                                                                                                                                                                                                                                                                                                                                  |
| Active              | Custom hostname has completed hostname validation and is active.                                                                                                                                                                                                                                                                                                                 |
| Active re-deploying | Customer hostname is active and the changes have been processed.                                                                                                                                                                                                                                                                                                                 |
| Blocked             | Custom hostname cannot be added to Cloudflare at this time. Custom hostname was likely associated with Cloudflare previously and flagged for abuse.If you are an Enterprise customer, contact your Customer Success Manager. Otherwise, email abusereply@cloudflare.com with the name of the web property and a detailed explanation of your association with this web property. |
| Moved               | Custom hostname is not active after **Pending** for the entirety of the [Validation Backoff Schedule](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/backoff-schedule/) or it no longer points to the fallback origin.                                                                                        |
| Deleted             | Custom hostname was deleted from the zone. Occurs when status is **Moved** for more than seven days.                                                                                                                                                                                                                                                                             |

## Refresh validation

To run the custom hostname validation check again, select **Refresh** on the dashboard or send a `PATCH` request to the [Edit custom hostname endpoint](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/). If using the API, make sure that the `--data` field contains an `ssl` object with the same `method` and `type` as the original request.

If the hostname is in a **Moved** or **Deleted** state, the refresh will set the custom hostname back to **Pending validation**.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/","name":"Hostname validation"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/validation-status/","name":"Validation status"}}]}
```

---

---
title: Move hostnames
description: Learn how to move hostnames between different zones.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/migrating-custom-hostnames.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Move hostnames

As a SaaS provider, you may want, or have, multiple zones to manage hostnames. Each zone can have different configurations or origins, as well as correlate to varying products. You might shift custom hostnames between zones to enable or disable certain features. Cloudflare allows migration within the same account through the steps below:

---

## CNAME

If your custom hostname uses a CNAME record, add the custom hostname to the new zone and [update your DNS record](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#edit-dns-records) to point to the new zone.

Note

If you would like to migrate the custom hostname without end customers changing the DNS target, use [apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/).

1. [Add custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) to your new zone.
2. Direct your customer to [change the DNS record](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#edit-dns-records) so that it points to the new zone.
3. Confirm that the custom hostname has validated in the new zone.
4. Wait for the certificate to validate automatically through Cloudflare or [validate it using Domain Control Validation (DCV)](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/methods/#perform-dcv).
5. Remove custom hostname from the old zone.

Once these steps are complete, the custom hostname's traffic will route to the second SaaS zone and will use its configuration.

## A record

Through [Apex Proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/) or [BYOIP](https://developers.cloudflare.com/byoip/), you can migrate the custom hostname without action from your end customer.

1. Verify with the account team that your apex proxying IPs have been assigned to both SaaS zones.
2. [Add custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) to the new zone.
3. Confirm that the custom hostname has validated in the new zone.
4. Wait for the certificate to validate automatically through Cloudflare or [validate it using DCV](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/methods/#perform-dcv).
5. Remove custom hostname from the old zone.

Note

The most recently edited custom hostname will be active. For instance, `example.com` exists on `SaaS Zone 1`. It is added to `SaaS Zone 2`. Because it was activated more recently on `SaaS Zone 2`, that is where it will be active. However, if edits are made to example.com on `SaaS Zone 1`, it will reactivate on that zone instead of `SaaS Zone 2`.

## Wildcard certificate

If you are migrating custom hostnames that rely on a Wildcard certificate, Cloudflare cannot automatically complete Domain Control Validation (DCV).

1. [Add custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) to the new zone.
2. Direct your customer to [change the DNS record](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#edit-dns-records) so that it points to the new zone.
3. [Validate the certificate](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/methods/#perform-dcv) on the new zone through DCV.

The custom hostname can activate on the new zone even if the certificate is still active on the old zone. This ensures a valid certificate exists during migration. However, it is important to validate the certificate on the new zone as soon as possible.

Note

Verify that the custom hostname successfully activated after the migration on the [**Custom Hostnames** ↗](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames) page.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/migrating-custom-hostnames/","name":"Move hostnames"}}]}
```

---

---
title: Remove custom hostnames
description: Learn how to remove custom hostnames for inactive customers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Remove custom hostnames

As a SaaS provider, your customers may decide to no longer participate in your service offering. If that happens, you need to stop routing traffic through those custom hostnames.

## Domains using Cloudflare

If your customer's domain is also using Cloudflare, they can stop routing their traffic through your custom hostname by updating their Cloudflare DNS.

If they update their [CNAME record](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record) so that it no longer points to your `CNAME` target:

* The domain's traffic will not route through your custom hostname.
* The custom hostname will enter into a **Moved** state.

If the custom hostname is in a **Moved** state for seven days, it will transition into a **Deleted** state.

You should remove a customer's custom hostname from your zone if they decide to churn. This is especially important if your end customers are using Cloudflare because if the churned customer changes the DNS target to point away from your SaaS zone but you have not removed it, the custom hostname will continue to route to your service. This is a result of the [custom hostname priority logic](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority).

## Domains not using Cloudflare

If your customer's domain is not using Cloudflare, you must remove a customer's custom hostname from your zone if they decide to churn.

* [ Dashboard ](#tab-panel-3362)
* [ API ](#tab-panel-3363)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select the custom hostname and select **Delete**.
3. A confirmation window will appear. Acknowledge the warning and select **Delete** again.

To delete a custom hostname and any issued certificates using the API, send a [DELETE request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/delete/).

## For end customers

If your SaaS domain is also a [domain using Cloudflare](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/), you can use your Cloudflare DNS to remove your domain from your SaaS provider.

This means that - if you [remove the DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#delete-dns-records) pointing to your SaaS provider - Cloudflare will stop routing domain traffic through your SaaS provider and the associated custom hostname will enter a **Moved** state.

This also means that you need to keep DNS records pointing to your SaaS provider for as long as you are a customer. Otherwise, you could accidentally remove your domain from their services.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/","name":"Custom hostnames"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames/","name":"Remove custom hostnames"}}]}
```

---

---
title: Analytics
description: You can use custom hostname analytics for two general purposes: exploring how your customers use your product and sharing the benefits provided by Cloudflare with your customers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/hostname-analytics.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Analytics

You can use custom hostname analytics for two general purposes: exploring how your customers use your product and sharing the benefits provided by Cloudflare with your customers.

These analytics include **Site Analytics**, **Bot Analytics**, **Cache Analytics**, **Security Events**, and [any other datasets](https://developers.cloudflare.com/analytics/graphql-api/features/data-sets/) with the `clientRequestHTTPHost` field.

Note

The plan of your Cloudflare for SaaS application determines the analytics available for your custom hostnames.

## Explore customer usage

Use custom hostname analytics to help your organization with billing and infrastructure decisions, answering questions like:

* "How many total requests is your service getting?"
* "Is one customer transferring significantly more data than the others?"
* "How many global customers do you have and where are they distributed?"

If you see one customer is using more data than another, you might increase their bill. If requests are increasing in a certain geographic region, you might want to increase the origin servers in that region.

To access custom hostname analytics, either [use the dashboard](https://developers.cloudflare.com/analytics/faq/about-analytics/) and filter by the `Host` field or [use the GraphQL API](https://developers.cloudflare.com/analytics/graphql-api/) and filter by the `clientRequestHTTPHost` field. For more details, refer to our tutorial on [Querying HTTP events by hostname with GraphQL](https://developers.cloudflare.com/analytics/graphql-api/tutorials/end-customer-analytics/).

## Share Cloudflare data with your customers

With custom hostname analytics, you can also share site information with your customers, including data about:

* How many pageviews their site is receiving.
* Whether their site has a large percentage of bot traffic.
* How fast their site is.

Build custom dashboards to share this information by specifying an individual custom hostname in `clientRequestHTTPHost` field of [any dataset](https://developers.cloudflare.com/analytics/graphql-api/features/data-sets/) that includes this field.

## Logpush

[Logpush](https://developers.cloudflare.com/logs/logpush/) sends metadata from Cloudflare products to your cloud storage destination or SIEM.

Using [filters](https://developers.cloudflare.com/logs/logpush/logpush-job/filters/), you can send set sample rates (or not include logs altogether) based on filter criteria. This flexibility allows you to maintain selective logs for custom hostnames without massively increasing your log volume.

Filtering is available for [all Cloudflare datasets](https://developers.cloudflare.com/logs/logpush/logpush-job/datasets/zone/).

Note

Filtering is not supported on the following data types: `objects`, `array[object]`.

For the Firewall events dataset, the following fields are not supported: `Action`, `Description`, `Kind`, `MatchIndex`, `Metadata`, `OriginatorRayID`, `RuleID`, and `Source`.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/hostname-analytics/","name":"Analytics"}}]}
```

---

---
title: Performance
description: Cloudflare for SaaS allows you to deliver the best performance to your end customers by helping enable you to reduce latency through:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/performance/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Performance

Cloudflare for SaaS allows you to deliver the best performance to your end customers by helping enable you to reduce latency through:

* [Argo Smart Routing for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/performance/argo-for-saas/) calculates and optimizes the fastest path for requests to travel to your origin.
* [Early Hints for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/performance/early-hints-for-saas/) provides faster loading speeds for individual custom hostnames by allowing the browser to begin loading responses while the origin server is compiling the full response.
* [Cache for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/performance/cache-for-saas/) makes customer websites faster by storing a copy of the website’s content on the servers of our globally distributed data centers.
* By using Cloudflare for SaaS, your customers automatically inherit the benefits of Cloudflare's vast [anycast network ↗](https://www.cloudflare.com/network/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/","name":"Performance"}}]}
```

---

---
title: Argo Smart Routing for SaaS
description: Argo Smart Routing uses real-time global network information to route traffic on the fastest possible path across the Internet. Regardless of geographic location, this allows Cloudflare to optimize routing to make it faster, more reliable, and more secure. As a SaaS provider, you may want to emphasize the quickest traffic delivery for your end customers. To do so, enable Argo Smart Routing.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/performance/argo-for-saas.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Argo Smart Routing for SaaS

Argo Smart Routing uses real-time global network information to route traffic on the fastest possible path across the Internet. Regardless of geographic location, this allows Cloudflare to optimize routing to make it faster, more reliable, and more secure. As a SaaS provider, you may want to emphasize the quickest traffic delivery for your end customers. To do so, [enable Argo Smart Routing](https://developers.cloudflare.com/argo-smart-routing/get-started/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/","name":"Performance"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/argo-for-saas/","name":"Argo Smart Routing for SaaS"}}]}
```

---

---
title: Cache for SaaS
description: Cloudflare makes customer websites faster by storing a copy of the website’s content on the servers of our globally distributed data centers. Content can be either static or dynamic: static content is “cacheable” or eligible for caching, and dynamic content is “uncacheable” or ineligible for caching. The cached copies of content are stored physically closer to users, optimized to be fast, and do not require recomputing.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/performance/cache-for-saas.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Cache for SaaS

Cloudflare makes customer websites faster by storing a copy of the website’s content on the servers of our globally distributed data centers. Content can be either static or dynamic: static content is “cacheable” or eligible for caching, and dynamic content is “uncacheable” or ineligible for caching. The cached copies of content are stored physically closer to users, optimized to be fast, and do not require recomputing.

As a SaaS provider, enabling caching reduces latency on your custom domains. For more information, refer to [Cache](https://developers.cloudflare.com/cache/). If you would like to enable caching, review [Getting Started with Cache](https://developers.cloudflare.com/cache/get-started/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/","name":"Performance"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/cache-for-saas/","name":"Cache for SaaS"}}]}
```

---

---
title: Early Hints for SaaS
description: Early Hints allows the browser to begin loading resources while the origin server is compiling the full response. This improves webpage’s loading speed for the end user. As a SaaS provider, you may prioritize speed for some of your custom hostnames. Using custom metadata, you can enable Early Hints per custom hostname.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/performance/early-hints-for-saas.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Early Hints for SaaS

[Early Hints](https://developers.cloudflare.com/cache/advanced-configuration/early-hints/) allows the browser to begin loading resources while the origin server is compiling the full response. This improves webpage’s loading speed for the end user. As a SaaS provider, you may prioritize speed for some of your custom hostnames. Using custom metadata, you can [enable Early Hints](https://developers.cloudflare.com/cache/advanced-configuration/early-hints/#enable-early-hints) per custom hostname.

---

## Prerequisites

Before you can employ Early Hints for SaaS, you need to create a custom hostname. Review [Get Started with Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) if you have not already done so.

---

## Enable Early Hints per custom hostname via the API

1. [Locate your zone ID](https://developers.cloudflare.com/fundamentals/account/find-account-and-zone-ids/), available in the Cloudflare dashboard.
2. Locate your Authentication Key on the [**API Tokens** ↗](https://dash.cloudflare.com/?to=/:account/profile/api-tokens) page, under **Global API Key**.
3. If you are [creating a new custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/), make an API call such as the example below, specifying `"early_hints": "on"`:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Create Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames" \

  --request POST \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "hostname": "<CUSTOM_HOSTNAME>",

    "ssl": {

        "method": "http",

        "type": "dv",

        "settings": {

            "http2": "on",

            "min_tls_version": "1.2",

            "tls_1_3": "on",

            "early_hints": "on"

        },

        "bundle_method": "ubiquitous",

        "wildcard": false

    }

  }'


```

1. For an existing custom hostname, locate the `id` of that hostname via a `GET` call:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

List Custom Hostnames

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames?hostname=%7Bhostname%7D" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

1. Then make an API call such as the example below, specifying `"early_hints": "on"`:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "ssl": {

        "method": "http",

        "type": "dv",

        "settings": {

            "http2": "on",

            "min_tls_version": "1.2",

            "tls_1_3": "on",

            "early_hints": "on"

        }

    }

  }'


```

Currently, all options within `settings` are required in order to prevent those options from being set to default. You can pull the current settings state prior to updating Early Hints by leveraging the output that returns the `id` for the hostname.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/","name":"Performance"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/performance/early-hints-for-saas/","name":"Early Hints for SaaS"}}]}
```

---

---
title: Plans
description: Learn what features and limits are part of various Cloudflare plans.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/plans.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Plans

| Free                                                                                                                                                                            | Pro                              | Business                         | Enterprise                       |                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------- | -------------------------------- | -------------------------------------------------- |
| Availability                                                                                                                                                                    | Yes                              | Yes                              | Yes                              | Contact your account team                          |
| Hostnames included                                                                                                                                                              | 100                              | 100                              | 100                              | Custom                                             |
| Max hostnames                                                                                                                                                                   | 50,000                           | 50,000                           | 50,000                           | Unlimited, but contact sales if using over 50,000. |
| Price per additional hostname                                                                                                                                                   | $0.10                            | $0.10                            | $0.10                            | Custom pricing                                     |
| [Custom analytics](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/hostname-analytics/)                                                          | Yes                              | Yes                              | Yes                              | Yes                                                |
| [Custom origin](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/)                                          | Yes                              | Yes                              | Yes                              | Yes                                                |
| [SNI Rewrite for Custom Origin](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/#sni-rewrites)             | No                               | No                               | No                               | Contact your account team                          |
| [Custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/)                      | No                               | No                               | No                               | Yes                                                |
| [CSR support](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/certificate-signing-requests/) | No                               | No                               | No                               | Yes                                                |
| [Selectable CA](https://developers.cloudflare.com/ssl/reference/certificate-authorities/)                                                                                       | No                               | No                               | No                               | Yes                                                |
| Wildcard custom hostnames                                                                                                                                                       | No                               | No                               | No                               | Yes                                                |
| Non-SNI support for SaaS zone                                                                                                                                                   | No                               | Yes                              | Yes                              | Yes                                                |
| [mTLS support](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/)                                    | No                               | No                               | No                               | Yes                                                |
| [WAF for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/)                                                           | WAF rules with current zone plan | WAF rules with current zone plan | WAF rules with current zone plan | Create and apply custom firewall rulesets.         |
| [Apex proxying/BYOIP](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/)                                    | No                               | No                               | No                               | Paid add-on                                        |
| [Custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/)                                               | No                               | No                               | No                               | Paid add-on                                        |

## Enterprise plan benefits

The Enterprise plan offers features that give SaaS providers flexibility when it comes to meeting their end customer's requirements. In addition to that, Enterprise customers are able to extend all of the benefits of the Enterprise plan to their customer's custom hostnames. This includes advanced Bot Mitigation, WAF rules, analytics, DDoS mitigation, and more.

In addition, large SaaS providers rely on Enterprise level support, multi-user accounts, SSO, and other benefits that are not provided in non-Enterprise plans.

Note

Enterprise customers can preview this product as a [non-contract service](https://developers.cloudflare.com/billing/preview-services/), which provides full access, free of metered usage fees, limits, and certain other restrictions.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/plans/","name":"Plans"}}]}
```

---

---
title: Certificate authorities
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/certificate-authorities.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate authorities

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/certificate-authorities/","name":"Certificate authorities"}}]}
```

---

---
title: Certificate statuses
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/certificate-statuses.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate statuses

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/certificate-statuses/","name":"Certificate statuses"}}]}
```

---

---
title: Connection request details
description: When forwarding connections to your origin server, Cloudflare will set request parameters according to the following:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/connection-details.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Connection request details

When forwarding connections to your origin server, Cloudflare will set request parameters according to the following:

## Host header

Cloudflare will not alter the Host header by default, and will forward exactly as sent by the client. If you wish to change the value of the Host header you can utilise [Page-Rules](https://developers.cloudflare.com/workers/configuration/workers-with-page-rules/) or [Workers](https://developers.cloudflare.com/workers/) using the steps outlined in [certificate management](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/).

## SNI

When establishing a TLS connection to your origin server, if the request is being sent to your configured Fallback Host then the value of the SNI sent by Cloudflare will match the value of the Host header sent by the client (i.e. the custom hostname).

If however the request is being forwarded to a Custom Origin, then the value of the SNI will be that of the Custom Origin.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/connection-details/","name":"Connection request details"}}]}
```

---

---
title: Domain control validation backoff schedule
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/dcv-validation-backoff.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Domain control validation backoff schedule

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/dcv-validation-backoff/","name":"Domain control validation backoff schedule"}}]}
```

---

---
title: Certificate and hostname priority
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/hostname-priority.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate and hostname priority

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/hostname-priority/","name":"Certificate and hostname priority"}}]}
```

---

---
title: Custom CSRs
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/custom-csrs.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom CSRs

## Success codes

| Endpoint                                              | Method | HTTP Status Code |
| ----------------------------------------------------- | ------ | ---------------- |
| /api/v4/zones/:zone\_id/custom\_csrs                  | POST   | 201 Created      |
| /api/v4/zones/:zone\_id/custom\_csrs                  | GET    | 200 OK           |
| /api/v4/zones/:zone\_id/custom\_csrs/:custom\_csr\_id | GET    | 200 OK           |
| /api/v4/zones/:zone\_id/custom\_csrs/:custom\_csr\_id | DELETE | 200 OK           |

## Error codes

| HTTP Status Code | API Error Code | Error Message                                                                                                                                                                                                                                                                                                                                   |
| ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400              | 1400           | Unable to decode the JSON request body. Check your input and try again.                                                                                                                                                                                                                                                                         |
| 400              | 1401           | Zone ID is required. Check your input and try again.                                                                                                                                                                                                                                                                                            |
| 400              | 1402           | The request has no Authorization header. Check your input and try again.                                                                                                                                                                                                                                                                        |
| 400              | 1405           | Country field is required. Check your input and try again.                                                                                                                                                                                                                                                                                      |
| 400              | 1406           | State field is required. Check your input and try again.                                                                                                                                                                                                                                                                                        |
| 400              | 1407           | Locality field is required. Check your input and try again.                                                                                                                                                                                                                                                                                     |
| 400              | 1408           | Organization field is required. Check your input and try again.                                                                                                                                                                                                                                                                                 |
| 400              | 1409           | Common Name field is required. Check your input and try again.                                                                                                                                                                                                                                                                                  |
| 400              | 1410           | The specified Common Name is too long. Maximum allowed length is %d characters. Check your input and try again.                                                                                                                                                                                                                                 |
| 400              | 1411           | At least one subject alternative name (SAN) is required. Check your input and try again.                                                                                                                                                                                                                                                        |
| 400              | 1412           | Invalid subject alternative name(s) (SAN). SANs have to be smaller than 256 characters in length, cannot be IP addresses, cannot contain any special characters such as \~\`!@#$%^&\*()=+\[\]                                                                                                                                                   |
| 400              | 1413           | Subject Alternative Names (SANs) with non-ASCII characters are not supported. Check your input and try again.                                                                                                                                                                                                                                   |
| 400              | 1414           | Reserved top domain subject alternative names (SAN), such as 'test', 'example', 'invalid' or 'localhost', is not supported. Check your input and try again.                                                                                                                                                                                     |
| 400              | 1415           | Unable to parse subject alternative name(s) (SAN) - :reason. Check your input and try again. Reasons: publicsuffix: cannot derive eTLD+1 for domain %q; publicsuffix: invalid public suffix %q for domain %q;                                                                                                                                   |
| 400              | 1416           | Subject Alternative Names (SANs) ending in example.com, example.net, or example.org are prohibited. Check your input and try again.                                                                                                                                                                                                             |
| 400              | 1417           | Invalid key type. Only 'rsa2048' or 'p256v1' is accepted. Check your input and try again.                                                                                                                                                                                                                                                       |
| 400              | 1418           | The custom CSR ID is invalid. Check your input and try again.                                                                                                                                                                                                                                                                                   |
| 401              | 1000           | Unable to extract bearer token                                                                                                                                                                                                                                                                                                                  |
| 401              | 1001           | Unable to parse JWT token                                                                                                                                                                                                                                                                                                                       |
| 401              | 1002           | Bad JWT header                                                                                                                                                                                                                                                                                                                                  |
| 401              | 1003           | Failed to verify JWT token                                                                                                                                                                                                                                                                                                                      |
| 401              | 1004           | Failed to get claims from JWT token                                                                                                                                                                                                                                                                                                             |
| 401              | 1005           | JWT token does not have required claims                                                                                                                                                                                                                                                                                                         |
| 403              | 1403           | No quota has been allocated for this zone. If you are already a paid Cloudflare for SaaS customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will contact you.                    |
| 403              | 1404           | Access to generating CSRs has not been granted for this zone. If you are already a paid Cloudflare for SaaS customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will contact you. |
| 404              | 1419           | The custom CSR was not found.                                                                                                                                                                                                                                                                                                                   |
| 409              | 1420           | The custom CSR is associated with an active certificate pack. You will need to delete all associated active certificate packs before you can delete the custom CSR.                                                                                                                                                                             |
| 500              | 1500           | Internal Server Error                                                                                                                                                                                                                                                                                                                           |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/","name":"Status codes"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/custom-csrs/","name":"Custom CSRs"}}]}
```

---

---
title: Custom hostnames
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/custom-hostnames.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom hostnames

---

## Success codes

| Endpoint                                                    | Method | Code         |
| ----------------------------------------------------------- | ------ | ------------ |
| /v4/zones/:zone\_id/custom\_hostnames                       | POST   | 201 Created  |
| /v4/zones/:zone\_id/custom\_hostnames/:custom\_hostname\_id | GET    | 200 OK       |
| /v4/zones/:zone\_id/custom\_hostnames                       | GET    | 200 OK       |
| /v4/zones/:zone\_id/custom\_hostnames/:custom\_hostname\_id | DELETE | 200 OK       |
| /v4/zones/:zone\_id/custom\_hostnames/:custom\_hostname\_id | PATCH  | 202 Accepted |

---

## Error codes

| HTTP Status Code | API Error Code | Error Message                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ---------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 400              | 1400           | Unable to decode the JSON request body. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                          |
| 400              | 1401           | Unable to encode the Custom Metadata as JSON. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                    |
| 400              | 1402           | Zone ID is required. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                                             |
| 400              | 1403           | The request has no Authorization header. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                         |
| 400              | 1407           | Invalid custom hostname. Custom hostnames have to be smaller than 256 characters in length, cannot be IP addresses, cannot contain any special characters such as \`\`\~\`!@#$%^&\*()=+\[\]\\                                                                                                                                                                                                                                                    |
| 400              | 1408           | Custom hostnames with non-ASCII characters are not supported. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                    |
| 400              | 1409           | Reserved top domain custom hostnames, such as 'test', 'example', 'invalid' or 'localhost', is not supported. Check your input and try again.                                                                                                                                                                                                                                                                                                     |
| 400              | 1410           | Unable to parse custom hostname - :reason. Check your input and try again. **Reasons:**  publicsuffix: cannot derive eTLD+1 for domain :domain  publicsuffix: invalid public suffix :suffix for domain :domain                                                                                                                                                                                                                                   |
| 400              | 1411           | Custom hostnames ending in example.com, example.net, or example.org are prohibited. Check your input and try again.                                                                                                                                                                                                                                                                                                                              |
| 400              | 1412           | Custom metadata for wildcard custom hostnames is not supported. Check your input and try again. **Note:**  This message is only presented to customers who have opted out of wildcard support for custom metadata.                                                                                                                                                                                                                               |
| 400              | 1415           | Invalid custom origin hostname. Custom origin hostnames have to be smaller than 256 characters in length, cannot be IP addresses, cannot contain any special characters such as ~~\`\`~~\`!@#$%^&\*()=+\[\]\\                                                                                                                                                                                                                                    |
| 400              | 1416           | Custom origin hostnames with non-ASCII characters are not supported. Check your input and try again.                                                                                                                                                                                                                                                                                                                                             |
| 400              | 1417           | Reserved top domain custom origin hostnames, such as 'test', 'example', 'invalid' or 'localhost', is not supported. Check your input and try again.                                                                                                                                                                                                                                                                                              |
| 400              | 1418           | Unable to parse custom origin hostname - :reason. Check your input and try again. **Reasons:**  publicsuffix: cannot derive eTLD+1 for domain :domain publicsuffix: invalid public suffix:suffixfor domain:domain                                                                                                                                                                                                                                |
| 400              | 1419           | Custom origin hostnames ending in example.com, example.net, or example.org are prohibited. Check your input and try again.                                                                                                                                                                                                                                                                                                                       |
| 400              | 1420           | Wildcard custom origin hostnames are not supported. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                              |
| 400              | 1421           | The custom origin hostname you specified does not exist on Cloudflare as a DNS record (A, AAAA or CNAME) in your zone::zone\\\_tag. Check your input and try again.                                                                                                                                                                                                                                                                              |
| 400              | 1422           | Invalid http2setting. Only 'on' or 'off' is accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                            |
| 400              | 1423           | Invalidtls\\\_1\\\_2\\\_onlysetting. Only 'on' or 'off' is accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                             |
| 400              | 1424           | Invalidtls\\\_1\\\_3setting. Only 'on' or 'off' is accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                     |
| 400              | 1425           | Invalidmin\\\_tls\\\_versionsetting. Only '1.0','1.1','1.2' or '1.3' is accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                |
| 400              | 1426           | The certificate that you uploaded cannot be parsed. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                              |
| 400              | 1427           | The certificate that you uploaded is empty. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                      |
| 400              | 1428           | The private key you uploaded cannot be parsed. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                   |
| 400              | 1429           | The private key you uploaded does not match the certificate. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                     |
| 400              | 1430           | The custom CSR ID is invalid. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                                    |
| 404              | 1431           | The custom CSR was not found.                                                                                                                                                                                                                                                                                                                                                                                                                    |
| 400              | 1432           | The validation method is not supported. Onlyhttp, email, or txt are accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                    |
| 400              | 1433           | The validation type is not supported. Only 'dv' is accepted. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                     |
| 400              | 1434           | The SSL attribute is invalid. Refer to the API documentation, check your input and try again.                                                                                                                                                                                                                                                                                                                                                    |
| 400              | 1435           | The custom hostname ID is invalid. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                               |
| 404              | 1436           | The custom hostname was not found.                                                                                                                                                                                                                                                                                                                                                                                                               |
| 400              | 1437           | Invalid hostname.contain query parameter. The hostname.contain query parameter has to be smaller than 256 characters in length, cannot be IP addresses, cannot contain any special characters such as \`\`\~\`!@#$%^&\*()=+\[\]\\                                                                                                                                                                                                                |
| 400              | 1438           | Cannot specify other filter parameters in addition to id. Only one must be specified. Check your input and try again.                                                                                                                                                                                                                                                                                                                            |
| 409              | 1439           | Modifying the custom hostname is not supported. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                                  |
| 400              | 1440           | Both validation type and validation method are required. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                         |
| 400              | 1441           | The certificate that you uploaded is having trouble bundling against the public trust store. Check your input and try again.                                                                                                                                                                                                                                                                                                                     |
| 400              | 1442           | Invalid ciphers setting. Refer to the documentation for the list of accepted cipher suites. Check your input and try again.                                                                                                                                                                                                                                                                                                                      |
| 400              | 1443           | Cipher suite selection is not supported for a minimum TLS version of 1.3\. Check your input and try again.                                                                                                                                                                                                                                                                                                                                       |
| 400              | 1444           | The certificate chain that you uploaded has multiple leaf certificates. Check your input and try again.                                                                                                                                                                                                                                                                                                                                          |
| 400              | 1445           | The certificate chain that you uploaded has no leaf certificates. Check your input and try again.                                                                                                                                                                                                                                                                                                                                                |
| 400              | 1446           | The certificate that you uploaded does not include the custom hostname - :custom\_hostname. Review your input and try again.                                                                                                                                                                                                                                                                                                                     |
| 400              | 1447           | The certificate that you uploaded does not use a supported signature algorithm. Only SHA-256/ECDSA, SHA-256/RSA, and SHA-1/RSA signature algorithms are supported. Review your input and try again.                                                                                                                                                                                                                                              |
| 400              | 1448           | Custom hostnames with wildcards are not supported for certificates managed by Cloudflare. Review your input and try again.                                                                                                                                                                                                                                                                                                                       |
| 400              | 1449           | The request input bundle\_method must be one of: ubiquitous, optimal, force.                                                                                                                                                                                                                                                                                                                                                                     |
| 401              | 1000           | Unable to extract bearer token                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 401              | 1001           | Unable to parse JWT token                                                                                                                                                                                                                                                                                                                                                                                                                        |
| 401              | 1002           | Bad JWT header                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 401              | 1003           | Failed to verify JWT token                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 401              | 1004           | Failed to get claims from JWT token                                                                                                                                                                                                                                                                                                                                                                                                              |
| 401              | 1005           | JWT token does not have required claims                                                                                                                                                                                                                                                                                                                                                                                                          |
| 403              | 1404           | No quota has been allocated for this zone. If you are already a paid Cloudflare for SaaS customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will reach out to you.                                                                                                                |
| 403              | 1405           | Quota exceeded. If you are already a paid Cloudflare for SaaS customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will reach out to you.                                                                                                                                           |
| 403              | 1413           | No [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) access has been allocated for this zone. If you are already a paid customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will reach out to you. |
| 403              | 1414           | Access to setting a custom origin server has not been granted for this zone. If you are already a paid Cloudflare for SaaS customer, contact your Customer Success Manager for additional provisioning. If you are not yet enrolled, [fill out this contact form ↗](https://www.cloudflare.com/plans/enterprise/contact/) and our sales team will reach out to you.                                                                              |
| 409              | 1406           | Duplicate custom hostname found.                                                                                                                                                                                                                                                                                                                                                                                                                 |
| 500              | 1500           | Internal Server Error                                                                                                                                                                                                                                                                                                                                                                                                                            |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/","name":"Status codes"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/status-codes/custom-hostnames/","name":"Custom hostnames"}}]}
```

---

---
title: Token validity periods
description: When you perform TXT domain control validation, you will need to share these tokens with your customers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/token-validity-periods.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Token validity periods

When you perform [TXT](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/) domain control validation, you will need to share these tokens with your customers.

However, these tokens expire after a certain amount of time, depending on your chosen certificate authority.

| Certificate authority | Token validity |
| --------------------- | -------------- |
| Let's Encrypt         | 7 days         |
| Google Trust Services | 14 days        |
| SSL.com               | 14 days        |

Warning

Tokens may also become invalid upon validation failure. For more details, refer to [Domain control validation flow](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/dcv-flow/#dcv-tokens).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/token-validity-periods/","name":"Token validity periods"}}]}
```

---

---
title: Troubleshooting
description: By default, you may issue up to 15 certificates per minute. Only successful submissions (POSTs that return 200) are counted towards your limit. If you exceed your limit, you will be prevented from issuing new certificates for 30 seconds.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/troubleshooting.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Troubleshooting

## Rate limits

By default, you may issue up to 15 certificates per minute. Only successful submissions (POSTs that return 200) are counted towards your limit. If you exceed your limit, you will be prevented from issuing new certificates for 30 seconds.

If you require a higher rate limit, contact your Customer Success Manager.

---

## Purge cache

To remove specific files from Cloudflare’s cache, [purge the cache](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-hostname/) while specifying one or more hostnames.

---

## Resolution error 1016 (Origin DNS error) when accessing the custom hostname

Cloudflare returns a 1016 error when the custom hostname cannot be routed or proxied.

There are three main causes of error 1016:

1. Custom Hostname ownership validation is not complete. To check validation status, run an API call to [search for a certificate by hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/common-api-calls/) and check the verification error field: `"verification_errors": ["custom hostname does not CNAME to this zone."]`.
2. Fallback Origin is not [correctly set](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#1-create-fallback-origin). Confirm that you have created a DNS record for the fallback origin and also set the fallback origin.
3. A Wildcard Custom Hostname has been created, but the requested hostname is associated with a domain that exists in Cloudflare as a standalone zone. In this case, the [hostname priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority) for the standalone zone will take precedence over the wildcard custom hostname. This behavior applies even if there is no DNS record for this standalone zone hostname.

In this scenario each hostname that needs to be served by the [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/) parent zone needs to be added as an individual Custom Hostname.

Note

If you encounter other 1XXX errors, refer to [Troubleshooting Cloudflare 1XXX Errors](https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-1xxx-errors/).

---

## Old SaaS provider content after updating a CNAME

When switching SaaS providers, an older configuration can take precedence if the old provider provisioned a specific custom hostname and the new provider provisioned a wildcard custom hostname. This is expected as per the [certificate and hostname priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority).

In this case there are two ways forward:

* (Recommended) Ask the new SaaS provider to provision a specific custom hostname for you instead of the wildcard - `mystore.example.com` instead of `*.example.com`.
* Ask the Super Administrator of your account to contact [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) to request an update of the SaaS configuration.

---

## Custom hostname in Moved status

To move a custom hostname back to an Active status, send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) to restart the hostname validation. A Custom Hostname in a Moved status is deleted after 7 days.

In some circumstances, custom hostnames can also enter a **Moved** state if your customer changes their DNS records pointing to your SaaS service. For more details, refer to [Remove custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames/).

---

## CAA Errors

The `caa_error` in the status of a custom hostname means that the CAA records configured on the domain prevented the Certificate Authority to issue the certificate.

You can check which CAA records are configured on a domain using the `dig` command:`dig CAA example.com`

You will need to ensure that the required CAA records for the selected Certificate Authority are configured. For example, here are the records required to issue [Let's Encrypt ↗](https://letsencrypt.org/docs/caa/) and [Google Trust Services ↗](https://pki.goog/faq/#caa) certificates:

```

example.com CAA 0 issue "pki.goog; cansignhttpexchanges=yes"

example.com CAA 0 issuewild "pki.goog; cansignhttpexchanges=yes"


example.com CAA 0 issue "letsencrypt.org"

example.com CAA 0 issuewild "letsencrypt.org"


example.com CAA 0 issue "ssl.com"

example.com CAA 0 issuewild "ssl.com"


```

For more details, refer to [CAA records FAQ](https://developers.cloudflare.com/ssl/faq/#caa-records).

---

## Custom hostname matches zone name (403 Forbidden)

Do not configure a custom hostname which matches the zone name. For example, if your SaaS zone is `example.com`, do not create a custom hostname named `example.com`.

This configuration will cause a 403 Forbidden error due to DNS override restrictions applied for security reasons. This limitation also affects Worker Routes making subrequests.

---

## Older devices have issues connecting

As Let's Encrypt - one of the [certificate authorities (CAs)](https://developers.cloudflare.com/ssl/reference/certificate-authorities/) used by Cloudflare - has announced changes in its [chain of trust](https://developers.cloudflare.com/ssl/concepts/#chain-of-trust), starting September 9, 2024, there may be issues with older devices trying to connect to your custom hostname certificate.

Consider the following solutions:

* Use the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint to set the `certificate_authority` parameter to an empty string (`""`): this sets the custom hostname certificate to "default CA", leaving the choice up to Cloudflare. Cloudflare will always attempt to issue the certificate from a more compatible CA, such as [Google Trust Services](https://developers.cloudflare.com/ssl/reference/certificate-authorities/#google-trust-services), and will only fall back to using Let’s Encrypt if there is a [CAA record](https://developers.cloudflare.com/ssl/edge-certificates/caa-records/) in place that blocks Google from issuing a certificate.  
Example API call  
Terminal window  
```  
curl --request PATCH \  
"https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_hostnames/{custom_hostname_id}" \  
--header "X-Auth-Email: <EMAIL>" \  
--header "X-Auth-Key: <API_KEY>" \  
--header "Content-Type: application/json" \  
--data '{  
  "ssl": {  
      "method": "txt",  
      "type": "dv",  
      "certificate_authority": ""  
  }  
}'  
```
* Use the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint to set the `certificate_authority` parameter to `google`: this sets Google Trust Services as the CA for your custom hostnames. In your API call, make sure to also include `method` and `type` in the `ssl` object.
* If you are using a custom certificate for your custom hostname, refer to the [custom certificates troubleshooting](https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/troubleshooting/#lets-encrypt-chain-update).

## Custom hostname fails to verify because the zone is held

The [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/) is a toggle that will prevent their zone from being activated on other Cloudflare account. When enabled, Cloudflare is not able to issue an SSL/TLS certificate on behalf of that domain name for either a zone or custom hostname. When the option `Also prevent subdomains` is enabled, this prevents the verification of custom hostnames for this domain. The custom hostname will remain in the `Blocked` status, with the following error message: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.` In this case, the owner of the zone needs to [release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds) before the custom hostname can become activated. After the hostname has been validated, the zone hold can be enabled again.

## Hostnames over 64 characters

The Common Name (CN) restriction establishes a limit of 64 characters ([RFC 5280 ↗](https://www.rfc-editor.org/rfc/rfc5280.html)). If you have a hostname that exceeds this length, you may find the following error:

```

Since no host is 64 characters or fewer, Cloudflare Branding is required. Please check your input and try again. (1469)


```

To solve this, you can set `cloudflare_branding` to `true` when [creating your custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/#hostnames-over-64-characters) via API.

Cloudflare branding means that `sni.cloudflaressl.com` will be added as the certificate Common Name (CN) and the long hostname will be included as a part of the Subject Alternative Name (SAN).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/troubleshooting/","name":"Troubleshooting"}}]}
```

---

---
title: Deprecation - Version 1
description: The first version of SSL for SaaS will be deprecated on September 1, 2021.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/reference/versioning.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Deprecation - Version 1

The first version of SSL for SaaS will be deprecated on September 1, 2021.

## Why is SSL for SaaS changing?

In SSL for SaaS v1, traffic for Custom Hostnames is proxied to the origin based on the IP addresses assigned to the zone with SSL for SaaS enabled. This IP-based routing introduces complexities that prevented customers from making changes with zero downtime.

SSL for SaaS v2 removes IP-based routing and its associated problems. Instead, traffic is proxied to the origin based on the custom hostname of the SaaS zone. This means that Custom Hostnames will now need to pass a **hostname verification** step after Custom Hostname creation and in addition to SSL certificate validation. This adds a layer of security from SSL for SaaS v1 by ensuring that only verified hostnames are proxied to your origin.

## What action is needed?

To ensure that your service is not disrupted, you need to perform an additional ownership check on every new Custom Hostname. There are three methods to verify ownership: TXT, HTTP, and CNAME. Use TXT and HTTP for pre-validation to validate the Custom Hostname before traffic is proxied by Cloudflare’s edge.

### Recommended validation methods

Using a [TXT](#dns-txt-record) or [HTTP](#http-token) validation method helps you avoid downtime during your migration. If you choose to use [CNAME validation](#cname-validation), your domain might fall behind on its [backoff schedule](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/).

#### DNS TXT Record

When creating a Custom Hostname with the TXT method through the [API](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/), a TXT ownership\_verification record is provided for your customer to add to their DNS for the ownership validation check. When the TXT record is added, the Custom Hostname will be marked as **Active** in the Cloudflare SSL/TLS app under the Custom Hostnames tab.

#### HTTP Token

When creating a Custom Hostname with the HTTP through the [API](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/), an HTTP ownership\_verification token is provided. HTTP verification is used mainly by organizations with a large deployed base of custom domains with HTTPS support. Serving the HTTP token from your origin web server allows hostname verification before proxying domain traffic through Cloudflare.

Cloudflare sends GET requests to the http\_url using `User-Agent: Cloudflare Custom Hostname Verification`.

If you validated a hostname that is not proxying traffic through Cloudflare, the Custom Hostname will be marked as **Active** in the Cloudflare SSL/TLS app when the HTTP token is verified (under the **Custom Hostnames** tab).

If your hostname is already proxying traffic through Cloudflare, then HTTP validation is not enough by itself and the hostname will only go active when DNS-based validation is complete.

### Other validation methods

Though you can use [CNAME validation](#cname-validation), we recommend you either use a [TXT](#dns-txt-record) or [HTTP](#http-token) validation method.

#### CNAME Validation

Custom Hostnames can also be validated once Cloudflare detects that the Custom Hostname is a CNAME record pointing to the fallback record configured for the SSL for SaaS domain. Though this is the simplest validation method, it increases the risk of errors. Since a CNAME record would also route traffic to Cloudflare’s edge, traffic may reach our edge before the Custom Hostname has completed validation or the SSL certificate has issued.

Once you have tested and added the hostname validation step to your Custom Hostname creation process, please contact your account team to schedule a date to migrate your SSL for SaaS v1 zones. Your account team will work with you to validate your existing Custom Hostnames without downtime.

## If you are using BYOIP or Apex Proxying:

Both BYOIP addresses and IP addresses configured for Apex Proxying allow for hostname validation to complete successfully by having either a BYOIP address or an Apex Proxy IP address as the target of a DNS A record for a custom hostname.

## What is available in the new version of SSL for SaaS?

SSL for SaaS v2 is functionally equivalent to SSL for SaaS v1, but removes the requirements to use specific anycast IP addresses at Cloudflare’s edge and Cloudflare’s Universal SSL product with the SSL for SaaS zone.

Note

SSL for SaaS v2 is now called Cloudflare for SaaS.

## What happens during the migration?

Once the migration has been started for your zone(s), Cloudflare will require every Custom Hostname to pass a hostname verification check. Existing Custom Hostnames that are proxying to Cloudflare with a DNS CNAME record will automatically re-validate and migrate to the new version with no downtime. Any Custom Hostnames created after the start of the migration will need to pass the hostname validation check using one of the validation methods mentioned above.

Note

You can revert the migration at any time.

### Before the migration

Before your migration, you should:

1. To test validation methods, set up a test zone and ask your account team to enable SSL for SaaS v2.
2. Wait for your account team to run our pre-migration tool. This tool groups your hostnames into one of the following statuses:  
   * `test_pending`: In the process of being verified or was unable to be verified and re-queued for verification. A custom hostname will be re-queued 25 times before moving to the `test_failed` status.  
   * `test_active`: Passed CNAME verification  
   * `test_active_apex`: Passed Apex Proxy verification  
   * `test_blocked`: Hostname will be blocked during the migration because hostname belongs to a banned zone. Contact your account team to verify banned custom hostnames and proceed with the migration.  
   * `test_failed`: Failed hostname verification 25 times
3. Review the results of our pre-migration tool (run by your account team) using one of the following methods:  
   * Via the API: `https://api.cloudflare.com/client/v4/zones/{zone_tag}/custom_hostnames?hostname_status={status}`  
   * Via a CSV file (provided by your account team)  
   * Via the Cloudflare dashboard:![Review SSL migration status in the dashboard](https://developers.cloudflare.com/_astro/ssl-migration-status.CLPmua84_25MgVb.webp)
4. Approve the migration. Your account team will work with you to schedule a migration window for each of your SSL for SaaS zones.

## During the migration

After the migration has started and has had some time to progress, Cloudflare will generate a list of Custom Hostnames that failed to migrate and ask for your approval to complete the migration. When you give your approval, the migration will be complete, SSL for SaaS v1 will be disabled for the zone, and any Custom Hostname that has not completed hostname validation will no longer function.

The migration timeline depends on the number of Custom Hostnames. For example, if a zone has fewer than 10,000 Custom Hostnames, the list can be generated around an hour after beginning the migration. If a zone has millions of Custom Hostnames, it may take up to 24 hours to identify instances that failed to successfully migrate.

When your account team asks for approval to complete the migration, please respond in a timely manner. You will have **two weeks** to validate any remaining Custom Hostnames before they are systematically deleted.

## When is the migration?

The migration process starts on March 31, 2021 and will continue until final deprecation on September 1, 2021.

If you would like to begin the migration process before March 31, 2021, please contact your account team and they will work with you to expedite the process. Otherwise, your account team will reach out to you with a time for a migration window so that your zones are migrated before **September 1, 2021** end-of-life date.

## What if I have additional questions?

If you have any questions, please contact your account team or [SaaSv2@cloudflare.com](mailto:saasv2@cloudflare.com).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/","name":"Reference"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/reference/versioning/","name":"Deprecation - Version 1"}}]}
```

---

---
title: SaaS customers
description: Cloudflare partners with many SaaS providers to extend our performance and security benefits to your website.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# SaaS customers

Cloudflare partners with many [SaaS providers](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/) to extend our performance and security benefits to your website.

If you are a SaaS customer, you can take this process a step further by managing your own zone on Cloudflare. This setup - known as **O2O** \- allows you to benefit from your provider's setup but still customize how Cloudflare treats incoming traffic to your zone.

## Related resources

* [ How it works ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/)
* [ Provider guides ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/)
* [ Product compatibility ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/)
* [ Remove domain ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/remove-domain/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}}]}
```

---

---
title: How it works
description: O2O is a specific traffic routing configuration where traffic routes through two Cloudflare zones: the first Cloudflare zone is owned by customer 1 and the second Cloudflare zone is owned by customer 2, who is considered a SaaS provider.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# How it works

O2O is a specific traffic routing configuration where traffic routes through two Cloudflare zones: the first Cloudflare zone is owned by customer 1 and the second Cloudflare zone is owned by customer 2, who is considered a SaaS provider.

If one or more hostnames are onboarded to a SaaS Provider that uses Cloudflare products as part of their platform - specifically the [Cloudflare for SaaS product](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/) \- those hostnames will be created as [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) in the SaaS Provider's zone.

To give the SaaS provider permission to route traffic through their zone, any custom hostname must be activated by you (the SaaS customer) by placing a [CNAME record](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record) on your authoritative DNS. If your authoritative DNS is Cloudflare, you have the option to [proxy](https://developers.cloudflare.com/fundamentals/concepts/how-cloudflare-works/#application-services) your CNAME record, achieving an O2O setup.

## Prerequisites

* O2O only applies when the two zones are part of different Cloudflare accounts.
* Since O2O is based on CNAME, it does not apply when an A record is used to point to the SaaS provider's ([apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/)).

## With O2O

If you have your own Cloudflare zone (`example.com`) and your zone contains a [proxied DNS record](https://developers.cloudflare.com/dns/proxy-status/) matching the custom hostname (`mystore.example.com`) with a **CNAME** target defined by the SaaS Provider, then O2O will be enabled.

DNS management for **example.com**

| **Type** | **Name** | **Target**                 | **Proxy status** |
| -------- | -------- | -------------------------- | ---------------- |
| CNAME    | mystore  | customers.saasprovider.com | Proxied          |

With O2O enabled, the settings configured in your Cloudflare zone will be applied to the traffic first, and then the settings configured in the SaaS provider's zone will be applied to the traffic second. In the SaaS provider-owned zone, a HTTP header will be set to `cf-connecting-o2o: 1`.

flowchart TD
accTitle: O2O-enabled traffic flow diagram

A[Website visitor]

subgraph Cloudflare
  B[Customer-owned zone]
  C[SaaS Provider-owned zone]
end

D[SaaS Provider Origin]

A --> B
B --> C
C --> D

## Without O2O

If you do not have your own Cloudflare zone and have only onboarded one or more of your hostnames to a SaaS Provider, then O2O will not be enabled.

Without O2O enabled, the settings configured in the SaaS Provider's zone will be applied to the traffic.

flowchart TD
accTitle: Your zone using a SaaS provider, but without O2O

A[Website visitor]

subgraph Cloudflare
    B[SaaS Provider-owned zone]
end

C[SaaS Provider Origin]

A --> B
B --> C

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/","name":"How it works"}}]}
```

---

---
title: Product compatibility
description: As a general rule, settings on the customer zone will override settings on the SaaS zone. In addition, O2O does not permit traffic directed to a custom hostname zone into another custom hostname zone.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Product compatibility

As a general rule, settings on the customer zone will override settings on the SaaS zone. In addition, [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/) does not permit traffic directed to a custom hostname zone into another custom hostname zone.

The following table provides a list of compatibility guidelines for various Cloudflare products and features.

Note

This is not an exhaustive list of Cloudflare products and features.

| Product                                                                                                               | Customer zone | SaaS provider zone | Notes                                                                                                                                                                                                                                                                                                                                         |
| --------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Access](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/secure-with-access/) | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [API Shield](https://developers.cloudflare.com/api-shield/)                                                           | Yes           | No                 |                                                                                                                                                                                                                                                                                                                                               |
| [Argo Smart Routing](https://developers.cloudflare.com/argo-smart-routing/)                                           | No            | Yes                | Customer zones can still use Smart Routing for non-O2O traffic.                                                                                                                                                                                                                                                                               |
| [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/)                                       | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [Browser Integrity Check](https://developers.cloudflare.com/waf/tools/browser-integrity-check/)                       | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [Cache](https://developers.cloudflare.com/cache/)                                                                     | Yes\*         | Yes                | Though caching is possible on a customer zone, it is generally discouraged (especially for HTML).Your SaaS provider likely performs its own caching outside of Cloudflare and caching on your zone might lead to out-of-sync or stale cache states.Customer zones can still cache content that are not routed through a SaaS provider's zone. |
| [China Network](https://developers.cloudflare.com/china-network/)                                                     | No            | No                 |                                                                                                                                                                                                                                                                                                                                               |
| [DNS](https://developers.cloudflare.com/dns/)                                                                         | Yes\*         | Yes                | As a SaaS customer, do not remove the records related to your Cloudflare for SaaS setup.Otherwise, your traffic will begin routing away from your SaaS provider.                                                                                                                                                                              |
| [HTTP/2 prioritization ↗](https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/)                 | Yes           | Yes\*              | This feature must be enabled on the customer zone to function.                                                                                                                                                                                                                                                                                |
| [Image resizing](https://developers.cloudflare.com/images/transform-images/)                                          | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| IPv6                                                                                                                  | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [IPv6 Compatibility](https://developers.cloudflare.com/network/ipv6-compatibility/)                                   | Yes           | Yes\*              | If the customer zone has **IPv6 Compatibility** enabled, generally the SaaS zone should as well.If not, make sure the SaaS zone enables [Pseudo IPv4](https://developers.cloudflare.com/network/pseudo-ipv4/).                                                                                                                                |
| [Load Balancing](https://developers.cloudflare.com/load-balancing/)                                                   | No            | Yes                | Customer zones can still use Load Balancing for non-O2O traffic.                                                                                                                                                                                                                                                                              |
| [Page Rules](https://developers.cloudflare.com/rules/page-rules/)                                                     | Yes\*         | Yes                | Page Rules that match the subdomain used for O2O may block or interfere with the flow of visitors to your website.                                                                                                                                                                                                                            |
| [Origin Rules](https://developers.cloudflare.com/rules/origin-rules/)                                                 | Yes           | Yes                | Enterprise zones can configure Origin Rules, by setting the Host Header and DNS Overrides to direct traffic to a SaaS zone.                                                                                                                                                                                                                   |
| [Client-side security](https://developers.cloudflare.com/client-side-security/) (formerly Page Shield)                | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [Polish](https://developers.cloudflare.com/images/polish/)                                                            | Yes\*         | Yes                | Polish only runs on cached assets. If the customer zone is bypassing cache for SaaS zone destined traffic, then images optimized by Polish will not be loaded from origin.                                                                                                                                                                    |
| [Rate Limiting](https://developers.cloudflare.com/waf/rate-limiting-rules/)                                           | Yes\*         | Yes                | Rate Limiting rules that match the subdomain used for O2O may block or interfere with the flow of visitors to your website.                                                                                                                                                                                                                   |
| [Rocket Loader](https://developers.cloudflare.com/speed/optimization/content/rocket-loader/)                          | No            | No                 |                                                                                                                                                                                                                                                                                                                                               |
| [Security Level](https://developers.cloudflare.com/waf/tools/security-level/)                                         | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [Spectrum](https://developers.cloudflare.com/spectrum/)                                                               | No            | No                 |                                                                                                                                                                                                                                                                                                                                               |
| [Transform Rules](https://developers.cloudflare.com/rules/transform/)                                                 | Yes\*         | Yes                | Transform Rules that match the subdomain used for O2O may block or interfere with the flow of visitors to your website.                                                                                                                                                                                                                       |
| [WAF custom rules](https://developers.cloudflare.com/waf/custom-rules/)                                               | Yes           | Yes                | WAF custom rules that match the subdomain used for O2O may block or interfere with the flow of visitors to your website.                                                                                                                                                                                                                      |
| [WAF managed rules](https://developers.cloudflare.com/waf/managed-rules/)                                             | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [Waiting Room](https://developers.cloudflare.com/waiting-room/)                                                       | Yes           | Yes                |                                                                                                                                                                                                                                                                                                                                               |
| [WebSockets](https://developers.cloudflare.com/network/websockets/)                                                   | No            | No                 |                                                                                                                                                                                                                                                                                                                                               |
| [Workers](https://developers.cloudflare.com/workers/)                                                                 | Yes\*         | Yes                | Similar to Page Rules, Workers that match the subdomain used for O2O may block or interfere with the flow of visitors to your website.                                                                                                                                                                                                        |
| [Zaraz](https://developers.cloudflare.com/zaraz/)                                                                     | Yes           | No                 |                                                                                                                                                                                                                                                                                                                                               |

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/","name":"Product compatibility"}}]}
```

---

---
title: BigCommerce
description: Learn how to configure your Enterprise zone with BigCommerce.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/bigcommerce.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# BigCommerce

Cloudflare partners with BigCommerce to provide BigCommerce customers’ websites with Cloudflare’s performance and security benefits.

If you use BigCommerce and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then BigCommerce's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your BigCommerce environment.

## How it works

For more details about how O2O is different than other Cloudflare setups, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

BigCommerce customers can enable O2O on any Cloudflare zone plan.

To enable O2O on your account, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a `CNAME` DNS record.

| Type  | Name             | Target                  | Proxy status |
| ----- | ---------------- | ----------------------- | ------------ |
| CNAME | <YOUR\_HOSTNAME> | shops.mybigcommerce.com | Proxied      |

Note

For more details about a BigCommerce setup, refer to their [support guide ↗](https://support.bigcommerce.com/s/article/Cloudflare-for-Performance-and-Security?language=en%5FUS#orange-to-orange).

If you cannot activate your domain using [proxied DNS records](https://developers.cloudflare.com/dns/proxy-status/), reach out to your account team.

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to BigCommerce. BigCommerce would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on BigCommerce, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to BigCommerce, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow BigCommerce's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a BigCommerce customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult BigCommerce if there are technical issues that Cloudflare cannot resolve.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/bigcommerce/","name":"BigCommerce"}}]}
```

---

---
title: HubSpot
description: Learn how to configure your zone with HubSpot.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/hubspot.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# HubSpot

Cloudflare partners with HubSpot to provide HubSpot customers’ websites with Cloudflare’s performance and security benefits.

If you use HubSpot and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then HubSpot's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your HubSpot environment.

## How it works

For more details about how O2O is different than other Cloudflare setups, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

O2O is enabled per hostname, so to enable O2O for a specific hostname within your Cloudflare zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied `CNAME` DNS record with a target of your corresponding HubSpot CNAME. Which HubSpot CNAME is targeted will depend on your current [HubSpot proxy settings ↗](https://developers.hubspot.com/docs/cms/developer-reference/reverse-proxy-support#configure-the-proxy).

| Type  | Name             | Target                               | Proxy status |
| ----- | ---------------- | ------------------------------------ | ------------ |
| CNAME | <YOUR\_HOSTNAME> | <HUBID>.sites-proxy.hscoscdn<##>.net | Proxied      |

Note

For questions about your HubSpot setup, refer to [HubSpot's reverse proxy support guide ↗](https://developers.hubspot.com/docs/cms/developer-reference/reverse-proxy-support).

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to HubSpot. HubSpot would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on HubSpot, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to HubSpot, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow HubSpot's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a HubSpot customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult HubSpot if there are technical issues that Cloudflare cannot resolve.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/hubspot/","name":"HubSpot"}}]}
```

---

---
title: Kinsta
description: Learn how to configure your Enterprise zone with Kinsta.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/kinsta.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Kinsta

Cloudflare partners with Kinsta to provide Kinsta customers’ websites with Cloudflare’s performance and security benefits.

If you use Kinsta and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then Kinsta's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your Kinsta environment.

## How it works

For additional detail about how traffic routes when O2O is enabled, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

Kinsta customers can enable O2O on any Cloudflare zone plan.

To enable O2O for a specific hostname within a Cloudflare zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied `CNAME` DNS record with your Kinsta site name as the target. Kinsta’s domain addition setup will walk you through other validation steps.

| Type  | Name             | Target                        | Proxy status |
| ----- | ---------------- | ----------------------------- | ------------ |
| CNAME | <YOUR\_HOSTNAME> | sitename.hosting.kinsta.cloud | Proxied      |

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to Kinsta. Kinsta would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on Kinsta, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to Kinsta, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow Kinsta's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a Kinsta customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult Kinsta if there are technical issues that Cloudflare cannot resolve.

### Resolving SSL errors using Cloudflare Managed Certificates

If you encounter SSL errors when attempting to activate a Cloudflare Managed Certificate, verify if you have a `CAA` record on your domain name with command `dig +short example.com CAA`.

If you do have a `CAA` record, verify that it permits SSL certificates to be issued by the [certificate authorities supported by Cloudflare](https://developers.cloudflare.com/ssl/reference/certificate-authorities/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/kinsta/","name":"Kinsta"}}]}
```

---

---
title: Render
description: Learn how to configure your Enterprise zone with Render.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/render.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Render

Cloudflare partners with [Render](https://render.com) to provide Render customers’ web services and static sites with Cloudflare’s performance and security benefits.

If you use Render and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then Render's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your Render services.

## How it works

For additional detail about how traffic routes when O2O is enabled, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

Render customers can enable O2O on any Cloudflare zone plan. Cloudflare support for O2O setups is only available for Enterprise customers.

To enable O2O for a specific hostname within a Cloudflare zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied `CNAME` DNS record with your Render site name as the target. Render's domain addition setup will walk you through other validation steps.

| Type  | Name             | Target                                                  | Proxy status |
| ----- | ---------------- | ------------------------------------------------------- | ------------ |
| CNAME | <YOUR\_HOSTNAME> | <RENDER\_SUBDOMAIN> (for example, example.onrender.com) | Proxied      |

Note

For more details about Render setup, refer to their [documentation ↗](https://render.com/docs/configure-cloudflare-dns).

If you cannot activate your domain using [proxied DNS records](https://developers.cloudflare.com/dns/proxy-status/), reach out to your Cloudflare account team or your Render support team.

### Additional requirements for wildcard subdomains

With O2O enabled, adding a wildcard subdomain to a Render service requires that the corresponding root domain is also routed to Render. If the root domain is routed elsewhere, wildcard routing will fail.

If your root domain needs to route somewhere besides Render, add individual subdomains to your Render service instead of a wildcard.

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to Render. Render would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on Render, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to Render, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow Render's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a Render customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult Render if there are technical issues that Cloudflare cannot resolve.

### Resolving SSL errors

If you encounter SSL errors, check if you have a `CAA` record.

If you have a `CAA` record, verify that it permits SSL certificates to be issued by Google Trust Services (`pki.goog`).

For more details, refer to [CAA records](https://developers.cloudflare.com/ssl/edge-certificates/caa-records/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/render/","name":"Render"}}]}
```

---

---
title: Salesforce Commerce Cloud
description: Learn how to configure your Enterprise zone with Salesforce Commerce Cloud.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/salesforce-commerce-cloud.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Salesforce Commerce Cloud

Cloudflare partners with Salesforce Commerce Cloud to provide Salesforce Commerce Cloud customers’ websites with Cloudflare’s performance and security benefits.

If you use Salesforce Commerce Cloud and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then Salesforce Commerce Cloud's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your Salesforce Commerce Cloud environment.

## How it works

For additional detail about how traffic routes when O2O is enabled, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

To enable O2O requires the following:

1. You must configure your SFCC environment as an "SFCC Proxy Zone". If you currently have an "SFCC Legacy Zone", you cannot enable O2O.  
   * For more details on the different types of SFCC configurations, refer to the [Salesforce FAQ on SFCC Proxy Zones ↗](https://help.salesforce.com/s/articleView?id=cc.b2c%5Fecdn%5Fproxy%5Fzone%5Ffaq.htm&type=5).  
   * For instructions on how to migrate your SFCC environment to an "SFCC Proxy Zone", refer to the [SFCC Legacy Zone to SFCC Proxy Zone migration guide ↗](https://help.salesforce.com/s/articleView?id=cc.b2c%5Fmigrate%5Flegacy%5Fzone%5Fto%5Fproxy%5Fzone.htm&type=5).
2. Your own Cloudflare zone on an Enterprise plan.

If you meet the above requirements, O2O can then be enabled per hostname. To enable O2O for a specific hostname within your Cloudflare zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied CNAME DNS record with a target of the CNAME provided by SFCC Business Manager, which is the dashboard used by SFCC customers to configure their storefront environment.

The CNAME provided by SFCC Business Manager will resemble `commcloud.prod-abcd-example-com.cc-ecdn.net` and contains 3 distinct parts. For each hostname routing traffic to SFCC, be sure to update each part of the example CNAME to match your SFCC environment:

1. **Environment**: `prod` should be changed to `prod` or `dev` or `stg`.
2. **Realm**: `abcd` should be changed to the Realm ID assigned to you by SFCC.
3. **Domain Name**: `example-com` should be changed to match your domain name in a hyphenated format.

| Type  | Name             | Target                                      | Proxy status |
| ----- | ---------------- | ------------------------------------------- | ------------ |
| CNAME | <YOUR\_HOSTNAME> | commcloud.prod-abcd-example-com.cc-ecdn.net | Proxied      |

For O2O to be configured properly, make sure your Proxied DNS record targets your SFCC CNAME **directly**. Do not indirectly target the SFCC CNAME by targeting another Proxied DNS record in your Cloudflare zone which targets the SFCC CNAME.

Correct configuration

For example, if the hostnames routing traffic to SFCC are `www.example.com` and `preview.example.com`, the following is a **correct** configuration in your Cloudflare zone:

| Type  | Name                | Target                                      | Proxy status |
| ----- | ------------------- | ------------------------------------------- | ------------ |
| CNAME | www.example.com     | commcloud.prod-abcd-example-com.cc-ecdn.net | Proxied      |
| CNAME | preview.example.com | commcloud.prod-abcd-example-com.cc-ecdn.net | Proxied      |

Incorrect configuration

And, the following is an **incorrect** configuration because `preview.example.com` indirectly targets the SFCC CNAME via the `www.example.com` Proxied DNS record, which means O2O will not be properly enabled for hostname `preview.example.com`:

| Type  | Name                | Target                                      | Proxy status |
| ----- | ------------------- | ------------------------------------------- | ------------ |
| CNAME | www.example.com     | commcloud.prod-abcd-example-com.cc-ecdn.net | Proxied      |
| CNAME | preview.example.com | www.example.com                             | Proxied      |

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to Salesforce Commerce Cloud. Salesforce Commerce Cloud would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on Salesforce Commerce Cloud, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to Salesforce Commerce Cloud, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow Salesforce Commerce Cloud's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a Salesforce Commerce Cloud customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult Salesforce Commerce Cloud if there are technical issues that Cloudflare cannot resolve.

### Resolving SSL errors using Cloudflare Managed Certificates

If you encounter SSL errors when attempting to activate a Cloudflare Managed Certificate, verify if you have a `CAA` record on your domain name with command `dig +short example.com CAA`.

If you do have a `CAA` record, verify that it permits SSL certificates to be issued by the [certificate authorities supported by Cloudflare](https://developers.cloudflare.com/ssl/reference/certificate-authorities/).

### Best practice Zone-level configuration

1. Set **Minimum TLS version** to **TLS 1.2**  
   1. Go to the [**Edge Certificates** ↗](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/edge-certificates) page, scroll down to find **Minimum TLS Version**, and set it to _TLS 1.2_. This setting applies to every Proxied DNS record in your Zone.
2. Match the **Security Level** set in **SFCC Business Manager**  
   1. _Option 1: Zone-level_ \- Go to the [**Settings** ↗](https://dash.cloudflare.com/?to=/:account/:zone/security/settings) page under Security, find **Security Level** and set **Security Level** to match what is configured in **SFCC Business Manager**. This setting applies to every Proxied DNS record in your Cloudflare zone.  
   2. _Option 2: Per Proxied DNS record_ \- If the **Security Level** differs between the Proxied DNS records targeting your SFCC environment and other Proxied DNS records in your Cloudflare zone, use a **Configuration Rule** to set the **Security Level** specifically for the Proxied DNS records targeting your SFCC environment. For example:  
         1. Create a new **Configuration Rule** on the [**Rules Overview** ↗](https://dash.cloudflare.com/?to=/:account/:zone/rules/overview) page by selecting **Create rule** next to **Configuration Rules**:  
                  1. **Rule name:** `Match Security Level on SFCC hostnames`  
                  2. **Field:** _Hostname_  
                  3. **Operator:** _is in_ (this will match against multiple hostnames specified in the **Value** field)  
                  4. **Value:** `www.example.com` `dev.example.com`  
                  5. Scroll down to **Security Level** and click **\+ Add**  
                              1. **Select Security Level:** _Medium_ (this should match the **Security Level** set in **SFCC Business Manager**)  
                  6. Scroll to the bottom of the page and click **Deploy**
3. Disable **Browser Integrity Check**  
   1. _Option 1: Zone-level_ \- Go to the [**Settings** ↗](https://dash.cloudflare.com/?to=/:account/:zone/security/settings) page under Security, find **Browser Integrity Check** and toggle it off to disable it. This setting applies to every Proxied DNS record in your Cloudflare zone.  
   2. _Option 2: Per Proxied DNS record_ \- If you want to keep **Browser Integrity Check** enabled for other Proxied DNS records in your Cloudflare zone but want to disable it on Proxied DNS records targeting your SFCC environment, keep the Zone-level **Browser Integrity Check** feature enabled and use a **Configuration Rule** to disable **Browser Integrity Check** specifically for the hostnames targeting your SFCC environment. For example:  
         1. Create a new **Configuration Rule** on the [**Rules Overview** ↗](https://dash.cloudflare.com/?to=/:account/:zone/rules/overview) page by selecting **Create rule** next to **Configuration Rules**:  
                  1. **Rule name:** `Disable Browser Integrity Check on SFCC hostnames`  
                  2. **Field:** _Hostname_  
                  3. **Operator:** _is in_ (this will match against multiple hostnames specified in the **Value** field)  
                  4. **Value:** `www.example.com` `dev.example.com`  
                  5. Scroll down to **Browser Integrity Check** and click the **\+ Add** button:  
                              1. Set the toggle to **Off** (a grey X will be displayed)  
                  6. Scroll to the bottom of the page and click **Deploy**
4. Bypass **Cache** on Proxied DNS records targeting your SFCC environment  
   1. Your SFCC environment, also called a **Realm**, will contain one to many SFCC Proxy Zones, which is where caching will always occur. In the corresponding SFCC Proxy Zone for your domain, SFCC performs their own cache optimization, so it is recommended to bypass the cache on the Proxied DNS records in your Cloudflare zone which target your SFCC environment to prevent a "double caching" scenario. This can be accomplished with a **Cache Rule**.  
   2. If the **Cache Rule** is not created, caching will occur in both your Cloudflare zone and your corresponding SFCC Proxy Zone, which can cause issues if and when the cache is invalidated or purged in your SFCC environment.  
         1. Additional information on caching in your SFCC environment can be found in [SFCC's Content Cache Documentation ↗](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/b2c-content-cache.html)  
   3. Create a new **Cache Rule** on the [**Rules Overview** ↗](https://dash.cloudflare.com/?to=/:account/:zone/rules/overview) page by selecting **Create rule** next to **Cache Rules**:  
         1. **Rule name:** `Bypass cache on SFCC hostnames`  
         2. **Field:** _Hostname_  
         3. **Operator:** _is in_ (this will match against multiple hostnames specified in the **Value** field)  
         4. **Value:** `www.example.com` `dev.example.com`  
         5. **Cache eligibility:** Select **Bypass cache**.  
         6. Scroll to the bottom of the page and select **Deploy**.
5. _Optional_ \- Upload your Custom Certificate from **SFCC Business Manager** to your Cloudflare zone:  
   1. The Custom Certificate you uploaded via **SFCC Business Manager** or **SFCC CDN-API**, which exists within your corresponding SFCC Proxy Zone, will terminate TLS connections for your SFCC storefront hostnames. Because of that, it is optional if you want to upload the same Custom Certificate to your own Cloudflare zone. Doing so will allow Cloudflare users with specific roles in your Cloudflare account to receive expiration notifications for your Custom Certificates. Please read [renew custom certificates](https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/renewing/#renew-custom-certificates) for further details.  
   2. Additionally, since you now have your own Cloudflare zone, you have access to Cloudflare's various edge certificate products which means you could have more than one certificate covering the same SANs. In that scenario, a certificate priority process occurs to determine which certificate to serve at the Cloudflare edge. If you find your SFCC storefront hostnames are presenting a different certificate compared to what you uploaded via **SFCC Business Manager** or **SFCC CDN-API**, the certificate priority process is likely the reason. Please read [certificate priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#certificate-deployment) for further details.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/salesforce-commerce-cloud/","name":"Salesforce Commerce Cloud"}}]}
```

---

---
title: Shopify
description: Learn how to configure your zone with Shopify.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/shopify.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Shopify

Cloudflare partners with Shopify to provide Shopify customers’ websites with Cloudflare’s performance and security benefits.

If you use Shopify and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then Shopify's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O routing also enables you to take advantage of Cloudflare zones specifically customized for Shopify traffic.

## How it works

For more details about how O2O is different than other Cloudflare setups, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

When you [set up O2O routing for your Shopify website](#enable), Cloudflare enables specific configurations for this SaaS provider. Currently, this includes the following:

* Workers and Snippets are disabled on the `/checkout` URI path.

## Enable

You can enable O2O on any Cloudflare zone plan.

To enable O2O on your account, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a `CNAME` DNS record.

| Type  | Name                 | Target              | Proxy status |
| ----- | -------------------- | ------------------- | ------------ |
| CNAME | <YOUR\_SHOP\_DOMAIN> | shops.myshopify.com | Proxied      |

Once you save the new DNS record, the Cloudflare dashboard will show a Shopify icon next to the CNAME record value. For example:

![Cloudflare dashboard showing a CNAME DNS entry for Shopify with a specific Shopify icon](https://developers.cloudflare.com/_astro/shopify-dns-entry.BVBaRuE6_1CQPez.webp) 

Do not use Always Use HTTPS

Do not enable the [Always Use HTTPS](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/always-use-https/) setting in an O2O scenario with Shopify.

This setting forces a redirect on all requests, including the `/.well-known/acme-challenge/*` URI path used for HTTP-01 domain validation. This prevents Shopify from automatically provisioning or renewing SSL certificates via Let's Encrypt for your domain.

Instead, create a [redirect rule](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/create-dashboard/) to enforce HTTPS while excluding the validation path mentioned above (use a [wildcard pattern](https://developers.cloudflare.com/ruleset-engine/rules-language/operators/#wildcard-matching) like `/.well-known/acme-challenge/*`).

For questions about Shopify setup, refer to their [support guide ↗](https://help.shopify.com/en/manual/domains/add-a-domain/connecting-domains/connect-domain-manual).

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to Shopify. Shopify would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on Shopify, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to Shopify, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow Shopify's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a Shopify customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult Shopify if there are technical issues that Cloudflare cannot resolve.

### DNS CAA records

For details about CAA records refer to the [Shopify documentation ↗](https://help.shopify.com/manual/domains/add-a-domain/connecting-domains/considerations).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/shopify/","name":"Shopify"}}]}
```

---

---
title: Webflow
description: Learn how to configure your Cloudflare zone with Webflow.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/webflow.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Webflow

Cloudflare partners with Webflow to provide Webflow customers’ websites with Cloudflare’s performance and security benefits.

If you use Webflow and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then Webflow's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as WAF, Bot Management, Waiting Room, and more — on the traffic destined for your Webflow environment.

## How it works

For more details about how O2O is different than other Cloudflare setups, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

Webflow customers can enable O2O on any Cloudflare zone plan.

To enable O2O for a specific hostname within a Cloudflare Zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied `CNAME` DNS record with your Webflow site name as the target. Webflow's domain addition setup will walk you through other validation steps.

| Type  | Name           | Target          | Proxy status |
| ----- | -------------- | --------------- | ------------ |
| CNAME | <YOUR\_DOMAIN> | cdn.webflow.com | Proxied      |

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to Webflow. Webflow would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on Webflow, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to Webflow, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow Webflow's instructions to refresh the custom hostname and it should activate.

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Additional support

If you are a Webflow customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult Webflow if there are technical issues that Cloudflare cannot resolve.

### DNS CAA records

Webflow issues SSL/TLS certificates for merchant domains using Let’s Encrypt and Google Trust Services. If you add any DNS CAA records, you must select **Let’s Encrypt** or **Google Trust Services** as the Certificate Authority (CA) or HTTPS connections may fail.

For more details, refer to [CAA records](https://developers.cloudflare.com/ssl/edge-certificates/caa-records/#caa-records-added-by-cloudflare).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/webflow/","name":"Webflow"}}]}
```

---

---
title: WP Engine
description: Learn how to configure your zone with WP Engine.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/wpengine.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# WP Engine

Cloudflare partners with WP Engine to provide WP Engine customers’ websites with Cloudflare’s performance and security benefits.

If you use WP Engine and also have a Cloudflare plan, you can use your own Cloudflare zone to proxy web traffic to your zone first, then WP Engine's (the SaaS Provider) zone second. This configuration option is called [O2O](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Benefits

O2O's benefits include applying your own Cloudflare zone's services and settings — such as [WAF](https://developers.cloudflare.com/waf/), [Bot Management](https://developers.cloudflare.com/bots/plans/bm-subscription/), [Waiting Room](https://developers.cloudflare.com/waiting-room/), and more — on the traffic destined for your WP Engine environment.

## How it works

For more details about how O2O is different than other Cloudflare setups, refer to [How O2O works](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/).

## Enable

WP Engine customers can enable O2O on any Cloudflare zone plan.

To enable O2O for a specific hostname within a Cloudflare zone, [create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a Proxied `CNAME` DNS record with a target of one of the following WP Engine CNAMEs. Which WP Engine CNAME is used will depend on your current [WP Engine network type ↗](https://wpengine.com/support/network/).

| Type  | Name             | Target                                                                          | Proxy status |
| ----- | ---------------- | ------------------------------------------------------------------------------- | ------------ |
| CNAME | <YOUR\_HOSTNAME> | wp.wpewaf.com (Global Edge Security)orwp.wpenginepowered.com (Advanced Network) | Proxied      |

Note

For questions about WP Engine setup, refer to their [support guide ↗](https://wpengine.com/support/wordpress-best-practice-configuring-dns-for-wp-engine/#Point%5FDNS%5FUsing%5FCNAME%5FFlattening).

If you cannot activate your domain using [proxied DNS records](https://developers.cloudflare.com/dns/proxy-status/), reach out to your account team.

## Product compatibility

When a hostname within your Cloudflare zone has O2O enabled, you assume additional responsibility for the traffic on that hostname because you can now configure various Cloudflare products to affect that traffic. Some of the Cloudflare products compatible with O2O are:

* [Caching](https://developers.cloudflare.com/cache/)
* [Workers](https://developers.cloudflare.com/workers/)
* [Rules](https://developers.cloudflare.com/rules/)

For a full list of compatible products and potential limitations, refer to [Product compatibility](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/product-compatibility/).

## Zone hold

If your own Cloudflare zone is on the Enterprise plan, you have access to the [zone hold feature](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/), which is a toggle that prevents your domain name from being created as a zone in a different Cloudflare account. Additionally, if the zone hold is enabled, it prevents the activation of custom hostnames onboarded to WP Engine. WP Engine would receive the following error message for your custom hostname: `The hostname is associated with a held zone. Please contact the owner of this domain to have the hold removed.`

To successfully activate the custom hostname on WP Engine, the owner of the zone needs to [temporarily release the hold](https://developers.cloudflare.com/fundamentals/account/account-security/zone-holds/#release-zone-holds). If you are only onboarding a subdomain as a custom hostname to WP Engine, only the subfeature titled **Also prevent Subdomains** needs to be temporarily disabled.

Once the zone hold is temporarily disabled, follow WP Engine's instructions to refresh the custom hostname and it should activate.

## Additional support

If you are a WP Engine customer and have set up your own Cloudflare zone with O2O enabled on specific hostnames, contact your Cloudflare Account Team or [Cloudflare Support](https://developers.cloudflare.com/support/contacting-cloudflare-support/) for help resolving issues in your own zone.

Cloudflare will consult WP Engine if there are technical issues that Cloudflare cannot resolve.

### Resolving SSL errors

If you encounter SSL errors, check if you have a `CAA` record.

If you do have a `CAA` record, check that it permits SSL certificates to be issued by `letsencrypt.org`.

For more details, refer to [Add CAA records](https://developers.cloudflare.com/ssl/edge-certificates/caa-records/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/","name":"Provider guides"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/provider-guides/wpengine/","name":"WP Engine"}}]}
```

---

---
title: Remove domain
description: If your SaaS domain is also a domain using Cloudflare, you can use your Cloudflare DNS to remove your domain from your SaaS provider.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/remove-domain.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Remove domain

If your SaaS domain is also a [domain using Cloudflare](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/), you can use your Cloudflare DNS to remove your domain from your SaaS provider.

This means that - if you [remove the DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#delete-dns-records) pointing to your SaaS provider - Cloudflare will stop routing domain traffic through your SaaS provider and the associated custom hostname will enter a **Moved** state.

This also means that you need to keep DNS records pointing to your SaaS provider for as long as you are a customer. Otherwise, you could accidentally remove your domain from their services.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/","name":"SaaS customers"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/remove-domain/","name":"Remove domain"}}]}
```

---

---
title: Security
description: Cloudflare for SaaS provides increased security per custom hostname through:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Security

Cloudflare for SaaS provides increased security per custom hostname through:

* [Certificate management](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/)  
   * [Issue certificates through Cloudflare](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/)  
   * [Upload your own certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/)
* Control your traffic's level of encryption with [TLS settings](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/)
* Create and deploy WAF custom rules, rate limiting rules, and managed rulesets using [WAF for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}}]}
```

---

---
title: Certificate management
description: Cloudflare for SaaS takes away the burden of certificate issuance and management from you, as the SaaS provider, by proxying traffic through Cloudflare's edge. You can choose between Cloudflare managing all the certificate issuance and renewals on your behalf, or maintain control over your TLS private keys by uploading your customers' own certificates.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate management

Cloudflare for SaaS takes away the burden of certificate issuance and management from you, as the SaaS provider, by proxying traffic through Cloudflare's edge. You can choose between Cloudflare managing all the certificate issuance and renewals on your behalf, or maintain control over your TLS private keys by uploading your customers' own certificates.

## Resources

* [ Certificate statuses ](https://developers.cloudflare.com/ssl/reference/certificate-statuses/)
* [ Issue and validate certificates ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/)
* [ TLS Management ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/)
* [ Custom certificates ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/)
* [ Webhook definitions ](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/webhook-definitions/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}}]}
```

---

---
title: Certificate statuses
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/certificate-statuses.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate statuses

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/certificate-statuses/","name":"Certificate statuses"}}]}
```

---

---
title: Custom certificates
description: If your customers need to provide their own key material, you may want to upload a custom certificate. Cloudflare will automatically bundle the certificate with a certificate chain optimized for maximum browser compatibility.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom certificates

If your customers need to provide their own key material, you may want to [upload a custom certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/). Cloudflare will automatically bundle the certificate with a certificate chain [optimized for maximum browser compatibility](https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/bundling-methodologies/#compatible).

As part of this process, you may also want to [generate a Certificate Signing Request (CSR)](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/certificate-signing-requests/) for your customer so they do not have to manage the private key on their own.

Note

Only certain customers have access to this feature. For more details, see the [Plans page](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

## Use cases

This situation commonly occurs when your customers use Extended Validation (EV) certificates (the “green bar”) or when their information security policy prohibits third parties from generating private keys on their behalf.

## Limitations

If you use custom certificates, you are responsible for the entire certificate lifecycle (initial upload, renewal, subsequent upload).

Cloudflare also only accepts publicly trusted certificates of these types:

* `SHA256WithRSA`
* `SHA1WithRSA`
* `ECDSAWithSHA256`

If you attempt to upload another type of certificate or a certificate that has been self-signed, it will be rejected.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/","name":"Custom certificates"}}]}
```

---

---
title: Certificate signing requests (CSRs)
description: Cloudflare for SaaS allows you to generate a Certificate Signing Request (CSR) A CSR contains information about your domain, common name, and Subject Alternative Names.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/certificate-signing-requests.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Certificate signing requests (CSRs)

**Last reviewed:**  over 5 years ago 

Generate a Certificate Signing Request (CSR) to get a custom certificate from the Certificate Authority (CA) of your choice while maintaining control of the private key on Cloudflare. The private key associated with the CSR will be generated by Cloudflare and will never leave our network.

A CSR contains information about your domain: your organization name and address, the common name (domain name), and Subject Alternative Names (SANs).

Once the CSR has been generated, provide it to your customer. Your customer will then pass it along to their preferred CA to obtain a certificate and return it to you. After you receive the certificate, you should upload it to Cloudflare and reference the unique CSR ID that was provided to you during CSR creation.

Note

Only certain customers have access to this feature. For more details, see the [Plans page](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

---

## Generate the private key and CSR

### 1\. Build the CSR payload

All fields except for organizational\_unit and key\_type are required. If you do not specify a `key_type`, the default of `rsa2048` (RSA 2048 bit) will be used; the other option is `p256v1` (NIST P-256).

Common names are restricted to 64 characters and subject alternative names (SANs) are limited to 255 characters, [per RFC 5280 ↗](https://tools.ietf.org/html/rfc5280). You must specify at least one SAN, and the list of SANs should include the common name.

Terminal window

```

request_body=$(< <(cat <<EOF

{

  "country": "US",

  "state": "MA",

  "locality": "Boston",

  "organization": "City of Boston",

  "organizational_unit": "Championship Parade Detail",

  "common_name": "app.example.com",

  "sans": [

    "app.example.com",

    "www.example.com",

    "blog.example.com",

    "example.com"

  ],

  "key_type": "p256v1"

}

EOF

))


```

### 2\. Generate a CSR

Now, you want to generate a CSR that you can provide to your customer.

Terminal window

```

curl https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_csrs \

--header "X-Auth-Email: <EMAIL>" \

--header "X-Auth-Key: <API_KEY>" \

--header "Content-Type: application/json" \

--data "$request_body"


# Response:

{

  "result": {

    "id": "7b163417-1d2b-4c84-a38a-2fb7a0cd7752",

    "country": "US",

    "state": "MA",

    "locality": "Boston",

    "organization": "City of Boston",

    "organizational_unit": "Championship Parade Detail",

    "common_name": "app.example.com",

    "sans": [

      "app.example.com",

      "www.example.com",

      "blog.example.com",

      "example.com",

    ],

    "key_type": "p256v1",

    "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBSzCB8gIBADBiMQswaQYDVQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcT\nBkJvc3RvbjEaMBgGA1UEChMRQ2l0eSBvZiBDaGFtcGlvbnMxGTAXBgNVBAMTEGNz\nci1wcm9kLnRscy5mdW4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAaTKf70NYlwr\n20P6P8xj8/4mTN5q28dbZR/gM3u4m/RPs24+PxAfMZCNvkVKAPVWYfUAadZI4Ha/\ndxLh5Q6X5bhIoC4wLAYJKoZIhvcNAQkOMR8wHTAbBqNVHREEFDASghBjc3ItcHJv\nZC50bHMuZnVuMAoGCCqGSM49BAMCA0gAMEUCIQDgtFUZav466SbT2FGBsIBlahDI\nVkg4y+u+V/K5DlY1+gIgQ9xLfUSKnSnJYbM9TwWr4Z964+lBtB9af4O5pp7/PSA=\n-----END CERTIFICATE REQUEST-----\n"

  },

  "success": true


```

Replace the `\n` characters with actual newlines before passing to your customer. This can be accomplished by piping the output of the prior call to a tool like jq and perl, such as:

Terminal window

```

curl https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_csrs \

--header "X-Auth-Email: <EMAIL>" \

--header "X-Auth-Key: <API_KEY>" \

--header "Content-Type: application/json" \

--data "$request_body" | jq .result.csr | perl -npe s'/\\n/\n/g; s/"//g' > csr.txt


```

### 3\. Customer obtains certificate

Your customer will take the provided CSR and work with their CA to obtain a signed, publicly trusted certificate.

### 4\. Upload the certificate

Upload the certificate and reference the ID that was provided when you generated the CSR.

You should replace newlines in the certificate with literal `\n` characters, as illustrated above in the custom certificate upload example. After doing so, build the request body and provide the ID that was returned in a previous step.

Cloudflare only accepts publicly trusted certificates. If you attempt to upload a self-signed certificate, it will be rejected.

Terminal window

```

$ MYCERT="$(cat app_example_com.pem|perl -pe 's/\r?\n/\\n/'|sed -e 's/..$//')"


$ request_body=$(< <(cat <<EOF

{

  "hostname": "app.example.com",

  "ssl": {

    "custom_csr_id": "7b163417-1d2b-4c84-a38a-2fb7a0cd7752",

    "custom_certificate": "$MYCERT"

  }

}

EOF

))


```

With the request body built, [create the custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) with the supplied custom certificate. If you intend to use the certificate with multiple hostnames, make multiple API calls replacing the `hostname` field.

---

## Other actions

### List all CSRs

You can request the (paginated) collection of all previously generated custom CSRs by making a `GET` request to `https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_csrs`.

### Delete a CSR

Delete one or more of the CSRs to delete the underlying private key by making a `DELETE` request to `https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_csrs/{csr_id}`.

You may delete a CSR provided there are no custom certificates using the private key that was generated for the CSR. If you attempt to delete a CSR whose private key is still in use, you will receive an error.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/","name":"Custom certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/certificate-signing-requests/","name":"Certificate signing requests (CSRs)"}}]}
```

---

---
title: Manage custom certificates
description: Learn how to manage custom certificates for your Cloudflare for SaaS custom hostnames.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Manage custom certificates

Learn how to manage custom certificates for your Cloudflare for SaaS custom hostnames. For use cases and limitations, refer to [custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/).

## Upload certificates

This section describes the general process for uploading a custom certificate corresponding to one of the [supported types](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/#limitations).

Note

If you must support both RSA and ECDSA refer to [certificate packs](#use-certificate-packs-rsa-and-ecdsa) below.

* [ Dashboard ](#tab-panel-3364)
* [ API ](#tab-panel-3365)

To upload a custom certificate in the dashboard, select **Custom certificate** while [creating your custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/).

For information about the **bundle method** options, refer to the [Cloudflare SSL/TLS documentation](https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/bundling-methodologies/).

The call below will upload a certificate for use with `app.example.com`.

Note that if you are using an ECC key generated by OpenSSL, you will need to first remove the `-----BEGIN EC PARAMETERS-----...-----END EC PARAMETERS-----` section of the file.

1. Update the file and build the payload

Terminal window

```

cat app_example_com.pem


```

```

-----BEGIN CERTIFICATE-----

MIIFJDCCBAygAwIBAgIQD0ifmj/Yi5NP/2gdUySbfzANBgkqhkiG9w0BAQsFADBN

MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E

...

SzSHfXp5lnu/3V08I72q1QNzOCgY1XeL4GKVcj4or6cT6tX6oJH7ePPmfrBfqI/O

OeH8gMJ+FuwtXYEPa4hBf38M5eU5xWG7

-----END CERTIFICATE-----


```

Terminal window

```

MYCERT="$(cat app_example_com.pem|perl -pe 's/\r?\n/\\n/'|sed -e 's/..$//')"

MYKEY="$(cat app_example_com.key|perl -pe 's/\r?\n/\\n/'|sed -e's/..$//')"


```

With the certificate and key saved to environment variables (using escaped newlines), build the payload:

Terminal window

```

$ echo $MYCERT

-----BEGIN CERTIFICATE-----\nMIIFJDCCBAygAwIBAgIQD0ifmj/Yi5NP/2gdUySbfzANBgkqhkiG9w0BAQsFADBN\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E...SzSHfXp5lnu/3V08I72q1QNzOCgY1XeL4GKVcj4or6cT6tX6oJH7ePPmfrBfqI/O\nOeH8gMJ+FuwtXYEPa4hBf38M5eU5xWG7\n-----END CERTIFICATE-----\n


$ request_body=$(< <(cat <<EOF

{

  "hostname": "app.example.com",

  "ssl": {

    "custom_certificate": "$MYCERT",

    "custom_key": "$MYKEY"

  }

}

EOF

))


```

1. Use a [POST request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) to upload your certificate and key.

Note

The serial number returned is unique to the issuer, but not globally unique. Additionally, it is returned as a string, not an integer.

## Use certificate packs: RSA and ECDSA

A certificate pack allows you to upload up to one RSA and one ECDSA custom certificates to a custom hostname. This process is currently only supported via API.

To upload an RSA and ECDSA certificate to a custom hostname, set the `bundle_method` to `force` and define the `custom_cert_bundle` property when [creating a custom hostname via API](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/).

You can also use `"bundle_method": "force"` and `custom_cert_bundle` with a `PATCH` request to the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint.

### Delete a custom certificate and private key

Use the [Delete Single Certificate And Key For Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/certificate%5Fpack/subresources/certificates/methods/delete/) endpoint to remove one of the custom certificates and corresponding key from a certificate pack.

You cannot delete a certificate if it is the only remaining certificate in the pack.

### Replace a custom certificate and private key

To replace a single custom certificate within a certificate pack that contains two bundled certificates, use the [Replace Custom Certificate And Custom Key In Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/certificate%5Fpack/subresources/certificates/methods/update/) endpoint.

You can only replace an RSA certificate with another RSA certificate, or an ECDSA certificate with another ECDSA certificate.

---

## Move to a Cloudflare certificate

If you want to switch from maintaining a custom certificate to using one issued by Cloudflare, you can migrate that certificate with zero downtime.

Send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) to your custom hostname with a value for the DCV `method`. As soon as the [certificate is validated](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/) and the [hostname is validated](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/), Cloudflare will remove the old custom certificate and begin serving the new one.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/","name":"Custom certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/","name":"Manage custom certificates"}}]}
```

---

---
title: TLS Management
description: Mutual TLS (mTLS) adds an extra layer of protection to application connections by validating certificates on the server and the client. When building a SaaS application, you may want to enforce mTLS to protect sensitive endpoints related to payment processing, database updates, and more.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# TLS Management

[Mutual TLS (mTLS) ↗](https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/) adds an extra layer of protection to application connections by validating certificates on the server and the client. When building a SaaS application, you may want to enforce mTLS to protect sensitive endpoints related to payment processing, database updates, and more.

[Minimum TLS Version](#minimum-tls-version) only allows HTTPS connections from visitors that support the selected TLS protocol version or newer. Cloudflare recommends TLS 1.2 to comply with the Payment Card Industry (PCI) Security Standards Council. As a SaaS provider, you can control the Minimum TLS version for your zone as a whole, as well as for individual custom hostnames.

[Cipher suites](#cipher-suites) are a combination of ciphers used to negotiate security settings during the [SSL/TLS handshake ↗](https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/). As a SaaS provider, you can specify configurations for cipher suites on your zone as a whole and cipher suites on individual custom hostnames via the API.

Warning

When you [issue a custom hostname certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/) with wildcards enabled, any cipher suites or Minimum TLS settings applied to that hostname will only apply to the direct hostname.

However, if you want to update the Minimum TLS settings for all wildcard hostnames, you can change Minimum TLS version at the [zone level](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/minimum-tls/).

## Enable mTLS

Once you have [added a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/), you can enable mTLS by using Cloudflare Access. Go to [Cloudflare Zero Trust ↗](https://one.dash.cloudflare.com/) and [add mTLS authentication](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/mutual-tls-authentication/) with a few clicks.

Note

Currently, you cannot add mTLS policies for custom hostnames using [API Shield](https://developers.cloudflare.com/api-shield/security/mtls/).

Also make sure to enforce mTLS on the specific custom hostname where it should be checked. It is not enough to have it set on the CNAME target.

## Minimum TLS Version

Note

While TLS 1.3 is the most recent and secure version, it is not supported by some older devices. Refer to Cloudflare's recommendations when [deciding what version to use](https://developers.cloudflare.com/ssl/reference/protocols/#decide-which-version-to-use).

### Scope

Minimum TLS version exists both as a [zone-level setting](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/minimum-tls/) (on the [**Edge Certificates** ↗](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/edge-certificates) page under **Minimum TLS Version**) and as a custom hostname setting. What this implies is:

* For custom hostnames created via API, it is possible not to explicitly define a value for `min_tls_version`. When that is the case, whatever value is defined as your zone's minimum TLS version will be applied. To confirm whether a given custom hostname has a specific minimum TLS version set, use the following API call.

Check custom hostname TLS settings

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

Custom Hostname Details

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response example

```

  "success": true,

  "result": {

    "id": "<CUSTOM_HOSTNAME_ID>",

    "ssl": {

12 collapsed lines

      "id": "<CERTIFICATE_ID>",

      "bundle_method": "ubiquitous",

      "certificate_authority": "<CERTIFICATE_AUTHORITY>",

      "custom_certificate": "",

      "custom_csr_id": "",

      "custom_key": "",

      "expires_on": "",

      "hosts": [

        "app.example.com",

        "*.app.example.com"

      ],

      "issuer": "",

      "method": "http",

      "settings": {},

      "signature": "SHA256WithRSA",

      "type": "dv",

20 collapsed lines

      "uploaded_on": "2020-02-06T18:11:23.531995Z",

      "validation_errors": [

        {

          "message": "SERVFAIL looking up CAA for app.example.com"

        }

      ],

      "validation_records": [

        {

          "emails": [

            "administrator@example.com",

            "webmaster@example.com"

          ],

          "http_body": "ca3-574923932a82475cb8592200f1a2a23d",

          "http_url": "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",

          "txt_name": "_acme-challenge.app.example.com",

          "txt_value": "810b7d5f01154524b961ba0cd578acc2"

        }

      ],

      "wildcard": false

    },

  }


```

* Whenever you make changes to a custom hostname via dashboard, the value that is set for Minimum TLS version will apply. If you have a scenario as explained in the bullet above, the dashboard change will override the zone-level configuration that was being applied.
* For custom hostnames with wildcards enabled, the direct custom hostname you create (for example, `saas-customer.test`) will use the hostname-specific setting, while the others (`sub1.saas-customer.test`, `sub2.saas-customer.test`, etc) will default to the zone-level setting.

### Setup

Minimum TLS version for your zone

Refer to [Minimum TLS version - SSL/TLS](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/minimum-tls/#zone-level).

Minimum TLS version for custom hostname

* [ Dashboard ](#tab-panel-3366)
* [ API ](#tab-panel-3367)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Find the hostname to which you want to apply Minimum TLS Version. Select **Edit**.
3. Choose the desired TLS version under **Minimum TLS Version** and select **Save**.

In the API documentation, refer to [SSL properties of a custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/). Besides the `settings` specifications, you must include `type` and `method` within the `ssl` object, as explained below.

1. Make a `GET` request to the [Custom Hostname Details](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/get/) endpoint to check what are the current values for `ssl.type` and `ssl.method`.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

Custom Hostname Details

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response example

```

  "success": true,

  "result": {

    "id": "<CUSTOM_HOSTNAME_ID>",

    "ssl": {

12 collapsed lines

      "id": "<CERTIFICATE_ID>",

      "bundle_method": "ubiquitous",

      "certificate_authority": "<CERTIFICATE_AUTHORITY>",

      "custom_certificate": "",

      "custom_csr_id": "",

      "custom_key": "",

      "expires_on": "",

      "hosts": [

        "app.example.com",

        "*.app.example.com"

      ],

      "issuer": "",

      "method": "http",

      "settings": {},

      "signature": "SHA256WithRSA",

      "type": "dv",

20 collapsed lines

      "uploaded_on": "2020-02-06T18:11:23.531995Z",

      "validation_errors": [

        {

          "message": "SERVFAIL looking up CAA for app.example.com"

        }

      ],

      "validation_records": [

        {

          "emails": [

            "administrator@example.com",

            "webmaster@example.com"

          ],

          "http_body": "ca3-574923932a82475cb8592200f1a2a23d",

          "http_url": "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",

          "txt_name": "_acme-challenge.app.example.com",

          "txt_value": "810b7d5f01154524b961ba0cd578acc2"

        }

      ],

      "wildcard": false

    },

  }


```

1. After you take note of these values, make a `PATCH` request to the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint, providing both the minimum TLS version you want to define and the same `type` and `method` values that you obtained from the previous step.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "ssl": {

        "method": "http",

        "type": "dv",

        "settings": {

            "min_tls_version:": "1.2"

        }

    }

  }'


```

## Cipher suites

For security and regulatory reasons, you may want to only allow connections from certain cipher suites. Cloudflare provides recommended values and full cipher suite reference in our [Cipher suites documentation](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/cipher-suites/#resources).

Restrict cipher suites for your zone

Refer to [Customize cipher suites - SSL/TLS](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/cipher-suites/customize-cipher-suites/).

Restrict cipher suites for custom hostname

In the API documentation, refer to [SSL properties of a custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/). Besides the `settings` specifications, you must include `type` and `method` within the `ssl` object, as explained below.

1. Make a `GET` request to the [Custom Hostname Details](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/get/) endpoint to check what are the current values for `ssl.type` and `ssl.method`.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

Custom Hostname Details

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response example

```

  "success": true,

  "result": {

    "id": "<CUSTOM_HOSTNAME_ID>",

    "ssl": {

12 collapsed lines

      "id": "<CERTIFICATE_ID>",

      "bundle_method": "ubiquitous",

      "certificate_authority": "<CERTIFICATE_AUTHORITY>",

      "custom_certificate": "",

      "custom_csr_id": "",

      "custom_key": "",

      "expires_on": "",

      "hosts": [

        "app.example.com",

        "*.app.example.com"

      ],

      "issuer": "",

      "method": "http",

      "settings": {},

      "signature": "SHA256WithRSA",

      "type": "dv",

20 collapsed lines

      "uploaded_on": "2020-02-06T18:11:23.531995Z",

      "validation_errors": [

        {

          "message": "SERVFAIL looking up CAA for app.example.com"

        }

      ],

      "validation_records": [

        {

          "emails": [

            "administrator@example.com",

            "webmaster@example.com"

          ],

          "http_body": "ca3-574923932a82475cb8592200f1a2a23d",

          "http_url": "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",

          "txt_name": "_acme-challenge.app.example.com",

          "txt_value": "810b7d5f01154524b961ba0cd578acc2"

        }

      ],

      "wildcard": false

    },

  }


```

1. After you take note of these values, make a `PATCH` request to the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint, providing both the list of authorized cipher suites and the same `type` and `method` values that you obtained from the previous step.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "ssl": {

        "method": "http",

        "type": "dv",

        "settings": {

            "ciphers": [

                "ECDHE-ECDSA-AES128-GCM-SHA256",

                "ECDHE-RSA-AES128-GCM-SHA256"

            ]

        }

    }

  }'


```

Restrict cipher suites for custom hostname with custom certificate

In the API documentation, refer to [SSL properties of a custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/). In the case of a custom hostname with custom certificate, you must include the custom certificate in the [Edit Custom Hostname PATCH call](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/), with the `settings` specifications where you must include `type` and `method` within the `ssl` object, as explained below.

1. Make a `GET` request to the [Custom Hostname Details](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/get/) endpoint to check what are the current values for `ssl.type` and `ssl.method`.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

Custom Hostname Details

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response example

```

  "success": true,

  "result": {

    "id": "<CUSTOM_HOSTNAME_ID>",

    "ssl": {

12 collapsed lines

      "id": "<CERTIFICATE_ID>",

      "bundle_method": "ubiquitous",

      "certificate_authority": "<CERTIFICATE_AUTHORITY>",

      "custom_certificate": "",

      "custom_csr_id": "",

      "custom_key": "",

      "expires_on": "",

      "hosts": [

        "app.example.com",

        "*.app.example.com"

      ],

      "issuer": "",

      "method": "http",

      "settings": {},

      "signature": "SHA256WithRSA",

      "type": "dv",

20 collapsed lines

      "uploaded_on": "2020-02-06T18:11:23.531995Z",

      "validation_errors": [

        {

          "message": "SERVFAIL looking up CAA for app.example.com"

        }

      ],

      "validation_records": [

        {

          "emails": [

            "administrator@example.com",

            "webmaster@example.com"

          ],

          "http_body": "ca3-574923932a82475cb8592200f1a2a23d",

          "http_url": "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",

          "txt_name": "_acme-challenge.app.example.com",

          "txt_value": "810b7d5f01154524b961ba0cd578acc2"

        }

      ],

      "wildcard": false

    },

  }


```

1. After you take note of these values, make a `PATCH` request to the [Edit Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) endpoint, providing both the list of authorized cipher suites and the same `type` and `method` values that you obtained from the previous step, but also the `custom_certificate` and `custom_key`.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "ssl": {

        "method": "http",

        "type": "dv",

        "custom_certificate": "<CERTIFICATE_STRING>",

        "custom_key": "<CERTIFICATE_PRIVATE_KEY>",

        "settings": {

            "ciphers": [

                "ECDHE-ECDSA-AES128-GCM-SHA256",

                "ECDHE-RSA-AES128-GCM-SHA256"

            ],

            "min_tls_version": "1.2"

        }

    }

  }'


```

## Alerts for mutual TLS certificates

You can configure alerts to receive notifications before your mutual TLS certificates expire.

Access mTLS Certificate Expiration Alert

**Who is it for?**

[Access](https://developers.cloudflare.com/cloudflare-one/access-controls/policies/) customers that use client certificates for mutual TLS authentication. This notification will be sent 30 and 14 days before the expiration of the certificate.

**Other options / filters**

None.

**Included with**

Purchase of [Access](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/mutual-tls-authentication/) and/or [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/).

**What should you do if you receive one?**

Upload a [renewed certificate](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/mutual-tls-authentication/#add-mtls-authentication-to-your-access-configuration).

Refer to [Cloudflare Notifications](https://developers.cloudflare.com/notifications/get-started/) for more information on how to set up an alert.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/","name":"TLS Management"}}]}
```

---

---
title: Issue
description: Cloudflare automatically issues certificates when you create a custom hostname.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Issue

Cloudflare automatically issues certificates when you [create a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/).

Note

There are several required steps before a custom hostname and its certificate can become active. For more details, refer to our [Get started guide](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/).

## Certificate authorities

If you create the custom hostname via API, you can leave the `certificate_authority` parameter empty to set it to “default CA”. With this option, Cloudflare checks the CAA records before requesting the certificates, which helps ensure the certificates can be issued from the CA.

Refer to [this certificate authorities reference page](https://developers.cloudflare.com/ssl/reference/certificate-authorities/) to learn more about the CAs that Cloudflare uses to issue SSL/TLS certificates.

## Certificate details and compatibility

For each custom hostname, Cloudflare issues two certificates bundled in chains that maximize browser compatibility (unless you [upload custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/)).

The primary certificate uses a `P-256` key, is `SHA-2/ECDSA` signed, and will be presented to browsers that support elliptic curve cryptography (ECC). The secondary or fallback certificate uses an `RSA 2048-bit` key, is `SHA-2/RSA` signed, and will be presented to browsers that do not support ECC.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates/","name":"Issue"}}]}
```

---

---
title: Renew
description: The exact method for certificate renewal depends on whether that hostname is active1 and whether it is a wildcard certificate.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/renew-certificates.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Renew

The exact method for certificate renewal depends on whether that hostname is active[1](#user-content-fn-1) and whether it is a wildcard certificate.

Custom hostname certificates have a 90-day validity period and are available for renewal 30 days before their expiration.

## Non-wildcard hostnames

If all of the following are true, Cloudflare will try to perform DCV automatically on the hostname's behalf by serving the [HTTP token](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/).

* You are using a non-wildcard hostname.
* The hostname is active.
* You are not using [Delegated DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/).

If the custom hostname is not active, then the custom hostname domain owner will need to add the TXT or HTTP DCV token for the new certificate to validate and issue. As the SaaS provider, you will be responsible for sharing this token with the custom hostname domain owner.

If you are using Delegated DCV, Cloudflare will continue to add TXT DCV tokens on your behalf as explained in [Issue and validate certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/).

## Wildcard hostnames

With wildcard hostnames, you cannot use HTTP. In this case, you will have to use TXT DCV tokens.

These tokens can be fetched through the API or the dashboard when the certificates are in a [pending validation](https://developers.cloudflare.com/ssl/reference/certificate-statuses/#new-certificates) state during custom hostname creation or during certificate renewals.

If your hostname is using another validation method, you will need to [update](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) the `"method"` field in the SSL object to be `"txt"`.

After this step, follow the normal steps for [TXT validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/).

Note

To allow Cloudflare to auto-renew all future certificate orders, consider [DCV delegation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/).

## Footnotes

1. Meaning Cloudflare could verify your customer's ownership of the hostname and the [hostname status](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/validation-status/) is active. [↩](#user-content-fnref-1)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/renew-certificates/","name":"Renew"}}]}
```

---

---
title: Validate
description: Learn which methods you should use to validate Cloudflare for SaaS certificates.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Validate

Before a certificate authority (CA) will issue a certificate for a domain, the requester must prove they have control over that domain. This process is known as domain control validation (DCV).

  
## DCV situations

### Non-wildcard certificates

Specific (non-wildcard) custom hostnames can use [HTTP based DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/) for certificate renewals, as long as:

* The hostname is pointing to the SaaS provider.
* The hostname's traffic is proxying through the Cloudflare network.

If your custom hostnames do not meet these requirements, use another validation method.

### Wildcard certificates

Wildcard custom hostnames require TXT-based validation. As the SaaS provider, you have two options for wildcard custom hostname certificate renewals:

  
* [DCV Delegation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/) (auto-issuance)
* [Manual](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/)

### Minimize downtime

If you want to minimize downtime, explore one of the following methods to issue and deploy the certificate before onboarding your customers:

* [Delegated DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/): Place a one-time record at your authoritative DNS that allows Cloudflare to auto-renew all future certificate orders.
* [TXT validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/): Have your customers add a `TXT` record to their authoritative DNS.
* [Manual HTTP validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-manual): Add a `TXT` record at your origin.

### Minimize customer effort

If you value simplicity and your customers can handle a few minutes of downtime, you can rely on Cloudflare [automatic HTTP validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-automatic).

## Potential issues

To avoid or solve potential issues, refer to our [troubleshooting guide](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/troubleshooting/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/","name":"Validate"}}]}
```

---

---
title: Delegated
description: Delegated DCV allows SaaS providers to delegate the DCV process to Cloudflare.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Delegated

Delegated DCV allows SaaS providers to delegate the DCV process to Cloudflare.

DCV Delegation requires your customers to place a one-time record at their authoritative DNS that allows Cloudflare to auto-renew all future certificate orders, so that there is no manual intervention from you or your customers at the time of the renewal.

---

## Setup

To set up Delegated DCV:

1. Add a [custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/create-custom-hostnames/) for your zone, choosing `TXT` as the **Certificate validation method**.
2. On the [**Custom Hostnames** ↗](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames) page, go to **DCV Delegation for Custom Hostnames**.
3. Copy the hostname value.
4. For each hostname, the domain owner needs to place a `CNAME` record at their authoritative DNS. In this example, the SaaS zone is `example.com`.  
```  
_acme-challenge.example.com CNAME example.com.<COPIED_HOSTNAME>.  
```

Once this is complete, Cloudflare will place two TXT DCV records - one for `example.com` and one for `*.example.com` \- at the `example.com.<COPIED_HOSTNAME>` hostname. The CNAME record will need to stay in place in order to allow Cloudflare to continue placing the records for the renewals.

If desired, you could also manually fetch the DCV tokens and share them with your customers.

Remove previous TXT records

Existing TXT records for `_acme-challenge` will conflict with the delegated DCV CNAME record. Make sure to check and remove records such as the following:

```

_acme-challenge.example.com TXT <CERTIFICATE_VALIDATION_VALUE>


```

## Moved domains

If you [move your SaaS zone to another account](https://developers.cloudflare.com/fundamentals/manage-domains/move-domain/), you will need to update the `CNAME` record with a new hostname value.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/","name":"Validate"}},{"@type":"ListItem","position":8,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/","name":"Delegated"}}]}
```

---

---
title: HTTP
description: HTTP validation involves adding a DCV token to your customer's origin.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# HTTP

HTTP validation involves adding a DCV token to your customer's origin.

---

## Non-wildcard custom hostnames

If your custom hostname does not include a wildcard, Cloudflare will always and automatically attempt to complete DCV through [HTTP validation](#http-automatic), even if you have selected **TXT** for your validation method.

This HTTP validation should succeed as long as your customer is pointing to your custom hostname and they do not have any [CAA records](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/troubleshooting/#certificate-authority-authorization-caa-records) blocking your chosen certificate authority.

## Wildcard custom hostnames

HTTP DCV validation is not allowed for wildcard certificates. You must use [TXT validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/) instead.

---

## Validation methods

### HTTP (automatic)

If you value simplicity and your customers can handle a few minutes of downtime, you can rely on Cloudflare automatic HTTP validation.

Once you [create a new hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates/) and choose the `http` validation method, all your customers have to do is add a CNAME to your `$CNAME_TARGET` and Cloudflare will take care of the rest.

What happens after you create the custom hostname

Cloudflare contacts one of our certificate authority (CA) providers and asks them to issue certificates for the specified hostname. The CA will then inform Cloudflare that we need to demonstrate control of this hostname by returning a `$DCV_TOKEN` at a specified `$DCV_FILENAME`; both the token and the filename are randomly generated by the CA and not known to Cloudflare ahead of time.

For example, if you create a new custom hostname for `site.example.com`, the CA might ask us to return the value `ca3-38734555d85e4421beb4a3e6d1645fe6` for a request to `http://site.example.com/.well-known/pki-validation/ca3-39f423f095be4983922ca0365308612d.txt"`. As soon as we receive that value from the CA we make it accessible at our edge and ask the CA to confirm it is there so that they can complete validation and the certificate order.

Note

Cloudflare is able to serve a random token from our edge due to the fact that `site.example.com` has a CNAME in place to `$CNAME_TARGET`, which ultimately resolves to Cloudflare IPs. If your customer has not yet added the CNAME, the CA will not be able to retrieve the token and the process will not complete.

We will attempt to retry this validation check for a finite period before timing out. Refer to [Validation Retry Schedule](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/) for more details.

If you would like to complete the issuance process before asking your customer to update their CNAME (or before changing the resolution of your target CNAME to be proxied by Cloudflare), choose another validation method.

### HTTP (manual)

Once you [create a new hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates/) and choose this validation method, you will see the following values after a few seconds:

  
* [**API**](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/get/): Within the `ssl` object, store the values present in the `validation_records` array (specifically `http_url` and `http_body`).
* **Dashboard**: When viewing an individual certificate on the [**Custom Hostnames** ↗](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames) page, refer to the values for **Certificate validation request** and **Certificate validation response**.

At your origin, make the `http_body` available in a TXT record at the path specified in `http_url`. This path should also be publicly accessible to anyone on the Internet so your CA can access it.

Here is an example NGINX configuration that would return a token:

```

location "/.well-known/pki-validation/ca3-0052344e54074d9693e89e27486692d6.txt" {

       return 200 "ca3-be794c5f757b468eba805d1a705e44f6\n";

}


```

Once your configuration is live, test that the DCV text file is in place with `curl`:

Terminal window

```

$ curl "http://http-preval.example.com/.well-known/pki-validation/ca3-0052344e54074d9693e89e27486692d6.txt"

ca3-be794c5f757b468eba805d1a705e44f6


```

The token is valid for one check cycle. On the next check cycle, Cloudflare will ask the CA to recheck the URL, complete validation, and issue the certificate.

If you would like to request an immediate recheck, [rather than wait for the next retry](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/), send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) with the same values as your initial `POST` request.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/","name":"Validate"}},{"@type":"ListItem","position":8,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/","name":"HTTP"}}]}
```

---

---
title: Troubleshooting
description: Occasionally, a domain will be flagged as “high risk” by Cloudflare’s CA partners. Typically this is done only for domains with an Alexa ranking of 1-1,000 and domains that have been flagged for phishing or malware by Google’s Safe Browsing service.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/troubleshooting.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Troubleshooting

## High-risk domains

Occasionally, a domain will be flagged as “high risk” by Cloudflare’s CA partners. Typically this is done only for domains with an Alexa ranking of 1-1,000 and domains that have been flagged for phishing or malware by Google’s Safe Browsing service.

If a domain is flagged by the CA, you need to contact Support before validation can finish. The API call will return indicating the failure, along with a link to where the ticket can be filed.

---

## Certificate Authority Authorization (CAA) records

CAA is a DNS resource record type defined in [RFC 6844 ↗](https://datatracker.ietf.org/doc/html/rfc6844) that allows a domain owner to indicate which CAs are allowed to issue certificates for them.

### For SaaS providers

If your customer has CAA records set on their domain, they will either need to add the following or remove CAA entirely:

```

example.com. IN CAA 0 issue "pki.goog"

example.com. IN CAA 0 issue "letsencrypt.org"

example.com. IN CAA 0 issue "ssl.com"


```

While it is possible for CAA records to be set on the subdomain your customer wishes to use with your service, it will usually be set on the domain apex. If they have CAA records on the subdomain, those will also have to be removed.

### For SaaS customers

In some cases, the validation may be prevented because your hostname points to a CNAME target where CAA records are defined.

In this case you would need to either select a Certificate Authority whose CAA records are present at the target, or review the configuration with the service provider that owns the target.

---

## Time outs

If a certificate issuance times out, the error message will indicate where the timeout occurred:

* Timed Out (Initializing)
* Timed Out (Validation)
* Timed Out (Issuance)
* Timed Out (Deployment)
* Timed Out (Deletion)

To fix this error, send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) through the API or select **Refresh** for the specific custom hostname in the dashboard. If using the API, make sure that the `--data` field contains an `ssl` object with the same `method` and `type` as the original request.

If these return an error, delete and recreate the custom hostname.

---

## Immediate validation checks

You can send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) to request an immediate validation check on any certificate. The PATCH data should include the same `ssl` object as the original request.

---

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/","name":"Validate"}},{"@type":"ListItem","position":8,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/troubleshooting/","name":"Troubleshooting"}}]}
```

---

---
title: TXT
description: TXT record validation requires the creation of a TXT record in the hostname's authoritative DNS.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# TXT

TXT record validation requires the creation of a TXT record in the hostname's authoritative DNS.

  
## When to use

Generally, you should use TXT-based DCV when you cannot use [HTTP validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/) or [Delegated DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/).

### Non-wildcard custom hostnames

If your custom hostname does not include a wildcard, Cloudflare will always and automatically attempt to complete DCV through [HTTP validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-automatic), even if you have selected **TXT** for your validation method.

This HTTP validation should succeed as long as your customer is pointing to your custom hostname and they do not have any [CAA records](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/troubleshooting/#certificate-authority-authorization-caa-records) blocking your chosen certificate authority.

### Wildcard custom hostnames

To validate a certificate on a wildcard custom hostname, you should either set up [Delegated DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/delegated-dcv/) or [TXT-based DCV](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/).

Cloudflare recommends Delegated DCV as it is much simpler for you and your customers.

If you choose TXT-based DCV, Cloudflare requires two TXT DCV tokens - one for the apex and one for the wildcard - to be placed at your customer’s authoritative DNS provider in order for the wildcard certificate to issue or renew.

These two tokens are required because Let’s Encrypt and Google Trust Services follow the [ACME Protocol ↗](https://datatracker.ietf.org/doc/html/rfc8555), which requires one DCV token to be placed for every hostname on the certificate.

This means that - if you choose to use wildcard custom hostnames - you will need a way to share these DCV tokens with your customer.

---

### 1\. Get TXT tokens

Once you [create a new hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/issue-certificates/) and choose this validation method, your tokens will be ready after a few seconds.

These tokens can be fetched through the API or the dashboard when the certificates are in a [pending validation](https://developers.cloudflare.com/ssl/reference/certificate-statuses/#new-certificates) state during custom hostname creation or during certificate renewals.

* [ API ](#tab-panel-3368)
* [ Dashboard ](#tab-panel-3369)

You can access these tokens using the API with the [GET custom hostnames endpoint](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/list/).

For example, here are two tokens highlighted in the API response for a **wildcard** custom hostname.

Response

```

{

  "result": [

    {

      "id": "<HOSTNAME_ID>",

      "hostname": "<HOSTNAME>",

      "ssl": {

        "id": "<CERTIFICATE_ID>",

        "type": "dv",

        "method": "txt",

        "status": "pending_validation",

        "validation_records": [

          {

            "status": "pending",

            "txt_name": "_acme-challenge.<HOSTNAME>",

            "txt_value": "gESljTB8fBT1mIuoEASU0qcK-oTd46baarnU_ZGjJIY"

          },

          {

            "status": "pending",

            "txt_name": "_acme-challenge.<HOSTNAME>",

            "txt_value": "Pd8ViwX8KuA78kLbQHGmdEh4tQSpHBRxiNuJOYStEC0"

          }

        ],

        "settings": {

          "min_tls_version": "1.0"

        },

        "bundle_method": "ubiquitous",

        "wildcard": true,

        "certificate_authority": "google"

      },

      "status": "pending",

      "ownership_verification": {

        "type": "txt",

        "name": "_cf-custom-hostname.<HOSTNAME>",

        "value": "ac4a9a9d-5469-44cb-9d76-cea7541c9ff8"

      },

      "ownership_verification_http": {

        "http_url": "http://<HOSTNAME>/.well-known/cf-custom-hostname-challenge/fabdf93c-a4ce-4075-9f3f-c553a5f93bed",

        "http_body": "ac4a9a9d-5469-44cb-9d76-cea7541c9ff8"

      },

      "created_at": "2022-10-06T19:35:33.143257Z"

    }

  ]

}


```

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select a hostname.
3. Copy the values for **Certificate validation TXT name** and **Certificate validation TXT value**.

If you had previously created a **wildcard** custom hostname, you would need to copy the values for two different validation TXT records.

### 2\. Share with your customer

You will then need to share these TXT tokens with your customers.

### 3\. Add DNS records (customer)

Your customers should place these at their authoritative DNS provider under the `"_acme-challenge"` DNS label. Once these TXT records are in place, validation and certificate issuance will automatically complete.

Note

These tokens are different than the hostname validation tokens.

If you would like to request an immediate recheck, [rather than wait for the next retry](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/), send a [PATCH request](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/) with the same values as your initial `POST` request.

### 4\. (Optional) Fetch new tokens

Your DCV tokens expire after a [certain amount of time](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/reference/token-validity-periods/), depending on your certificate authority.

This means that, if your customers take too long to place their tokens at their authoritative DNS provider, you may need to [get new tokens](#1-get-txt-tokens) and re-share them with your customer.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/","name":"Issue and validate certificates"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/","name":"Validate"}},{"@type":"ListItem","position":8,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/txt/","name":"TXT"}}]}
```

---

---
title: Webhook definitions
description: When you create a webhook notification for SSL for SaaS Custom Hostnames, you may want to automate responses to specific events (certificate issuance, failed validation, etc.).
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/webhook-definitions.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Webhook definitions

When you [create a webhook notification](https://developers.cloudflare.com/notifications/get-started/configure-webhooks/) for **SSL for SaaS Custom Hostnames**, you may want to automate responses to specific events (certificate issuance, failed validation, etc.).

The following section details the data Cloudflare sends to a webhook destination.

## Certificate validation

Before a Certificate Authority will issue a certificate for a domain, the requester must prove they have control over that domain. This process is known as [domain control validation (DCV)](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).

### Validation succeeded

Cloudflare sends this alert when certificates move from a status of `pending_validation` to `pending_issuance`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.validation.succeeded",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_issuance",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Validation failed

Cloudflare sends this alert each time a certificate remains in a `pending_validation` status during [DCV retries](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/).

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.validation.failed",

      "created_at": "2018-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_validation",

      "cname": "_ca3-64ce913ebfe74edeb2e8813e3928e359.app.example2.com",

      "cname_target": "dcv.digicert.com",

      "validation_errors": [

        {

          "message": "blog.example.com reported as potential risk: google_safe_browsing"

        }

      ],

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

---

## Certificate issuance

Once validated, certificates are issued by Cloudflare in conjunction with your chosen [certificate authority](https://developers.cloudflare.com/ssl/reference/certificate-authorities/).

### Issuance succeeded

Cloudflare sends this alert when certificates move from a status of `pending_validation` or `pending_issuance` to `pending_deployment`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.issuance.succeeded",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_deployment",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Issuance failed

Cloudflare sends this alert each time a certificate remains in a status of `pending_issuance` during [DCV retries](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/).

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.issuance.failed",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_issuance",

      "cname": "_ca3-64ce913ebfe74edeb2e8813e3928e359.app.example2.com",

      "cname_target": "dcv.digicert.com",

      "validation_errors": [

        {

          "message": "caa_error: blog.example.com"

        }

      ],

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

---

## Certificate deployment

Once issued, certificates are deployed to Cloudflare's global edge network.

### Deployment succeeded

Cloudflare sends this alert when certificates move from a status of `pending_deployment` to `active`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.deployment.succeeded",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "active",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Deployment failed

Cloudflare sends this alert each time a certificate remains in a status of `pending_deployment` during [DCV retries](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/).

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.deployment.failed",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_deployment",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

---

## Certificate deletion

### Deletion succeeded

Cloudflare sends this alert when certificates move from a status of `pending_deletion` to `deleted`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.deletion.succeeded",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "deleted"

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Deletion failed

Cloudflare sends this alert each time a certificate remains in status of `pending_deletion` during [DCV retries](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/validation-backoff-schedule/).

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.deletion.failed",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_deletion"

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

---

## Certificate renewal

Once issued, certificates are valid for a period of time depending on the [certificate authority](https://developers.cloudflare.com/ssl/reference/certificate-validity-periods/).

The actions that you need to perform to renew certificates depend on your [validation method](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/renew-certificates/).

### Upcoming renewal

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.renewal.upcoming_certificate_expiration_notification",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "status": "active",

      "hosts": ["blog.example.com"],

      "issuer": "DigiCertInc",

      "serial_number": "1001172778337169491",

      "signature": "ECDSAWithSHA256",

      "uploaded_on": "2021-11-17T04:33:54.561747Z",

      "expires_on": "2022-11-21T12:00:00Z",

      "custom_csr_id": "7b163417-1d2b-4c84-a38a-2fb7a0cd7752",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Renewal succeeded

Cloudflare sends this alert when certificates move from a status of `active` to `pending_deployment`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.renewal.succeeded",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_deployment",

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

### Renewal failed

Cloudflare sends this alert when certificates move from a status of `active` to `pending_issuance`.

```

{

  "metadata": {

    "event": {

      "id": "<<WEBHOOK_ID>",

      "type": "ssl.custom_hostname_certificate.renewal.failed",

      "created_at": "2022-02-09T00:03:28.385080Z"

    },

    "account": {

      "id": "<<ACCOUNT_ID>"

    },

    "zone": {

      "id": "<<ZONE_ID>"

    }

  },

  "data": {

    "id": "<<CUSTOM_HOSTNAME_ID>",

    "hostname": "blog.com",

    "ssl": {

      "id": "<<CERTIFICATE_ID>",

      "type": "dv",

      "method": "cname",

      "status": "pending_issuance",

      "cname": "_ca3-64ce913ebfe74edeb2e8813e3928e359.app.example2.com",

      "cname_target": "dcv.digicert.com",

      "validation_errors": [

        {

          "message": "caa_error: blog.example.com"

        }

      ],

      "settings": {

        "min_tls_version": "1.2",

        "http2": "on"

      }

    },

    "custom_metadata": {

      "key1": "value1",

      "key2": "value2"

    },

    "custom_origin_server": "0001.blog.com"

  }

}


```

## Troubleshooting

Occasionally, you may see webhook notifications that do not include a corresponding `<<CUSTOM_HOSTNAME_ID>>` and `hostname` values.

This behavior is because each custom hostname can only have one certificate attached to it. Previously attached certificates can still emit webhook events but will not include the associated hostname and ID values.

## Alerts

You can configure alerts to receive notifications for changes in your custom hostname certificates.

SSL for SaaS Custom Hostnames Alert

**Who is it for?**

Customers with custom hostname certificates who want to receive a notification on validation, issuance, renewal, and expiration of certificates. For more details around data formatting for webhooks, refer to the [Cloudflare for SaaS docs](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/webhook-definitions/).

**Other options / filters**

None.

**Included with**

Purchase of [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/).

**What should you do if you receive one?**

You only need to take action if you are notified that you have a certificate that failed. You can find the reasons why a certificate is not being issued in [Troubleshooting SSL errors](https://developers.cloudflare.com/ssl/troubleshooting/general-ssl-errors/).

Refer to [Cloudflare Notifications](https://developers.cloudflare.com/notifications/get-started/) for more information on how to set up an alert.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/","name":"Certificate management"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/webhook-definitions/","name":"Webhook definitions"}}]}
```

---

---
title: Secure with Cloudflare Access
description: Cloudflare Access provides visibility and control over who has access to your custom hostnames. You can allow or block users based on identity, device posture, and other Access rules.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/secure-with-access.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Secure with Cloudflare Access

Cloudflare Access provides visibility and control over who has access to your [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/). You can allow or block users based on identity, device posture, and other [Access rules](https://developers.cloudflare.com/cloudflare-one/access-controls/policies/).

## Prerequisites

* You must have an active custom hostname. For setup instructions, refer to [Configuring Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/).
* You must have a Cloudflare Zero Trust plan in your SaaS provider account. Learn more about [getting started with Zero Trust](https://developers.cloudflare.com/cloudflare-one/setup/).
* You can only run Access on custom hostnames if they are managed externally to Cloudflare or in a separate Cloudflare account. If the custom hostname zone is in the same account as the SaaS zone, the Access application will not be applied.

## Setup

1. At your SaaS provider account, select [Zero Trust ↗](https://one.dash.cloudflare.com).
2. Go to **Access** \> **Applications**.
3. Select **Add an application** and, for type of application, select **Self-hosted**.
4. Enter a name for your Access application and, in **Session Duration**, choose how often the user's [application token](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/authorization-cookie/application-token/) should expire.
5. Select **Add public hostname**.
6. For **Input method**, select _Custom_.
7. In **Hostname**, enter your custom hostname (for example, `mycustomhostname.com`).
8. Follow the remaining [self-hosted application creation steps](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/) to publish the application.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/secure-with-access/","name":"Secure with Cloudflare Access"}}]}
```

---

---
title: WAF for SaaS
description: Web Application Firewall (WAF) allows you to create additional security measures through Cloudflare. As a SaaS provider, you can link custom rules, rate limiting rules, and managed rules to your custom hostnames. This provides more control to keep your domains safe from malicious traffic.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# WAF for SaaS

[Web Application Firewall (WAF)](https://developers.cloudflare.com/waf/) allows you to create additional security measures through Cloudflare. As a SaaS provider, you can link custom rules, rate limiting rules, and managed rules to your custom hostnames. This provides more control to keep your domains safe from malicious traffic.

As a SaaS provider, you may want to apply different security measures to different custom hostnames. With WAF for SaaS, you can create multiple WAF configuration that you can apply to different sets of custom hostnames. This added flexibility and security leads to optimal protection across the domains of your end customers.

---

## Prerequisites

Before you can use WAF for SaaS, you need to create a custom hostname. Review [Get started with Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) if you have not already done so.

You can also create a custom hostname through the API:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Create Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames" \

  --request POST \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "hostname": "<CUSTOM_HOSTNAME>",

    "ssl": {

        "wildcard": false

    }

  }'


```

## 1\. Associate custom metadata to a custom hostname

To apply WAF to your custom hostname, you need to create an association between your customer's domain and the WAF configuration that you would like to attach to it. Cloudflare's product, [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) allows you to do this via the API.

1. [Locate your zone ID](https://developers.cloudflare.com/fundamentals/account/find-account-and-zone-ids/), available in the Cloudflare dashboard.
2. Locate your Authentication Key on the [**API Tokens** ↗](https://dash.cloudflare.com/?to=/:account/profile/api-tokens) page, under **Global API Key**.
3. Locate your custom hostname ID by making a `GET` call in the API:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`
* `SSL and Certificates Read`

List Custom Hostnames

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

1. Plan your [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/). It is fully customizable. In the example below, we have chosen the tag `"security_level"` to which we expect to assign three values (low, medium, and high).

Note

One instance of low, medium, and high rules could be rate limiting. You can specify three different thresholds: low - 100 requests/minute, medium - 85 requests/minute, high - 50 requests/minute, for example. Another possibility is a WAF custom rule in which low challenges requests and high blocks them.

1. Make an API call in the format below using your Cloudflare email and the IDs gathered above:

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `SSL and Certificates Write`

Edit Custom Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$CUSTOM_HOSTNAME_ID" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "custom_metadata": {

        "customer_id": "12345",

        "security_level": "low"

    }

  }'


```

This assigns custom metadata to your custom hostname so that it has a security tag associated with its ID.

## 2\. Trigger security products based on tags

1. Locate the custom metadata field in the Ruleset Engine where the WAF runs. This can be used to trigger different configurations of products such as [WAF custom rules](https://developers.cloudflare.com/waf/custom-rules/), [rate limiting rules](https://developers.cloudflare.com/waf/rate-limiting-rules/), and [Transform Rules](https://developers.cloudflare.com/rules/transform/).
2. Build your rules either [through the dashboard](https://developers.cloudflare.com/waf/custom-rules/create-dashboard/) or via the API. An example rate limiting rule, corresponding to `"security_level"` low, is shown below as an API call.

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `Response Compression Write`
* `Config Settings Write`
* `Dynamic URL Redirects Write`
* `Cache Settings Write`
* `Custom Errors Write`
* `Origin Write`
* `Managed headers Write`
* `Zone Transform Rules Write`
* `Mass URL Redirects Write`
* `Magic Firewall Write`
* `L4 DDoS Managed Ruleset Write`
* `HTTP DDoS Managed Ruleset Write`
* `Sanitize Write`
* `Transform Rules Write`
* `Select Configuration Write`
* `Bot Management Write`
* `Zone WAF Write`
* `Account WAF Write`
* `Account Rulesets Write`
* `Logs Write`
* `Logs Write`

Update a zone entry point ruleset

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_ratelimit/entrypoint" \

  --request PUT \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "rules": [

        {

            "action": "block",

            "ratelimit": {

                "characteristics": [

                    "cf.colo.id",

                    "ip.src"

                ],

                "period": 10,

                "requests_per_period": 2,

                "mitigation_timeout": 60

            },

            "expression": "lookup_json_string(cf.hostname.metadata, \"security_level\") eq \"low\" and http.request.uri contains \"login\""

        }

    ]

  }'


```

To build rules through the dashboard:

1. In the Cloudflare dashboard, go to the **WAF** page.  
[ Go to **WAF** ](https://dash.cloudflare.com/?to=/:account/application-security/waf)
2. Follow the instructions on the dashboard specific to custom rules, rate limiting rules, or managed rules, depending on your security goal.
3. Once the rule is active, you should see it under the applicable tab (custom rules, rate limiting, or managed rules).  
Warning  
This API call will replace any existing rate limiting rules in the zone.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/","name":"WAF for SaaS"}}]}
```

---

---
title: Managed rulesets
description: If you are interested in WAF for SaaS but unsure of where to start, Cloudflare recommends using WAF Managed Rules. The Cloudflare security team creates and manages a variety of rules designed to detect common attack vectors and protect applications from vulnerabilities. These rules are offered in managed rulesets, like Cloudflare Managed and OWASP, which can be deployed with different settings and sensitivity levels.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/managed-rulesets.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Managed rulesets

If you are interested in [WAF for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/) but unsure of where to start, Cloudflare recommends using WAF Managed Rules. The Cloudflare security team creates and manages a variety of rules designed to detect common attack vectors and protect applications from vulnerabilities. These rules are offered in [managed rulesets](https://developers.cloudflare.com/waf/managed-rules/), like Cloudflare Managed and OWASP, which can be deployed with different settings and sensitivity levels.

---

## Prerequisites

WAF for SaaS is available for customers on an Enterprise plan.

If you would like to deploy a managed ruleset at the account level, refer to the [WAF documentation](https://developers.cloudflare.com/waf/account/managed-rulesets/deploy-dashboard/).

Ensure you have reviewed [Get Started with Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) and familiarize yourself with [WAF for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/).

Customers can automate the [custom metadata](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) tagging by adding it to the custom hostnames at creation. For more information on tagging a custom hostname with custom metadata, refer to the [API documentation](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/).

---

## 1\. Choose security tagging system

1. Outline `security_tag` buckets. These are fully customizable with no strict limit on quantity. For example, you can set `security_tag` to `low`,`medium`, and `high` as a default, with one tag per custom hostname.
2. If you have not already done so, [associate your custom metadata to custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/#1-associate-custom-metadata-to-a-custom-hostname) by including the `security_tag`in the custom metadata associated with the custom hostname. The JSON blob associated with the custom hostname is fully customizable.

After the association is complete, the JSON blob is added to the defined custom hostname. This blob is then associated to every incoming request and exposed in the WAF through the [cf.hostname.metadata](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/reference/cf.hostname.metadata/) field. In the rule, you can access `cf.hostname.metadata` and get the data you need from that blob.

---

## 2\. Deploy rulesets

Note

Account-level WAF requires an Enterprise plan with a paid add-on.

1. In the Cloudflare dashboard, go to the **WAF** page.  
[ Go to **WAF** ](https://dash.cloudflare.com/?to=/:account/application-security/waf)
2. Go to the **Managed rulesets** tab.
3. Select **Deploy** \> **Deploy managed ruleset**.
4. Next to **Cloudflare Managed Ruleset**, choose **Select ruleset**.
5. Give a name to the rule deploying the ruleset in **Execution name**.
6. Select **Edit scope** to execute the managed ruleset for a subset of incoming requests.
7. Select **Custom filter expression**.
8. Select **Edit expression** to switch to the [Expression Editor](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/edit-expressions/#expression-editor).
9. The basic expression should look like this, plus any logic you would like to add (like filtering by a specific custom hostname with `http.host eq "<HOSTNAME>"`):  
```  
(lookup_json_string(cf.hostname.metadata, "security_tag") eq "low") and (cf.zone.plan eq "ENT")  
```  
Note  
Rulesets deployed at the account level will only apply to incoming traffic of Enterprise domains on your account. When you define a custom expression using the Expression Editor, use parentheses to enclose any custom conditions and end your expression with `and (cf.zone.plan eq "ENT")` so that the rule only applies to domains on an Enterprise plan.
10. Select **Next**.
11. (Optional) You can modify the ruleset configuration by changing, for example, what rules are enabled or what action should be the default.
12. Select **Deploy**.

## Next steps

While this guide uses the Cloudflare Managed Ruleset, you can also create a custom ruleset and deploy on your custom hostnames. To do this, go to the **Custom rulesets** tab and select **Create ruleset**. For examples of a low/medium/high ruleset, refer to [WAF for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/","name":"Security"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/","name":"WAF for SaaS"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/security/waf-for-saas/managed-rulesets/","name":"Managed rulesets"}}]}
```

---

---
title: Apex proxying
description: Apex proxying allows your customers to use their apex domains (example.com) with your SaaS application.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/index.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Apex proxying

Apex proxying allows your customers to use their apex domains (`example.com`) with your SaaS application.

Note

Only certain customers have access to this feature. For more details, see the [Plans page](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

## Benefits

In a normal Cloudflare for SaaS [setup](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/), your customers route traffic to your hostname by creating a `CNAME` record pointing to your CNAME target.

However, most DNS providers do not allow `CNAME` records at the zone's root[1](#user-content-fn-1). This means that your customers have to use a subdomain as a vanity domain (`shop.example.com`) instead of their domain apex (`example.com`).

This limitation does not apply with apex proxying. Cloudflare assigns a set of IP prefixes - cost associated, reach out to your account team - to your account (or uses your own if you have [BYOIP](https://developers.cloudflare.com/byoip/)). This means that customers can create a standard `A` record to route traffic to your domain, which can support the domain apex.

## Setup

* [Set up Apex Proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/setup/)

## Footnotes

1. Cloudflare offers this functionality through [CNAME flattening](https://developers.cloudflare.com/dns/cname-flattening/). [↩](#user-content-fnref-1)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/","name":"Advanced Settings"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/","name":"Apex proxying"}}]}
```

---

---
title: Setup
description: To set up Cloudflare for SaaS for apex proxying - as opposed to the normal setup - perform the following steps.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/setup.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Setup

To set up Cloudflare for SaaS for [apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/) \- as opposed to the [normal setup](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) \- perform the following steps.

---

## Before you begin

Before you start creating custom hostnames:

1. [Add](https://developers.cloudflare.com/fundamentals/manage-domains/add-site/) your zone to Cloudflare (this should be within the account associated with your IP prefixes).
2. [Enable](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/enable/) Cloudflare for SaaS for your zone.
3. Review the [Hostname prioritization guidelines](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority). Wildcard custom hostnames behave differently than an exact hostname match.
4. (optional) Review the following documentation:
* [API documentation](https://developers.cloudflare.com/fundamentals/api/) (if you have not worked with the Cloudflare API before).
* [Certificate validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).

---

## Initial setup

When you first [enable](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/enable/) Cloudflare for SaaS, you need to perform a few steps prior to creating any custom hostnames.

  
### 1\. Get IP range

With apex proxying, you can either [bring your own IP range](https://developers.cloudflare.com/byoip/) or use a set of IP addresses provided by Cloudflare.

For more details on this step, reach out to your account team.

Warning

These IP addresses are different than those associated with your Cloudflare zone.

### 2\. Create fallback origin

The fallback origin is where Cloudflare will route traffic sent to your custom hostnames (must be proxied).

Note

To route custom hostnames to distinct origins, refer to [custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/).

To create your fallback origin:

1. [Create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a proxied `A`, `AAAA`, or `CNAME` record pointing to the IP address of your fallback origin (where Cloudflare will send custom hostname traffic).

| **Type** | **Name**       | **IPv4 address** | **Proxy status** |
| -------- | -------------- | ---------------- | ---------------- |
| A        | proxy-fallback | 192.0.2.1        | Proxied          |

1. Designate that record as your fallback origin.

* [ Dashboard ](#tab-panel-3370)
* [ API ](#tab-panel-3371)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. For **Fallback Origin**, enter the hostname for your fallback origin.
3. Select **Add Fallback Origin**.

Using the hostname of the record you just created, [update the fallback origin value](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/fallback%5Forigin/methods/update/).

1. Once you have added the fallback origin, confirm that its status is **Active**.

Note

When Cloudflare marks your fallback origin as **Active**, that only reflects that we are ready to send traffic to that DNS record.

You need to make sure your DNS record is sending traffic to the correct origin location.

---

## Per-hostname setup

You need to perform the following steps for each custom hostname.

### 1\. Plan for validation

Before you create a hostname, you need to plan for:

1. [Certificate validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/): Upon successful validation, the certificates are deployed to Cloudflare’s global network.
2. [Hostname validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/): Upon successful validation, Cloudflare proxies traffic for this hostname.

You must complete both these steps for the hostname to work as expected.

Note

Depending on which method you select for each of these options, additional steps might be required for you and your customers.

### 2\. Create custom hostname

After planning for certification and hostname validation, you can create the custom hostname.

Zone name restriction

Do not configure a custom hostname which matches the zone name. For example, if your SaaS zone is `example.com`, do not create a custom hostname named `example.com`.

To create a custom hostname:

* [ Dashboard ](#tab-panel-3372)
* [ API ](#tab-panel-3373)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select **Add Custom Hostname**.
3. Add your customer's hostname `app.customer.com` and set the relevant options, including:  
   * The [minimum TLS version](https://developers.cloudflare.com/ssl/reference/protocols/).  
   * Defining whether you want to use a certificate provided by Cloudflare or [upload a custom certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/).  
   * Selecting the [certificate authority (CA)](https://developers.cloudflare.com/ssl/reference/certificate-authorities/) that will issue the certificate.  
   * Choosing the [validation method](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).  
   * Whether you want to **Enable wildcard**, which adds a `*.<custom-hostname>` SAN to the custom hostname certificate. For more details, refer to [Hostname priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority).  
   * Choosing a value for [Custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/).
4. Select **Add Custom Hostname**.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

1. To create a custom hostname using the API, use the [Create Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) endpoint.  
   * You can leave the `certificate_authority` parameter empty to set it to "default CA". With this option, Cloudflare checks the CAA records before requesting the certificates, which helps ensure the certificates can be issued from the CA.
2. For the newly created custom hostname, the `POST` response may not return the DCV validation token `validation_records`. It is recommended to make a second [GET command](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/list/) (with a delay) to retrieve these details.

The response contains the complete definition of the new custom hostname.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

Note

For each custom hostname, Cloudflare issues two certificates bundled in chains that maximize browser compatibility (unless you [upload custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/)).

The primary certificate uses a `P-256` key, is `SHA-2/ECDSA` signed, and will be presented to browsers that support elliptic curve cryptography (ECC). The secondary or fallback certificate uses an `RSA 2048-bit` key, is `SHA-2/RSA` signed, and will be presented to browsers that do not support ECC.

### 3\. Have customer create DNS record

To finish the custom hostname setup, your customer can set up either an A or CNAME record at their authoritative DNS provider.

Note

If you want your customers to be able to use CNAME records, you will need to complete the [normal setup process](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/) as well.

#### A record

If your customer uses an A record at their authoritative DNS provider, they need to point their hostname to the IP prefix allocated for your account. You should also make sure that they point to the specific IPs that you want to use for apex proxying - if you have Static IPs or BYOIP, and your customer points to any of the IPs associated to your account, validation will run.

Warning

Before your customer does this step, confirm that the hostname's **Certificate status** and **Hostname status** are both **Active**.

If not, confirm that you are using a method of [certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-automatic) or [hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/) validation that occurs after your customer adds their DNS record.

Your customer's A record might look like the following:

```

example.com.  60  IN  A   192.0.2.1


```

#### CNAME record

If your customer uses a CNAME record at their authoritative DNS, they need to point their hostname to your [CNAME target](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#2-optional-create-cname-target) [1](#user-content-fn-1).

Warning

Before your customer does this step, confirm that the hostname's **Certificate status** and **Hostname status** are both **Active**.

If not, confirm that you are using a method of [certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-automatic) or [hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/) validation that occurs after your customer adds their DNS record.

Your customer's CNAME record might look like the following:

```

mystore.com CNAME customers.saasprovider.com


```

#### Service continuation

If your customer is also using Cloudflare for their domain, they should keep their DNS record pointing to your SaaS provider in place for as long as they want to use your service.

For more details, refer to [Remove custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames/).

## Footnotes

1. If you have [regional services](https://developers.cloudflare.com/data-localization/regional-services/) set up for your custom hostnames, Cloudflare always uses the processing region associated with your DNS target record (instead of the processing region of any [custom origins](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/)).  
[↩](#user-content-fnref-1)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/","name":"Advanced Settings"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/","name":"Apex proxying"}},{"@type":"ListItem","position":7,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/setup/","name":"Setup"}}]}
```

---

---
title: Custom origin server
description: A custom origin server lets you send traffic from one or more custom hostnames to somewhere besides your default proxy fallback, such as:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Custom origin server

A **custom origin server** lets you send traffic from one or more custom hostnames to somewhere besides your default proxy fallback, such as:

* `soap.stores.com` goes to `origin1.com`
* `towel.stores.com` goes to `origin2.com`

## Requirements

To use a custom origin server, you need to meet the following requirements:

* Each custom origin needs to be a valid hostname with a proxied (orange-clouded) A, AAAA, or CNAME record in your account's DNS. You cannot use an IP address.
* The DNS record for the custom origin server does not currently support wildcard values.

## Use a custom origin

To use a custom origin, select that option when [creating a new custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/) in the dashboard or include the `"custom_origin_server": your_custom_origin_server` parameter when using the API [POST command](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/).

## SNI rewrites

Note

Only certain customers have access to this feature. For more details, see the [Plans page](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

When Cloudflare establishes a connection to your default origin server, the `Host` header and SNI will both be the value of the original custom hostname.

However, if you configure that custom hostname with a custom origin, the value of the SNI will be that of the custom origin and the `Host` header will be the original custom hostname. Since these values will not match, you will not be able to use the [Full (strict)](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/) on your origins.

To solve this problem, you can contact your account team to request an entitlement for **SNI rewrites**.

### SNI rewrite options

Choose how your custom hostname populates the SNI value with SNI rewrites:

* **Origin server name** (default): Set SNI to the custom origin  
   * If custom origin is `custom-origin.example.com`, then the SNI is `custom-origin.example.com`.
* **Host header**: Set SNI to the host header (or a host header override)  
   * If wildcards are not enabled and the hostname is `example.com`, then the SNI is `example.com`.  
   * If wildcards are enabled, the hostname is `example.com`, and a request comes to `www.example.com`, then the SNI is `www.example.com`.
* **Subdomain of zone**: Choose what to set as the SNI value (custom hostname or any subdomain)  
   * If wildcards are not enabled and a request comes to `example.com`, choose whether to set the SNI as `example.com` or `www.example.com`.  
   * If wildcards are enabled, you set the SNI to `example.com`, and a request comes to `www.example.com`, then the SNI is `example.com`.

Important

* Currently, SNI Rewrite is not supported for wildcard custom hostnames. Subdomains covered by a wildcard custom hostname send the custom origin server name as the SNI value.
* In the [O2O context](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/) (when requests are originating from a proxied hostname on a zone also on Cloudflare), changing the SNI value to use host header is currently not supported.
* SNI overrides defined in an [Origin Rule](https://developers.cloudflare.com/rules/origin-rules/) will take precedence over SNI rewrites.
* SNI Rewrite usage is subject to the [Service-Specific Terms ↗](https://www.cloudflare.com/service-specific-terms-application-services/#ssl-for-saas-terms).

### Set an SNI rewrite

To set an SNI rewrite in the dashboard, choose your preferred option from **Origin SNI value** when [creating a custom hostname](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/).

To set an SNI rewrite via the API, set the `custom_origin_sni` parameter when [creating a custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/):

* **Custom origin name** (default): Applies if you do not set the parameter
* **Host header**: Specify `":request_host_header:"`
* **Subdomain of zone**: Set to `"example.com"` or another subdomain of the custom hostname

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/","name":"Advanced Settings"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/","name":"Custom origin server"}}]}
```

---

---
title: Get started
description: You can use Regional Services through the dashboard or via API.
image: https://developers.cloudflare.com/zt-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/data-localization/regional-services/get-started.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Get started

Note

Interested customers need to contact their account team to enable DNS Regionalisation.

You can use Regional Services through the dashboard or via API.

## Configure Regional Services in the dashboard

To use Regional Services, you need to first create a DNS record in the dashboard:

1. In the Cloudflare dashboard, go to the **Records** page.  
[ Go to **Records** ](https://dash.cloudflare.com/?to=/:account/:zone/dns/records)
2. Follow these steps to [create a DNS record](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/).
3. From the **Region** dropdown, select the region you would like to use on your domain. This value will be applied to all DNS records on the same hostname. This means that if you have two DNS records of the same hostname and change the region for one of them, both records will have the same region.

Note

Some regions may not appear on the dropdown because newly announced regions mentioned in the [blog post ↗](https://blog.cloudflare.com/expanding-regional-services-configuration-flexibility-for-customers) are subject to approval by Cloudflare's internal team. For more information and entitlement reach out to your account team.

Refer to the table on [Available regions and product support](https://developers.cloudflare.com/data-localization/region-support/) for the complete list of available regions, their definitions and product support

## Configure Regional Services via API

You can also use Regional Services via API.

Currently, only SuperAdmins and Admin roles can edit DLS configurations. Use the Zone-level **DNS: Read/Write** API permission for the `/addressing/` endpoint to read or write Regional Services configurations.

These are some examples of API requests.

List all the available regions

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Read`
* `DNS Write`

List Regions

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/addressing/regional_hostnames/regions" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response

```

{

  "success": true,

  "errors": [],

  "result": [

    {

      "key": "ca",

      "label": "Canada"

    },

    {

      "key": "eu",

      "label": "Europe"

    }

  ],

  "messages": []

}


```

Create a new regional hostname entry

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Write`

Create Regional Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/addressing/regional_hostnames" \

  --request POST \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "hostname": "ca.regional.ipam.rocks",

    "region_key": "ca"

  }'


```

Response

```

{

  "success": true,

  "errors": [],

  "result": {

    "hostname": "ca.regional.ipam.rocks",

    "region_key": "ca",

    "created_on": "2023-01-13T23:59:45.276558Z"

  },

  "messages": []

}


```

List all regional hostnames for a zone or get a specific one

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Read`
* `DNS Write`

List Regional Hostnames

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/addressing/regional_hostnames" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response

```

{

  "success": true,

  "errors": [],

  "result": [

    {

      "hostname": "ca.regional.ipam.rocks",

      "region_key": "ca",

      "created_on": "2023-01-14T00:47:57.060267Z"

    }

  ],

  "messages": []

}


```

List all regional hostnames for a specific zone

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Read`
* `DNS Write`

Fetch Regional Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/addressing/regional_hostnames/$HOSTNAME" \

  --request GET \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response

```

{

  "success": true,

  "errors": [],

  "result": {

    "hostname": "ca.regional.ipam.rocks",

    "region_key": "ca",

    "created_on": "2023-01-13T23:59:45.276558Z"

  },

  "messages": []

}


```

Patch the region for a specific hostname

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Write`

Update Regional Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/addressing/regional_hostnames/$HOSTNAME" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "region_key": "eu"

  }'


```

Response

```

{

  "success": true,

  "errors": [],

  "result": {

    "hostname": "ca.regional.ipam.rocks",

    "region_key": "eu",

    "created_on": "2023-01-13T23:59:45.276558Z"

  },

  "messages": []

}


```

Delete the region configuration

Required API token permissions

At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:
* `DNS Write`

Delete Regional Hostname

```

curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/addressing/regional_hostnames/$HOSTNAME" \

  --request DELETE \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"


```

Response

```

{

  "success": true,

  "errors": [],

  "result": null,

  "messages": []

}


```

## Verify regional map for Zero Trust

To verify that your regional map is being applied correctly, check the `IngressColoName` field in your [Zero Trust Network Session logs](https://developers.cloudflare.com/logs/logpush/logpush-job/datasets/account/zero%5Ftrust%5Fnetwork%5Fsessions/#ingresscoloname). This field shows the name of the Cloudflare data center where traffic ingressed. Since regionalization is applied upstream from Gateway, the ingress data center will be located within your configured regional map, confirming that traffic is being processed in the correct region.

## Terraform support

You can also configure Regional Services using Terraform. For more details, refer to the [cloudflare\_regional\_hostname resource ↗](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/regional%5Fhostname) in the Terraform documentation.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/data-localization/","name":"Data Localization Suite"}},{"@type":"ListItem","position":3,"item":{"@id":"/data-localization/regional-services/","name":"Regional Services"}},{"@type":"ListItem","position":4,"item":{"@id":"/data-localization/regional-services/get-started/","name":"Get started"}}]}
```

---

---
title: Workers as your fallback origin
description: Learn how to use a Worker as the fallback origin for your SaaS zone.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/worker-as-origin.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Workers as your fallback origin

If you are building your application on [Cloudflare Workers](https://developers.cloudflare.com/workers/), you can use a Worker as the origin for your SaaS zone (also known as your fallback origin).

## How custom hostname traffic reaches your Worker

When customers point their domains to your SaaS zone (for example, `mystore.customer.com` CNAMEs to `service.saasprovider.com`), their traffic enters your Cloudflare zone. Any Worker routes configured on your zone will match this incoming traffic.

For example, if you have:

* Your SaaS zone: `saasprovider.com`
* Your fallback origin: `service.saasprovider.com`
* Customer's custom hostname: `mystore.customer.com` (pointed to your zone via CNAME)
* Worker route: `*/*`

When a visitor requests `mystore.customer.com`, Cloudflare routes that request through your zone. The `*/*` route pattern matches all traffic entering your zone, including traffic from custom hostnames like `mystore.customer.com`.

Note

You do not need to add individual Worker routes for each custom hostname. The wildcard route pattern (`*/*`) automatically captures all traffic entering your zone, including traffic from customer vanity domains.

## Set up a Worker as your fallback origin

1. In your SaaS zone, [create and set a fallback origin](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#1-create-fallback-origin). Ensure the fallback origin only has an [originless DNS record](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#originless-setups):  
   * **Example**: `service.example.com AAAA 100::`
2. In that same zone, navigate to **Workers Routes**.
3. Click **Add route**.
4. Configure a route to send traffic to your Worker. Choose one of the following options based on your needs:  
   * **Route all traffic to the Worker** (recommended for most SaaS applications):  
         * **Route**: `*/*`  
         * **Worker**: Select the Worker used for your SaaS application.  
   This pattern routes all traffic entering your zone to the Worker, including requests from custom hostnames (for example, `mystore.customer.com`) and requests to your own subdomains (for example, `app.saasprovider.com`).  
   * **Route all but specific routes to worker**:  
         * **Route**: `*/*`  
         * **Worker**: Select the Worker used for your SaaS application.  
         * Add a second route for your zone's own hostnames with **Worker** set to **None** to exclude them.  
   For example, if your zone is `saasprovider.com` and you want `api.saasprovider.com` to bypass the Worker, create an additional route `api.saasprovider.com/*` with no Worker assigned. More specific routes take precedence over wildcard routes.  
   * **Route only custom hostname traffic to the Worker**:  
   * **Route**: `vanity.customer.com`  
   * **Worker**: Select the Worker used for your SaaS application.
5. Click **Save**.

---

Zone name restriction

Do not configure a custom hostname which matches the zone name. For example, if your SaaS zone is `example.com`, do not create a custom hostname named `example.com`.

## Related resources

* [Hostname routing](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/hostname-routing/) \- Learn about advanced routing patterns, including dispatch Workers and O2O behavior.
* [Workers routes](https://developers.cloudflare.com/workers/configuration/routing/routes/) \- Learn more about route pattern matching and validity rules.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/","name":"Advanced Settings"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/worker-as-origin/","name":"Workers as your fallback origin"}}]}
```

---

---
title: Common API Calls
description: As a SaaS provider, you may want to configure and manage Cloudflare for SaaS via the API rather than the Cloudflare dashboard. Below are relevant API calls for creating, editing, and deleting custom hostnames, as well as monitoring, updating, and deleting fallback origins. Further details can be found in the Cloudflare API documentation.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/common-api-calls.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Common API Calls

As a SaaS provider, you may want to configure and manage Cloudflare for SaaS [via the API](https://developers.cloudflare.com/api/) rather than the [Cloudflare dashboard ↗](https://dash.cloudflare.com/). Below are relevant API calls for creating, editing, and deleting custom hostnames, as well as monitoring, updating, and deleting fallback origins. Further details can be found in the [Cloudflare API documentation](https://developers.cloudflare.com/api/).

---

## Custom hostnames

| Endpoint                                                                                                     | Notes                                                                                                                                 |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| [List custom hostnames](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/list/)    | Use the page parameter to pull additional pages. Add a hostname parameter to search for specific hostnames.                           |
| [Create custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) | In the validation\_records object of the response, use the txt\_name and txt\_record listed to validate the custom hostname.          |
| [Custom hostname details](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/get/)   |                                                                                                                                       |
| [Edit custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/edit/)     | When sent with an ssl object that matches the existing value, indicates that hostname should restart domain control validation (DCV). |
| [Delete custom hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/delete/) | Also deletes any associated SSL/TLS certificates.                                                                                     |

## Fallback origins

Our API includes the following endpoints related to the [fallback origin](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#1-create-fallback-origin) of a custom hostname:

* [Get fallback origin](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/fallback%5Forigin/methods/get/)
* [Update fallback origin](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/fallback%5Forigin/methods/update/)
* [Remove fallback origin](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/fallback%5Forigin/methods/delete/)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/common-api-calls/","name":"Common API Calls"}}]}
```

---

---
title: Enable
description: To enable Cloudflare for SaaS for your account:
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/enable.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Enable

To enable Cloudflare for SaaS for your account:

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select **Enable**.
3. The next step depends on the zone's plan:  
   * **Enterprise**: Can preview this product as a [non-contract service](https://developers.cloudflare.com/billing/preview-services/), which provide full access, free of metered usage fees, limits, and certain other restrictions.  
   * **Non-enterprise**: Will have to enter payment information.

Note

Different zone plan levels have access to different features. For more details, refer to [Plans](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/plans/).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/enable/","name":"Enable"}}]}
```

---

---
title: Configuring Cloudflare for SaaS
description: Get started with Cloudflare for SaaS
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Configuring Cloudflare for SaaS

---

## Before you begin

Before you start creating custom hostnames:

1. [Add](https://developers.cloudflare.com/fundamentals/manage-domains/add-site/) your zone to Cloudflare on a Free plan.
2. [Enable](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/enable/) Cloudflare for SaaS for your zone.
3. Review the [Hostname prioritization guidelines](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority). Wildcard custom hostnames behave differently than an exact hostname match.
4. (optional) Review the following documentation:
* [API documentation](https://developers.cloudflare.com/fundamentals/api/) (if you have not worked with the Cloudflare API before).
* [Certificate validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).

---

## Initial setup

When you first [enable](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/enable/) Cloudflare for SaaS, you need to perform a few steps prior to creating any custom hostnames.

  
### 1\. Create fallback origin

The fallback origin is where Cloudflare will route traffic sent to your custom hostnames (must be proxied).

Note

To route custom hostnames to distinct origins, refer to [custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/).

To create your fallback origin:

1. [Create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a proxied `A`, `AAAA`, or `CNAME` record pointing to the IP address of your fallback origin (where Cloudflare will send custom hostname traffic).

| **Type** | **Name**       | **IPv4 address** | **Proxy status** |
| -------- | -------------- | ---------------- | ---------------- |
| A        | proxy-fallback | 192.0.2.1        | Proxied          |

1. Designate that record as your fallback origin.

* [ Dashboard ](#tab-panel-3374)
* [ API ](#tab-panel-3375)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. For **Fallback Origin**, enter the hostname for your fallback origin.
3. Select **Add Fallback Origin**.

Using the hostname of the record you just created, [update the fallback origin value](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/subresources/fallback%5Forigin/methods/update/).

1. Once you have added the fallback origin, confirm that its status is **Active**.

Note

When Cloudflare marks your fallback origin as **Active**, that only reflects that we are ready to send traffic to that DNS record.

You need to make sure your DNS record is sending traffic to the correct origin location.

### 2\. (Optional) Create CNAME target

The CNAME target — optional, but highly encouraged — provides a friendly and more flexible place for customers to [route their traffic](#3-have-customer-create-cname-record). You may want to use a subdomain such as `customers.<SAAS_PROVIDER>.com`.

[Create](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records) a proxied CNAME that points your CNAME target to your fallback origin (can be a wildcard such as `*.customers.saasprovider.com`).

| **Type** | **Name**   | **Target**                      | **Proxy status** |
| -------- | ---------- | ------------------------------- | ---------------- |
| CNAME    | .customers | proxy-fallback.saasprovider.com | Proxied          |

---

## Per-hostname setup

You need to perform the following steps for each custom hostname.

### 1\. Plan for validation

Before you create a hostname, you need to plan for:

1. [Certificate validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/): Upon successful validation, the certificates are deployed to Cloudflare’s global network.
2. [Hostname validation](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/): Upon successful validation, Cloudflare proxies traffic for this hostname.

You must complete both these steps for the hostname to work as expected.

Note

Depending on which method you select for each of these options, additional steps might be required for you and your customers.

### 2\. Create custom hostname

After planning for certification and hostname validation, you can create the custom hostname.

Zone name restriction

Do not configure a custom hostname which matches the zone name. For example, if your SaaS zone is `example.com`, do not create a custom hostname named `example.com`.

To create a custom hostname:

* [ Dashboard ](#tab-panel-3376)
* [ API ](#tab-panel-3377)

1. In the Cloudflare dashboard, go to the **Custom Hostnames** page.  
[ Go to **Custom Hostnames** ](https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/custom-hostnames)
2. Select **Add Custom Hostname**.
3. Add your customer's hostname `app.customer.com` and set the relevant options, including:  
   * The [minimum TLS version](https://developers.cloudflare.com/ssl/reference/protocols/).  
   * Defining whether you want to use a certificate provided by Cloudflare or [upload a custom certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/).  
   * Selecting the [certificate authority (CA)](https://developers.cloudflare.com/ssl/reference/certificate-authorities/) that will issue the certificate.  
   * Choosing the [validation method](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/).  
   * Whether you want to **Enable wildcard**, which adds a `*.<custom-hostname>` SAN to the custom hostname certificate. For more details, refer to [Hostname priority](https://developers.cloudflare.com/ssl/reference/certificate-and-hostname-priority/#hostname-priority).  
   * Choosing a value for [Custom origin server](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/).
4. Select **Add Custom Hostname**.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

1. To create a custom hostname using the API, use the [Create Custom Hostname](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/create/) endpoint.  
   * You can leave the `certificate_authority` parameter empty to set it to "default CA". With this option, Cloudflare checks the CAA records before requesting the certificates, which helps ensure the certificates can be issued from the CA.
2. For the newly created custom hostname, the `POST` response may not return the DCV validation token `validation_records`. It is recommended to make a second [GET command](https://developers.cloudflare.com/api/resources/custom%5Fhostnames/methods/list/) (with a delay) to retrieve these details.

The response contains the complete definition of the new custom hostname.

Default behavior

When you create a custom hostname:

* If you issue a custom hostname certificate with wildcards enabled, you cannot customize TLS settings for these wildcard hostnames.
* If you do not specify the **Minimum TLS Version**, it defaults to the zone's Minimum TLS Version. You can still [edit this setting](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/enforce-mtls/#minimum-tls-version) after creation.

Note

For each custom hostname, Cloudflare issues two certificates bundled in chains that maximize browser compatibility (unless you [upload custom certificates](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/custom-certificates/uploading-certificates/)).

The primary certificate uses a `P-256` key, is `SHA-2/ECDSA` signed, and will be presented to browsers that support elliptic curve cryptography (ECC). The secondary or fallback certificate uses an `RSA 2048-bit` key, is `SHA-2/RSA` signed, and will be presented to browsers that do not support ECC.

### 3\. Have customer create CNAME record

To finish the custom hostname setup, your customer needs to set up a CNAME record at their authoritative DNS that points to your [CNAME target](#2-optional-create-cname-target) [1](#user-content-fn-1).

Warning

Before your customer does this step, confirm that the hostname's **Certificate status** and **Hostname status** are both **Active**.

If not, confirm that you are using a method of [certificate](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/security/certificate-management/issue-and-validate/validate-certificates/http/#http-automatic) or [hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/hostname-validation/realtime-validation/) validation that occurs after your customer adds their DNS record.

Your customer's CNAME record might look like the following:

```

mystore.example.com CNAME customers.saasprovider.com


```

This record would route traffic in the following way:

flowchart TD
accTitle: How traffic routing works with a CNAME target
A[Request to <code>mystore.example.com</code>] --> B[<code>customers.saasprovider.com</code>]
B --> C[<code>proxy-fallback.saasprovider.com</code>]

  
Requests to `mystore.example.com` would go to your CNAME target (`customers.saasprovider.com`), which would then route to your fallback origin (`proxy-fallback.saasprovider.com`).

Warning

If your customer needs to use an A record to point to the SaaS target, you will need to get [apex proxying](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/). By default, using an A record to point to the target is not a supported setup.

#### Service continuation

If your customer is also using Cloudflare for their domain, they should keep their DNS record pointing to your SaaS provider in place for as long as they want to use your service.

For more details, refer to [Remove custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/remove-custom-hostnames/).

## Footnotes

1. If you have [regional services](https://developers.cloudflare.com/data-localization/regional-services/) set up for your custom hostnames, Cloudflare always uses the processing region associated with your DNS target record (instead of the processing region of any [custom origins](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/)).  
[↩](#user-content-fnref-1)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-for-platforms/","name":"Cloudflare for Platforms"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/","name":"Cloudflare for SaaS"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/","name":"Get started"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/","name":"Configuring Cloudflare for SaaS"}}]}
```
