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

# Request transforms

> Dynamically modify search requests based on targeting conditions to apply query transformations, filter injections, and sort overrides across search types.

## Overview

Request transforms customize how search requests are processed based on specific conditions. Unlike static search configurations, request transforms evaluate targeting conditions at query time and modify each matching request before it runs.

> [!NOTE]
>
> Request transforms support every request type, advanced targeting conditions, and multiple action types.

## How request transforms work

When Layers receives a search request, it evaluates all enabled request transforms in creation order. Layers applies each matching transform's actions to the request before execution, so later transforms layer on top of earlier ones. Request transforms let you rewrite queries, inject filters, attach discount entitlements, or override sort orders based on the context of each search.

## Request types

Request transforms can be configured to apply to specific types of search requests:

**All Search Types** applies the transform to every search request regardless of type. **Text Search** targets traditional keyword-based searches. **Image Search** applies to visual search requests where customers search by uploading an image. **Similar Search** targets requests for finding products similar to a specific item. **Browse** applies to collection browsing requests. **Blocks** applies to product-recommendation blocks rendered outside of the main search and browse surfaces, across every block strategy (similar products, manual, interaction, trending, personalized, contextual, and set).

You can select multiple request types for a single transform to target several discovery experiences at once.

> [!NOTE]
>
> **Blocks** is scoped independently. A transform that only selects **All Search Types** does not match block requests, and a transform that only selects **Blocks** does not match search or browse. Select **Blocks** explicitly (alongside other types if needed) when you want a transform to apply to recommendation blocks.

> [!NOTE]
>
> On block requests, **Add filter group**, **Apply/Remove discount entitlement**, and **Set/Override context value** apply to every block strategy. **Replace query**, **Modify query**, **Override sort order**, and **Modify tuning parameters** only affect the similar-products and collection-backed manual strategies. The other strategies don't run a text or vector query, so these actions have nothing to modify. The `query_product.*` targeting fields are also only resolved on the similar-products path.

## Targeting conditions

Targeting conditions determine when a request transform applies. Conditions can be combined using AND/OR logic.

**Search Query** matches against the customer's search terms. You can use operators like contains, equals, starts with, or ends with to match specific query patterns.

**Collection Handle** targets searches within specific collections. Use it to apply different search behaviors to different product categories.

**Query Product Type** and **Query Product Vendor** target based on the types of products or vendors in your catalog, for category-specific or brand-specific search modifications.

### Request targeting

Request transforms can target based on properties of the incoming request itself, so a transform can respond to how a shopper is browsing.

**Sort Order Code** (`request.sort_order_code`) targets based on which sort order is currently active for the request. Use it when you want to apply specific filters, query modifications, or tuning adjustments only when a particular sort order is selected. For example, you can inject a stock availability filter when a shopper sorts by "Best Sellers" or adjust relevance tuning when a promotional sort order is active.

**Applied Filter** (`request.applied_filters`) targets based on which filters the shopper has actively applied to the request. The value is a flat array of property codes extracted from the request's filter group, including filters inside nested groups, so a condition matches whether the filter sits at the top level of the filter group or under an AND/OR nest.

Use the **Applied Filter** field in the rule editor with the `in`, `notIn`, `contains`, or `doesNotContain` operators and pick the filterable attribute you want to detect. Common patterns:

* Inject a sort override when a shopper applies a `color` filter so color-relevance ranking kicks in.
* Use `notIn` on `availability` to widen recall (e.g. include out-of-stock items) only when the shopper hasn't already filtered availability themselves.
* Combine with contextual targeting (e.g. `request.applied_filters contains "brand" AND context.customer.signedIn = true`) to tune behavior for signed-in shoppers who are narrowing by brand.

### Contextual targeting

Request transforms also support contextual targeting conditions, so a transform can respond to the shopper's environment and behavior. These conditions use dot notation to access nested contextual data passed with each search request.

**Shopping Channel** (`context.shoppingChannel`) targets based on where the customer is browsing. Values include `web` for desktop/mobile web browsers and `app` for mobile app experiences (automatically detected from request headers for Tapcart, Fuego, and Canvas integrations).

**Geo Location** targets based on the customer's geographic location:

* `context.geo.country` - Two-letter country code (e.g., "US", "CA", "GB")
* `context.geo.province` - State or province
* `context.geo.city` - City name

**Customer Data** targets based on customer account status and purchase history:

