> ## Documentation Index
> Fetch the complete documentation index at: https://doc.lucidworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack V2

> The Slack V2 connector allows you to index Slack channels and messages.

export const schema = {
  "type": "object",
  "title": "Slack (v2)",
  "description": "Connector for Slack",
  "required": ["parserId", "id", "properties", "pipeline"],
  "properties": {
    "parserId": {
      "type": "string",
      "title": "Parser ID",
      "description": "The Parser to use in the associated IndexPipeline."
    },
    "id": {
      "type": "string",
      "title": "Configuration ID",
      "description": "A unique identifier for this Configuration.",
      "minLength": 1,
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "pipeline": {
      "type": "string",
      "title": "Pipeline ID",
      "description": "Name of the IndexPipeline used for processing output.",
      "minLength": 1,
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "description": {
      "type": "string",
      "title": "Description",
      "description": "Optional description",
      "hints": ["lengthy"],
      "maxLength": 125
    },
    "modified": {
      "type": "string",
      "title": "Date Modified",
      "description": "The date at which this Configuration was last modified.",
      "hints": ["readonly", "hidden"]
    },
    "type": {
      "type": "string",
      "title": "Type",
      "description": "A type ID for this connector.",
      "hints": ["readonly", "hidden"]
    },
    "created": {
      "type": "string",
      "title": "Date Created",
      "description": "The date at which this Configuration was created.",
      "hints": ["readonly", "hidden"]
    },
    "collection": {
      "type": "string",
      "title": "Collection ID",
      "description": "The associated content Collection.",
      "hints": ["readonly", "hidden"],
      "minLength": 1,
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "diagnosticLogging": {
      "type": "boolean",
      "title": "Diagnostic Logging",
      "description": "[Deprecated] Enables verbose diagnostic logging for troubleshooting. May increase log volume. Disabled by default.",
      "default": false
    },
    "type_description": {
      "type": "string",
      "title": "Type Description",
      "default": "Connector for Slack",
      "hints": ["hidden", "readonly"]
    },
    "category": {
      "type": "string",
      "title": "Category",
      "default": "Connector for Slack",
      "hints": ["hidden", "readonly"]
    },
    "connector": {
      "title": "Connector Type",
      "description": "Connector type.",
      "minLength": 1,
      "type": "string",
      "hints": ["hidden"]
    },
    "properties": {
      "type": "object",
      "title": "Slack properties",
      "description": "Plugin specific properties.",
      "required": [],
      "properties": {
        "slackAppToken": {
          "type": "string",
          "title": "Slack App access token",
          "description": "The Slack application access token, this token is provided after installing the application in the workspace",
          "hints": ["secret"]
        },
        "slackAppTokenVaultLabel": {
          "type": "string",
          "title": "Slack App access token from Vault",
          "description": "The Fusion managed secret to use for Slack App access token.",
          "hints": ["vaultvaluetarget:slackAppToken", "enumUrl:/apps-manager/vault/labels?type=secret", "vaultref"]
        },
        "profilesConfig": {
          "type": "object",
          "title": "Profiles settings",
          "description": "Settings to control the indexation of Slack profiles",
          "required": ["indexProfiles"],
          "properties": {
            "indexProfiles": {
              "type": "boolean",
              "title": "Index profiles",
              "description": "Should profiles be indexed",
              "default": true
            },
            "indexGuestProfiles": {
              "type": "boolean",
              "title": "Index guest profiles",
              "description": "If indexing profiles, include profiles of guest users",
              "default": true
            },
            "indexInactiveProfiles": {
              "type": "boolean",
              "title": "Index inactive profiles",
              "description": "If indexing profiles, include profiles of inactive users",
              "default": false
            }
          }
        },
        "channelsConfig": {
          "type": "object",
          "title": "Channels and messages settings",
          "description": "Settings to control the indexation of Slack channels and messages",
          "required": [],
          "properties": {
            "indexChannels": {
              "type": "boolean",
              "title": "Index channels",
              "description": "Generate a document in the index for each channel",
              "default": true
            },
            "indexMessages": {
              "type": "boolean",
              "title": "Index messages",
              "description": "Should individual messages be indexed",
              "default": true
            },
            "indexFromArchivedChannels": {
              "type": "boolean",
              "title": "Index archived channels",
              "description": "If indexing messages or channel data, include data from archived channels",
              "default": false
            },
            "indexFromPublicChannels": {
              "type": "boolean",
              "title": "Index from public channels",
              "description": "If indexing messages or channel data, include data from public channels",
              "default": true
            },
            "indexPrivateChannels": {
              "type": "boolean",
              "title": "Index from private channels",
              "description": "If indexing messages or channel data, include data from private channels",
              "default": false
            },
            "indexDirectMessages": {
              "type": "boolean",
              "title": "Index from direct messages",
              "description": "If indexing messages, include private messages",
              "default": false
            },
            "indexBotMessages": {
              "type": "boolean",
              "title": "Index bot messages",
              "description": "If indexing messages, include messages that came from bots",
              "default": false
            },
            "indexThreadReplies": {
              "type": "boolean",
              "title": "Index thread replies",
              "description": "If indexing messages, include messages that are replies to threads. Note: Each thread found will result in it's own API call, and is subject to rate limiting. Using this can significantly slow down indexing.",
              "default": false
            },
            "channelFilter": {
              "type": "array",
              "title": "Channels to include",
              "description": "If indexing messages or channel data, include data only from channels with names matching the specified regular expressions",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "requests": {
          "type": "object",
          "title": "Requests settings",
          "required": ["pageSize"],
          "properties": {
            "pageSize": {
              "type": "number",
              "title": "Page size",
              "description": "The number of objects requested per page from Slack",
              "default": 200,
              "maximum": 1000,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            }
          },
          "hints": ["advanced"]
        },
        "itemRetryProperties": {
          "type": "object",
          "title": "Item retry settings",
          "description": "Options to configure the retry operation for items.",
          "required": [],
          "properties": {
            "maxRetries": {
              "type": "number",
              "title": "Max retry attempts",
              "description": "The maximum number of attempts for a failed item",
              "default": 3,
              "maximum": 20,
              "exclusiveMaximum": false,
              "minimum": 0,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "retryDelayInSeconds": {
              "type": "number",
              "title": "Retry delay",
              "description": "The amount of time, in seconds, before process again a failed item",
              "default": 30,
              "maximum": 600,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            }
          },
          "hints": ["advanced"]
        },
        "connectionsProperties": {
          "type": "object",
          "title": "Connections Settings",
          "description": "A set of options for configuring the HTTP client.",
          "required": ["maxConnections"],
          "properties": {
            "maxConnections": {
              "type": "number",
              "title": "Max connections",
              "description": "The maximum number of connections",
              "default": 20,
              "maximum": 2147483647,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "maxPerRoute": {
              "type": "number",
              "title": "Max per route",
              "description": "Defines a connection limit per one HTTP route. In simple cases you can understand this as a per target host limit. Under the hood things are a bit more interesting: HttpClient maintains a couple of HttpRoute objects, which represent a chain of hosts each, like proxy1 -> proxy2 -> targetHost. Connections are pooled on per-route basis. In simple cases, when you're using default route-building mechanism and provide no proxy suport, your routes are likely to include target host only, so per-route connection pool limit effectively becomes per-host limit.",
              "default": 20,
              "hints": ["hidden", "readonly"],
              "maximum": 2147483647,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "ignoreSSLValidationExceptions": {
              "type": "boolean",
              "title": "Ignore SSL Validation Exceptions",
              "description": "Do not attempt to do an SSL Handshake and do not verify the hostname of SSL certificates. Use this when accessing an https url with a self-signed or enterprise certificate authority that you do not want to put in the Java keystore.",
              "default": false,
              "hints": ["hidden", "readonly"]
            }
          }
        },
        "timeouts": {
          "type": "object",
          "title": "Timeout Settings",
          "description": "A set of options for configuring the HTTP client.",
          "required": [],
          "properties": {
            "readTimeoutMs": {
              "type": "number",
              "title": "",
              "default": 300000,
              "maximum": 600000,
              "exclusiveMaximum": false,
              "minimum": 0,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "connectTimeoutMs": {
              "type": "number",
              "title": "",
              "default": 60000,
              "maximum": 300000,
              "exclusiveMaximum": false,
              "minimum": 0,
              "exclusiveMinimum": false,
              "multipleOf": 1
            }
          }
        },
        "security": {
          "type": "object",
          "title": "Security filtering configuration",
          "required": [],
          "properties": {
            "enabled": {
              "type": "boolean",
              "title": "Enable security trimming",
              "description": "Enable query-time security-trimming",
              "default": true
            },
            "collectionId": {
              "type": "string",
              "title": "ACL collection id",
              "description": "Id of the collection to be used for storing ACL records. If not specified, ACL collection name will be generated automatically using pattern '<datasource_id>_access_control_hierarchy'."
            }
          }
        }
      }
    },
    "coreProperties": {
      "type": "object",
      "title": "Core Properties",
      "description": "Common behavior and performance settings.",
      "required": [],
      "properties": {
        "fetchSettings": {
          "type": "object",
          "title": "Fetch Settings",
          "description": "System level settings for controlling fetch behavior and performance.",
          "required": [],
          "properties": {
            "numFetchThreads": {
              "type": "number",
              "title": "Fetch Threads",
              "description": "Maximum number of fetch threads; defaults to 1. Slack REST API calls are throttled, and going above this number may harm performance more than it helps.",
              "default": 1,
              "hints": ["hidden"],
              "maximum": 500,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "indexingThreads": {
              "type": "number",
              "title": "Index Subscription Threads",
              "description": "Maximum number of indexing threads; defaults to 4.This setting controls the number of threads in the indexing service used for processing content documents emitted by this datasource.Higher values can sometimes help with overall fetch performance.",
              "default": 4,
              "maximum": 10,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "pluginInstances": {
              "type": "number",
              "title": "Number of plugin instances for distributed fetching",
              "description": "Maximum number of plugin instances for distributed fetching. Only specified number of plugin instanceswill do fetching. This is useful for distributing load between different instances.",
              "default": 0,
              "maximum": 500,
              "exclusiveMaximum": false,
              "minimum": 0,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "fetchItemQueueSize": {
              "type": "number",
              "title": "Fetch Item Queue Size",
              "description": "Size of the fetch item queue.Larger values result in increased memory usage, but potentially higher performance.Default is 10k.",
              "default": 10000,
              "hints": ["hidden"],
              "maximum": 500000,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "fetchRequestCheckInterval": {
              "type": "number",
              "title": "Fetch request check interval(ms)",
              "description": "The amount of time to wait before check if a request is done",
              "default": 15000,
              "hints": ["hidden"],
              "maximum": 500000,
              "exclusiveMaximum": false,
              "minimum": 1000,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "fetchResponseScheduledTimeout": {
              "type": "number",
              "title": "Fetch response scheduled timeout(ms)",
              "description": "The maximum amount of time for a response to be scheduled. The task will be canceled if this setting is exceeded.",
              "default": 300000,
              "maximum": 500000,
              "exclusiveMaximum": false,
              "minimum": 1000,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "fetchResponseCompletedTimeout": {
              "type": "number",
              "title": "Fetch response completion timeout(ms)",
              "description": "The maximum amount of time for a response to be completed. If exceeded, the task will be retried if the job is still running",
              "default": 300000,
              "hints": ["hidden"],
              "maximum": 600000,
              "exclusiveMaximum": false,
              "minimum": 1,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "indexingInactivityTimeout": {
              "type": "number",
              "title": "Indexing inactivity timeout(seconds)",
              "description": "The maximum amount of time to wait for indexing results (in seconds). If exceeded, the job will fail with an indexing inactivity timeout.",
              "default": 86400,
              "maximum": 691200,
              "exclusiveMaximum": false,
              "minimum": 60,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "pluginInactivityTimeout": {
              "type": "number",
              "title": "Plugin inactivity timeout(seconds)",
              "description": "The maximum amount of time to wait for plugin activity (in seconds). If exceeded, the job will fail with a plugin inactivity timeout.",
              "default": 600,
              "maximum": 691200,
              "exclusiveMaximum": false,
              "minimum": 60,
              "exclusiveMinimum": false,
              "multipleOf": 1
            },
            "indexMetadata": {
              "type": "boolean",
              "title": "Index metadata",
              "description": "When enabled the metadata of skipped items will be indexed to the content collection.",
              "default": false
            },
            "indexContentFields": {
              "type": "boolean",
              "title": "Index content fields",
              "description": "When enabled, content fields will be indexed to the crawl-db collection.",
              "default": false
            },
            "asyncParsing": {
              "type": "boolean",
              "title": "Async Parsing",
              "description": "When enabled, content will be indexed asynchronously.",
              "default": false
            }
          }
        },
        "strayDeletionSettings": {
          "type": "object",
          "title": "Stray Content Deletion Settings",
          "description": "System level settings for controlling stray content deletion behavior",
          "required": [],
          "properties": {
            "enableStrayDeletion": {
              "type": "boolean",
              "title": "Enable Stray Deletion",
              "description": "When enabled, items not re-encountered in the current crawl are deleted from the content collection. Defaults to true.",
              "default": true
            },
            "circuitBreakerSettings": {
              "type": "object",
              "title": "Circuit Breaker Settings",
              "description": "Settings that control the circuit breaker, which prevents mass deletion when an unusually high percentage of items are identified as stray in a crawl.",
              "required": [],
              "properties": {
                "percentageThreshold": {
                  "type": "number",
                  "title": "Stray Deletion Threshold (%)",
                  "description": "Maximum percentage of indexed items that may be deleted as stray in a crawl. If the total stray item exceeds this percentage, the circuit breaker blocks the deletion to prevent accidental data loss. Accepts values from 0 to 100. Defaults to 80.",
                  "default": 80,
                  "maximum": 100,
                  "exclusiveMaximum": false,
                  "minimum": 0,
                  "exclusiveMinimum": false,
                  "multipleOf": 1
                },
                "enableCircuitBreaker": {
                  "type": "boolean",
                  "title": "Enable Circuit Breaker",
                  "description": "When enabled, stray deletion is blocked if the percentage of items to be deleted exceeds the configured threshold. Disable only if unconditional stray deletion is required regardless of volume. Defaults to true.",
                  "default": true
                }
              }
            }
          }
        },
        "skipConfigValidation": {
          "type": "boolean",
          "title": "Skip Validation",
          "description": "Enable to skip configuration validation when it takes too long and causes timeout issue",
          "default": false
        }
      },
      "hints": ["advanced"]
    }
  },
  "category": "Web",
  "categoryPriority": 1
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const formatDescription = str => {
    const s = sanitize(str);
    return (/[.!?]\)*$/).test(s) ? s : `${s}.`;
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  return <div>
      {description && <p>{formatDescription(description)}</p>}

      {visibleProps.map(([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...prop.title && ({
        post: [<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>]
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
            {prop.description && <p>{formatDescription(prop.description)}</p>}

            {isComplexDefault && <div className="flex">
                <p>
                  <strong>Default:</strong>
                </p>
                <pre className="!my-0">
                  <code>
                    {JSON.stringify(rawDefault, null, 2)}
                  </code>
                </pre>
              </div>}

            {isArrayOfObjects && <div className="flex">
              <p>
                <strong>Object attributes:</strong>
              </p>
              <pre className="!my-0">
                <code>
                  {'{\n'}
                  {Object.entries(prop.items.properties).map(([iname, iprop]) => <>
                      {`  ${iname}`}
                      {prop.items?.required?.includes(iname) && <span style={{
      color: 'red'
    }}> required</span>}
                      {`: {\n    display name: ${sanitize(iprop.title || '')}\n    type: ${iprop.type}\n  }\n`}
                    </>)}
                  {'}'}
                </code>
              </pre>
              </div>}

            {isObject && <Expandable title="properties">
                <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
              </Expandable>}
          </ParamField>;
  })}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/fusion-connectors/connectors/slack-v2

[mintlify link]: https://doc.lucidworks.com/docs/fusion-connectors/connectors/slack-v2

[old doc.lw link]: https://doc.lucidworks.com/fusion-connectors/jej1ee

<Callout icon="plug" color="#A4C6F7" iconType="solid">
  * **Latest version:** v1.0.0
  * **Compatible with Fusion version:** 5.4.0 and later
</Callout>

<Warning>
  The Slack connector does not function due to Slack disabling crawling access.
</Warning>

<LwTemplate />

## Authentication

You must install a Slack application in the workspace that will be indexed before using the Slack V2 connector. See [Slack’s Basic app setup](https://api.slack.com/authentication/basics) for more information about installing a Slack application.

Once the app is correctly installed in the workspace, Slack will provide an access token, which you will then use in the Slack V2 connector configuration.

## Required application scopes

The Slack application must provide access to the following **User Token Scopes** in order to work with Slack V2 connector:

<img src="https://mintcdn.com/lucidworks/tklssWuUmNaxlF0b/assets/images/5.4/slack-user-token-scopes.png?fit=max&auto=format&n=tklssWuUmNaxlF0b&q=85&s=1f4c5ac718526935109c72c1ad14c7db" alt="Slack User Token Scopes" width="713" height="871" data-path="assets/images/5.4/slack-user-token-scopes.png" />

## Initial actions

The Slack V2 connector will perform the following actions at the beginning of each job:

* Load all users in the users cache. This information will be used later to resolve user names when processing mentions in messages.\
  It will also be useful for avoiding requests to retrieve user’s metadata.
* Load the channels to be processed using the channel filtering properties from the configuration.\
  This will be useful to establish a source of truth when determining whether a channel should be indexed or deleted on each job.

## Document filtering

| Profiles indexing                  |                                                                            |
| ---------------------------------- | -------------------------------------------------------------------------- |
| `Index profiles`                   | Determines whether users are indexed                                       |
| `Index guest profiles`             | Determines whether profiles from guest users are indexed                   |
| `Index inactive profiles`          | Determines whether profiles of deactivated users are indexed               |
| **Channels indexing**              |                                                                            |
| `Index channels`                   | Determines whether a document per channel is indexed                       |
| `Index archived channels`          | Determines whether archived channels are indexed to the content collection |
| `Index public channels`            | Determines whether public channels are indexed                             |
| `Index private channels`           | Determines whether private channels are indexed                            |
| `Index direct messages`            | Determines whether direct and multi-party direct message only are indexed  |
| `Channels to include`              | A list of the channel names to be included in the crawling process         |
| **Messages indexing**              |                                                                            |
| `Index messages`                   | Determines whether messages from the channels are indexed                  |
| `Index bot messages`               | Determines where messages from bots in channels are indexed                |
| `Index messages replies (threads)` | Determines whether the replies (if applicable) to messages are indexed     |

## Crawling process

<Warning>
  Due to limitations in the [Slack Web API](https://api.slack.com/messaging/retrieving), edited and deleted messages **cannot** be retrieved. You must clear the datasource and start a new connectors job to index edited messages and/or remove deleted messages.
</Warning>

### Crawl process diagram

<img src="https://mintcdn.com/lucidworks/tklssWuUmNaxlF0b/assets/images/5.4/diagrams/crawl-process-diagram.png?fit=max&auto=format&n=tklssWuUmNaxlF0b&q=85&s=0aff530611a4706d555a9e096ea90e83" alt="Crawl process diagram" width="770" height="930" data-path="assets/images/5.4/diagrams/crawl-process-diagram.png" />

### Endpoints used in the crawling process

| Endpoints                                     | Description                                                                                                                                                                    |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `https://slack.com/api/users.list`            | Lists all users in the workspace. This is not controlled by the properties in [Document Filtering](#security-filtering). All users are retrieved at the beginning of each job. |
| `https://slack.com/api/conversations.list`    | Lists the channels that should be indexed. This fetching is guided by the properties listed in [Document Filtering](#security-filtering).                                      |
| `https://slack.com/api/conversations.members` | Lists the members of specific channels being indexed.                                                                                                                          |
| `https://slack.com/api/conversations.history` | Retrieves a page of messages from a specific channel                                                                                                                           |
| `https://slack.com/api/users.info`            | Retrieves the information of a single user, if it’s not present in the users cache (message document generation).                                                              |
| `https://slack.com/api/conversations.info`    | Retrieves the information of a single channel, if it’s not present in the channel’s cache (message document generation).                                                       |
| `https://slack.com/api/team.info`             | Retrieves the information of a team (message document generation).                                                                                                             |
| `https://slack.com/api/conversations.replies` | Retrieves a page of replies from a specific message from a channel.                                                                                                            |

### Message mentions processing

The Slack V2 connector retrieves messages from the Slack API in the following format:

```json wrap  theme={"dark"}
 "type": "message",
 "text": "this is a mention in a message: <@U01U580HSDN>",
```

In this example, **@U01U580HSDN** is the user Id. The connector will resolve the user Id with the user’s display name, if it exists. Otherwise, it will use the full name in the user’s profile.

## Incremental Crawling processors

<img src="https://mintcdn.com/lucidworks/tklssWuUmNaxlF0b/assets/images/5.4/diagrams/incremental-crawling-process.png?fit=max&auto=format&n=tklssWuUmNaxlF0b&q=85&s=faa5226d6ec8978857a6ee99e8330b02" alt="Incremental crawling process" width="766" height="630" data-path="assets/images/5.4/diagrams/incremental-crawling-process.png" />

Each incremental job will re-index the User ACL to update all users in the Access Control Collection, and the Channel ACL to update the members of each channel.

| Processor                     | Description                                                                                                                                                                                                                           |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ProfilesCheckpointProcessor` | Performs the following actions:  <br />● Triggers the indexing of all user profiles and the profile’s ACL <br />● Verifies that profiles should still be indexed. If not, it deletes them <br />● Verifies guest and deleted profiles |
| `ChannelsCheckpointProcessor` | Detects new and deleted channels by comparison and the triggers the re-indexing of the channel ACL documents.                                                                                                                         |
| `ChannelCheckpointProcessor`  | Verifies that the current channel should still be indexed.  If the channel should still be indexed, then it triggers the indexing of new messages providing the timestamp (`ts`) of the last seen message from the previous job.      |

## Security filtering

### Security filtering processors

| Processor             | Description                                                                                                                                                                                                                                                                                                |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ProfileAclProcessor` | Builds a document representing a Slack user, which is then sent to the Access Control Collection.  Regular users can access public channels, even if they are not members of the channel.  Guest users can access only the channels they are members of.                                                   |
| `ChannelAclProcessor` | Retrieves the current members of the given channel, builds a document with those values, and sends the document to the Access Control Collection.  In public channels, an extra document is sent to the Access Control Collection to provide access to regular users who are not members of public groups. |

### Access Control Document links

<img src="https://mintcdn.com/lucidworks/tklssWuUmNaxlF0b/assets/images/5.4/diagrams/access-control-document-links.png?fit=max&auto=format&n=tklssWuUmNaxlF0b&q=85&s=13eda12343d2ad57a955f231230faae7" alt="Access Control Document links" width="6379" height="1240" data-path="assets/images/5.4/diagrams/access-control-document-links.png" />

### Security trimming rules

Security trimming uses the following rules:

* All users (regular and guest) can see the profile of any user in the Slack workspace.
* All regular users can access public channels and messages, even if they are not members of the channel.
* Guest users can only access the public or private channels they are members of.
* Only the members of private channels can access the channel and messages.
* Only the users involved can access direct messages and multi-party direct messages.

## Remote connectors

V2 connectors support [running remotely](/docs/fusion-connectors/developers/remote-v2-connectors) in Fusion versions 5.7.1 and later.

<Accordion title="Configure remote V2 connectors">
  If you need to index data from behind a firewall, you can configure a V2 connector to run remotely on-premises using TLS-enabled gRPC.

  ## Prerequisites

  Before you can set up an on-prem V2 connector, you must configure the egress from your network to allow HTTP/2 communication into the Fusion cloud. You can use a [forward proxy server](#egress-and-proxy-server-configuration) to act as an intermediary between the connector and Fusion.

  The following is required to run V2 connectors remotely:

  * The [plugin zip file and the connector-plugin-standalone JAR](https://plugins.lucidworks.com/).
  * A configured connector backend gRPC endpoint.
  * Username and password of a user with a `remote-connectors` or `admin` role.
  * If the host where the remote connector is running is not configured to trust the server’s TLS certificate, you must configure the file path of the trust certificate collection.

  <Note>If your version of Fusion doesn’t have the `remote-connectors` role by default, you can create one. No API or UI permissions are required for the role.</Note>

  ## Connector compatibility

  Only V2 connectors are able to run remotely on-premises.
  You also need the remote connector client JAR file that matches your Fusion version.
  You can download the latest files at [V2 Connectors Downloads](/docs/fusion-connectors/downloads/v2-connectors-downloads).

  <Note>Whenever you upgrade Fusion, you must also update your remote connectors to match the new version of Fusion.</Note>

  The gRPC connector backend is not supported in Fusion environments deployed on AWS.

  ## System requirements

  The following is required for the on-prem host of the remote connector:

  * (Fusion 5.9.0-5.9.10) JVM version 11
  * (Fusion 5.9.11) JVM version 17
  * Minimum of 2 CPUs
  * 4GB Memory

  Note that memory requirements depend on the number and size of ingested documents.

  ## Enable backend ingress

  In your `values.yaml` file, configure this section as needed:

  ```yaml theme={"dark"}
  ingress:
    enabled: false
    pathtype: "Prefix"
    path: "/"
    #host: "ingress.example.com"
    ingressClassName: "nginx"   # Fusion 5.9.6 only
    tls:
      enabled: false
      certificateArn: ""
      # Enable the annotations field to override the default annotations
      #annotations: ""
  ```

  * Set `enabled` to `true` to enable the backend ingress.
  * Set `pathtype` to `Prefix` or `Exact`.
  * Set `path` to the path where the backend will be available.
  * Set `host` to the host where the backend will be available.
  * In Fusion 5.9.6 *only*, you can set `ingressClassName` to one of the following:
    * `nginx` for Nginx Ingress Controller
    * `alb` for AWS Application Load Balancer (ALB)
  * Configure TLS and certificates according to your CA’s procedures and policies.

    <Note>  TLS must be enabled in order to use AWS ALB for ingress.</Note>

  ## Connector configuration example

  ```yaml theme={"dark"}
  kafka-bridge:
    target: mynamespace-connectors-backend.lucidworkstest.com:443 # mandatory
    plain-text: false # optional, false by default.  
      proxy-server: # optional - needed when a forward proxy server is used to provide outbound access to the standalone connector
      host: host
      port: some-port
      user: user # optional
      password: password # optional
    trust: # optional - needed when the client's system doesn't trust the server's certificate
      cert-collection-filepath: path1

  proxy: # mandatory fusion-proxy
    user: admin
    password: password123
    url: https://fusiontest.com/ # needed only when the connector plugin requires blob store access

  plugin: # mandatory
    path: ./fs.zip
    type: #optional - the suffix is added to the connector id
      suffix: remote
  ```

  ### Minimal example

  ```yaml theme={"dark"}
  kafka-bridge:
    target: mynamespace-connectors-backend.lucidworkstest.com:443

  proxy:
    user: admin
    password: "password123"

  plugin:
    path: ./testplugin.zip
  ```

  ### Logback XML configuration file example

  ```xml theme={"dark"}
  <configuration>
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
          <encoder class="com.lucidworks.logging.logback.classic.LucidworksPatternLayoutEncoder">
              <pattern>%d - %-5p [%t:%C{3.}@%L] - %m{nolookups}%n</pattern>
              <charset>utf8</charset>
          </encoder>
      </appender>

      <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>${LOGDIR:-.}/connector.log</file>
          <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
              <!-- rollover daily -->
              <fileNamePattern>${LOGDIR:-.}/connector-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
              <maxFileSize>50MB</maxFileSize>
              <totalSizeCap>10GB</totalSizeCap>
          </rollingPolicy>
          <encoder class="com.lucidworks.logging.logback.classic.LucidworksPatternLayoutEncoder">
              <pattern>%d - %-5p [%t:%C{3.}@%L] - %m{nolookups}%n</pattern>
              <charset>utf8</charset>
          </encoder>
      </appender>

      <root level="INFO">
          <appender-ref ref="CONSOLE"/>
          <appender-ref ref="FILE"/>
      </root>
  </configuration>
  ```

  ## Run the remote connector

  ```java theme={"dark"}
  java [-Dlogging.config=[LOGBACK_XML_FILE]] \
    -jar connector-plugin-client-standalone.jar [YAML_CONFIG_FILE]
  ```

  The `logging.config` property is optional. If not set, logging messages are sent to the console.

  ## Test communication

  You can run the connector in communication testing mode. This mode tests the communication with the backend without running the plugin, reports the result, and exits.

  ```java theme={"dark"}
  java -Dstandalone.connector.connectivity.test=true -jar connector-plugin-client-standalone.jar [YAML_CONFIG_FILE]
  ```

  ## Encryption

  In a deployment, communication to the connector’s backend server is encrypted using TLS. You should only run this configuration without TLS in a testing scenario. To disable TLS, set `plain-text` to `true`.

  ## Egress and proxy server configuration

  One of the methods you can use to allow outbound communication from behind a firewall is a proxy server. You can configure a proxy server to allow certain communication traffic while blocking unauthorized communication. If you use a proxy server at the site where the connector is running, you must configure the following properties:

  * **Host.** The hosts where the proxy server is running.
  * **Port.** The port the proxy server is listening to for communication requests.
  * **Credentials.** Optional proxy server user and password.

  When you configure egress, it is important to disable any connection or activity timeouts because the connector uses long running gRPC calls.

  ## Password encryption

  If you use a login name and password in your configuration, run the following utility to encrypt the password:

  1. Enter a user name and password in the [connector configuration YAML](#configuration).

  2. Run the standalone JAR with this property:

     ```java theme={"dark"}
     -Dstandalone.connector.encrypt.password=true
     ```

  3. Retrieve the encrypted passwords from the log that is created.

  4. Replace the clear password in the configuration YAML with the encrypted password.

  ## Connector restart (5.7 and earlier)

  The connector will shut down automatically whenever the connection to the server is disrupted, to prevent it from getting into a bad state. Communication disruption can happen, for example, when the server running in the `connectors-backend` pod shuts down and is replaced by a new pod. Once the connector shuts down, connector configuration and job execution are disabled. To prevent that from happening, you should restart the connector as soon as possible.

  You can use Linux scripts and utilities to restart the connector automatically, such as [Monit](https://mmonit.com/monit/).

  ## Recoverable bridge (5.8 and later)

  If communication to the remote connector is disrupted, the connector will try to recover communication and gRPC calls. By default, six attempts will be made to recover each gRPC call. The number of attempts can be configured with the `max-grpc-retries` bridge parameters.

  ## Job expiration duration (5.9.5 only)

  The timeout value for irresponsive backend jobs can be configured with the `job-expiration-duration-seconds` parameter. The default value is `120` seconds.

  ## Use the remote connector

  Once the connector is running, it is available in the Datasources dropdown. If the standalone connector terminates, it disappears from the list of available connectors. Once it is re-run, it is available again and configured connector instances will not get lost.

  ## Enable asynchronous parsing (5.9 and later)

  To separate document crawling from document parsing, enable Tika Asynchronous Parsing on remote V2 connectors.
</Accordion>

Below is an example configuration showing how to specify the file system to index under the `connector-plugins` entry in your `values.yaml` file:

```yaml wrap  theme={"dark"}
additionalVolumes:
- name: fusion-data1-pvc
    persistentVolumeClaim:
    claimName: fusion-data1-pvc
- name: fusion-data2-pvc
    persistentVolumeClaim:
    claimName: fusion-data2-pvc
additionalVolumeMounts:
- name: fusion-data1-pvc
    mountPath: "/connector/data1"
- name: fusion-data2-pvc
    mountPath: "/connector/data2"
```

You may also need to specify the user that is authorized to access the file system, as in this example:

```yaml wrap  theme={"dark"}
securityContext:
    fsGroup: 1002100000
    runAsUser: 1002100000
```

## Configuration

<SchemaParamFields schema={schema} />
