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

# QueryRuleCustomData

> Shows custom data from applied index rules.

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">iOS</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/query-rule-custom-data/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/query-rule-custom-data/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/query-rule-custom-data/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/api-reference/widgets/query-rule-custom-data/ios"><span className="afs-option-name">iOS</span><span className="afs-option-lib">InstantSearch iOS</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/query-rule-custom-data/android"><span className="afs-option-name">Android</span><span className="afs-option-lib">InstantSearch Android</span></a></li>
    </ul>
  </div>
</div>

{/* vale Algolia.HeadingPronouns = NO */}

## About this widget

The `QueryRuleCustomData` widget displays custom data from [rules](/doc/guides/managing-results/rules/detecting-intent).

You may want to use this widget to display banners or recommendations returned by Rules, and that match search parameters.

<Card title="Explore example code" icon="github" href="https://github.com/algolia/instantsearch-ios/tree/master/Examples/Showcase/QueryRuleCustomData/">
  Browse the QueryRuleCustomData example code on GitHub.
</Card>

## Examples

Instantiate a `QueryRuleCustomDataConnector` and launch an initial search on its [`Searcher`](/doc/api-reference/widgets/instantsearch/ios) triggering a Rule that returns custom data.

```swift Swift icon=code theme={"system"}
let searcher = HitsSearcher(appID: "YourApplicationID",
                            apiKey: "YourSearchOnlyAPIKey",
                            indexName: "YourIndexName")
let bannerViewController = BannerViewController()
let queryRuleCustomDataConnector = QueryRuleCustomDataConnector<Banner>(searcher: searcher,
                                                                        controller: bannerViewController)

searcher.search()
```

## Parameters

<ParamField body="searcher" type="HitsSearcher" required>
  The [`Searcher`](/doc/api-reference/widgets/instantsearch/ios) that handles your searches.
</ParamField>

<ParamField body="interactor" type="QueryRuleCustomDataInteractor<Model>" post={["default: .init()"]} required>
  The logic applied to the custom model.
</ParamField>

<ParamField body="controller" type="ItemController" post={["default: nil"]}>
  The Controller interfacing with a concrete custom data view.
</ParamField>

<ParamField body="presenter" type="Presenter<SearchStats?, Output>" post={["default: nil"]}>
  The Presenter defining how a model appears in the controller.
</ParamField>

## Low-level API

If you want to fully control the `QueryRuleCustomData` components and connect them manually, you can use the following components:

* `Searcher`. The [`Searcher`](/doc/api-reference/widgets/instantsearch/ios) that handles your searches.
* `QueryRuleCustomDataInteractor`. The logic applied to the custom model.
* `ItemController`. The Controller interfacing with a concrete custom data view.

```swift Swift icon=code theme={"system"}
let searcher = HitsSearcher(appID: "YourApplicationID",
                            apiKey: "YourSearchOnlyAPIKey",
                            indexName: "YourIndexName")
let queryRuleCustomDataInteractor: QueryRuleCustomDataInteractor<Banner> = .init()
let bannerViewController: BannerViewController = .init()

queryRuleCustomDataInteractor.connectSearcher(searcher)
queryRuleCustomDataInteractor.connectController(bannerViewController)
```

## Customizing your view

If you want to use a third-party input view,
or you want to introduce some custom behavior to the already provided UIKit component,
you can create your own controller conforming to the `ItemController` protocol.

### Protocol

`func setItem(_ item: String?)`:

Function called when new metadata are received.

### Example

Suppose your custom JSON data contains a banner URL that can be decoded to the following structure:

```swift Swift icon=code theme={"system"}
struct Banner: Decodable {
  let bannerURL: URL
}
```

You could implement the `BannerViewController` presenting the banner image as follows:

```swift Swift icon=code theme={"system"}
class BannerViewController: UIViewController, ItemController {

  let bannerView: UIImageView = .init()

  override func viewDidLoad() {
    super.viewDidLoad()
    // some setup layout code
  }

  func setItem(_ item: Banner?) {
    guard let bannerURL = item?.bannerURL else {
      bannerView.image = nil
      return
    }
    URLSession.shared.dataTask(with: bannerURL) { (data, _, _) in
      self.bannerView.image = data.flatMap(UIImage.init)
    }.resume()
  }

}
```

### SwiftUI

To create a rule custom data view with SwiftUI start with implementation of the `ItemController` containing your custom model as a published property.

```swift Swift icon=code theme={"system"}
class BannerObservableController: ObservableObject, ItemController {

  @Published var banner: Banner?

  func setItem(_ item: Banner?) {
    self.banner = item
  }

}
```

Then connect this controller to the `QueryRuleCustomDataConnector` or `QueryRuleCustomDataInteractor` and build a SwiftUI view presenting the fetched custom model.

```swift Swift icon=code theme={"system"}
struct ContentView: View {

  @ObservedObject var bannerController: BannerObservableController

  var body: some View {
    if let bannerURL = bannerController.banner?.bannerURL {
      // present a banner using the fetched URL
    }
  }

}
```