* `context.customer.signedIn` - Boolean indicating if customer is logged in
* `context.customer.returning` - Boolean indicating if customer has previous orders
* `context.customer.numberOfOrders` - Total number of orders placed
* `context.customer.totalSpent` - Total amount spent across all orders
* `context.customer.averageOrderValue` - Average order value
* `context.customer.daysSinceLastOrder` - Days since most recent order
* `context.customer.daysSinceOldestOrder` - Days since first order
* `context.customer.daysBetweenOrders` - Average days between orders
* `context.customer.tags` - Shopify customer tags on the shopper's profile

**Marketing Parameters** targets based on UTM parameters and traffic source:

* `context.marketing.source` - UTM source (e.g., "google", "facebook", "email")
* `context.marketing.medium` - UTM medium (e.g., "cpc", "organic", "social")
* `context.marketing.campaign` - UTM campaign name
* `context.marketing.term` - UTM term (search keywords)

#### Use cases

**Channel-specific filtering**: Create a transform with `context.shoppingChannel != web` to hide web-only products from mobile app users, or boost app-exclusive items when browsing through your mobile app. When `shoppingChannel` is `app`, products not published to the online store are automatically included in results, so app users can discover app-exclusive products.

**Geographic merchandising**: Target customers in specific regions with `context.geo.country = US` to promote products available only in certain markets, or adjust search relevance for region-specific preferences.

**Personalized search for signed-in customers**: Use `context.customer.signedIn = true` to boost previously purchased product types or show VIP-exclusive items to high-value customers based on `context.customer.totalSpent`.

**Campaign-specific search behavior**: Target traffic from specific marketing campaigns with `context.marketing.source = google` and `context.marketing.campaign = summer-sale` to automatically filter results to sale items or boost promoted products.

**Combined contextual conditions**: Layer multiple contextual conditions using AND/OR logic. For example, target mobile app users in the US who are signed in: `context.shoppingChannel = app AND context.geo.country = US AND context.customer.signedIn = true`.

**Sort-order-specific behavior**: Target requests using a particular sort order with `request.sort_order_code = best-sellers` to inject a filter that hides out-of-stock products. You can also combine this with contextual conditions like `request.sort_order_code = price-low-to-high AND context.geo.country = US` to apply region-specific price filtering when shoppers sort by price.

**Filter-aware tuning**: Target requests where a shopper has already narrowed the catalog using `request.applied_filters contains "size"` to override the sort order, or use `request.applied_filters notIn ["availability"]` to widen results only when availability isn't already constrained by the shopper.

## Action types

Each request transform can have one or more actions that modify the search request:

### Replace query

Completely replaces the customer's search query with a different query. Use this when you want to redirect searches for specific terms to more relevant alternatives.

### Modify query

Adjusts the search query without fully replacing it. Modification options include appending text to the end of the query, prepending text to the beginning, or replacing specific words within the query with alternatives.

### Add filter group

Injects additional filters into the search request, so results narrow automatically based on the targeting conditions without the customer selecting filters.

A filter group can contain nested groups up to two levels deep, so you can express conditions like `availability = true AND (vendor = "NIKE" OR vendor = "ADIDAS")`.

Layers carries injected filters separately from the shopper's own filters and combines the two groups with AND when the query runs. The injected group keeps its own AND/OR conditional and NOT setting instead of being flattened into the shopper's filters. A transform therefore yields the same product set whether the request arrives bare or with facet filters applied.

Because injected filters stay separate from shopper filters:

