# Global Scripts

> Configure Global Scripts in Connector Builder to run JavaScript before or after every API request for consistent request and response processing.

The **Global Scripts** tab in Connector Builder lets you write JavaScript that runs before or after every API request made by your connector. Use pre-request scripts to modify outgoing requests and post-request scripts to process incoming responses.

## When to use Global Scripts

Global Scripts are useful when you need to apply consistent logic across all requests in a connector, such as:

* Injecting or overriding request headers, parameters, or body before sending
* Dynamically constructing the vendor URL based on configuration values
* Transforming a vendor response body before it is returned to the workflow
* Stopping a request based on custom conditions without calling the vendor API

## Scripts for a single resource

Each resource also has its own **Scripts** tab, alongside **Parameters**, **Request fields**, **Response fields**, and **Activity designer**. It provides the same **Pre-request script** and **Post-request script** editors, the same snippets, and the same variables and `done()` contract as the connector-level **Global Scripts** tab.

The difference is scope:

* A script on the **Global Scripts** tab runs for every request the connector makes.
* A script on a resource's **Scripts** tab runs only for that resource.

Use a resource script when the logic applies to one endpoint, and a global script when it applies to the whole connector.

## Writing scripts

To open the Global Scripts tab:

1. In Integration Service, open Connector Builder and select your custom connector.
2. Select **Global Scripts** from the top navigation.
3. Expand **Pre-request script** or **Post-request script** and enter your JavaScript.

Scripts run in a sandboxed JavaScript environment, with no network access and no way to import packages.

Standard JavaScript built-ins are available: `JSON`, `Date`, `Array`, `Object`, `URL`, `encodeURIComponent`, `URLSearchParams`, `TextEncoder`, `TextDecoder`, `btoa`, `atob`, `crypto`, `Blob`, `FormData`, `Headers`, `Intl`, and `BigInt`.

:::important
`Buffer` is **not** available. Use `btoa` and `atob` for base64 encoding instead.
:::

The following are not available in the sandbox:

| Category | Not available |
|---|---|
| Evaluation and imports | `eval`, any `require()` call, a top-level `import` or `export` statement, a dynamic `import(...)` expression |
| Network | `fetch`, `XMLHttpRequest`, `WebSocket` |
| Timers and workers | `setTimeout`, `setInterval`, `setImmediate`, `Worker`, `importScripts`, `postMessage` |
| Runtime and globals | `Deno`, `process`, `globalThis`, `self`, `window`, `WebAssembly`, `Buffer` |

## The `done()` function

Every script **must** call `done()` to signal completion. `done()` terminates execution immediately — any code written after `done()` is unreachable.

```javascript
// Pass through unchanged
done();

// Override one or more output values
done({
  request_vendor_headers: updatedHeaders
});

// Return multiple overrides
done({
  request_vendor_body: newBody,
  request_vendor_headers: newHeaders
});

// Stop the request — do not call the vendor API
done({ continue: false });

// Stop the request and return an error
done({
  continue: false,
  response_status_code: 400,
  response_error_message: "Invalid action"
});
```

## Using Snippets

Select **Snippets** in the script panel to insert code templates into the active script editor.

The **Pre-request script** panel offers the following templates, grouped under **Prerequest scripts**:

