search

Use the `search` stage to perform free-text string searching across your ingested data, allowing you to find specified text strings within fields of single or multiple datasets.

## Syntax

```sql
search "<free_text1>"[,"<free_text2>", ...] [mode="<search_mode>"] [dataset = <dataset name>]
```

## Parameters

| Name | Type | Required | Description |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<free_text>` | string | Yes | The text string to search for. Multiple strings imply an OR condition. |
| `mode` | string | No | Scopes the investigation to route execution. Scoping the query accelerates response times for complex queries and provides granular control over the query. Accepted values are `raw`, `normalize`, and `all`. Syntax: `mode="search_mode"`. See [Search modes](#search-modes). |
| `dataset` | dataset | No | Refines the search by explicitly specifying a dataset. |

### Search modes

The `mode` parameter accepts the following values:

| Mode | Description |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `raw` | Searches across all columns in raw datasets. This is the default mode for general and wildcard searches. |
| `normalize` | Restricts the search to normalized datasets (such as `xdr_data`). For maximum performance, this mode searches string columns only and explicitly bypasses enum fields. |
| `all` | Searches across all datasets in the tenant. This is the legacy behavior. |

## Returns

The `search` stage returns records containing the specified text string(s). When searching a single dataset, all field columns of that dataset are included. When searching multiple datasets, the results include key columns such as `_time`, `_vendor`, `_product`, `_dataset`, and `raw_data`.

## Usage notes

* The `search` stage must be the first stage in your XQL query, though it can be preceded by a `config` stage.
* Queries containing the `search` stage do not support aggregation stages such as `bin`, `comp`, `top`, or `dedup`.
* Queries using the `search` stage are limited to the last 90 days of data.
* By default, forensic datasets are not included in `search` stage queries unless specifically enabled.
* If searching multiple datasets, the `raw_data` field column contains the JSON with the relevant raw information, allowing for drill-down.
* **Syntax limitation**: The `mode` parameter cannot be combined with a specific, non-wildcard dataset. For example, `search "login failure" mode=normalize dataset = xdr_data` returns an error. If you know the exact dataset, query it directly without the `mode` parameter.
* **Optimized search volume**: The `raw` and `normalize` modes are optimal for 1 to 10 distinct terms, such as specific IPs or hostnames. For heavy workflows that span large tenants across all datasets, use the `all` mode.

## Syntax examples

The following tables summarize valid and invalid combinations of the `search` stage syntax.

**Use cases**

| Use case | Example | Result |
| ---------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| Basic default search | `search "login failure"` | Automatically defaults to the raw mode and searches across wildcard tables |
| Explicit mode definition | `search "login failure" mode=all` | Forces the search across both raw and normalized datasets |
| Explicit mode with wildcard-only dataset | `search "login failure" mode=raw dataset = *` | Explicitly assigns the mode while searching all wildcard tables |
| Using modes with wildcard datasets | `search "login failure" mode=normalize dataset = xdr_*` | Explicitly scopes the normalized mode to datasets matching the wildcard |
| Searching multiple wildcard datasets | `search "login failure" mode=normalize dataset in (xdr_*, panw_*)` | Applies the performance mode across multiple wildcard dataset patterns |
| Implicit mode assignment (wildcard) | `search "login failure" dataset = xdr_*` | Because a wildcard is used without an explicit mode, this automatically defaults to the raw mode |
| Specific dataset query (no mode needed) | `search "login failure" dataset = xdr_data` | Directly queries a specific dataset. The mode parameter is intentionally left blank |
| Piping to additional filters | `search "login failure" mode=raw \| filter agent_os = WINDOWS` | Quickly searches raw datasets and filters the subsequent results |

**Invalid use cases**

| Use case | Example | Result |
| -------------------------------------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| Mode combined with a specific dataset (invalid) | `search "login failure" mode=normalize dataset = xdr_data` | Returns an error: the mode parameter is not allowed when querying a specific, non-wildcard dataset |
| Multiple modes provided (invalid) | `search "login failure" mode=raw mode=all` | Returns an error for a duplicate argument |
| Mode combined with a list of specific datasets (invalid) | `search "login failure" mode=raw dataset in (xdr_data, panw_data)` | Returns an error: wildcards must be present in the dataset list when using a mode |

## Examples

### Example 1: Basic free-text search across all datasets

**Goal**: Searches for the phrase "login successful" across all available datasets in the tenant (implicitly).

**XQL code**:

```sql
search "login successful" mode=all
```

**Explanation**: This query searches for the string "login successful" across all datasets. In the context of the sample data, it finds the relevant login event.

**Output**:

| \_time | \_dataset | event\_description | raw\_log\_data |
| ----------------------- | ---------------- | ----------------------- | ---------------------------------------- |
| 2023-10-26 10:00:00 UTC | sample\_xql\_raw | "User login successful" | "User Alice logged in from 192.168.1.10" |

### Example 2: Free-text search within a specific dataset

**Goal**: Explicitly searches for the string "cmd.exe" only within the `sample_xql_raw` dataset.

**XQL code**:

```sql
search "cmd.exe" dataset = sample_xql_raw
```

**Explanation**: This query restricts the free-text search for "cmd.exe" to the specified `sample_xql_raw` dataset.

**Output**:

| \_time | \_dataset | event\_description | raw\_log\_data |
| ----------------------- | ---------------- | --------------------- | ------------------------------------------------- |
| 2023-10-26 10:05:30 UTC | sample\_xql\_raw | "File access attempt" | "Process cmd.exe attempted to access /etc/passwd" |

### Example 3: Searching for multiple free-text strings

**Goal**: Searches for events containing either "connection" or "backup" within the `sample_xql_raw` dataset.

**XQL code**:

```sql
search "connection", "backup" dataset = sample_xql_raw
```

**Explanation**: This query searches for records containing either "connection" OR "backup" within the specified dataset.

**Output**:

| \_time | \_dataset | event\_description | raw\_log\_data |
| ----------------------- | ---------------- | -------------------------------- | ------------------------------------------------------ |
| 2023-10-26 10:15:15 UTC | sample\_xql\_raw | "Network connection established" | "Outbound connection to 1.1.1.1:443 initiated by AppX" |
| 2023-10-26 11:00:10 UTC | sample\_xql\_raw | "Database backup completed" | "Full backup of prod\_db to S3 completed." |

### Example 4: Using config timeframe with search

**Goal**: Searches for "successful" events within the last 24 hours.

**XQL code**:

```sql
config timeframe = 24h
search "successful" dataset = sample_xql_raw
```

**Explanation**: The `config timeframe` stage is used before the `search` stage to limit the query execution window to the last 24 hours.

**Output**:

| \_time | \_dataset | event\_description | is\_successful |
| ----------------------- | ---------------- | ----------------------- | -------------- |
| 2023-10-26 10:00:00 UTC | sample\_xql\_raw | "User login successful" | true |

### Example 5: Searching raw datasets

**Goal**: Searches for the phrase "login failure" across all columns in raw datasets.

**XQL code**:

```sql
search "login failure"
```

**Explanation**: The default mode for the search stage is raw. The default mode scopes the search to all columns in raw datasets.

**Output**:

| \_time | \_dataset | event\_description | raw\_log\_data |
| ----------------------- | ---------------- | -------------------- | ----------------------------------------- |
| 2023-10-26 10:20:00 UTC | sample\_xql\_raw | "User login failure" | "User Bob failed to log in from 10.0.0.5" |

### Example 6: Restricting the search to normalized datasets using the Normalize mode

**Goal**: Searches for the phrase "login failure" within normalized datasets only.

**XQL code**:

```sql
search "login failure" mode="normalize"
```

**Explanation**: The `mode="normalize"` parameter restricts the search to normalized datasets (such as `xdr_data`). For maximum performance, this mode searches string columns only and explicitly bypasses enum fields.

**Output**:

| \_time | \_dataset | event\_description | raw\_log\_data |
| ----------------------- | --------- | -------------------- | ----------------------------------------- |
| 2023-10-26 10:20:00 UTC | xdr\_data | "User login failure" | "User Bob failed to log in from 10.0.0.5" |

## Related articles

* **Stages**: [`config`](config)