> For the complete documentation index, see [llms.txt](https://docs.n8n.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.n8n.io/deploy/host-n8n/configure-n8n/external-hooks.md).

# External hooks

External hooks let you run custom code whenever n8n performs a specific operation. Use them to log data, change data, or forbid an action by throwing an error.

There are two types:

* **Backend hooks**: run server-side, registered using the `EXTERNAL_HOOK_FILES` environment variable.
* **Frontend hooks**: run in the browser, loaded with a script tag.

For the environment variables used to register hooks, refer to [External hooks environment variables](/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/external-hooks.md).

## Backend hooks <a href="#backend-hooks" id="backend-hooks"></a>

### Available hooks <a href="#available-hooks" id="available-hooks"></a>

| Hook                      | Arguments                                                                                                                                                            | Description                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `credentials.create`      | `[credentialData: ICredentialsDb]`                                                                                                                                   | Called before new credentials get created. Use to restrict the number of credentials.                                                                                                                                                                                                                                                                                  |
| `credentials.delete`      | `[id: credentialId]`                                                                                                                                                 | Called before credentials get deleted.                                                                                                                                                                                                                                                                                                                                 |
| `credentials.update`      | `[credentialData: ICredentialsDb]`                                                                                                                                   | Called before n8n saves existing credentials.                                                                                                                                                                                                                                                                                                                          |
| `frontend.settings`       | `[frontendSettings: IN8nUISettings]`                                                                                                                                 | Gets called on n8n startup. Allows you to, for example, overwrite frontend data like the displayed OAuth URL.                                                                                                                                                                                                                                                          |
| `n8n.ready`               | `[app: App]`                                                                                                                                                         | Called once n8n is ready. Use to, for example, register custom API endpoints.                                                                                                                                                                                                                                                                                          |
| `n8n.stop`                |                                                                                                                                                                      | Called when an n8n process gets stopped. Allows you to save some process data.                                                                                                                                                                                                                                                                                         |
| `oauth1.authenticate`     | `[oAuthOptions: clientOAuth1.Options, oauthRequestData: {oauth_callback: string}]`                                                                                   | Called before an OAuth1 authentication. Use to overwrite an OAuth callback URL.                                                                                                                                                                                                                                                                                        |
| `oauth2.callback`         | `[oAuth2Parameters: {clientId: string, clientSecret: string \| undefined, accessTokenUri: string, authorizationUri: string, redirectUri: string, scopes: string[]}]` | Called in an OAuth2 callback. Use to overwrite an OAuth callback URL.                                                                                                                                                                                                                                                                                                  |
| `workflow.activate`       | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called before a workflow gets activated. Use to restrict the number of active workflows. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                     |
| `workflow.afterCreate`    | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called after a workflow gets created. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                        |
| `workflow.afterDelete`    | `[workflowId: string, actor?: WorkflowLifecycleHookActor]`                                                                                                           | Called after a workflow gets deleted. Refer to [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                                                                                                               |
| `workflow.afterUpdate`    | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called after an existing workflow gets saved. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                |
| `workflow.create`         | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called before a workflow gets created. Use to restrict the number of saved workflows. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                        |
| `workflow.deactivate`     | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called before a workflow gets deactivated, while `active` is still `true`. Throw an error to abort the deactivation and keep the workflow active. Available from n8n 2.33.1. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument. |
| `workflow.delete`         | `[workflowId: string, actor?: WorkflowLifecycleHookActor]`                                                                                                           | Called before a workflow gets deleted. Refer to [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                                                                                                              |
| `workflow.postExecute`    | `[fullRunData: IRun \| undefined, workflowData: IWorkflowBase, executionId: string, workflowContext: WorkflowHookContextService]`                                    | Called after a workflow gets executed. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument.                                                                                                                                                                                                                                    |
| `workflow.preExecute`     | `[workflow: Workflow, mode: WorkflowExecuteMode, workflowContext: WorkflowHookContextService]`                                                                       | Called before a workflow gets executed. Allows you to count or limit the number of workflow executions. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument (available from n8n 2.23.0).                                                                                                                                       |
| `workflow.update`         | `[workflowData: IWorkflowBase, workflowContext: WorkflowHookContextService, actor?: WorkflowLifecycleHookActor]`                                                     | Called before an existing workflow gets saved. Refer to [Workflow hook context](#workflow-hook-context) for the `workflowContext` argument and [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                               |
| `workflow.afterArchive`   | `[workflowId: string, actor?: WorkflowLifecycleHookActor]`                                                                                                           | Called after you archive a workflow. Refer to [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                                                                                                                |
| `workflow.afterUnarchive` | `[workflowId: string, actor?: WorkflowLifecycleHookActor]`                                                                                                           | Called after you restore a workflow from the archive. Refer to [Workflow lifecycle hook actor](#workflow-lifecycle-hook-actor) for the `actor` argument.                                                                                                                                                                                                               |

### Registering hooks <a href="#registering-hooks" id="registering-hooks"></a>

Set hooks by registering a hook file that contains the hook functions. To register a hook, set the environment variable `EXTERNAL_HOOK_FILES`.

You can set the variable to a single file:

`EXTERNAL_HOOK_FILES=/data/hook.js`

Or to contain multiple files separated by a colon:

`EXTERNAL_HOOK_FILES=/data/hook1.js:/data/hook2.js`

### Hook files <a href="#hook-files" id="hook-files"></a>

Hook files are regular JavaScript files that have the following format:

```js
module.exports = {
    "frontend": {
        "settings": [
            async function (settings) {
                settings.oauthCallbackUrls.oauth1 = 'https://n8n.example.com/oauth1/callback';
                settings.oauthCallbackUrls.oauth2 = 'https://n8n.example.com/oauth2/callback';
            }
        ]
    },
    "workflow": {
        "activate": [
            async function (workflowData) {
                const activeWorkflows = await this.dbCollections.Workflow.count({ active: true });

                if (activeWorkflows > 1) {
                    throw new Error(
                        'Active workflow limit reached.'
                    );
                }
            }
        ]
    }
}
```

### Hook examples <a href="#hook-examples" id="hook-examples"></a>

#### Block workflow execution if a required tag is missing <a href="#block-workflow-execution-if-a-required-tag-is-missing" id="block-workflow-execution-if-a-required-tag-is-missing"></a>

Please note: the `workflowContext` argument is supplied to `workflow.preExecute` hooks from n8n 2.23.0. Refer to [Workflow hook context](#workflow-hook-context) for the full list of hooks that receive it and from which version.

Use `workflow.preExecute` to abort execution when a workflow doesn't have a required tag:

```js
module.exports = {
	workflow: {
		preExecute: [
			async function (workflow, mode, workflowContext) {
				const requiredTag = 'exampleTag';
				const workflowTags = await workflowContext.getWorkflowTags(workflow.id);
				if (!workflowTags.includes(requiredTag)) {
					throw new Error(`Workflow is missing required tag "${requiredTag}", aborting`);
				}
			},
		],
	},
};
```

### Workflow hook context

Some workflow hooks receive a `workflowContext` argument, an instance of `WorkflowHookContextService`. It exposes helper methods you can call inside the hook function.

{% hint style="info" %}
**Available from n8n 2.23.0**

n8n passes `workflowContext` to the `workflow.preExecute` hook.
{% endhint %}

{% hint style="info" %}
**Available from n8n 2.33.1**

n8n passes `workflowContext` to the `workflow.create`, `workflow.afterCreate`, `workflow.activate`, `workflow.deactivate`, `workflow.update`, `workflow.afterUpdate`, and `workflow.postExecute` hooks.
{% endhint %}

The context provides these methods:

| Method                                                         | Returns             | Description                                                                                                                                                                                                                                                                                                        |
| -------------------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `getWorkflowTags(workflowId: string)`                          | `Promise<string[]>` | Returns the names of the tags attached to the given workflow.                                                                                                                                                                                                                                                      |
| `resolveIsTriggerNodeType(type: string, typeVersion?: number)` | `boolean`           | Returns `true` if the given node type is a trigger. `type` is the fully qualified node type name, for example `n8n-nodes-base.manualTrigger`. `typeVersion` defaults to the latest registered version. Returns `false` when n8n can't resolve the node type, for example when it isn't registered on the instance. |

This example uses `resolveIsTriggerNodeType` to block activating a workflow that doesn't contain a trigger node:

```js
module.exports = {
	workflow: {
		activate: [
			async function (workflowData, workflowContext) {
				const hasTrigger = workflowData.nodes.some((node) =>
					workflowContext.resolveIsTriggerNodeType(node.type, node.typeVersion),
				);
				if (!hasTrigger) {
					throw new Error('Workflow must contain a trigger node, aborting activation');
				}
			},
		],
	},
};
```

### Workflow lifecycle hook actor

Some workflow lifecycle hooks receive an `actor` argument, a minimal projection of the user who performed the operation. Use it to attribute the action, for example to allow or reject an operation based on the user's identity or role.

{% hint style="info" %}
**Available from n8n 2.33.1**

n8n passes `actor` to the `workflow.create`, `workflow.afterCreate`, `workflow.activate`, `workflow.deactivate`, `workflow.update`, `workflow.afterUpdate`, `workflow.delete`, `workflow.afterDelete`, `workflow.afterArchive`, and `workflow.afterUnarchive` hooks. The argument is optional and can be `undefined` when n8n can't determine the acting user.
{% endhint %}

The `actor` object has these properties:

| Property    | Type             | Description                                                                                 |
| ----------- | ---------------- | ------------------------------------------------------------------------------------------- |
| `id`        | `string`         | The user's unique ID.                                                                       |
| `email`     | `string \| null` | The user's email address. Can be `null`, for example for a user invited but not yet set up. |
| `firstName` | `string \| null` | The user's first name. Can be `null`, for example for a user invited but not yet set up.    |
| `lastName`  | `string \| null` | The user's last name. Can be `null`, for example for a user invited but not yet set up.     |
| `role`      | `string`         | The user's role slug, for example `global:admin`. Optional.                                 |

This example uses `actor` to log who deleted a workflow:

```js
module.exports = {
	workflow: {
		delete: [
			async function (workflowId, actor) {
				console.log(`Workflow ${workflowId} deleted by ${actor?.email} (${actor?.role})`);
			},
		],
	},
};
```

### Hook functions <a href="#hook-functions" id="hook-functions"></a>

A hook or a hook file can contain multiple hook functions, with all functions executed one after another.

If the parameters of the hook function are objects, it's possible to change the data of that parameter to change the behavior of n8n.

You can also access the database in any hook function using `this.dbCollections` (refer to the code sample in [Hook files](#hook-files) above).

## Frontend external hooks <a href="#frontend-external-hooks" id="frontend-external-hooks"></a>

Like backend external hooks, it's possible to define external hooks in the frontend code that get executed by n8n whenever a user performs a specific operation. You can use them, for example, to log data and change data.

### Available hooks <a href="#available-hooks" id="available-hooks"></a>

| Hook                                       | Description                                                                 |
| ------------------------------------------ | --------------------------------------------------------------------------- |
| `credentialsEdit.credentialTypeChanged`    | Called when an existing credential's type changes.                          |
| `credentials.create`                       | Called when someone creates a new credential.                               |
| `credentialsList.dialogVisibleChanged`     |                                                                             |
| `dataDisplay.nodeTypeChanged`              |                                                                             |
| `dataDisplay.onDocumentationUrlClick`      | Called when someone selects the help documentation link.                    |
| `execution.open`                           | Called when an existing execution opens.                                    |
| `executionsList.openDialog`                | Called when someone selects an execution from existing Workflow Executions. |
| `expressionEdit.itemSelected`              |                                                                             |
| `expressionEdit.dialogVisibleChanged`      |                                                                             |
| `nodeCreateList.filteredNodeTypesComputed` |                                                                             |
| `nodeCreateList.nodeFilterChanged`         | Called when someone makes any changes to the node panel filter.             |
| `nodeCreateList.selectedTypeChanged`       |                                                                             |
| `nodeCreateList.mounted`                   |                                                                             |
| `nodeCreateList.destroyed`                 |                                                                             |
| `nodeSettings.credentialSelected`          |                                                                             |
| `nodeSettings.valueChanged`                |                                                                             |
| `nodeView.createNodeActiveChanged`         |                                                                             |
| `nodeView.addNodeButton`                   |                                                                             |
| `nodeView.mount`                           |                                                                             |
| `pushConnection.executionFinished`         |                                                                             |
| `showMessage.showError`                    |                                                                             |
| `runData.displayModeChanged`               |                                                                             |
| `workflow.activeChange`                    |                                                                             |
| `workflow.activeChangeCurrent`             |                                                                             |
| `workflow.afterUpdate`                     | Called when someone updates an existing workflow.                           |
| `workflow.open`                            |                                                                             |
| `workflowRun.runError`                     |                                                                             |
| `workflowRun.runWorkflow`                  | Called when a workflow executes.                                            |
| `workflowSettings.dialogVisibleChanged`    |                                                                             |
| `workflowSettings.saveSettings`            | Called when someone saves the settings of a workflow.                       |

### Registering frontend hooks <a href="#registering-frontend-hooks" id="registering-frontend-hooks"></a>

You can set hooks by loading the hooks script on the page. One way to do this is by creating a hooks file in the project and adding a script tag in your `editor-ui/public/index.html` file:

```html
<script src="frontend-hooks.js"></script>
```

### Frontend hook files <a href="#frontend-hook-files" id="frontend-hook-files"></a>

Frontend external hook files are regular JavaScript files which have the following format:

```js
window.n8nExternalHooks = {
  nodeView: {
    mount: [
      function (store, meta) {
        // do something
      },
    ],
    createNodeActiveChanged: [
      function (store, meta) {
        // do something
      },
      function (store, meta) {
        // do something else
      },
    ],
    addNodeButton: [
      function (store, meta) {
        // do something
      },
    ],
  },
};
```

### Frontend hook functions <a href="#frontend-hook-functions" id="frontend-hook-functions"></a>

You can define multiple hook functions per hook. n8n calls each hook function with the following arguments:

* `store`: The Vuex store object. You can use this to change or get data from the store.
* `metadata`: The object that contains any data provided by the hook. To see what's passed, search for the hook in the `editor-ui` package.