* **Update provider URL** — Sets `request_vendor_path` to a full URL, replacing the provider URL for that request.
* **Use a configuration** — Reads a value from `configuration` (the connector's base URL, in the sample) and sends it to the provider as a request header.
* **Skip a provider request** — Sets `continue` to `false` so the request is never sent to the provider.

The **Post-request script** panel offers the following templates, grouped under **Postrequest scripts**:

* **Update the response body** — Copies `response_body` into a local variable, adds a field to it, and returns the modified body.
* **SR metadata generation from vendor metadata** — Builds standard resource field metadata from a vendor metadata response, deriving each custom field's type, format, display name, description, supported methods, and enum values.

## Pre-request scripts

A pre-request script runs before each API call is sent to the provider. Variables with **Write** or **Read & Write** access can be set via `done()`.

| Variable | Access | Description |
|---|---|---|
| `request_method` | Read | HTTP method of the API call (`GET`, `POST`, etc.). |
| `request_vendor_method` | Read & Write | HTTP method that will be passed to the provider. |
| `request_headers` | Read | Request headers passed as part of the API call. |
| `request_vendor_headers` | Read & Write | Headers that will be sent to the provider. |
| `request_path` | Read | Request path of the API call. |
| `request_vendor_path` | Read & Write | Request path that will be sent to the provider. If the path starts with `http`, it is used as the full request URL. |
| `request_path_variables` | Read | Path variables extracted from the URL template. |
| `request_parameters` | Read | Query parameters passed as part of the API call. |
| `request_vendor_parameters` | Read & Write | Query parameters that will be sent to the provider. |
| `request_body` | Read | Request body passed as part of the API call, as a string. |
| `request_body_raw` | Read | Request body passed as part of the API call, as an unprocessed string. |
| `request_vendor_body` | Read & Write | Request body that will be sent to the provider. Accepts string, list, or map on write. |
| `request_body_map` | Read | Request body passed as part of the API call, as a map. |
| `request_vendor_body_map` | Read | Request body that will be sent to the provider, as a map. |
| `request_vendor_url` | Read | Fully formed endpoint URL that will be used for the vendor call. |
| `request_expression` | Read | CEQL `where` parameter converted to a list of `{attribute, value, operator}` maps. |
| `request_previous_response` | Read | Response body from the previous chained resource. `null` if not part of a chain. |
| `request_previous_response_headers` | Read | Response headers from the previous chained resource. `null` if not part of a chain. |
| `request_root_key` | Read & Write | Dot-notation path to build a sub-object in the request JSON payload (e.g. `data.record`). |
| `object_name` | Read | Canonical object name for the request. |
| `vendor_object_name` | Read | Vendor object name. Same as `object_name` unless overridden on the resource. |
| `configuration` | Read | Connector configuration properties. |
| `response_status_code` | Write | HTTP status code to return when `continue` is `false`. |
| `response_error_message` | Write | Error message to return before the request is sent to the vendor. |
| `response_body` | Write | Response body to return when `continue` is `false`. |
| `response_body_raw` | Write | Response body as a string to return when `continue` is `false`. |
| `response_root_key` | Read & Write | Dot-notation path to limit the response to a sub-object (e.g. `data.records`). |
| `multipart_hook_context_items` | Read & Write | Multipart form items for file upload requests. |
| `continue` | Write | Set to `false` to skip the vendor call. Defaults to `true`. |

### Example: Inject a dynamic header from configuration

```javascript
var headers = request_vendor_headers || {};
var config = configuration || {};

headers['Authorization'] = 'Bearer ' + config['oauth_token'];

done({ request_vendor_headers: headers });
```

### Example: Override the vendor URL path

```javascript
var baseUrl = configuration['base_url'];
if (!baseUrl) {
  done({ continue: false, response_error_message: "Missing configuration: 'base_url'" });
  return;
}

var apiVersion = configuration['api_version'] || 'v1';
var modelId = request_path_variables.modelId;
var vendorUrl = baseUrl.startsWith('http') ? baseUrl : 'https://' + baseUrl;

done({
  request_vendor_path: vendorUrl + '/' + apiVersion + '/models/' + modelId + '/completions'
});
```

### Example: Modify the request body

```javascript
var body = typeof request_body_map === 'string'
  ? JSON.parse(request_body_map)
  : request_body_map;

body.max_tokens = body.max_tokens || 1024;
body.temperature = 0.7;

done({
  request_vendor_headers: { 'Content-Type': 'application/json' },
  request_vendor_body: JSON.stringify(body)
});
```

## Post-request scripts

A post-request script runs after a response is received from the vendor. All pre-request variables remain available as Read. The response-specific variables below are added, and `configuration` becomes Read & Write. Variables with **Write** or **Read & Write** access can be set via `done()`.

| Variable | Access | Description |
|---|---|---|
| `response_iserror` | Read | `true` if the vendor response indicates an error (status codes outside 200–207). |
| `response_status_code` | Read & Write | HTTP status code from the vendor. |
| `response_body` | Read & Write | Response body from the vendor. |
| `response_body_raw` | Read & Write | Raw response body from the vendor, as a string. |
| `response_body_raw_map` | Read | Raw response body from the vendor, as a map. |
| `response_body_map` | Read | Response body from the vendor, as a map. |
| `response_headers` | Read & Write | Response headers from the vendor. |
| `response_error_message` | Write | Error message to return. Converts the response into an error. |
| `response_root_key` | Read & Write | Dot-notation path to limit the response to a sub-object (e.g. `data.records`). |
| `configuration` | Read & Write | Connector configuration properties. Changes persist to the connector instance. |
| `multipart_hook_context_items` | Read & Write | Multipart form items for file upload requests. |
| `metadata_merge` | Write | Set to `true` to combine vendor metadata with model metadata. |

:::tip
Start every post-request script with an error guard. If the response is an error, call `done()` with no arguments to pass it through unchanged.
:::

### Example: Transform the response body

```javascript
if (response_iserror) {
  done();
  return;
}

var body = typeof response_body === 'string'
  ? JSON.parse(response_body)
  : response_body;

body.processed = true;
body.timestamp = new Date().toISOString();

done({ response_body: body });
```

## Utility functions

The following utility functions are available in both script types:

| Function | Description |
|---|---|
| `console.log()` | Outputs a debug message. |

## Bring your own LLM connector use case

If you are building a connector for an LLM provider — such as a self-hosted model or a third-party inference endpoint — Global Scripts let you adapt requests and responses to match the expected contract without modifying each resource individually.

:::tip
For common LLM providers (AWS Bedrock, Azure OpenAI, Google Vertex AI, OpenAI V1 Compatible), you can start from a connector template that pre-populates the authentication setup and scripts for you. For details, see [Using connector templates](https://docs.uipath.com/automation-cloud/automation-cloud/latest/admin-guide/using-connector-templates).
:::

The following scripts show a complete pre-request and post-request setup for this scenario.

### Pre-request: Set authentication headers

Inject the provider's API key from the connector configuration and enforce the expected `Content-Type`:

```javascript
var headers = {
  'Content-Type': 'application/json',
  'x-api-key': configuration['api_key']
};

done({
  request_vendor_headers: headers,
  request_vendor_body: request_body_map
});
```

### Pre-request: Inject a system message

Set default model parameters and ensure a system message is present in every conversation sent to the model:

```javascript
var body = typeof request_body_map === 'string'
  ? JSON.parse(request_body_map)
  : request_body_map;

body.max_tokens = body.max_tokens || 1024;
body.temperature = 0.7;

var hasSystemMessage = body.messages.some(function(msg) {
  return msg.role === 'system';
});

if (!hasSystemMessage) {
  body.messages.unshift({
    role: 'system',
    content: 'You are a helpful assistant.'
  });
}

done({
  request_vendor_headers: { 'Content-Type': 'application/json' },
  request_vendor_body: JSON.stringify(body)
});
```

### Post-request: Process the choices array

Iterate the `choices` array in the vendor response and add custom metadata before returning to the workflow:

```javascript
if (response_iserror) {
  done();
  return;
}

var body = typeof response_body === 'string'
  ? JSON.parse(response_body)
  : response_body;

if (body.choices && body.choices.length > 0) {
  body.choices.forEach(function(choice) {
    choice.processed_by = 'connector-post-script';
  });
}

body.custom_metadata = {
  processed: true,
  timestamp: new Date().toISOString()
};

done({ response_body: body });
```

## Best practices

* **Always call `done()`** — a script that does not call `done()` hangs the request.
* **Copy variables before mutating** — the runtime uses strict mode. Assign to a local variable first: `var headers = request_vendor_headers;`, then modify `headers`.
* **Do not write code after `done()`** — it is unreachable.
* **Check for `null` or `undefined`** — `request_body` and `request_vendor_body` are `undefined` for GET and DELETE requests.
* **Use `continue: false` to short-circuit** — return a response directly without calling the vendor.
