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

# Contains String

Validating string presence in LLM-generated content and user inputs presents unique challenges. The contains string guardrail solves these challenges through instant, deterministic pattern matching that costs nothing and responds in under 10 milliseconds.

<Tabs>
  <Tab title="Instant Validation" icon="bolt">
    When you need to ensure legal disclaimers appear in LLM outputs, block sensitive information in user inputs, or verify required sections exist in generated documents, you need validation that happens instantly without waiting for LLM analysis.

    Contains string provides sub-10ms response times with zero cost since it runs locally using simple pattern matching. This makes it perfect as a front-line filter before more expensive LLM-powered guardrails.
  </Tab>

  <Tab title="Complete Predictability" icon="check-circle">
    Unlike LLM-powered guardrails that interpret meaning and context, contains string validates exactly what you specify. If you check for "password," it finds "password"—no interpretation, no ambiguity, no variation in results.

    This deterministic behavior means 100% reproducibility. The same input always produces the same result, which is essential for compliance verification, security filtering, and quality assurance.
  </Tab>

  <Tab title="Three Validation Modes" icon="list-check">
    Different validation scenarios require different logic. Sometimes you need at least one string present (ANY mode for disclaimers), sometimes you need all strings present (ALL mode for required sections), and sometimes you need none of the strings present (NONE mode for forbidden content).

    Configure which mode matches your use case, provide your string list, and optionally enable case-sensitive matching for precise validation like brand names or technical terms.
  </Tab>
</Tabs>

# How Contains String Works

Understanding the validation process helps you choose the right mode and configure effective string lists:

<Steps>
  <Step title="Content submission with configuration" icon="paper-plane">
    You send text to the contains string guardrail along with your configuration: a list of strings to check for, which mode to use (ANY, ALL, or NONE), and optionally whether to use case-sensitive matching. The configuration determines exactly how the validation behaves.
  </Step>

  <Step title="Pattern matching execution" icon="magnifying-glass">
    The guardrail performs simple string matching against your content. This happens locally on ABV's infrastructure without any LLM calls, making it instant (under 10ms) and free.

    **ANY mode**: Checks if at least one string from your list appears in the text. Passes when any match is found.

    **ALL mode**: Checks if every string from your list appears in the text. Passes only when all strings are present.

    **NONE mode**: Checks that no strings from your list appear in the text. Passes only when zero matches are found.

    By default, matching is case-insensitive ("Password" matches "password"). Enable case-sensitive matching when exact capitalization matters.
  </Step>

  <Step title="Deterministic result" icon="clipboard-check">
    The guardrail returns a result indicating pass or fail. Since this is rule-based validation, there's no "unsure" status—the result is always definitive. The confidence is always 1.0 because pattern matching has no uncertainty.

    The reason field explains which strings were found or missing. Log this internally for debugging and analysis, but as with all guardrails, never expose detailed reasons to end users to prevent evasion learning.
  </Step>

  <Step title="Automatic observability" icon="chart-line">
    Every validation automatically creates an observation in ABV capturing the input text, result, configuration (strings, mode, case sensitivity), and performance metrics. This happens even though the guardrail is free to use, giving you visibility into validation patterns and helping you tune your string lists over time.
  </Step>
</Steps>

# When to Use This Guardrail

Contains string excels in specific scenarios where you can enumerate exactly what to check:

<AccordionGroup>
  <Accordion title="Legal Disclaimer Enforcement" icon="scale-balanced">
    Regulatory requirements often mandate specific disclaimers in generated content. Financial advice requires "not financial advice," medical content needs liability disclaimers, and general-purpose LLM outputs benefit from clarity statements.

    Use ANY mode to accept multiple valid phrasings of the same disclaimer, giving content creators flexibility while ensuring compliance. Check instantly before showing content to users.
  </Accordion>

  <Accordion title="Sensitive Information Blocking" icon="shield-xmark">
    Users sometimes share passwords, credit card numbers, social security numbers, or other sensitive information they shouldn't submit to LLMs. These inputs create security risks and compliance violations.

    Use NONE mode to block content containing forbidden terms like "password," "SSN," "credit card," and "bank account." This pre-filtering happens instantly, blocking obvious violations before more expensive content analysis.
  </Accordion>

  <Accordion title="Required Section Verification" icon="list-check">
    Generated documents, emails, and content often need specific elements for compliance or quality. Marketing emails need unsubscribe links, privacy policy links, and copyright notices. Generated contracts need specific clauses.

    Use ALL mode to ensure every required element appears. If any element is missing, the validation fails, preventing incomplete content from reaching users or requiring manual review.
  </Accordion>

  <Accordion title="Competitor Mention Prevention" icon="ban">
    Marketing content, product descriptions, and customer communications should avoid mentioning competitor brands. Even indirect references can violate brand guidelines or create legal issues.

    Use NONE mode with a comprehensive list of competitor names, product names, and domain names. The instant validation catches mentions before content is published.
  </Accordion>

  <Accordion title="Fast Pre-Filtering Before Expensive Checks" icon="filter">
    When combining multiple guardrails, run the fastest checks first. Contains string costs nothing and responds in under 10ms, while LLM-powered guardrails take 1-3 seconds and consume tokens.

    Use contains string to catch obvious violations instantly, then only run expensive LLM-powered checks on content that passes the initial filter. This pattern dramatically reduces costs and latency.
  </Accordion>
