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

# Save rule

> Create or update a rule.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Create or replace a rule" href="/doc/libraries/sdk/methods/search/save-rule" />

**Required ACL:** `editSettings`

## Examples

### Save a rule

<CodeGroup>
  ```cs C# theme={"system"}
  Rule ruleToSave = new Rule
  {
      ObjectID = "a-rule-id",
      Enabled = false,
      Conditions = new List<Condition>
      {
        new Condition { Anchoring = "contains", Pattern = "smartphone" },
      },
      Consequence = new Consequence
      {
          Params = new ConsequenceParams
          {
              AutomaticFacetFilters = new List<AutomaticFacetFilter>
              {
                  new AutomaticFacetFilter { Facet = "category = 1" }
              }
          }
      },
      Validity = new List<TimeRange>
      {
          new TimeRange
          {
              From = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds(),
              Until = new DateTimeOffset(DateTime.UtcNow.AddDays(10)).ToUnixTimeSeconds()
          }
      }
    };

  index.SaveRule(rule, forwardToReplicas: false);

  // Asynchronous
  await index.SaveRuleAsync(rule, forwardToReplicas: false);
  ```

  ```go Go theme={"system"}
  forwardToReplicas := opt.ForwardToReplicas(false)

  rule := search.Rule{
    ObjectID:  "a-rule-id",
    Conditions: []search.RuleCondition{
      {
        Anchoring: search.Contains, Pattern: "smartphone"
      },
    },
    Consequence: search.RuleConsequence{
      Params: &search.RuleParams{
        QueryParams: search.QueryParams{
          Filters: opt.Filters("category = 1"),
        },
      },
    },
    Enabled: opt.Enabled(false), // Optional, to turn the rule off
    Validity: []search.TimeRange{ // Optional, to add valid time ranges
      {
        From:  time.Now(),
        Until: time.Now().AddDate(0, 0, 10),
      },
    },
  }

  res, err := index.SaveRule(rule, forwardToReplicas)
  ```

  ```java Java theme={"system"}
  Condition condition = new Condition()
          .setPattern("smartphone")
          .setAnchoring("contains");

  ConsequenceParams params = (ConsequenceParams) new ConsequenceParams()
          .setFilters("category = 1");

  Consequence consequence =  new Consequence()
          .setParams(params);

  Rule rule = new Rule()
          .setObjectID("a-unique-identifier")
          .setConditions(Collections.singletonList(condition))
          .setConsequence(consequence);

  // Optional: turn the rule off
  rule.setEnabled(false);

  // Optional: add valid time ranges
  List<TimeRange> validity =
          Collections.singletonList(
                  new TimeRange(
                          OffsetDateTime.now(ZoneOffset.UTC),
                          OffsetDateTime.now(ZoneOffset.UTC).plusDays(10));
  rule.setValidity(validity);

  index.saveRule(rule);

  // Asynchronous
  index.saveRuleAsync(rule);
  ```

  ```js JavaScript theme={"system"}
  const rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        pattern: "smartphone",
        anchoring: "contains",
      },
    ],
    consequence: {
      params: {
        filters: "category = 1",
      },
    },

    // Optional: turn the rule off
    enabled: false,

    // Optional: add valid time ranges
    validity: [
      {
        from: Math.floor(Date.now() / 1000),
        until: Math.floor(Date.now() / 1000) + 10 * 24 * 60 * 60,
      },
    ],
  };

  // Save the rule
  index.saveRule(rule).then(() => {
    // done
  });

  // Save the rule and forward it to all replicas of the index.
  index.saveRule(rule, { forwardToReplicas: true }).then(() => {
    // done
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val rule = Rule(
      objectID = ObjectID("a-rule-id"),
      enabled = false,
      conditions = listOf(Condition(
          pattern = Pattern.Literal("smartphone"),
          anchoring = Anchoring.Contains,
          alternative = Alternatives.True
      )),
      consequence = Consequence(
          query = Query(filters = "category = 1")
      ),
      validity = listOf(TimeRange(0, 10))
  )

  index.saveRule(rule, forwardToReplicas = true)
  ```

  ```php PHP theme={"system"}
  $rule = array(
      'objectID' => 'a-rule-id',
      'conditions' => array(array(
          'pattern'   => 'smartphone',
          'anchoring' => 'contains',
      )),
      'consequence' => array(
          'params' => array(
              'filters' => 'category = 1',
          )
      )
  );

  // Optional: turn the rule off
  $rule['enabled'] = false;

  // Optional: add valid time ranges
  $rule['validity'] = array(
    array(
      'from' => time(),
      'until' => time() + 10*24*60*60,
    )
  );

  $index->saveRule($rule);
  ```

  ```python Python theme={"system"}
  rule = {
      "objectID": "a-rule-id",
      "conditions": [{"pattern": "smartphone", "anchoring": "contains"}],
      "consequence": {"params": {"filters": "category = 1"}},
  }

  # Optional: turn the rule off
  rule["enabled"] = False

  # Optional: add valid time ranges
  rule["validity"] = [
      {
          "from": int((datetime.datetime.utcnow().timestamp())),
          "until": int((datetime.datetime.utcnow() + timedelta(days=10)).timestamp()),
      }
  ]

  # Save the rule
  response = index.save_rule(rule)

  # Save the rule and forward it to all replicas of the index.
  response = index.save_rule(rule, {"forwardToReplicas": True})
  ```

  ```ruby Ruby theme={"system"}
  rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        pattern: "smartphone",
        anchoring: "contains"
      }
    ],
    consequence: {
      params: {
        filters: "category = 1"
      }
    }
  }

  # Optional: turn the rule off
  rule["enabled"] = false

  # Optional: add valid time ranges
  # (with `require 'date'`)
  rule["validity"] = [
    {
      from: Time.now.to_i,
      until: (DateTime.now + 10).to_time.to_i
    }
  ]

  # Save the rule
  index.save_rule(rule)
  # Save the rule and wait until it's saved before continuing
  index.save_rule!(rule)
  # Save the rule and forward it to all replicas of the index.
  response = index.save_rule(rule, {forwardToReplicas: true})
  ```

  ```scala Scala theme={"system"}
  val from = ZonedDateTime.now(ZoneId.of("UTC").normalized());
  val until = from.plusDays(10);

  val ruleToSave = Rule(
    objectID = "a-rule-id",
    enabled = Some(false), // Optional: turn the rule off
    validity = Some(Seq(TimeRange(from, until))), // Optional: add valid time ranges
    conditions = Some(Seq(Condition(
      pattern = "smartphone",
      anchoring = "contains",
    ))),
    consequence = Consequence(
      params = Some(Map("filters" -> "category = 1")),
    ),
  )
  client.execute {
    save rule ruleToSave inIndex "index_name"
  }
  ```

  ```swift Swift theme={"system"}
  let rule = Rule(objectID: "a-rule-id")
    .set(\.isEnabled, to: false)
    .set(\.conditions, to: [
      Rule.Condition()
        .set(\.anchoring, to: .contains)
        .set(\.pattern, to: .literal("smartphone"))
    ])
    .set(\.consequence, to: Rule.Consequence()
      .set(\.query, to: Query()
        .set(\.filters, to: "category = 1")
      )
    )
    .set(\.validity, to: [
      TimeRange(from: Date(),
                until: Date().addingTimeInterval(10 * 24 * 60 * 60)) // 10 days
      ]
    )

  index.saveRule(rule, forwardToReplicas: true) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

### Save a rule with alternatives enabled

<CodeGroup>
  ```cs C# theme={"system"}
  Rule ruleToSave = new Rule
  {
      ObjectID = "a-rule-id",
      Conditions = new List<Condition>
      {
        new Condition { Anchoring = "contains", Pattern = "smartphone", Alternatives = true },
      }
      Consequence = new Consequence
      {
          Params = new ConsequenceParams
          {
              Filters = "category = 1"
          }
      },
    };
  index.SaveRule(rule);
  ```

  ```go Go theme={"system"}
  rule := search.Rule{
    ObjectID:  "a-rule-id",
    Conditions: []search.RuleCondition{
      {
        Anchoring: search.Contains, Pattern: "smartphone", Alternatives: true
      },
    },
    Consequence: search.RuleConsequence{
      Params: &search.RuleParams{
        QueryParams: search.QueryParams{
          Filters: opt.Filters("category = 1"),
        },
      },
    },
  }
  res, err := index.SaveRule(rule)
  ```

  ```java Java theme={"system"}
  Condition condition = new Condition()
          .setPattern("smartphone")
          .setAnchoring("contains")
          .setAlternatives(true);
  ConsequenceParams params = (ConsequenceParams) new ConsequenceParams()
          .setFilters("category = 1");
  Consequence consequence =  new Consequence()
          .setParams(params);
  Rule rule = new Rule()
          .setObjectID("a-rule-id")
          .setConditions(Collections.singletonList(condition))
          .setConsequence(consequence);
  index.saveRule(rule);
  ```

  ```js JavaScript theme={"system"}
  const rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        pattern: "smartphone",
        anchoring: "contains",
        alternatives: true,
      },
    ],
    consequence: {
      params: {
        filters: "category = 1",
      },
    },
  };

  index.saveRule(rule).then(() => {
    // done
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val rule = Rule(
      objectID = ObjectID("a-rule-id"),
      conditions = listOf(Condition(
          pattern = Pattern.Literal("smartphone"),
          anchoring = Anchoring.Contains
          alternatives = Alternatives.true
      )),
      consequence = Consequence(
          params = Params(filters = "category = 1")
      )
  )
  index.saveRule(rule)
  ```

  ```php PHP theme={"system"}
  $rule = array(
      'objectID' => 'a-rule-id',
      'conditions' => array(array(
          'pattern'   => 'smartphone',
          'anchoring' => 'contains',
          'alternatives' => true
      )),
      'consequence' => array(
          'params' => array(
              'filters' => 'category = 1',
          )
      )
  );
  $index->saveRule($rule);
  ```

  ```python Python theme={"system"}
  rule = {
      "objectID": "a-rule-id",
      "conditions": [
          {"pattern": "smartphone", "anchoring": "contains", "alternatives": True}
      ],
      "consequence": {"params": {"filters": "category = 1"}},
  }
  response = index.save_rule(rule)
  ```

  ```ruby Ruby theme={"system"}
  rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        pattern: "smartphone",
        anchoring: "contains",
        alternatives: true
      }
    ],
    consequence: {
      params: {
        filters: "category = 1"
      }
    }
  }
  index.save_rule(rule)
  ```

  ```scala Scala theme={"system"}
  val ruleToSave = Rule(
    objectID = "a-rule-id",
    conditions = Some(Seq(Condition(
      pattern = "smartphone",
      anchoring = "contains",
      alternatives = true
    ))),
    consequence = Consequence(
      params = Some(Map("filters" -> "category = 1")),
    ),
  )

  client.execute {
    save rule ruleToSave inIndex "index_name"
  }
  ```

  ```swift Swift theme={"system"}
  let rule = Rule(objectID: "a-rule-id")
    .set(\.conditions, to: [
      Rule.Condition()
        .set(\.anchoring, to: .contains)
        .set(\.pattern, to: .literal("smartphone"))
        .set(\.alternatives, to: .true)
    ])
    .set(\.consequence, to: Rule.Consequence()
      .set(\.query, to: Query()
        .set(\.filters, to: "category = 1")
      )
    )

  index.saveRule(rule, forwardToReplicas: true) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

