# Enable CORS between Flex Plugins and Functions

> \[!WARNING]
>
> This example uses headers and cookies, which are only accessible when your Function is running `@twilio/runtime-handler` version `1.2.0` or later. Consult the [Runtime Handler guide](/docs/serverless/functions-assets/handler) to learn more about the latest version and how to update.

A common use case is to call Functions from a [Flex Plugin](/docs/flex/developer/ui-and-plugins) to retrieve external data such as statistics. Sometimes, this results in Cross-Origin Resource Sharing ([CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)) restrictions in production environments due to the different hostnames between the Flex Plugin and the Function being called.

Fortunately, CORS errors, in this context or other situations, can be addressed by leveraging the response headers of the Function to allow any Origin, as shown in the following example code.

## Create and host a Function

Before you run any of the examples on this page, create a Function and paste the example code into it. You can create a Function in the Twilio Console or by using the [Serverless Toolkit](/docs/labs/serverless-toolkit).

## Console

If you prefer a UI-driven approach, complete these steps in the Twilio Console:

1. Log in to the [Twilio Console](https://1console.twilio.com) and navigate to **Develop > Functions & Assets**. If you're using the *legacy* Console, open the [**Functions** tab](https://www.twilio.com/console/functions/overview).
2. Functions are contained within **Services**. Click **[Create Service](https://www.twilio.com/console/functions/overview/services)** to create a new **[Service](/docs/serverless/functions-assets/functions/create-service)**.
3. Click **Add +** and select **Add Function** from the dropdown.
4. The Console creates a new [protected](/docs/serverless/functions-assets/visibility) Function that you can rename. The filename becomes the URL path of the Function.
5. Copy one of the example code snippets from this page and paste the code into your newly created Function. You can switch examples by using the dropdown menu in the code rail.
6. Click **Save**.
7. Click **Deploy All** to build and deploy the Function. After deployment, you can access your Function at `https://<service-name>-<random-characters>-<optional-domain-suffix>.twil.io/<function-path>`\
   For example: `test-function-3548.twil.io/hello-world`.

## Serverless Toolkit

The [Serverless Toolkit](/docs/labs/serverless-toolkit) lets you develop locally, deploy projects, and perform other tasks through the [Twilio CLI](/docs/twilio-cli/quickstart).

1. From the CLI, run `twilio serverless:init <YOUR-SERVICE-NAME> --empty` to bootstrap your local environment.
2. Go to your new project directory using `cd <YOUR-SERVICE-NAME>`.
3. In the `/functions` directory, create a JavaScript file whose name reflects the purpose of the Function. For example, `sms-reply.protected.js` for a [protected](/docs/serverless/functions-assets/visibility) Function intended to handle incoming SMS.
4. Add the code example of your choice to the file and save it. Note that a Function can only export a single handler. You need to create separate files to run or deploy multiple examples at once.

After you save the Function code, you can test it locally (and optionally tunnel requests to it using a tool like [ngrok](https://ngrok.com/)), or deploy it.

### Run your Function in local development

Run `twilio serverless:start` from your CLI to start the project locally. The Function(s) in your project are accessible from `http://localhost:3000/sms-reply`

* If you want to test a Function as a [Twilio webhook](/docs/usage/webhooks/getting-started-twilio-webhooks), run: `twilio phone-numbers:update <your Twilio phone number> --sms-url "http://localhost:3000/sms-reply"`\
  This automatically generates an ngrok tunnel from Twilio to your locally running Function, so you can start sending texts to it. You can apply the same process but with the `voice-url` flag instead to test with [Twilio Voice](/docs/voice).
* If your code does *not* connect to Twilio Voice or Messages as a webhook, start your dev server and start an ngrok tunnel in the same command with the `ngrok` flag. For example: `twilio serverless:start --ngrok=""`

### Deploy your Function

To deploy your Function and have access to live url(s), run `twilio serverless:deploy` from your CLI. This deploys your Function(s) to Twilio under a development Environment by default, where they can be accessed from:

`https://<service-name>-<random-characters>-dev.twil.io/<function-path>`

For example: `https://incoming-sms-examples-3421-dev.twil.io/sms-reply`

You can now invoke your Function with HTTP requests, configure it as the [webhook](/docs/usage/webhooks/getting-started-twilio-webhooks) for a Twilio phone number, call it from a Twilio Studio [**Run Function** Widget](/docs/studio/widget-library/run-function), and more.

```js title="Enable CORS" description="Allow for a client-side Flex Plugin to communicate with a Function on a different host"
exports.handler = (context, event, callback) => {
  // Access the NodeJS SDK by calling context.getTwilioClient()
  const client = context.getTwilioClient();

  // Create a custom Twilio Response
  const response = new Twilio.Response();
  // Set the CORS headers to allow Flex to make an error-free HTTP request
  // to this Function
  response.appendHeader('Access-Control-Allow-Origin', '*');
  response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS, POST, GET');
  response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');

  // Use the NodeJS SDK to make an API call and gather
  // statistics for the Flex Plugin.
  // Note that the workspace SID is passed from the event parameter
  // of the incoming request.
  client.taskrouter.v1
    .workspaces(event.WorkspaceSid)
    .workers()
    .cumulativeStatistics()
    .fetch()
    .then((data) => {
      response.appendHeader('Content-Type', 'application/json');
      response.setBody(data);
      // Return a success response using the callback function
      return callback(null, response);
    })
    .catch((err) => {
      response.appendHeader('Content-Type', 'plain/text');
      response.setBody(err.message);
      response.setStatusCode(500);
      // If there's an error, send an error response.
      // Keep using the response object for CORS purposes.
      return callback(null, response);
    });
};
```

If you want to learn more about Flex Plugins that would be invoking a Function in this way, check out this tutorial on [calling a Function from a Flex Plugin](/docs/flex/developer/plugins/call-functions#call-your-function-from-a-flex-plugin).