</AccordionGroup>

# Understanding Match Modes

The three modes fundamentally change validation behavior. Choosing the right mode is essential:

## ANY Mode (OR Logic)

**Behavior:** Content passes when at least one string from your list appears.

**Use cases:**

* Legal disclaimers where multiple phrasings are acceptable
* Detecting any of several forbidden categories
* Ensuring at least one required element exists

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    // Accept any valid disclaimer phrasing
    await abv.guardrails.containsString.validate(llmOutput, {
      strings: [
        "not financial advice",
        "consult a professional",
        "for informational purposes only",
        "not legal advice"
      ],
      mode: "any"
    });
    // Passes if ANY of these phrases appears
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    # Accept any valid disclaimer phrasing
    await abv.guardrails.contains_string.validate_async(llm_output, {
        "strings": [
            "not financial advice",
            "consult a professional",
            "for informational purposes only",
            "not legal advice"
        ],
        "mode": "any"
    })
    # Passes if ANY of these phrases appears
    ```
  </Tab>
</Tabs>

## ALL Mode (AND Logic)

**Behavior:** Content passes only when every string from your list appears.

**Use cases:**

* Email compliance requiring unsubscribe link, privacy policy, and copyright
* Document templates needing all required sections
* Quality checks ensuring completeness

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    // Ensure all required email elements are present
    await abv.guardrails.containsString.validate(emailBody, {
      strings: [
        "Unsubscribe",
        "Privacy Policy",
        "Contact Us",
        "© 2024"
      ],
      mode: "all"
    });
    // Passes only if ALL elements are present
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    # Ensure all required email elements are present
    await abv.guardrails.contains_string.validate_async(email_body, {
        "strings": [
            "Unsubscribe",
            "Privacy Policy",
            "Contact Us",
            "© 2024"
        ],
        "mode": "all"
    })
    # Passes only if ALL elements are present
    ```
  </Tab>
</Tabs>

## NONE Mode (NOT Logic)

**Behavior:** Content passes only when zero strings from your list appear.

**Use cases:**

* Blocking sensitive information (passwords, credit cards, SSNs)
* Preventing competitor mentions
* Filtering forbidden terms before expensive checks

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    // Block sensitive information in user inputs
    await abv.guardrails.containsString.validate(userMessage, {
      strings: [
        "password",
        "credit card",
        "ssn",
        "social security",
        "bank account",
        "routing number"
      ],
      mode: "none",
      caseSensitive: false  // Catch any capitalization
    });
    // Passes only if NONE of these terms appear
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    # Block sensitive information in user inputs
    await abv.guardrails.contains_string.validate_async(user_message, {
        "strings": [
            "password",
            "credit card",
            "ssn",
            "social security",
            "bank account",
            "routing number"
        ],
        "mode": "none",
        "caseSensitive": False  # Catch any capitalization
    })
    # Passes only if NONE of these terms appear
    ```
  </Tab>
</Tabs>

# Case-Sensitive Matching

By default, matching is case-insensitive: "PASSWORD," "Password," and "password" all match. This catches variations in how people write.

Enable case-sensitive matching when exact capitalization matters:

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    // Exact brand name matching
    await abv.guardrails.containsString.validate(content, {
      strings: ["iPhone", "MacBook", "JavaScript"],
      mode: "any",
      caseSensitive: true  // "iphone" won't match "iPhone"
    });
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    # Exact brand name matching
    await abv.guardrails.contains_string.validate_async(content, {
        "strings": ["iPhone", "MacBook", "JavaScript"],
        "mode": "any",
        "caseSensitive": True  # "iphone" won't match "iPhone"
    })
    ```
  </Tab>