### Save a rule with a context-based condition

<CodeGroup>
  ```cs C# theme={"system"}
  Rule ruleToSave = new Rule
  {
      ObjectID = "a-rule-id",
      Conditions = new List<Condition>
      {
        new Condition { Context = "mobile"  }
      },
      Consequence = new Consequence
      {
          Params = new ConsequenceParams
          {
              AutomaticFacetFilters = new List<AutomaticFacetFilter>
              {
                  new AutomaticFacetFilter { Facet = "release_date >= 1568498400" }
              }
          }
      }
    };

  index.SaveRule(rule, forwardToReplicas: false);
  ```

  ```go Go theme={"system"}
  forwardToReplicas := opt.ForwardToReplicas(false)

  rule := search.Rule{
  	ObjectID:   "a-rule-id",
  	Conditions: []search.RuleCondition{{Context: "mobile"}},
  	Consequence: search.RuleConsequence{
  		Params: &search.RuleParams{
  			QueryParams: search.QueryParams{
  				Filters: opt.Filters("release_date >= 1568498400"),
  			},
  		},
  	},
  }

  res, err := index.SaveRule(rule, forwardToReplicas)
  ```

  ```java Java theme={"system"}
  Condition condition = new Condition()
          .setContext("smartphone")

  ConsequenceParams params = (ConsequenceParams) new ConsequenceParams()
          .setFilters("release_date >= 1568498400");

  Consequence consequence =  new Consequence()
          .setParams(params);

  Rule rule = new Rule()
          .setObjectID("a-unique-identifier")
          .setConditions(Collections.singletonList(condition))
          .setConsequence(consequence);

  index.saveRule(rule);

  // Asynchronous
  index.saveRuleAsync(rule);
  ```

  ```js JavaScript theme={"system"}
  const rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        context: "mobile",
      },
    ],
    consequence: {
      params: {
        filters: "release_date >= 1568498400",
      },
    },
  };

  index.saveRule(rule).then(() => {
    // done
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val rule = Rule(
      objectID = ObjectID("a-rule-id"),
      conditions = listOf(Condition(
          context = Context.Literal("mobile")
      )),
      consequence = Consequence(
          query = Query(filters = "release_date >= 1568498400")
      ),
  )

  index.saveRule(rule)
  ```

  ```php PHP theme={"system"}
  $rule = array(
      'objectID' => 'a-rule-id',
      'conditions' => array(array(
          'context' => 'mobile',
      )),
      'consequence' => array(
          'params' => array(
              'filters' => 'release_date >= 1568498400',
          )
      )
  );

  $index->saveRule($rule);
  ```

  ```python Python theme={"system"}
  rule = {
      'objectID': 'a-rule-id',
      'conditions': [{
          'context': 'mobile'
      }]s,
      'consequence': {
          'params': {
              'filters': 'release_date >= 1568498400'
          }
      }
  }

  response = movies.save_rule(rule)
  ```

  ```ruby Ruby theme={"system"}
  rule = {
    objectID: "a-rule-id",
    conditions: [
      {
        context: "mobile"
      }
    ],
    consequence: {
      params: {
        filters: "release_date >= 1568498400"
      }
    }
  }

  index.save_rule(rule)
  ```

  ```scala Scala theme={"system"}
  val ruleToSave = Rule(
    objectID = "a-rule-id",
    conditions = Some(Seq(Condition(
      context = "mobile",
    ))),
    consequence = Consequence(
      params = Some(Map("filters" -> "release_date >=  1568498400")),
    ),
  )
  client.execute {
    save rule ruleToSave inIndex "index"
  }
  ```

  ```swift Swift theme={"system"}
  let rule = Rule(objectID: "a-rule-id")
    .set(\.conditions, to: [
      Rule.Condition().set(\.context, to: "mobile")
    ])
    .set(\.consequence, to: Rule.Consequence()
      .set(\.query, to: Query()
        .set(\.filters, to: "release_date >= 1568498400")
      )
    )

  index.saveRule(rule, forwardToReplicas: true) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

## Parameters

<ParamField body="rule" type="object" required>
  The rule object with conditions and consequences.
  For a complete JSON rule object, see the [`saveRule` HTTP API reference](/doc/rest-api/search/save-rule).

  <Expandable>
    <ParamField body="consequence" type="object" required>
      Action to perform when this rule is triggered.
      For more information, see [Consquences](/doc/guides/managing-results/rules/rules-overview#consequences).

      <Expandable>
        <ParamField body="filterPromotes" type="boolean" default={false}>
          Determines whether promoted records must also match active filters for the consequence to apply.

          This ensures user-applied filters take priority and irrelevant matches aren't shown.
          For example, if you promote a record with color: red but the user filters for color: blue,
          the "red" record won't be shown.
        </ParamField>

        <ParamField body="hide" type="object[]">
          List of objects with `objectID` properties for records you want to hide.

          **Example:**

          ```json JSON icon=braces theme={"system"}
          {
            "consequence": {
              "hide": [
                {
                  "objectID": "test-record-123"
                }
              ]
            }
          }
          ```
        </ParamField>

        <ParamField body="promote" type="object[]">
          Fix positions of records in the search results.
          You can promote up to 300 records per rule.

          <Expandable>
            <ParamField body="objectID" type="string">
              Object ID of the record to promote.
              Either `objectID` or `objectIDs` is required.
            </ParamField>

            <ParamField body="objectIDs" type="string">
              Object IDs of a *group* of records to promote.
              A group can have up to 100 records.
              Either `objectID` or `objectIDs` is required.

              The records are placed as a group at `position`.
              For example, if you want to promote four records to position 0,
              they will be the first four search results.
            </ParamField>

            <ParamField body="position" type="integer" required>
              Position in the search results where you want to show the promoted records,
              starting with 0.
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="params" type="object">
          Parameters to apply to this search.
          You can use all [search parameters](/doc/api-reference/search-api-parameters),
          plus the special fields `query`, `automaticFacetFilters`, and `automaticOptionalFacetFilters`.

          <Expandable>
            <ParamField body="automaticFacetFilters" type="string[] | object[]">
              Facet filters to apply to this search.
              You can use this to respond to search queries that match a facet value.
              For example, if users search for "comedy", which matches a facet value of the "genre" facet,
              you can filter the results to show the top-ranked comedy movies.

              <Expandable>
                <ParamField body="facet" type="string" required>
                  Facet name. It must match the placeholder used in the `patterns` parameter of the rule's condition.
                  For example, with `pattern: {facet:genre}`, `automaticFacetFilters.facet` must be `genre`.
                </ParamField>

                <ParamField body="disjunctive" type="boolean" default={false}>
                  Whether multiple matching filter conditions should be combined with `OR`.
                  By default, multiple matching filter conditions are combined with `AND`.
                </ParamField>

                <ParamField body="score" type="integer" default={1}>
                  Filter scores to give different weights to individual filters.
                </ParamField>
              </Expandable>
            </ParamField>

            <ParamField body="automaticOptionalFacetFilters" type="string[] | object[]">
              Optional filters to apply to this search.
              This is the same as [`automaticFacetFilters`](#param-automatic-facet-filters),
              but with [`optionalFilters`](/doc/api-reference/api-parameters/optionalFilters):
              records that don't match the filters will be ranked below matching records.
            </ParamField>

            <ParamField body="query" type="string | object">
              If `query` is a string, it replaces the entire search query.
              If `query` is an object, it describes the incremental edits made to the query.

              <Expandable>
                <ParamField body="remove" type="string[]">
                  Words to delete from the query.
                </ParamField>

                <ParamField body="edits" type="object[]">
                  Changes to make to the query.

                  * Remove words or patterns from the query:
                    (Example: remove "red" from the query)

                    ```json JSON icon=braces theme={"system"}
                    {
                      "query": {
                        "edits": [
                          {
                            "type": "remove",
                            "delete": "red"
                          }
                        ]
                      }
                    }
                    ```

                  * Replace words or patterns in the query:
                    (Example: replace "red" with "blue")

                    ```json JSON icon=braces theme={"system"}
                    {
                      "query": {
                        "edits": [
                          {
                            "type": "replace",
                            "delete": "red",
                            "insert": "blue"
                          }
                        ]
                      }
                    }
                    ```
                </ParamField>
              </Expandable>
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="userData" type="object">
          A JSON object with custom data that will be appended to the `userData` array in the search response.
          This object isn't interpreted by the API and is limited to 1 kB of minified JSON.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="objectID" type="string" required>
      Unique identifier of the rule object.
    </ParamField>

    <ParamField body="conditions" type="object[]">
      List of conditions that should trigger this rule.
      You can add up to 25 conditions per rule.

      <Expandable>
        <ParamField body="alternatives" type="boolean" default={false}>
          Whether the pattern should match plurals, synonyms, and typos.
          For example, if `pattern` is `shoe`, and `alternatives` is true,
          the rule is also triggered when the query is `shoes`, or `sheo` (typo).

          For each word in `pattern`, Algolia checks up to 10 alternatives.

          <Warning>
            If the total number of alternatives is more than 10,
            Algolia may not check some or even any of the words.
          </Warning>
        </ParamField>

        <ParamField body="anchoring" type="enum<string>">
          Which part of the query pattern must match to trigger the rule:

          * `contains`: the pattern can match anywhere in the query
          * `is`: the pattern must exactly match the query
          * `endsWith`: the pattern must match the end of the query
          * `startsWith`: the pattern must match the beginning of the query

          Empty queries are only allowed with `is`.
        </ParamField>

        <ParamField body="context" type="string">
          An additional restriction that only triggers the rule, when the search has the same value as `ruleContexts` parameter.
          For example, if `context: "mobile"`,
          the rule is only triggered when the search request has a matching `ruleContexts: "mobile"`.
          A rule context must only contain alphanumeric characters.
        </ParamField>

        <ParamField body="filters" type="string">
          Filters that trigger the rule.

          You can add filters using the syntax `facet:value` so that the rule is triggered, when the specific filter is selected.
          You can use filters on its own or combine it with the pattern parameter.
          You can't combine multiple filters with `OR` and you can't use numeric filters.
        </ParamField>

        <ParamField body="pattern" type="string">
          Query pattern that triggers the rule.

          You can use either a literal string, or a special pattern `{facet:ATTRIBUTE}`, where `ATTRIBUTE` is a facet name.
          The rule is triggered if the query matches the literal string or a value of the specified facet.
          For example, with `pattern: {facet:genre}`,
          the rule is triggered when users search for a genre, such as "comedy".

          When specifying a query pattern, you must also specify an `anchoring`.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="description" type="string">
      Descriptive text, that helps you find the rule when searching and understand its purpose.
    </ParamField>

    <ParamField body="enabled" type="boolean" default={true}>
      Whether the rule is active.
      If `false`, the rule is still added to the index but it's not applied when searching.
    </ParamField>

    <ParamField body="validity" type="object[]">
      Time ranges when this rule should be active.
      By default, a rule is always active.

      <Expandable>
        <ParamField body="from" type="integer">
          Timestamp when the rule should become active, in seconds since the Unix epoch.
        </ParamField>

        <ParamField body="to" type="integer">
          Timestamp when the rule should become inactive again,
          in seconds since the Unix epoch.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="forwardToReplicas" type="boolean" default={false}>
  Whether to add or update the rule for all replicas of the index.
</ParamField>

## Response

<ResponseField name="taskID" type="integer">
  The task ID used with the [`waitTask`](/doc/libraries/sdk/v1/methods/wait-task) method.
</ResponseField>

<ResponseField name="updatedAt" type="string">
  Date at which the indexing job has been created.
</ResponseField>

### Response as JSON

This section shows the JSON response returned by the API.
Each API client wraps this response in language-specific objects, so the structure may vary.
To view the response, use the `getLogs` method.
Don't rely on the order of properties—JSON objects don't preserve key order.

```jsonc JSON icon=braces theme={"system"}
{
  "updatedAt":"2013-01-18T15:33:13.556Z",
  "taskID": 678
}
```