* Facet responses report only shopper-selected values as selected. Injected values never appear as facet state.
* The **Applied Filter** (`request.applied_filters`) targeting condition matches shopper-applied filters only. Filters injected by another transform do not satisfy it.
* Zero-result recovery behaviors, such as retry and query expansion, still run for requests scoped by a transform. Layers treats these requests as unfiltered by the shopper.
* Analytics that track shopper filtering, such as the `zero_results` metric, count only shopper filters. Use the `transform_scoped_requests` and `transform_scoped_rate` metrics in the [Search (text) dataset](https://docs.uselayers.com/platform/layersql/datasets/search-text.md) to measure how much traffic your transforms constrain.

### Set default selected options

Sets the option values Layers prefers when selecting a product's default variant for search and browse requests. Configure one to 20 options with the option name and value pickers. For each option, choose **Fixed value** or **Changes by month** and enter a fixed value or a value for each month. Layers uses the current month in your store's timezone. If a month's value is blank, Layers skips that option for the month. Use **Add option** to add another option.

Without **Override shopper-provided defaults**, the action does nothing when the request already has non-empty default options. With the switch enabled, it replaces the complete options list rather than merging with the shopper's list.

This action controls presentation only. It does not filter products or collapse variant breakout tiles, and it applies to search and browse requests. Pinned variants and variants that match the query or keyword signals take priority over these defaults. Configured defaults take priority over a clear semantic match to a variant; position is the final fallback.

### Override sort order

Forces a specific sort order for matched search requests, overriding the default or customer-selected sorting.

### Modify tuning parameters

Adjusts the relevance tuning weights used to blend textual and visual signals. Set `textualWeight` and/or `visualWeight` (each between 0 and 1) to bias ranking for the matched requests, for example leaning on visual similarity for image-heavy categories or on text relevance for spec-driven searches.

### Apply discount entitlement

Attaches a discount entitlement to the request so downstream pricing surfaces a discounted price for the products it targets. Configure:

* **Entitled scope** — select **All products**, or narrow to specific **products**, **variants**, **collections**, or a **conditions** filter group (same builder as [Add filter group](#add-filter-group), including dynamic values sourced from the query product).
* **Discount** — select `PERCENTAGE` or `FIXED_AMOUNT` and set the value.

Use this to preview promotions in-session (for example, "20% off outerwear for signed-in returning customers") without creating a Shopify discount. Combine it with [Contextual targeting](#contextual-targeting) to gate the entitlement on customer segment, channel, or campaign.

### Remove discount entitlement

Strips discount entitlements from the request. Provide a discount type (`PERCENTAGE` or `FIXED_AMOUNT`) to remove only entitlements of that type, or leave it empty to clear every entitlement previously attached to the request. Use this to suppress a stacked promotion for specific segments or after another transform has already applied a broader entitlement.

### Set context value

Writes a value to the request's contextual session data at a `context.custom.*` path. `set_context` only writes when the path is currently empty. Existing values are left alone, so upstream integrations that already populate the field win.

Use this to hydrate optional context that downstream rules or integrations read. For example, tag a request with `context.custom.audience = "vip"` when the shopper matches a set of conditions, then reference `context.custom.audience` in a later transform's targeting.

### Override context value

Like **Set context value**, but always overwrites any existing value at the `context.custom.*` path. Use this when the transform is the authoritative source for the field and should replace whatever the integration passed in.

> [!NOTE]
>
> Only paths under `context.custom.*` are writable. Typed fields like `context.customer.*`, `context.geo.*`, and `context.marketing.*` are owned by the integration layer and cannot be modified from a request transform.

## Transform application order

Request transforms apply in the order they were created. The oldest matching transform runs first, and later transforms layer on top. Create broad transforms first, then add narrower overrides that adjust or replace their effects.

## Debugging with `_meta`

The [Search](https://docs.uselayers.com/api-reference/search.md) and [Browse](https://docs.uselayers.com/api-reference/browse.md) API responses include two request-transform fields in the `_meta` object:

* `appliedSearchRules` contains the IDs of all request transforms whose targeting conditions matched the request. When no transforms matched, the array is empty.
* `appliedSearchRuleActions` contains one entry per action those transforms executed, in execution order. Each entry reports the owning `ruleId`, the action `type`, and a `changed` boolean.

```json theme={null}
"_meta": {
    "appliedSearchRules": ["01JRVX7K2M8N9P4Q5R6S7T8U9V"],
    "appliedSearchRuleActions": [
        {
            "ruleId": "01JRVX7K2M8N9P4Q5R6S7T8U9V",
            "type": "add_filter_group",
            "changed": true
        }
    ]
}
```

Use `changed` to distinguish a transform that matched from a transform that actually modified the request. An action reports `changed: false` when it was a no-op. Examples include a **Replace query** action on a request with no query, an **Override sort order** action matching the already-active sort order, and a **Modify tuning parameters** action that leaves the weights unchanged. If an action cannot run at all, its entry includes an `error` field and the rest of the request proceeds normally.

Use `appliedSearchRules` and `appliedSearchRuleActions` to verify that your request transforms trigger as expected. Pass `includeMeta: true` in your request (or use the SDK's `includeMeta` option) to receive the `_meta` object in the response. Both fields are also recorded on each entry in the request logs, so you can audit which transforms changed past requests from the dashboard.

## Best practices

When creating request transforms, start with broad transforms and refine based on search analytics. Because transforms apply in creation order, add general transforms first and layer narrower overrides on top of them. Test transforms with the search evaluation tools before enabling them in production. Monitor search performance after enabling new transforms to confirm they improve the customer experience.

Consider using request transforms for common scenarios like redirecting misspellings to correct terms, boosting seasonal or promotional content, and filtering out irrelevant results for specific query patterns.

## See also

* [Configure search behavior](https://docs.uselayers.com/help/configuration/configure-search-behavior.md)
* [Test text search](https://docs.uselayers.com/help/evaluate/test-text-search.md)
* [User intent processing](https://docs.uselayers.com/engine/user-intent-processing.md)