</Tabs>

# Implementation Patterns

## Legal Disclaimer Validation

Ensure LLM-generated content includes appropriate disclaimers while allowing flexibility in phrasing:

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    async function ensureDisclaimer(content: string): Promise<{ valid: boolean; error?: string }> {
      const result = await abv.guardrails.containsString.validate(content, {
        strings: [
          "not financial advice",
          "not legal advice",
          "consult a professional",
          "for informational purposes only"
        ],
        mode: "any"
      });

      if (result.status === "pass") {
        return { valid: true };
      }

      return {
        valid: false,
        error: "Content must include an appropriate disclaimer"
      };
    }
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    async def ensure_disclaimer(content: str) -> dict:
        result = await abv.guardrails.contains_string.validate_async(content, {
            "strings": [
                "not financial advice",
                "not legal advice",
                "consult a professional",
                "for informational purposes only"
            ],
            "mode": "any"
        })

        if result["status"] == "pass":
            return {"valid": True}

        return {
            "valid": False,
            "error": "Content must include an appropriate disclaimer"
        }
    ```
  </Tab>
</Tabs>

## Sensitive Information Blocking

Prevent users from sharing sensitive information that creates security and compliance risks:

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    async function blockSensitiveInfo(userInput: string): Promise<{ allowed: boolean; message?: string }> {
      const result = await abv.guardrails.containsString.validate(userInput, {
        strings: [
          "password", "pwd", "passcode",
          "credit card", "cc", "card number", "mastercard", "visa",
          "ssn", "social security",
          "bank account", "routing number",
          "pin", "cvv"
        ],
        mode: "none",
        caseSensitive: false
      });

      if (result.status === "pass") {
        return { allowed: true };
      }

      return {
        allowed: false,
        message: "Please don't share sensitive personal information in your message"
      };
    }
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    async def block_sensitive_info(user_input: str) -> dict:
        result = await abv.guardrails.contains_string.validate_async(user_input, {
            "strings": [
                "password", "pwd", "passcode",
                "credit card", "cc", "card number", "mastercard", "visa",
                "ssn", "social security",
                "bank account", "routing number",
                "pin", "cvv"
            ],
            "mode": "none",
            "caseSensitive": False
        })

        if result["status"] == "pass":
            return {"allowed": True}

        return {
            "allowed": False,
            "message": "Please don't share sensitive personal information in your message"
        }
    ```
  </Tab>
</Tabs>

## Email Compliance Verification

Ensure all required elements appear in marketing emails for CAN-SPAM and other compliance:

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    async function validateEmailCompliance(emailBody: string): Promise<{ compliant: boolean; missing?: string[] }> {
      const requiredElements = [
        "Unsubscribe",
        "Privacy Policy",
        "Contact Us",
        "© 2024"  // Current year copyright
      ];

      const result = await abv.guardrails.containsString.validate(emailBody, {
        strings: requiredElements,
        mode: "all"
      });

      if (result.status === "pass") {
        return { compliant: true };
      }

      return {
        compliant: false,
        // In production, determine specific missing elements
        missing: requiredElements
      };
    }
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    async def validate_email_compliance(email_body: str) -> dict:
        required_elements = [
            "Unsubscribe",
            "Privacy Policy",
            "Contact Us",
            "© 2024"  # Current year copyright
        ]

        result = await abv.guardrails.contains_string.validate_async(email_body, {
            "strings": required_elements,
            "mode": "all"
        })

        if result["status"] == "pass":
            return {"compliant": True}

        return {
            "compliant": False,
            # In production, determine specific missing elements
            "missing": required_elements
        }
    ```
  </Tab>
</Tabs>

## Efficient Pre-Filtering Pattern

Use contains string as a fast pre-filter before expensive LLM-powered guardrails:

<Tabs>
  <Tab title="TypeScript/JavaScript" icon="js">
    ```typescript theme={null}
    async function efficientValidation(content: string): Promise<boolean> {
      // Fast check first: block explicitly forbidden terms (< 10ms, free)
      const quickCheck = await abv.guardrails.containsString.validate(content, {
        strings: ["explicit-slur", "forbidden-term", "banned-phrase"],
        mode: "none"
      });

      // If quick check fails, we're done - no need for expensive LLM check
      if (quickCheck.status === "fail") {
        console.log("Blocked by fast pre-filter");
        return false;
      }

      // Only run expensive LLM-powered check if content passed pre-filter
      // This saves 1-3 seconds and token costs when quick check catches issues
      const deepCheck = await abv.guardrails.toxicLanguage.validate(content);
      return deepCheck.status === "pass";
    }
    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    async def efficient_validation(content: str) -> bool:
        # Fast check first: block explicitly forbidden terms (< 10ms, free)
        quick_check = await abv.guardrails.contains_string.validate_async(content, {
            "strings": ["explicit-slur", "forbidden-term", "banned-phrase"],
            "mode": "none"
        })

        # If quick check fails, we're done - no need for expensive LLM check
        if quick_check["status"] == "fail":
            print("Blocked by fast pre-filter")
            return False

        # Only run expensive LLM-powered check if content passed pre-filter
        # This saves 1-3 seconds and token costs when quick check catches issues
        deep_check = await abv.guardrails.toxic_language.validate_async(content)
        return deep_check["status"] == "pass"
    ```
  </Tab>
</Tabs>

# Building Effective String Lists

The effectiveness of contains string depends entirely on the quality of your string lists:

<AccordionGroup>
  <Accordion title="Blocking Sensitive Information" icon="shield-xmark">
    Cast a wide net by including variations. Rather than just "password," include "pwd," "pass," "passcode," "pw." For credit cards, include "credit card," "cc," "card number," "mastercard," "visa," "amex."

    **Pattern:** Think about every reasonable way someone might express the concept, including abbreviations, common misspellings, and related terms.
  </Accordion>

  <Accordion title="Requiring Disclaimers" icon="scale-balanced">
    Offer multiple phrasings that accomplish the same legal purpose. For financial advice disclaimers: "not financial advice," "consult a financial professional," "for informational purposes only," "not investment advice."

    **Pattern:** All variations protect you legally while giving content creators flexibility in exact wording.
  </Accordion>

  <Accordion title="Competitor Blocking" icon="ban">
    Be comprehensive. Include company names, product names, domain names, and common misspellings. For "CompetitorCo": also include "competitor-co," "competitorco," "competitor.com," "CompetitorCorp."

    **Pattern:** Cover official names, informal names, domains, and variations people actually use when mentioning competitors.
  </Accordion>

  <Accordion title="Case Sensitivity Decisions" icon="text">
    Use case-insensitive matching (default) for general terms where capitalization varies. Use case-sensitive matching for brand names ("iPhone" not "iphone"), proper nouns, and technical terms where capitalization has specific meaning ("JavaScript" vs "javascript").

    **Pattern:** Case-sensitive when exact form matters for correctness or brand identity. Case-insensitive for broader coverage of general terms.
  </Accordion>
</AccordionGroup>

# Combining with Other Guardrails

Contains string works particularly well as part of layered validation:

**Sequential filtering pipeline**: Run contains string first (instant, free) to catch obvious violations, then run LLM-powered guardrails (1-3 seconds, token cost) only on content that passes. This dramatically reduces costs while maintaining comprehensive protection.

**With toxic language detection**: Block explicitly forbidden slurs with contains string, then use toxic language detection for context-aware analysis of everything else. The contains string pre-filter catches the obvious cases instantly.

**With valid JSON**: When LLM generates JSON, validate JSON structure first (instant), then use contains string to verify specific required fields exist before checking content quality with LLM-powered guardrails.

**With biased language detection**: Block obviously discriminatory terms with contains string, then use biased language detection for subtle coded language and contextual bias. Two-layer protection at different speeds and costs.

# Next Steps

<CardGroup cols={2}>
  <Card title="Best Practices" icon="star" href="/developer/guardrails/best-practices">
    Learn optimal patterns for combining guardrails, error handling, and cost optimization
  </Card>

  <Card title="Toxic Language" icon="message-slash" href="/developer/guardrails/available/toxic-language">
    Add context-aware toxicity detection after contains string pre-filtering
  </Card>

  <Card title="Valid JSON" icon="brackets-curly" href="/developer/guardrails/available/valid-json">
    Combine with JSON validation for structured LLM outputs
  </Card>

  <Card title="Concepts" icon="book" href="/developer/guardrails/concepts">
    Understand layered validation patterns and decision strategies
  </Card>
</CardGroup>
