This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix. The content has been processed where empty lines have been removed.

================================================================
File Summary
================================================================

Purpose:
--------
This file contains a packed representation of the entire repository's contents.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.

File Format:
------------
The content is organized as follows:
1. This summary section
2. Repository information
3. Directory structure
4. Multiple file entries, each consisting of:
  a. A separator line (================)
  b. The file path (File: path/to/file)
  c. Another separator line
  d. The full contents of the file
  e. A blank line

Usage Guidelines:
-----------------
- This file should be treated as read-only. Any changes should be made to the
  original repository files, not this packed version.
- When processing this file, use the file path to distinguish
  between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
  the same level of security as you would the original repository.

Notes:
------
- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Files matching these patterns are excluded: .specstory/**/*.md, .venv/**, _private/**, CLEANUP.txt, **/*.json, *.lock
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Empty lines have been removed from all files

Additional Info:
----------------

================================================================
Directory Structure
================================================================
.cursor/
  rules/
    0project.mdc
    cleanup.mdc
    filetree.mdc
.github/
  workflows/
    push.yml
    release.yml
debug_output/
  qwant_analysis.txt
  qwant_content.html
  yahoo_analysis.txt
  yahoo_content.html
resources/
  brave/
    brave_image.md
    brave_news.md
    brave_video.md
    brave.md
  pplx/
    pplx_urls.txt
    pplx.md
  you/
    you_news.md
    you_news.txt
    you.md
    you.txt
  pricing.md
src/
  twat_search/
    web/
      engines/
        lib_falla/
          core/
            __init__.py
            aol.py
            ask.py
            bing.py
            dogpile.py
            duckduckgo.py
            falla.py
            fetch_page.py
            gibiru.py
            google.py
            mojeek.py
            qwant.py
            searchencrypt.py
            startpage.py
            yahoo.py
            yandex.py
          __init__.py
          main.py
          requirements.txt
          settings.py
          utils.py
        __init__.py
        base.py
        bing_scraper.py
        brave.py
        critique.py
        duckduckgo.py
        falla.py
        google_scraper.py
        hasdata.py
        pplx.py
        serpapi.py
        tavily.py
        you.py
      __init__.py
      api.py
      cli.py
      config.py
      engine_constants.py
      exceptions.py
      models.py
      utils.py
    __init__.py
    __main__.py
tests/
  unit/
    web/
      engines/
        __init__.py
        test_base.py
      __init__.py
      test_api.py
      test_config.py
      test_exceptions.py
      test_models.py
      test_utils.py
    __init__.py
    mock_engine.py
  web/
    test_bing_scraper.py
  conftest.py
  test_twat_search.py
.gitignore
.pre-commit-config.yaml
CHANGELOG.md
cleanup.py
debug_fetch.py
falla_search.py
google_debug_Python_programming_language.html
google_debug_test_query.html
LICENSE
pyproject.toml
README.md
requirements.txt
test_async_falla.py
test_falla.py
test_google_falla_debug.py
test_simple.py
test_sync_falla.py
TODO.md
VERSION.txt

================================================================
Files
================================================================

================
File: .cursor/rules/0project.mdc
================
---
description: About this project
globs: 
alwaysApply: false
---
# About this project

`twat-search` is a multi-provider search 

## Development Notes
- Uses `uv` for Python package management
- Quality tools: ruff, mypy, pytest
- Clear provider protocol for adding new search backends
- Strong typing and runtime checks throughout

================
File: .cursor/rules/cleanup.mdc
================
---
description: Run `cleanup.py` script before and after changes
globs: 
alwaysApply: false
---
Before you do any changes or if I say "cleanup", run the `cleanup.py update` script in the main folder. Analyze the results, describe recent changes in [PROGRESS.md](mdc:PROGRESS.md) and edit @TODO.md to update priorities and plan next changes. PERFORM THE CHANGES, then run the `cleanup.py status` script and react to the results.

When you edit @TODO.md, lead in lines with empty GFM checkboxes if things aren't done (`- [ ] `) vs. filled (`- [x] `) if done.

================
File: .cursor/rules/filetree.mdc
================
---
description: File tree of the project
globs: 
---
[1.3K]  .
├── [  64]  .benchmarks
├── [  96]  .cursor
│   └── [ 192]  rules
│       ├── [ 334]  0project.mdc
│       ├── [ 559]  cleanup.mdc
│       └── [ 10K]  filetree.mdc
├── [  96]  .github
│   └── [ 128]  workflows
│       ├── [2.7K]  push.yml
│       └── [1.4K]  release.yml
├── [3.5K]  .gitignore
├── [1.2K]  .pre-commit-config.yaml
├── [ 128]  .specstory
│   ├── [1.6K]  history
│   │   ├── [2.7K]  .what-is-this.md
│   │   ├── [ 52K]  2025-02-25_01-58-creating-and-tracking-project-tasks.md
│   │   ├── [7.4K]  2025-02-25_02-17-project-task-continuation-and-progress-update.md
│   │   ├── [ 11K]  2025-02-25_02-24-planning-tests-for-twat-search-web-package.md
│   │   ├── [196K]  2025-02-25_02-27-implementing-tests-for-twat-search-package.md
│   │   ├── [ 46K]  2025-02-25_02-58-transforming-python-script-into-cli-tool.md
│   │   ├── [ 93K]  2025-02-25_03-09-generating-a-name-for-the-chat.md
│   │   ├── [5.5K]  2025-02-25_03-33-untitled.md
│   │   ├── [ 57K]  2025-02-25_03-54-integrating-search-engines-into-twat-search.md
│   │   ├── [ 72K]  2025-02-25_04-05-consolidating-you-py-and-youcom-py.md
│   │   ├── [6.1K]  2025-02-25_04-13-missing-env-api-key-names-in-pplx-py.md
│   │   ├── [118K]  2025-02-25_04-16-implementing-functions-for-brave-search-engines.md
│   │   ├── [286K]  2025-02-25_04-48-unifying-search-engine-parameters-in-twat-search.md
│   │   ├── [ 83K]  2025-02-25_05-36-implementing-duckduckgo-search-engine.md
│   │   ├── [194K]  2025-02-25_05-43-implementing-the-webscout-search-engine.md
│   │   ├── [ 23K]  2025-02-25_06-07-implementing-bing-scraper-engine.md
│   │   ├── [ 15K]  2025-02-25_06-12-continuing-bing-scraper-engine-implementation.md
│   │   ├── [121K]  2025-02-25_06-34-implementing-safe-import-patterns-in-modules.md
│   │   ├── [9.9K]  2025-02-25_07-09-refactoring-plan-and-progress-update.md
│   │   ├── [ 40K]  2025-02-25_07-17-implementing-phase-1-from-todo-md.md
│   │   ├── [292K]  2025-02-25_07-34-integrating-hasdata-google-serp-apis.md
│   │   ├── [142K]  2025-02-25_08-19-implementing-search-engines-from-nextengines-md.md
│   │   ├── [175K]  2025-02-26_09-54-implementing-plain-option-for-search-commands.md
│   │   ├── [264K]  2025-02-26_10-55-standardizing-engine-naming-conventions.md
│   │   ├── [4.3K]  2025-02-26_11-30-untitled.md
│   │   ├── [102K]  2025-02-26_12-11-update-config-py-to-use-engine-constants.md
│   │   ├── [278K]  2025-02-26_12-18-update-engine-imports-and-exports-in-init-py.md
│   │   ├── [268K]  2025-02-26_13-40-search-engine-initialization-errors.md
│   │   ├── [ 61K]  2025-02-26_14-15-codebase-issue-analysis-and-fix-plan.md
│   │   ├── [ 43K]  2025-02-26_14-52-resolving-critical-issues-in-todo-md.md
│   │   ├── [247K]  2025-02-26_17-48-progress-update-for-twat-search-project.md
│   │   ├── [ 28K]  2025-02-26_18-28-fixing-num-results-parameter-in-twat-search.md
│   │   ├── [ 63K]  2025-02-26_18-44-fixing-search-engine-issues-in-codebase.md
│   │   ├── [ 72K]  2025-02-26_19-37-removing-anywebsearch-references-from-codebase.md
│   │   ├── [ 98K]  2025-02-26_19-49-fixing-linting-errors-in-code.md
│   │   ├── [761K]  2025-02-26_20-02-analyzing-todo-md-and-updating-progress-md.md
│   │   ├── [ 69K]  2025-02-26_22-55-bing-scraper-result-inconsistency-investigation.md
│   │   ├── [591K]  2025-02-26_23-13-google-scraper-result-validation-issues.md
│   │   ├── [ 23K]  2025-02-27_12-02-plan-for-adding-support-for-falla-engines.md
│   │   ├── [615K]  2025-02-27_13-08-implementing-falla-and-tracking-progress.md
│   │   ├── [ 43K]  2025-02-27_15-08-project-update-and-task-management.md
│   │   ├── [317K]  2025-02-27_15-45-updating-falla-library-selenium-to-playwright.md
│   │   ├── [133K]  2025-02-27_17-02-fixing-falla-py-async-issues.md
│   │   ├── [ 17K]  2025-02-27_17-34-improving-search-engine-selectors-in-falla.md
│   │   ├── [ 76K]  2025-03-04_05-12-fixing-ruff-linting-errors-in-code.md
│   │   ├── [488K]  2025-03-04_05-38-implementing-phases-1-and-2-from-todo-md.md
│   │   ├── [2.8K]  2025-03-04_07-32-project-documentation-and-cleanup-tasks.md
│   │   └── [ 644]  2025-03-04_07-53-untitled.md
│   └── [2.2M]  history.txt
├── [2.8K]  CHANGELOG.md
├── [ 499]  CLEANUP.txt
├── [1.0K]  LICENSE
├── [ 14K]  README.md
├── [ 12K]  TODO.md
├── [   7]  VERSION.txt
├── [ 13K]  cleanup.py
├── [6.3K]  debug_fetch.py
├── [ 256]  debug_output
│   ├── [ 445]  qwant_analysis.txt
│   ├── [100K]  qwant_content.html
│   ├── [153K]  qwant_screenshot.png
│   ├── [ 476]  yahoo_analysis.txt
│   ├── [ 88K]  yahoo_content.html
│   └── [402K]  yahoo_screenshot.png
├── [ 192]  dist
├── [7.4K]  falla_search.py
├── [4.0K]  google_debug_Python_programming_language.html
├── [3.9K]  google_debug_test_query.html
├── [5.4K]  pyproject.toml
├── [  43]  requirements.txt
├── [ 224]  resources
│   ├── [ 224]  brave
│   │   ├── [ 65K]  brave.md
│   │   ├── [ 29K]  brave_image.md
│   │   ├── [ 22K]  brave_news.md
│   │   └── [ 22K]  brave_video.md
│   ├── [ 128]  pplx
│   │   ├── [ 32K]  pplx.md
│   │   └── [ 335]  pplx_urls.txt
│   ├── [ 15K]  pricing.md
│   └── [ 192]  you
│       ├── [ 54K]  you.md
│       ├── [ 251]  you.txt
│       ├── [ 58K]  you_news.md
│       └── [  98]  you_news.txt
├── [ 128]  src
│   └── [ 256]  twat_search
│       ├── [ 613]  __init__.py
│       ├── [2.5K]  __main__.py
│       └── [ 416]  web
│           ├── [1.8K]  __init__.py
│           ├── [ 12K]  api.py
│           ├── [ 48K]  cli.py
│           ├── [ 19K]  config.py
│           ├── [2.8K]  engine_constants.py
│           ├── [ 576]  engines
│           │   ├── [8.7K]  __init__.py
│           │   ├── [ 17K]  base.py
│           │   ├── [ 11K]  bing_scraper.py
│           │   ├── [ 15K]  brave.py
│           │   ├── [9.2K]  critique.py
│           │   ├── [7.8K]  duckduckgo.py
│           │   ├── [ 12K]  falla.py
│           │   ├── [ 12K]  google_scraper.py
│           │   ├── [7.9K]  hasdata.py
│           │   ├── [ 288]  lib_falla
│           │   │   ├── [ 822]  __init__.py
│           │   │   ├── [ 608]  core
│           │   │   │   ├── [1.4K]  __init__.py
│           │   │   │   ├── [ 763]  aol.py
│           │   │   │   ├── [ 892]  ask.py
│           │   │   │   ├── [2.4K]  bing.py
│           │   │   │   ├── [ 855]  dogpile.py
│           │   │   │   ├── [6.7K]  duckduckgo.py
│           │   │   │   ├── [ 18K]  falla.py
│           │   │   │   ├── [2.4K]  fetch_page.py
│           │   │   │   ├── [ 860]  gibiru.py
│           │   │   │   ├── [ 12K]  google.py
│           │   │   │   ├── [ 762]  mojeek.py
│           │   │   │   ├── [5.9K]  qwant.py
│           │   │   │   ├── [ 923]  searchencrypt.py
│           │   │   │   ├── [ 900]  startpage.py
│           │   │   │   ├── [5.4K]  yahoo.py
│           │   │   │   └── [2.1K]  yandex.py
│           │   │   ├── [2.9K]  main.py
│           │   │   ├── [ 365]  requirements.txt
│           │   │   ├── [ 378]  settings.py
│           │   │   └── [4.8K]  utils.py
│           │   ├── [7.7K]  pplx.py
│           │   ├── [7.3K]  serpapi.py
│           │   ├── [8.2K]  tavily.py
│           │   └── [8.6K]  you.py
│           ├── [1.0K]  exceptions.py
│           ├── [1.6K]  models.py
│           └── [4.1K]  utils.py
├── [ 453]  test_async_falla.py
├── [ 443]  test_falla.py
├── [3.3K]  test_google_falla_debug.py
├── [1.7K]  test_simple.py
├── [ 341]  test_sync_falla.py
├── [ 256]  tests
│   ├── [  64]  .benchmarks
│   ├── [2.0K]  conftest.py
│   ├── [ 193]  test_twat_search.py
│   ├── [ 192]  unit
│   │   ├── [  78]  __init__.py
│   │   ├── [1.6K]  mock_engine.py
│   │   └── [ 320]  web
│   │       ├── [  82]  __init__.py
│   │       ├── [ 160]  engines
│   │       │   ├── [  73]  __init__.py
│   │       │   └── [4.4K]  test_base.py
│   │       ├── [5.2K]  test_api.py
│   │       ├── [2.7K]  test_config.py
│   │       ├── [2.0K]  test_exceptions.py
│   │       ├── [4.1K]  test_models.py
│   │       └── [3.5K]  test_utils.py
│   └── [ 160]  web
│       └── [ 10K]  test_bing_scraper.py
├── [664K]  twat_search.txt
└── [195K]  uv.lock

26 directories, 150 files

================
File: .github/workflows/push.yml
================
name: Build & Test
on:
  push:
    branches: [main]
    tags-ignore: ["v*"]
  pull_request:
    branches: [main]
  workflow_dispatch:
permissions:
  contents: write
  id-token: write
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
jobs:
  quality:
    name: Code Quality
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Run Ruff lint
        uses: astral-sh/ruff-action@v3
        with:
          version: "latest"
          args: "check --output-format=github"
      - name: Run Ruff Format
        uses: astral-sh/ruff-action@v3
        with:
          version: "latest"
          args: "format --check --respect-gitignore"
  test:
    name: Run Tests
    needs: quality
    strategy:
      matrix:
        python-version: ["3.10", "3.11", "3.12"]
        os: [ubuntu-latest]
      fail-fast: true
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install UV
        uses: astral-sh/setup-uv@v5
        with:
          version: "latest"
          python-version: ${{ matrix.python-version }}
          enable-cache: true
          cache-suffix: ${{ matrix.os }}-${{ matrix.python-version }}
      - name: Install test dependencies
        run: |
          uv pip install --system --upgrade pip
          uv pip install --system ".[test]"
      - name: Run tests with Pytest
        run: uv run pytest -n auto --maxfail=1 --disable-warnings --cov-report=xml --cov-config=pyproject.toml --cov=src/twat_search --cov=tests tests/
      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.python-version }}-${{ matrix.os }}
          path: coverage.xml
  build:
    name: Build Distribution
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install UV
        uses: astral-sh/setup-uv@v5
        with:
          version: "latest"
          python-version: "3.12"
          enable-cache: true
      - name: Install build tools
        run: uv pip install build hatchling hatch-vcs
      - name: Build distributions
        run: uv run python -m build --outdir dist
      - name: Upload distribution artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-files
          path: dist/
          retention-days: 5

================
File: .github/workflows/release.yml
================
name: Release
on:
  push:
    tags: ["v*"]
permissions:
  contents: write
  id-token: write
jobs:
  release:
    name: Release to PyPI
    runs-on: ubuntu-latest
    environment:
      name: pypi
      url: https://pypi.org/p/twat-search
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install UV
        uses: astral-sh/setup-uv@v5
        with:
          version: "latest"
          python-version: "3.12"
          enable-cache: true
      - name: Install build tools
        run: uv pip install build hatchling hatch-vcs
      - name: Build distributions
        run: uv run python -m build --outdir dist
      - name: Verify distribution files
        run: |
          ls -la dist/
          test -n "$(find dist -name '*.whl')" || (echo "Wheel file missing" && exit 1)
          test -n "$(find dist -name '*.tar.gz')" || (echo "Source distribution missing" && exit 1)
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_TOKEN }}
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          files: dist/*
          generate_release_notes: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

================
File: debug_output/qwant_analysis.txt
================
Analysis for qwant
================================================================================

Potential containers found:
div.dd.algo: 0 elements found
div.algo-sr: 0 elements found
div.dd.algo.algo-sr: 0 elements found
article.webResult: 0 elements found
div.result: 0 elements found
div.web-result: 0 elements found
div.result: 0 elements found
div.search-result: 0 elements found
li.result: 0 elements found

Other potential elements:

================
File: debug_output/qwant_content.html
================
<!DOCTYPE html><html lang="en"><head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta http-equiv="Accept-CH" content="Sec-CH-UA-Bitness, Sec-CH-UA-Arch, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Platform, Sec-CH-UA, UA-Bitness, UA-Arch, UA-Full-Version, UA-Mobile, UA-Model, UA-Platform-Version, UA-Platform, UA, Sec-CH-Prefers-Color-Scheme">
    <base href="https://www.qwant.com">
    <meta name="theme-color" content="#FFFFFF">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="@QwantCom">
    <meta name="twitter:creator" content="@QwantCom">
    <meta name="twitter:domain" content="https://www.qwant.com">
    <meta name="twitter:widgets:csp" content="on">
        <meta property="og:image" content="https://www.qwant.com/public/qwant-logo-seo.0ea4e62ad0a6047e242cdb57128d7995.png">
        <meta property="og:image:width" content="1000">
        <meta property="og:image:height" content="536">
        <meta name="twitter:image" content="https://www.qwant.com/public/qwant-logo-seo.0ea4e62ad0a6047e242cdb57128d7995.png">
    <meta property="og:type" content="website">
    <meta property="og:url" content="https://www.qwant.com" id="meta_og_url">
    <meta name="application-name" content="Qwant">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
    <meta name="description" content="Fast, reliable answers and still in trust: Qwant does not store your search data, does not sell your personal data and is hosted in Europe.">
    <meta name="keywords" content="search engine">
    <meta property="og:description" content="Fast, reliable answers and still in trust: Qwant does not store your search data, does not sell your personal data and is hosted in Europe.">
    <meta property="og:site_name" content="Qwant">
    <title>Qwant - The search engine that values you as a user, not as a product</title>
    <meta property="og:title" content="FontLab – Qwant Search">
    <meta property="twitter:title" content="FontLab – Qwant Search">
    <link rel="manifest" href="/manifest.json">
    <link data-chunk="app" rel="preload" as="style" href="/1f7c4e111261b3ad8a04_app.chunks.css">
<link data-chunk="app" rel="preload" as="script" href="/a61ec0921f734a0d5dee_runtime.Phoenix.js">
<link data-chunk="app" rel="preload" as="script" href="/eccc33be0ced324f778a_vendors~app.chunks.js">
<link data-chunk="app" rel="preload" as="script" href="/46a6c1fdc290b3b0cbd5_app.chunks.js">
    <link data-chunk="app" rel="stylesheet" href="/1f7c4e111261b3ad8a04_app.chunks.css">
    <meta name="robots" content="index">
    <link rel="shortcut icon" href="/public/favicon.066f5ee2ab77b590bb5846c32c57cb84.ico" type="image/x-icon">
    <link rel="icon" href="/public/favicon.97e9bd6cd3d07b5f096430c1b09ea705.png" type="image/png">
    <link rel="icon" sizes="32x32" type="image/png" href="/public/favicon-32.9d2af599f2a0364630ddb8a2a32026ec.png">
    <link rel="icon" sizes="64x64" type="image/png" href="/public/favicon-64.ddb1092939bad1aaca378c29744e7be3.png">
    <link rel="icon" sizes="96x96" type="image/png" href="/public/favicon-96.3a477836f89ad0ed8e0420c7c7ef4679.png">
    <link rel="icon" sizes="144x144" type="image/png" href="/public/favicon-144.6fdb01169d8537aeadd4f95dce2982e4.png">
    <link rel="icon" sizes="152x152" href="/public/favicon-152.8c87cc8fd7862d72eee478c8f503d3e8.png" type="image/png">
    <link rel="icon" sizes="196x196" href="/public/favicon-196.b2a1214ee3c261334512a377f1d678f7.png" type="image/png">
    <link rel="apple-touch-icon" sizes="152x152" href="/public/apple-touch-icon.e9d3092ec9fb9e1a28c1ea1a3b10777a.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/public/apple-touch-icon-60x60.2f06b254c6f7bc88c95cb88780b2548d.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/public/apple-touch-icon-76x76.64dd5e4f44dc904646e7b304031cf763.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/public/apple-touch-icon-114x114.442d3c1be69b232f3eaae7d19ca653c0.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/public/apple-touch-icon-120x120.97e9bd6cd3d07b5f096430c1b09ea705.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/public/apple-touch-icon-144x144.6fdb01169d8537aeadd4f95dce2982e4.png">
    <link rel="apple-touch-icon-precomposed" href="/public/favicon-152.8c87cc8fd7862d72eee478c8f503d3e8.png">
    <meta name="msapplication-config" content="https://www.qwant.com/browserconfig.xml"> 
    <meta name="referrer" content="origin">
    <link rel="canonical" href="https://www.qwant.com">
    <link rel="search" type="application/opensearchdescription+xml" title="Qwant" href="https://www.qwant.com/opensearch.xml">
    <link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/hnlkiofnhhoahaiimdicppgemmmomijo">
    <link rel="alternate" hreflang="fr" href="https://www.qwant.com/?l=fr">
	<link rel="alternate" hreflang="en" href="https://www.qwant.com/?l=en">
	<link rel="alternate" hreflang="de" href="https://www.qwant.com/?l=de">
	<link rel="alternate" hreflang="it" href="https://www.qwant.com/?l=it">
	<link rel="alternate" hreflang="br" href="https://www.qwant.com/?l=br">
	<link rel="alternate" hreflang="ca" href="https://www.qwant.com/?l=ca">
	<link rel="alternate" hreflang="co" href="https://www.qwant.com/?l=co">
	<link rel="alternate" hreflang="es" href="https://www.qwant.com/?l=es">
	<link rel="alternate" hreflang="eu" href="https://www.qwant.com/?l=eu">
	<link rel="alternate" hreflang="nl" href="https://www.qwant.com/?l=nl">
	<link rel="alternate" hreflang="pl" href="https://www.qwant.com/?l=pl">
	<link rel="alternate" hreflang="pt" href="https://www.qwant.com/?l=pt">
    <link rel="alternate" href="https://www.qwant.com" hreflang="x-default">
    <link rel="preconnect" href="https://mn.qwant.com/v2">
    <link rel="preconnect" href="https://api.qwant.com/v3">
  <link rel="stylesheet" type="text/css" href="/c1288907ef4c62505104_apps-errors-DatadomeCaptcha.chunks.css"><script charset="utf-8" src="/9c0275a1ca1698783ba2_apps-errors-DatadomeCaptcha.chunks.js"></script><script id="ppas_container_configuration" data-appid="98cbd59f-731c-4874-a402-04f51ed9069a" data-host="k.qwant.com"></script></head>
  <body class="" data-device="desktop" data-product="qwant" data-theme="light">
  <!-- render markup phoenix -->
  <div id="root"><div style="display: block;"><iframe class="_m56B" data-testid="captchaDatadomeContainer" src="https://geo.captcha-delivery.com/captcha/?initialCid=AHrlqAAAAAMA_uUIbTzAlFwAWUAcMA==&amp;cid=Yi476GtTtdBnxk2U_0z0GWu~JUehKSVKrRM8oOfEy_IcQLbhLuWRlquGdPMnbzh9uTqMIqypBfMuuBs5P8VExp~iFBF73Atlzexr~xQIsLS3aMC8cUsRZqRcwoe~ZN2U&amp;referer=http%3A%2F%2Ffdn.qwant.com%2Fv3%2Fsearch%2Fweb%3Fq%3De236108c4c1e3f45885edc3f14e36afa80de4c2f8e1f5397262455c8b1d8b72d4cb7078aeb61790c3a3125164edcf12d15544bfc9b511f3d23a0c4e9d17fc8da%26count%3D10%26locale%3Dpl_PL%26offset%3D0%26device%3Ddesktop%26tgp%3D1%26safesearch%3D1%26displayed%3Dtrue%26llm%3Dtrue&amp;hash=78B13B7513D180B7AB6D6FF9EB0A51&amp;t=fe&amp;s=44484&amp;e=920c0bb4642e95d5bd768bfa18dad6705c3137aad0fb0271e0735cdb175b0446" title="Antiscrap Captcha"></iframe></div></div>
  <!-- inject i18n and phoenix scripts -->
  <script type="text/javascript" async="" defer="" src="https://k.qwant.com/2aecbbf86c74c1c2fb798e0a39f0678e.js"></script><script async="" src="https://k.qwant.com/containers/98cbd59f-731c-4874-a402-04f51ed9069a.js"></script><script>INITIAL_PROPS = {"testGroupPer":1,"llm":{"apiUrl":"https:\u002F\u002Fapi.qwant.com"},"piwik":{"url":"https:\u002F\u002Fk.qwant.com","id":"98cbd59f-731c-4874-a402-04f51ed9069a","permittedDomains":["shdw.me","www.qwantjunior.com"],"crossDomains":["shdw.me","www.qwantjunior.com","about.qwant.com","help.qwant.com","betterweb.qwant.com","auth.qwant.com"]},"didomi":{"apiKey":"0dbf2631-6bba-4497-9048-745301a3f637","noticeFr":"NrdXrK89","noticeRow":"j4NDeL4k","noticeEs":"a7gixD3Q","clarityId":"km57m6oo9k","datadomeId":"78B13B7513D180B7AB6D6FF9EB0A51"},"device":{"browserName":"Chrome","completeUa":"Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F91.0.4472.124 Safari\u002F537.36","isWindowsDesktop":true,"isMacDesktop":false,"isAndroid":false,"isIos":false,"isMobile":false,"isNativeApp":false,"isPhone":false,"isTablet":false},"urls":{"domain":"qwant.com","apiUrlClient":"https:\u002F\u002Fapi.qwant.com\u002Fapi","apiUrlClientV2":"https:\u002F\u002Fapi.qwant.com\u002Fv3","minervaUrlClient":"https:\u002F\u002Fmn.qwant.com\u002Fv2","apmServerExternal":"https:\u002F\u002Fapm.qwant.com","reportUrl":"https:\u002F\u002Freport.qwant.com","martinUrl":"https:\u002F\u002Ftiles.qwant.com","maps":"https:\u002F\u002Fmap.qwant.com\u002F","lite":"https:\u002F\u002Flite.qwant.com","junior":"https:\u002F\u002Fwww.qwantjunior.com\u002F","blog":"\u002F\u002Fbetterweb.qwant.com\u002F","shop":"\u002F\u002Fshop.spreadshirt.fr\u002Fqwantstore","help":"\u002F\u002Fhelp.qwant.com\u002F","jobs":"\u002F\u002Fwww.welcometothejungle.com\u002Ffr\u002Fcompanies\u002Fqwant\u002Fjobs","downloads":"\u002F\u002Fdownloads.qwant.com"},"isMailEnabled":false,"features":{"drawerSettingLogin":false,"drawerSettingSync":false,"enableAccount":true,"enableApmMonitoring":true,"enableCssLint":false,"enableDatadomeCaptcha":true,"enableDebugRenderReact":false,"enableDegradedMode":false,"enableDidomiConsentEs":true,"enableDidomiConsentFr":true,"enableDidomiConsentRow":true,"enableGoogleModule":true,"enableHomeTiles":true,"enableHomeIaGen":true,"enableLlm":true,"enableOutage":false,"enableLandingGame":false,"enableProductsAdsMicrosoft":true,"enableQwantAlpha":false,"enableQwantJunior":false,"enableQwantReward":true,"enableQwantRewardPopover":false,"enableTextToKids":true,"piwik":true,"productsAds":false,"settingSearchLanguage":true},"configuration":{"baseUrl":"https:\u002F\u002Fwww.qwant.com","appName":"phoenix","appVersion":"ad433566e0d622b5837cd198b58cc0e489397c5b","clientRequestTimeoutInMS":12000,"clientRequestTimeoutWithRetryInMS":12000,"apmTransactionSampleRateForRUM":0.5,"pageLoadTraceId":"f9e3327f9e6017f9c792248e66bb6f62","pageLoadSpanId":"06d71cad59c3bdfb","pageLoadSampled":true},"regionLocale":"pl_PL","urlParams":{"q":"FontLab"},"query":"FontLab","languages":{"fr":{"name":"Français"},"en":{"name":"English"},"de":{"name":"Deutsch"},"it":{"name":"Italiano"},"br":{"name":"Brezhoneg"},"ca":{"name":"Català"},"co":{"name":"Corsu"},"es":{"name":"Español"},"eu":{"name":"Euskara"},"nl":{"name":"Nederlands"},"pl":{"name":"Polski"},"pt":{"name":"Português"}},"locales":{"FR":{"langs":["fr"]},"GB":{"langs":["en"]},"DE":{"langs":["de"]},"IT":{"langs":["it"]},"AR":{"langs":["es"]},"AU":{"langs":["en"]},"US":{"langs":["en"]},"ES":{"langs":["es","ca"]},"CZ":{"langs":["cs"]},"RO":{"langs":["ro"]},"GR":{"langs":["el"]},"CN":{"langs":["zh"]},"HK":{"langs":["zh"]},"NZ":{"langs":["en"]},"TH":{"langs":["th"]},"KR":{"langs":["ko"]},"SE":{"langs":["sv"]},"NO":{"langs":["nb"]},"DK":{"langs":["da"]},"HU":{"langs":["hu"]},"EE":{"langs":["et"]},"MX":{"langs":["es"]},"CL":{"langs":["es"]},"CA":{"langs":["en","fr"]},"MY":{"langs":["en"]},"BG":{"langs":["bg"]},"FI":{"langs":["fi"]},"PL":{"langs":["pl"]},"NL":{"langs":["nl"]},"PT":{"langs":["pt"]},"CH":{"langs":["de","fr","it"]},"AT":{"langs":["de"]},"BE":{"langs":["fr","nl"]},"IE":{"langs":["en"]},"IL":{"langs":["he"]}},"blacklistedMarkets":["JP","RU","TR","PH","SG","ID","TW","BR","IN","VN"],"market":"pl","geoCountryCode":"PL","serverState":{"theme":"-1","extInstalled":false,"randomAutoPromo":0},"dataPage":{"data":null},"accountConfiguration":{"iamUrl":"https:\u002F\u002Fauth.qwant.com\u002Fkratos","accountApiUrl":"https:\u002F\u002Faccount.qwant.com","authenticatorKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fui\u002Fsettings\u002Fsecurity\u002Fauthenticator","loginKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fkratos\u002Fself-service\u002Flogin\u002Fbrowser","registrationKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fkratos\u002Fself-service\u002Fregistration\u002Fbrowser","verificationKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fkratos\u002Fself-service\u002Fverification\u002Fbrowser","profileKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fui\u002Fsettings\u002Fprofile","socialsKratosUrl":"https:\u002F\u002Fauth.qwant.com\u002Fui\u002Fsettings\u002Fsocials"},"isCookieAccountPresent":false}</script>
  <script>
                  initialI18nStore = {"en": {"account":{"misc":{"loggedOutByError":"An error occurred while retrieving your account. Please try logging in again."},"menu":{"profile":"My profile","security":"Login and security","reward":"Rewards","notifications":"Notifications"},"pages":{"notifications":{"title":"Notifications","newsletter":{"title":"Newsletter","description":"Receive occasional information about our technological advances or product releases"},"qwant_community":{"title":"Communauté Qwant","description":"Be notified to preview our new products and give your opinion"},"qwant_rewards":{"title":"Qwant loyalty program","description":"View progress notifications on Qwant.com","second_description":"Receive emails (required)"}},"reward":{"title":"Rewards","program":{"title":"Qwant loyalty program","inactive":"Not active","requiredConsent":"Consent required","active":"Active","inactiveCta":"Start","requiredConsentCta":"Change","activeCta":"Opt out"},"bank_account":{"title":"Account holder","description":"No information","cta":"Add"},"iban":{"title":"IBAN","description":"No information","cta":"Add"},"terms":{"title":"Terms of use"},"privacy_policy":{"title":"Privacy policy"}},"profile":{"title":"My profile","avatar":{"cta":"Change","secondCta":"Reset"},"email":{"title":"Email","meta":"Verified","cta":"Edit"},"username":{"title":"Username","cta":"Change","modal":{"title":"Change your username ","label":"Your username","cancel":"Cancel","confirm":"Edit"}},"language":{"title":"Language","cta":"Change"}},"security":{"title":"Login and security","password":{"title":"Password","cta":"Modify"},"2fa":{"title":"Double authentication","description":"Two-factor authentication protects your account by adding an extra step of security when you log in.","cta":"Manage"},"external_account":{"title":"Alternative login methods","description":"Link your Qwant account to a social account to log in.","cta":"Manage"},"my_privacy_preferences":{"title":"My privacy preferences","description":"Adjust your privacy settings","cta":"Modify"},"personal_data":{"title":"My personal data","description":"Receive a copy of my personal data"},"delete":{"title":"Delete my account","description":"Irreversible action"}}},"modals":{"delete":{"title":"Delete my account","body":"All associated data will be deleted and you will no longer be able to log in to Qwant","confirmCta":"Confirm account deletion","cancelCta":"Cancel and return to my account"},"optOutReward":{"title":"Opt out of the Qwant loyalty program","body":"By opting out, you agree to lose all your points, your ranking and the value of your Qwant wallet.","confirmCta":"Confirm my opting out","cancelCta":"Cancel and return to my account"},"deleted":{"title":"Account deleted !","body":"We're sorry to see you go.\u003Cbr\u002F\u003EWe hope you will continue to use Qwant products in the future.\u003Cbr\u002F\u003ESee you soon!","cta":"Back to Qwant.com"}}},"alpha":{},"common":{"brandName":"Qwant","close":"Close","share":"Share","send":"Send","reportContent":"Report content","alreadyReported":"Already reported","fullScreen":"Full screen","edit":"Edit","ad":"Ad","partnership":"Partnership","event":"Event","new":"New","resultsNotRelevant":"The following results are probably not relevant, please rephrase your query.","comCenter":{"privacy":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fconfidentialite\u002F","hrefHuawei":"https:\u002F\u002Fabout.qwant.com\u002Fprivacy-happ\u002F"}},"seo":{"searchTitle":"Qwant Search","description":"Fast, reliable answers and still in trust: Qwant does not store your search data, does not sell your personal data and is hosted in Europe.","tagline":"The search engine that values you as a user, not as a product","keywords":"search engine"},"clipboard":{"copied":"Copied","success":"The URL was copied to your clipboard.","failure":"The URL could not be copied to your clipboard. Your browser might not allow it.","textSuccess":"Text copied!","label":"Copy"},"validationErrors":{"required":"This field is required","minLength":"This field requires at least {{min}} character","maxLength":"This field cannot exceed {{max}} characters","alphaDashPoint":"This field must only contain alpha-numeric characters, dashes, underscores and dots"},"next":"Next","no_results":"No results found.","showAllResults":"Show all the results","search":"Search","language":"Language","aria_search":"Enter your search term","aria_search_button":"Search the web","suggestions":"Suggestions","country":"Country","confirm":"Confirm","cancel":"Cancel","errorInPage":{"firstPart":"Qwant is temporarily unavailable","secondPart":"Please check your connection or \u003C0\u003Erefresh page\u003C\u002F0\u003E.","refreshButton":"Relaunch your search","strictModeTitle":"The content you are looking for may be inappropriate","strictModeDescription":"Your current SafeSearch setting filters out results that might return adult content. To view those results as well, \u003C0\u003Echange your SafeSearch setting\u003C\u002F0\u003E"},"accessibility":{"share":"Share","fullScreen":"Full screen","report":"Report"},"account":{"login":"Login","logout":"Logout"},"secondAgo":"{{count}} second ago","secondAgo_plural":"{{count}} seconds ago","minuteAgo":"{{count}} minute ago","minuteAgo_plural":"{{count}} minutes ago","hourAgo":"{{count}} hour ago","hourAgo_plural":"{{count}} hours ago","yesterday":"yesterday","dayAgo":"{{count}} day ago","dayAgo_plural":"{{count}} days ago","now":"just now","weekAgo":"{{count}} week ago","weekAgo_plural":"{{count}} weeks ago","monthAgo":"{{count}} month ago","monthAgo_plural":"{{count}} months ago","countries":{"AR":"Argentina","AT":"Austria","AU":"Australia","BE":"Belgium","BR":"Brazil","BG":"Bulgaria","CA":"Canada","CH":"Switzerland","CL":"Chile","CZ":"Czech Republic","DK":"Denmark","DE":"Germany","FI":"Finland","GR":"Greece","HK":"Hong Kong","HU":"Hungary","KR":"South Korea","EE":"Estonia","ES":"Spain","FR":"France","GB":"Great Britain","IE":"Ireland","IN":"India","IT":"Italy","MY":"Malaysia","MX":"Mexico","NO":"Norway","PL":"Poland","PT":"Portugal","NL":"Netherlands","NZ":"New Zealand","RO":"Romania","SE":"Sweden","TH":"Thailand","US":"United States","CN":"China","IL":"Israel"},"addon":{"firefoxAddon":"https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fqwant-the-search-engine\u002F","edgeAddon":"https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fqwant-the-search-engine\u002Fadmmanannmnegodaboehkdhangccabio","chromeAddon":"https:\u002F\u002Fchromewebstore.google.com\u002Fdetail\u002Fqwant-the-search-engine\u002Fkplfenefaakjhjkklghidleljeocgdap","safariAddon":"https:\u002F\u002Fapps.apple.com\u002Fapp\u002Fqwant-for-safari\u002Fid1645050159"},"userFeedback":{"option_useful":"It's useful","option_useless":"It's not useful","option_bug":"There's a mistake","option_other":"Other comments","inputPlaceholder":"Tell us more!","modalTitle":"What do you think?","successSubtitle":"Thank you for your comment","successTitle":"Well received!","moreConfetti":"More confetti!","errorRequired":"Could you please tell us more?","labelFloating":"Feedback","label":"Share your feedback","title":"What do you think of your Qwant experience?","selectElementNegative":"What can we improve?","selectElementPositive":"What did you like?","selectElementLabel":"Select an item...","commentPlaceholder":"Comment","selectElementOptionHome":"Home page","selectElementOptionResults":"Results page","selectElementOptionAds":"Advertisements","selectElementOptionNews":"News","selectElementOptionImages":"Images","selectElementOptionVideos":"Videos","selectElementOptionShopping":"Shopping products","selectElementOptionBrand":"The Qwant brand","selectElementOptionOther":"Other"},"contactUs":"Contact us","degradedMode":{"ribbonDescription":"MAINTENANCE in progress. Some features, as well as links at the bottom of the page, may be temporarily unavailable. Thank you for your understanding."},"outage":{"ribbonDescription":"We are currently experiencing issues with search service being temporarily unavailable. Thank you for your understanding."},"ribbons":{"firefox":{"title":"New","description":"Make your choice","linkText":"Use Qwant on Firefox","linkUrl":"https:\u002F\u002Fbetterweb.qwant.com\u002Fen\u002F2024\u002F03\u002F19\u002Ftake-your-pick-use-qwant-on-firefox\u002F?utm_source=ap_Ribbon_desk_EN&utm_medium=clicks&utm_campaign=blog_camp_mozilla&utm_id=art.blog"},"newQwantRibbon":{"new":"New!","text":"Qwant artificial intelligence for your searches : ","linkText":"Learn more","link":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002F"},"retrib":{"new":"New!","text":"Qwant launches its fidelity program: win up to 10€ per week with your search engine. ","linkText":"Learn More","link":"https:\u002F\u002Fabout.qwant.com\u002Fprogramme-de-fidelite\u002F"}}},"drawers":{"drawerSettings":{"titleDrawerMobileMenu":"Settings","titleSafeSearchFilter":"Filter adult content","titleCountryFilter":"Country\u002FRegion","titleInterfaceLanguage":"Interface Language","cookieInfo":"Any changes you make to these options must be saved \u003C0\u003Ein a cookie\u003C\u002F0\u003E created exclusively for this purpose. You can delete this cookie in your browser options.","cookieHide":"Do not show anymore"},"bottomMenu":{"home":"Home","products":"Our Products","about":"About","settings":"Settings"},"drawerProducts":{"cardNewModelLink":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002F","partner":{"label":"Partner","link":"https:\u002F\u002Fshdw.me\u002Fqwant-tool","name":"Shadow Drive","title":"Get 20GB of free storage!","wording":"Keep your private files safe and secure with Shadow Drive, the cloud storage solution from Qwant’s partner, designed and hosted in Europe.","cta":"Discover"}},"drawerCookieManagement":{"title":"Managing your cookie preferences","wording1":"Certain features of this site rely on the use of cookies.\nThe cookies banner is not displayed on the home page during your navigation because only cookies necessary for the operation of the site are deposited (you can, however, object to this by clicking on the “Refuse” button below).","wording2":"Statistical audience measurement services are necessary for the operation of the site by enabling its proper administration. However, you have the possibility to object to their use.","actionTitle":"Statistical audience measurement","authorize":"Authorize","refuse":"Refuse","TestsAB":"Performance Measurement Tests (AB Test)"},"pushExtension":{"description":"Qwant becomes your default search engine, blocks trackers and protects your personal data","name":"Install {{name}} extension"}},"header":{"appMenu":{"llmMode":"Flash Response","llmBanner":{"title":"Flash Response saves you time","description":"Qwant finds the right information from the most relevant web pages. You get your answer immediately at the top of the page!","linkText":"Find out more","link":"https:\u002F\u002Fabout.qwant.com\u002F#ia-gen"},"Web":"All","News":"News","Images":"Images","Videos":"Videos","Shopping":"Shopping","Maps":"Maps","about":"About us","mail":"Mail","new":"new","products":"Products","settings":"Settings","burgerMenu":"Show menu"},"backToQwantCom":"Back to Qwant.com","login":"Login","search":{"placeholder":"Search","altLogo":"Qwant Logo"}},"errorpage":{"errorNotFound":{"title":"Oops 404 lunar page","description":"You have been sent too far mea culpa!","link":"Back to the planet Qwant"},"errorPage":{"title":"Maintenance","description":"Our service will be back in a few moments, we apologize for the inconvenience.","link":"Refresh page"},"errorUnavailable":{"title":"Service unavailable","thanks":"Thanks for your visit","sadly":"Unfortunately we are not yet available in your country.","learnMore":"Would you like to know more about our actions?","linkToBlog":"Visit our blog"}},"filters":{"Brand_filters":"Brand","Category_filters":"Category","Any color_filters":"Any color","Color_filters":"Color","Format_filters":"Format","Any freshness_filters":"Any freshness","Freshness_filters":"Freshness","Language_filters":"Language","Any license_filters":"Any license","License_filters":"License","Price_filters":"Price","min_filters":"min","max_filters":"max","Region_filters":"Region","Shop_filters":"Shop","Any size_filters":"Any size","Size_filters":"Size","order_by_filters":"Order by","Any source_filters":"Any source","Source_filters":"Any source","Any type_filters":"Any type","Type_filters":"Type","Hide_filters":"Hide","OK_filters":"OK","all_filters":"all","Relevance_filters":"Relevance","Views_filters":"Views","Most recent_filters":"Most recent","Price : Low to High_filters":"Price : Low to High","Price : High to Low_filters":"Price : High to Low","All sizes_filters":"All sizes","Small_filters":"Small","Medium_filters":"Medium","Large_filters":"Large","Wallpaper_filters":"Wallpaper","Wide wallpaper_filters":"Wide wallpaper","All_filters":"All","Public domain_filters":"Public domain","Non-commercial reproduction and sharing_filters":"Non-commercial reproduction and sharing","Reproduction and sharing_filters":"Reproduction and sharing","Non-commercial reproduction, sharing and modification_filters":"Non-commercial reproduction, sharing and modification","Reproduction, sharing and modification_filters":"Reproduction, sharing and modification","Color only_filters":"Color only","Monochrome_filters":"Monochrome","black_filters":"Black","blue_filters":"Blue","brown_filters":"Brown","gray_filters":"Gray","green_filters":"Green","orange_filters":"Orange","pink_filters":"Pink","purple_filters":"Purple","red_filters":"Red","teal_filters":"Teal","white_filters":"White","yellow_filters":"Yellow","Animated Gif_filters":"Animated Gif","Photograph_filters":"Photograph","Transparent_filters":"Transparent","All time_filters":"All time","Less than 1 hour ago_filters":"Less than 1 hour ago","Past 24 hours_filters":"Past 24 hours","Past week_filters":"Past week","Past month_filters":"Past month","Low price_filters":"Low price","High price_filters":"High price","Newest first_filters":"Newest first","Oldest first_filters":"Oldest first","Show the next {number} filter_brand_filter":"Show the next {{number}}","Show the next {number} filter_brand_filter_plural":"Show the next {{number}}","Show less brands_filter":"Show less brands","All_filter":"All","Show the next {number} filter_shop_filter":"Show the next {{number}}","Show the next {number} filter_shop_filter_plural":"Show the next {{number}}","Show less shops_filter":"Show less shops","Min price {min}€_filter":"Min price {{min}}€","Max price {max}€_filter":"Max price {{max}}€","An error occurred in removing filters_filter":"An error occurred in removing filters","Filters_filter":"Filters","Back_filter":"Back","Validate_filter":"Validate","Filter_filter":"Filter","Reinitialize filters_filter":"Reinitialize filters","Reinitialize_filter":"Reinitialize","Show the products_filter":"Show the products","Filters_button":"Filters"},"footer":{"label":"Footer","tagline":"The search engine that values you as a user, not as a product","results":{"title":"Results","links":{"ranking":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fclassement\u002F","label":"Ranking"},"report":{"label":"Report"}},"copyright":"© 2025 Qwant. All rights reserved."},"privacy":{"label":"Privacy"},"legal":{"title":"Legal","links":{"termsOfService":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fqwant-search\u002F","label":"Terms of Service"},"legalNotices":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fmentions-legales\u002F","label":"Legal notices"}}},"company":{"title":"Companies","links":{"qwantatwork":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fqwantatwork\u002F","label":"Qwant @ Work"},"blog":{"href":"https:\u002F\u002Fbetterweb.qwant.com\u002Fen\u002F","label":"Better Web"},"jobs":{"href":"https:\u002F\u002Fwww.welcometothejungle.com\u002Fen\u002Fcompanies\u002Fqwant","label":"Join Us"},"press":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Fpresse\u002F","label":"Press"},"contact":{"href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Fcontact\u002F","label":"Contact Us"}}},"helpCenter":{"href":"https:\u002F\u002Fhelp.qwant.com\u002Fen","label":"Help Center"},"apps":{"android":"Android App","ios":"iOS App"},"whyQwant":{"label":"Why Qwant?","href":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002F"},"products":{"qwantExtension":"Qwant Extension","maps":"Maps","search":"Search","junior":"Junior"},"aboutQwant":"About Qwant","followUs":"Follow us","services":"Services","makeDefaultSearchEngine":"Make Qwant my default search engine","settings":"Settings","cookieManagement":"Cookie management","discoverQwant":{"label":"Discover the service","href":{"multi":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002F"}},"socials":{"instagram":"Instagram","facebook":"Facebook","twitter":"X (ex-Twitter)","tiktok":"TikTok","linkedin":"LinkedIn","discord":"Discord"}},"images":{"websitePreview":"View website","openFullscreen":"Open image in fullscreen","tooltip":"Qwant is careful to keep your searches private (\u003Ca href=\"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fconfidentialite\u002F\"\u003ELearn more\u003C\u002Fa\u003E). These ads from the Microsoft Advertising network match the keywords entered. Clicks are subject to the \u003Ca href=\"http:\u002F\u002Fgo.microsoft.com\u002Ffwlink\u002F?LinkId=248681\"\u003EMicrosoft Privacy Statement\u003C\u002Fa\u003E"},"junior":{},"modules":{"pushDesktop":{"title":"Qwant extension","content":"Install Qwant as your default search engine.","button":"Add to {{name}}"}},"robots":{"title":"Information","introduction":"A high amount of connections have been detected from your location and you have been blocked.","introduction2":"Please, validate the anti-robot below to be allowed access to the website.","instruction":"Click on the only unique symbol.","description":"The use of a Virtual Private Network (VPN), a browser plugin or another program might be related to the current blocking. You might try uninstalling the VPN from your computer or network and see if that makes a difference.\u003Cbr\u003E Some VPNs send traffic that violates the law or websites' terms of service. When the abuse to Qwant's network stops, we automatically stop blocking the IP that were sending the bad traffic.\u003Cbr\u003E If you are unsure about a malicious usage of your network, \u003Ca href=\"http:\u002F\u002Fadios-hola.org\u002F\"\u003Ethis website\u003C\u002Fa\u003E (english only) may be a good reference to start with.","error":"You haven't clicked on the right symbol.","serverError":"Server error, cannot display the captcha.","refresh":"Please check your connection or \u003C0\u003E refresh page \u003C\u002F0\u003E."},"ia":{"showMore":"Show more","allocineWebsite":"allocine.fr","readMore":"Read more","readMoreOn":"Read more on {{source}}","seeAll":"See all","contributeWiki":"How to contribute?","wikipediaContributeUrl":"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWikipedia:Contributing_to_Wikipedia","wikidataContributeUrl":"https:\u002F\u002Fwww.wikidata.org\u002Fwiki\u002FWikidata:Contribute\u002Fen","newsOn":"News","productsBuy":"Buy \u003C0\u003E{{name}}\u003C\u002F0\u003E","ads":"Ads","fromTo":"{{start}} to {{end}}","birthInformation":"Date and place of birth","nationality":"Nationality","filmography":"Filmography","from":"From","minutesShort":"min","duration":"Duration","watchMovie":"Watch this movie","durationText":"{{hours}}h {{min}}min","seasons":"Seasons","otherSeasons":"Other seasons","episodes":"Episodes","actors":"Actors","actorsOfSeason":"Actors of season {{n}}","episodesOfSeason":"Episodes of season {{n}}","seeAllEpisodes":"See all the episodes of season {{n}}","seasonNumber":"Season {{n}}","seasonNumberOf":"Season {{n}} of {{name}}","videoOfSeason":"Video of season {{n}}","press":"Press","audience":"Audience","ratings":"notes","video":"Video","startingPrice":"Starting at {{price}}","watch":"Watch","answerBy":"Answer by","status":{"progress":"In progress","cancelled":"Cancelled","toCome":"To come"},"movie":{"genres":{"ACTION":"Action","ADVENTURE":"Adventure","ANIMATION":"Animation","BIOPIC":"Biopic","BOLLYWOOD":"Bollywood","CARTOON":"Cartoon","CLASSIC":"Classic","COMEDY":"Comedy","COMEDY_DRAMA":"Comedy\u002FDrama","CONCERT":"Concert","DETECTIVE":"Detective","DIVERS":"Misc","DOCUMENTARY":"Documentary","DRAMA":"Drama","EROTIC":"Erotic","EXPERIMENTAL":"Experimental","FAMILY":"Family","FANTASY":"Fantasy","HISTORICAL":"Historical","HISTORICAL_EPIC":"Historical Epic","HORROR":"Horror","JUDICIAL":"Judicial","KOREAN_DRAMA":"Korean drama","MARTIAL_ARTS":"Martial arts","MEDICAL":"Medical","MOVIE_NIGHT":"Movie night","MUSIC":"Music","MUSICAL":"Musical","OPERA":"Opera","ROMANCE":"Romance","SCIENCE_FICTION":"Science fiction","PERFORMANCE":"Performance","SOAP":"Soap opera","SPORT_EVENT":"Sport event","SPY":"Spy","THRILLER":"Thriller","WARMOVIE":"Warmovie","WEB_SERIES":"Web series","WESTERN":"Western"}},"shopping":{"allColors":"All colors"},"daysShort":{"monday":"Mon.","tuesday":"Tue.","wednesday":"Wed.","thursday":"Thu.","friday":"Fri.","saturday":"Sat.","sunday":"Sun."},"daysLong":{"monday":"Monday","tuesday":"Tuesday","wednesday":"Wednesday","thursday":"Thursday","friday":"Friday","saturday":"Saturday","sunday":"Sunday"},"weather":{"precipitation":"Precipitation","humidity":"Humidity","wind":"Wind","temperatures":"Temperatures","precipitations":"Precipitations","type":{"CLOUDY":"Cloudy","FOGGY":"Foggy","HAIL":"Hail","NIGHT":"Night","NIGHT_CLOUDY":"Cloudy night","RAINBOW":"Rainbow","RAINY":"Rainy","SNOW":"Snowy","SUNNY":"Sunny","PARTLY_CLOUDY":"Partly cloudy","THUNDER":"Thunder","WINDY":"Windy"}},"maps":{"directions":"Directions","website":"Website","open":"Open","closed":"Closed","inPartnershipWith":"in partnership with","revealPhoneNumber":"Show the number","review":"{{count}} review","review_plural":"{{count}} reviews","seeMoreResults":"See more results"},"flight":{"titleWithLocations":"Flights {{from}} - {{to}}","allAirports":"All","cheapFlight":"Find a cheap flight","roundTrip":"Round trip","oneWay":"One way","departure":"Depart","return":"Return","searchFlight":"Search for a flight","moreFlight":"Display more results","from":"From","to":"To","type":"Type","direct":"Direct","stop":"Stop(s)","priceFrom":"Starting from {{price}}","multiCarriers":"Multiple airlines","anywhere":"Anywhere","searchAnywhere":"Search everywhere!","searchAnywhereDescription":"In case you don't know where to go","currency":"Prices shown in {{currency}}","reset":"Reset","submit":"Ok","flags":{"cheapest":"Low price","top-travel":"Top destination"},"where":"Where are we going?","tooltip":"Qwant takes care to preserve the confidentiality of your searches  (\u003Ca href=\"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fconfidentialite\u002F\"\u003ELearn more\u003C\u002Fa\u003E). \nThese results from the Skyscanner network match the keywords entered. Some prices are cached. The clicks are subject to \u003Ca href=\"https:\u002F\u002Fwww.skyscanner.fr\u002Fmedia\u002Fpolitique-confidentialite\"\u003ESkyscanner's privacy policy\u003C\u002Fa\u003E."},"technicalHelp":{"copy":"The code was copied to your clipboard.","example":"Example"},"productsAds":{"refurbished":"Refurbished"},"music":{"discography":"Discography","officialWebsite":"Official website","discoverArtist":"Discover {{artist}}"},"recipes":{"recipes":"Recipes of \u003C0\u003E{{value}}\u003C\u002F0\u003E","quantityInterval":"{{a}} to {{b}}"},"overline":{"new":"New"},"translate":{"placeholderSource":"Enter text","placeholderTarget":"Translation","warning":"The first {{limit}} characters were translated.","translatedBy":"Translated by","sourceSelectTitle":"Source language","targetSelectTitle":"Target language","detected":"{{lang}} (detected language)","automaticLabel":"Automatic detection","swapLabel":"Swap languages","clearSourceLabel":"Clear source text","thanks":"Thanks","deeplPro":"DeepL Pro","translateMoreOnDeepL":"Translate more on DeepL","deeplProSubtext":"Fast and secure translations","tryDeeplPro":"Try DeepL Pro for free","language":{"CS":"Czech","DA":"Danish","DE":"German","EL":"Greek","EN":"English","ES":"Spanish","ET":"Estonian","FI":"Finnish","FR":"French","HU":"Hungarian","IT":"Italian","JA":"Japanese","LT":"Lithuanian","LV":"Latvian","NL":"Dutch","PL":"Polish","PT":"Portuguese","RO":"Romanian","RU":"Russian","SK":"Slovak","SL":"Slovenian","SV":"Swedish","ZH":"Chinese"}},"olympics":{"games_winter":"Winter Games 2022","location_beijing":"Beijing, China","title":"Medals ranking","countries":"Countries","athletes":"Athletes","seemore":"See more on","date":"February 4 - February 20","cc3":"Content subject to CC-BY-SA 3.0 license. Source:","cc3_link":"https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby-sa\u002F3.0\u002F","para_games_winter":"Winter Paralympics Games 2022","para_date":"March 4 - March 13"},"knowledge":{"website":"Website","related":{"french_president":"French Presidents","explore":"Explore"}},"snapearth":{"longitude":"Longitude","latitude":"Latitude","min":"Min","max":"Max","seeMore":"See more"},"howTo":{"seemoreSteps":"Discover the {{count}} steps","seemoreMethods":"Discover the {{count}} methods","seemoreFallback":"Discover the steps","videos":"Tutorials on the same subject"},"worldcup":{"title":"FIFA World Cup","subtitle":"2022 Season","matches":"Matches","rankings":"Groups","footerMention":"All times are Romance Standard Time","ongoing":"Ongoing","halftime":"Half-time","location":"Qatar","worldcup":"World cup","share":"Share","upcomingGame":"TBD","lastUpdate":"Last updated:","rankingMj":"MP","rankingG":"W","rankingN":"D","rankingP":"L","rankingBp":"GF","rankingBc":"GA","rankingDb":"GD","rankingPts":"PTS","group":"Group","eight":"Round of 16","quarter":"Quarter-final","semi":"Semi-final","third":"Third place match","final":"Final","AU":"Australia","CA":"Canada","CH":"Switzerland","CR":"Costa Rica","DE":"Germany","DK":"Denmark","EC":"Ecuador","GH":"Ghana","IR":"Iran","MA":"Morocco","MX":"Mexico","RS":"Serbia","SA":"Saudi Arabia","SN":"Senegal","US":"USA","UY":"Uruguay","AR":"Argentina","BE":"Belgium","BR":"Brazil","CM":"Cameroon","ES":"Spain","FR":"France","GB-ENG":"England","GB-WLS":"Wales","HR":"Croatia","JP":"Japan","KR":"Republic of Korea","NL":"Netherlands","PL":"Poland","PT":"Portugal","QA":"Qatar","TN":"Tunisia","1c-ou-2d":"1C or 2D","1d-ou-2c":"1D or 2C","1g-ou-2h":"1G or 2H","1h-ou-2g":"1H or 2G","2e-groupe-a":"2nd Group A","2e-groupe-b":"2nd Group B","2e-groupe-c":"2nd Group C","2e-groupe-d":"2nd Group D","2e-groupe-e":"2nd Group E","2e-groupe-f":"2nd Group F","2e-groupe-g":"2nd Group G","2e-groupe-h":"2nd Group H","vainqueur-dm2":"Winner SF2","vainqueur-q2":"Winner Q2","vainqueur-q4":"Winner Q4","1a-ou-2b":"1A or 2B","1b-ou-2a":"1B or 2A","1e-ou-2f":"1E or 2F","1er-groupe-a":"1st Group A","1er-groupe-b":"1st Group B","1er-groupe-c":"1st Group C","1er-groupe-d":"1st Group D","1er-groupe-e":"1st Group E","1er-groupe-f":"1st Group F","1er-groupe-g":"1st Group G","1er-groupe-h":"1st Group H","1f-ou-2e":"1F or 2E","vainqueur-dm1":"Winner SF1","vainqueur-q1":"Winner Q1","vainqueur-q3":"Winner Q3","perdant-dm1":"Looser SM1","perdant-dm2":"Looser SM2","sourceUrl":"https:\u002F\u002Fwww.lequipe.fr\u002F","sourceText":"lequipe.fr"},"autopromo":{"pushMobileApps":{"adoptMobileApp":"Download Qwant app!"},"extension":{"title":"Surf safely on all websites with Qwant.com","titleMiniDesktop":"Surf safely on all websites with Qwant.com","titleMobile":"Switch to Qwant on Safari","addQwantSafari":"Add Qwant to Safari","addQwant":"Add Qwant to {{browser}}","addQwantItsFree":"Add Qwant to {{browser}} - It's free!","defaultSearchEngine":"Qwant as default search engine.","lessCookies":"Fewer cookies, no more intrusive banners!","trackerBlocking":"Fewer trackers, finally free!"},"firefox":{"try":"Make your choice","contribute":"Use Qwant on Firefox"},"PrivacyDay":{"title":"Protégez vos données personnelles !\u003Cbr\u002F\u003EOui mais comment ?","button":"Téléchargez notre guide"}},"llm":{"summary":"Summary by Qwant's artificial intelligence","placeholderFeedback":"Share your opinion","disableAnswers":"Disable Artificial Intelligence Answers","titleFeedback":"Give your feedback","dangerous":"Inappropriate\u002Fdangerous","inexact":"This is incorrect","other":"Other","sendButton":"Send","alertSuccess":"Thank you, your feedback has been received","errorSummary":"For technical reasons, we are unable to summarize the content of this page. Thank you for your understanding","llmPromoTag":"Instant answer","llmPromoText":"The new service to know everything about","llmPromoTry":"Try it","llmPromoClose":"No thanks","tooltipSummarizer":"Summarize with Qwant's\u003Cbr\u002F\u003E artificial intelligence","ctaSummarizer":"See the site","viewDetailedAnswer":"View detailed answer","readingSources":"Reading sources","signUpBanner":{"title":"Right now: Enjoy instant answers with Qwant's artificial intelligence!"},"sources":"Sources","dday":{"promo":{"labelCta":"Activate unlimited AI","labelCta2":"Discover","description":"Save time with unlimited access to Qwant's artificial intelligence summaries"},"cta":{"labelCta":"Trigger AI","description":"Save time with an artificial intelligence summary from Qwant"}}},"google":{"title":"Are you leaving us already?","subtitle":"On Qwant:","argument1":"You save time with fast, relevant answers generated by artificial intelligence.","argument2":"Your searches are not stored, your personal data is not sold.","cta1":"I search on Qwant","cta2":"I prefer to go to Google"}},"settings":{"settings":"Settings","interface":"Interface","homeTrends":"News on homepage","homeTiles":"Sponsored shortcuts on Homepage","smartNews":"Display news next to web results","outgoingTab":"Open outgoing links in a new tab","displaySiteIcons":"Display site icons","link":"Every settings available in a link","linkDescription":"Do you sometimes delete your cookies? Use this link as your browser's start page, or drag it to your favorites:","searchResults":"Search results","searchLanguage":"Language","saveSuccessfully":"Settings updated successfully","localSave":"Local backup","drawers":{"interface":"Interface language","locale":"Region"},"helloUsername":"\u003C0\u003E{{username}}\u003C\u002F0\u003E","personalizeYourSearches":"Personalize your searches","manageAccount":"Manage my account","llm":{"placeholder":"Flash Responses","label":"Generated by artificial intelligence","title":{"0":"Deactivated","1":"Activated by Qwant","2":"Always activated"},"description":{"0":"The flash response will not be displayed","1":"The flash response will be displayed only when relevant","2":"The flash response will always be displayed"}},"theme":{"placeholder":"Mode","label":"Appearance","default":"Automatic","light":"Light","dark":"Dark"},"safeSearch":{"placeholder":"Filter","label":"Filter adult content","title":{"0":"None","1":"Moderate","2":"Strict"},"description":{"0":"Do not filter adult content","1":"No adult images or videos","2":"No adult texts, images or videos"}},"privacy":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fconfidentialite\u002Fcookie-policy\u002F"},"report":{"title":"Report content","desc_de":"In Germany, Qwant displays the search results as provided in real-time by our partner Microsoft Bing. \nIn case of illicit content, please notify the result to Microsoft so they can review and delete it.","button_label_de":"Report to Microsoft"},"homepage":{"hero":{"switch":"Go to the homepage","no_search_tracking":"Zero tracking of your searches","no_ad_tracking":"Zero advertising tracking","no_data_sell":"Zero sale of your personal data","title":"The search engine that values you as a user, not as a product","title_branding":"The search engine that doesn't know anything about you, and that changes everything!","aria_scrolling_button":"Next section","title_carousel":"\u003C1\u003E90\u003C\u002F1\u003E \u003C0\u003Eof anonymous users satisfied\u003C\u002F0\u003E\u003C3\u003E*\u003C\u002F3\u003E","title_credits":"*regular anonymous surveys on Qwant.com"},"toggle":{"qwant":"What is Qwant?","news":"News of the day"},"skin":{"partnership":"Partnership","ad":"Ad"},"sections":{"section_clickmachine_description":"Turning our users into click machines goes against our ethics. That's why, at Qwant, we don't track advertising or analyze your personal data. Qwant puts aside the algorithms that pre-format the web and turn you into a commodity.","section_tracker_description":"Have you noticed that there is no advertising cookie banner on Qwant? Does that surprise you? We think that's normal. We do not sell your data, it belongs to you!","section_ads_description":"Simply to finance our model, as a European search engine that does not track or store your data and intends to remain free. In short, contextual ads are the same for everyone, we don't track you while you search.","section_clickmachine_title":"\u003C0\u003EBeing informed should not turn you into a\u003C\u002F0\u003E \u003C1\u003EClick machine\u003C\u002F1\u003E","section_clickmachine_image_alt":"Being informed should not turn you into a \"Click machine\"","section_tracker_title":"\u003C0\u003EHere,\u003C\u002F0\u003E \u003C1\u003Eno trackers\u003C\u002F1\u003E \u003C0\u003Eor advertising\u003C\u002F0\u003E \u003C2\u003Ecookies\u003C\u002F2\u003E","section_tracker_image_alt":"Here, no trackers or advertising cookies","section_ads_title":"\u003C0\u003EBut why is there\u003C\u002F0\u003E \u003C1\u003Eadvertising\u003C\u002F1\u003E \u003C0\u003Eon\u003C\u002F0\u003E \u003C2\u003EQwant\u003C\u002F2\u003E\u003C0\u003E?\u003C\u002F0\u003E","section_ads_image_alt":"But why is there advertising on Qwant?","section_searchWithQwant_link":"Search with Qwant","section_searchWithQwant_link_url":"https:\u002F\u002Fqwant.com\u002F","section_knowMore_link":"Know more","section_knowMore_link_url":"https:\u002F\u002Fabout.qwant.com\u002F","section_extension_title_app":"\u003C0\u003EDownload\u003C\u002F0\u003E \u003C1\u003EQwant\u003C\u002F1\u003E","section_extension_title_extension":"\u003C0\u003EDownload\u003C\u002F0\u003E \u003C1\u003EQwant\u003C\u002F1\u003E","brands_checklist":{"title":"\u003C0\u003EDiscover our check-list to keep you private life\u003C\u002F0\u003E \u003C1\u003Ereally private\u003C\u002F1\u003E","discover":"Discover","qwant_search":{"text":"We do not care about your personal data, nor your searches.","name":"Qwant Search","link":"https:\u002F\u002Fwww.qwant.com"},"qwant_maps":{"text":"Get around anywhere untracked.","name":"Qwant Maps","link":"https:\u002F\u002Fmap.qwant.com"},"qwant_junior":{"text":"Let your children discover the Internet safely.","name":"Qwant Junior","link":"https:\u002F\u002Fwww.qwantjunior.com"},"qwant_VIPrivacy":{"text":"Browse the web without trackers on any websites.","name":"Qwant VIPrivacy","link":"https:\u002F\u002Fabout.qwant.com\u002Fextension\u002F"}},"brands_userReviews":{"0":{"text":"« Finally, some digital peace of mind thanks to this application. And it's French ! Thank you very much. »","date":"User of September 24, 2022"},"1":{"text":"« After years of wanting to get rid of Google, I finally did and I must say well done!  The results are relevant, there are plenty of options and the search engine interface is well-designed across all devices. »","date":"User of February 4, 2022"},"2":{"text":"« I have been using Qwant for many year and it is great. »","date":"User of October 7, 2022"},"3":{"text":"« Great search engine, I recommend it to all who want to get away from censored results and who care about protecting their personal data. »","date":"User of July 30, 2022"},"4":{"text":"« Excellent French search engine. »","date":"User of October 7, 2022"},"5":{"text":"« I have used Qwant for many years to protect my personal data. »","date":"User of October 13, 2022"},"title":"\u003C1\u003E90\u003C\u002F1\u003E \u003C0\u003Esatisfied users\u003C\u002F0\u003E\u003C3\u003E*\u003C\u002F3\u003E","credits":"*regular anonymous surveys on Qwant.com"},"branding":{"title":"Always \u003C0\u003Econfident and secure with\u003C\u002F0\u003E Qwant","knowMore":"Know more","joinFree":"Sign up for free","enjoyNewQwant":"Enjoy the new Qwant","noConservation":"Qwant does not retain your search data","noSell":"No selling of your personal data","madeInFrance":"French search engine, hosted in Europe"}},"tiles":{"sponsored":"Sponsored","sponsoredTooltip":"This sponsored content is published without any sending of personal data to the advertiser. Hyperlinks are provided by our \u003Cstrong\u003Eadvertising partner\u003C\u002Fstrong\u003E whose \u003Cstrong\u003Eprivacy policy\u003C\u002Fstrong\u003E is applied when you click on them.","sponsoredShortcuts":"Sponsored shortcuts"},"trends":{"moreNews":"Discover more news","sponsored":"Sponsored","altAutoPromo":"A person with a panda mask looking at his phone, under which the values of Qwant.com are presented. A search engine that does not track your searches, does not sell your personal data, does not target your ads.","altAutoPromoOpera":"Reverse, A person with a panda mask looking at his phone, under which the values of Qwant.com are presented. A search engine that does not track your searches, does not sell your personal data, does not target your ads."},"addon":{"banner":"\u003Cstrong\u003EQwant VIP\u003C\u002Fstrong\u003Erivacy protects you from trackers and makes Qwant your default search engine","learn_more":"Learn more","add_qwant":"Add Qwant to {{browser}}","add_qwant_for_safari":"Add Qwant for Safari","make_default":"Make Qwant my default search engine","available_soon":"Available soon on {{browser}}","already_available_on_store":"Already available on \u003Ca href='https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fqwantcom-for-firefox' alt='Qwant VIPrivacy for Firefox' target='_blank' rel='noopener'\u003EFirefox\u003C\u002Fa\u003E and \u003Ca href='https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fqwant-for-chrome\u002Fhnlkiofnhhoahaiimdicppgemmmomijo\u002F' alt='Qwant VIPrivacy for Chrome' target='_blank' rel='noopener'\u003EChrome\u003C\u002Fa\u003E"},"mobile_app":{"title":"Switch to Qwant app","download":"Use the application","reviews":"+ {{total}} reviews"},"products":{"mobile_apps":"Our mobile apps","search":"Search","search_text":"The search engine that doesn't know anything about you, and that changes everything: zero tracking of your searches, zero personal data use, zero targeted advertising.","maps":"Maps","maps_text":"The map service that finds the right addresses and guides you around without tracking you.","junior":"Junior","junior_text":"The only secure search engine designed for children's learning and their parents' peace of mind."},"flag":{"branding":{"brand_phrase":"The search engine that respects your privacy"}},"welcome":{"alt_test":"Arrow pointing towards searchbar saying \"Test me\"","reasons":"\u003C1\u003E3 reasons\u003C\u002F1\u003E \u003C0\u003Eto use Qwant\u003C\u002F0\u003E","suggest":{"title":"Examples of searches","fake1":"TikTok digital majority","fake2":"The shortcomings of ChatGPT","fake3":"Pension reform strikes","fake3_highlighted":"Pension reform"},"alt_try":"Arrow pointing towards the above list and et says try these searches"},"rtb":{"fr":{"frenchMade":"Developed in \u003C0\u003EFrance\u003C\u002F0\u003E by our teams","hostedInFrance":"Hosted in France in \u003C0\u003Eour data centers\u003C0\u003E","privacy":"\u003C0\u003ENo. 1 in Europe\u003C\u002F0\u003E for privacy"},"yellow":{"data":"\u003C0\u003EHundreds\u003C\u002F0\u003E of data collected per day on you","profits":"\u003C0\u003EBillions\u003C\u002F0\u003E in profits made by you for others","cookies":"\u003C0\u003EHundreds\u003C\u002F0\u003E of cookie banners to refuse","tooltipCookies":"With Qwant VIPrivacy navigator extension"}},"homepageCards":{"reward":{"title":"Earn up to €10 per week by using Qwant","description":"Do research, earn points and move up the leaderboard to receive rewards every week!","buttonLabel":"Join"},"ia":{"title":"Flash Response saves you time.","description":"Qwant finds the right information among the most relevant web pages. You get your answer instantly!","tagLabel":"Free","buttonLabel":"Let's try"}},"dday":{"title":"Enjoy instant answers with Qwant's artificial intelligence"}},"reward":{"drawers":{"promo":{"title":"Loyalty program","title2":"Earn up to €10 per week by using Qwant!","claim1":"Do your searches on Qwant","claim2":"Earn points and climb the rankings","claim3":"Over 1,300 winners receive up to €10 each week!","cta":"Sign up for free","info":"How does it work?"},"ranking":{"title":"Loyalty program","walletLinkTitle":"Wallet","walletLinkSubtitle":"According to your ranking, receive your reward at the end of the week.","walletLinkSubtitleAttributionPending":"This week's new earnings are being allocated, so please be patient","countdownTitle":"End in","countdownUnitDays":"d","countdownUnitHours":"h","countdownUnitMinutes":"min","rankingTitle":"Weekly ranking","rankingDescription":"Use Qwant every day to move up the rankings. Over 1,300 winners each week.","rankingWinningZone":"Winner's zone"},"activity":{"title":"Today's Activities","bonusMobile":"Search on the Qwant mobile app","bonusDesktop":"Search on the web","days":{"title":"7 consecutive days bonus","text":"Use Qwant regularly to boost your ranking!","day":{"large":{"monday":"Mon.","tuesday":"Tue.","wednesday":"Wed.","thursday":"Thu.","friday":"Fri.","saturday":"Sat.","sunday":"Sun."},"small":{"monday":"M","tuesday":"T","wednesday":"W","thursday":"T","friday":"F","saturday":"S","sunday":"S"}}}},"wallet":{"title":"Wallet","cta":"Transfer","text":"The minimum amount for making a transfer is €5","textWithExpiry":"As soon as your wallet reaches €5, each earning expires after 3 months.","attributionPending":"New earnings in the process of being awarded","emptyOperation":"No transactions conducted at the moment.","history":{"title":"List of operations","credit":"Rewards earned","debit":"Debit","expiry":"Expiry of more than 3 months' earnings"}}},"alerts":{"welcome":"✅ Loyalty program activated\u003Cbr\u002F\u003E💰🏆 It’s your turn! Use Qwant to move up the rankings","welcomeTitle":"Congratulations on your registration","firstDay":"First activity day of the week... and we're off!","newGame":"A new week begins, we reset the counters and here we go again!","rankingRise":"Congratulation, you're moving up in the ranking! You're on the right track!","maxActivity":"Congratulations, you've used Qwant for 7 consecutive days. Your daily points are now doubled!","activityStreak":"{{count}}\u003Cspan\u003Eth\u003C\u002Fspan\u003E consecutive day on Qwant. Congrats, keep it up!","activityStreakEnd":"Ouch, you didn't come yesterday. You've lost your bonus days in a row.","winningZone":"Wow, you've just entered the winner's zone. Don't let up until the end of the week."},"popovers":{"unlogged":{"title":"Loyalty program","desc":"Earn up to €10 per week by using Qwant !","cta":"Start"}},"onboarding":{"form":{"title":"Join the Qwant loyalty program","text":"Your username","checkboxProgram":"I accept the \u003Ca href='https:\u002F\u002Fabout.qwant.com\u002Flegal\u002Fqwant-search\u002Fconditions-particulieres-programme-de-fidelite' target='_blank'\u003Eterms of use\u003C\u002Fa\u003E and the \u003Ca href='https:\u002F\u002Fabout.qwant.com\u002Flegal\u002Fpolitique-de-confidentialite-programme-de-fidelite\u002F' target='_blank'\u003Eprivacy policy\u003C\u002Fa\u003E","checkboxEmails":"I agree to receive emails from the loyalty program to keep me informed of my rankings and earnings","checkboxAdult":"I certify that I am over 18","cta1":"Validate","cta2":"I do not wish to participate","avatarTitle":"Choose you avatar","avatarbgColorTitle":"Choose a background color","avatarCancel":"Cancel","avatarConfirm":"Confirm"},"privacyAgreement":{"title":"Just one more step to go!","content":"To participate in the loyalty program, you must accept all Qwant's privacy settings.","adblocker":"If you use an AdBlocker, you won’t be able to see the privacy settings. Turn it off to proceed.","openCMP":"Access privacy settings","modalTitle":"Refusal of privacy settings","modalBody":"Are you sure you want to refuse all Qwant privacy settings? If you confirm, you won't be able to join the loyalty program.","modalAccept":"I've changed my mind, and I accept","modalRefuse":"I confirm my refusal","needHelp":"Need help?"},"privacyAgreementFinal":{"title":"Sorry, you cannot join the loyalty program","content":"Without accepting Qwant's privacy settings, you cannot participate in the loyalty program.","openCMP":"Return to privacy settings","backToQwant":"Back to Qwant.com"},"info":{"title":"\u003Cspan\u003EEarn up to €10\u003C\u002Fspan\u003E per week by using Qwant !","text":"It's simple:","paragraph1":"Do your searches on Qwant","paragraph2":"Earn points and climb the rankings","paragraph3":"Over 1,300 winners receive up to €10 each week!"}},"transfer":{"title":"Transfer to your bank account","description":"The transfer to your bank account may take 1 to 2 working days.","tax":"Bank charges of €0.70 apply to this transaction.","start":"Start"},"transferUserInfo":{"title":"Fill in your bank information","holder":"Account holder","iban":"IBAN","submit":"Submit"},"transferSuccess":{"title":"Transfer completed","alertTitle":"The money transfer has been successfully completed.","alertMessage":"The usual transfer time is between 1 and 2 working days.","backToQwantCom":"Back to Qwant.com"},"transferError":{"title":"Transfer failed","alertDefaultTitle":"The money transfer failed.","alertDefaultMessage":"Please try again in a few minutes","alertIbanAlreadyUsedMessage":"IBAN already used by another user","alertAmountTooLowMessage":"Amount too low","alertWalletLockedMessage":"An error has occurred. Please try again later.","alertIbanInvalidMessage":"Invalid IBAN","alertBeneficiaryInvalidMessage":"Invalid beneficiary","alertBeneficiaryEmptyMessage":"Invalid beneficiary","retry":"Retry"},"disableAdblockerModal":{"title":"You do not manage to display the privacy settings?","step1":"Disable your AdBlocker if you have one.","step2":"For Firefox users, check that the browser's privacy settings are set to \u003Cb\u003EStandard\u003C\u002Fb\u003E to display the consent window.","closeButton":"Close"},"landing":{"hero":{"title":"Win up to 10€ per week!","description":"Join the Qwant loyalty program and earn money thanks to your searches on the internet.","statistic":{"participants":{"number":"20,000+","description":"Participants"},"winners":{"number":"2,000+","description":"Winners"}}},"reasons":{"1":{"title":"An \u003C0\u003Einnovative\u003C\u002F0\u003E search engine","description":"Qwant, this is the innovative search engine that offers you a more pleasant and fluid search experience. By creating an account, you benefit from Qwant at 100% thanks to our AI and our \"Summary\" feature, which offers you a summary of a web page in one click!","subdescription":"Our AI answers all your questions and all your searches to accompany you every day."},"2":{"title":"No search \u003C0\u003Ehistory\u003C\u002F0\u003E","description":"With the Qwant search engine, there is no search history or sale of your personal data! Your searches belong to you and we don't know your name, gender, or what you're interested in on the web.","subdescription":"Make the choice of a more discreet and respectful navigation of your online privacy."}},"steps":{"1":{"description":"Make your daily searches on Qwant.com"},"2":{"description":"Accumulate points and climb the ranking"},"3":{"description":"Win up to 10 € per week"}},"message":{"title":"Are you ready to win money thanks to your searches on the internet?","button":"Register"},"faq":{"1":{"title":"What is Qwant?","description":"Qwant is a 100% free French search engine that allows you to earn money through your internet searches. It also incorporates artificial intelligence modules for a more relevant search experience, all without keeping your search history!"},"2":{"title":"How do I participate in the loyalty program?","description":"To participate in the loyalty program, it is enough simply to create a Qwant account and register for the program. Once your pseudo and your avatar are chosen, you will just have to make your searches."},"3":{"title":"Earning money through my searches, how does it work?","description":"Once your account is created, you can perform your searches on Qwant to earn points. These points allow you to climb the ranking and at the end of each week, the first in the ranking win money. The higher you finish in the ranking, the greater your reward. And that, every week!"},"4":{"title":"How do I withdraw my money?","description":"To withdraw your money, you must have reached a minimum of 5 euros in your Qwant wallet. Then you will be able to transfer this money from your Qwant wallet to your bank account in a totally secure way. Note, once the sum of 5 euros is reached, you have 3 months to withdraw your money before it expires."},"5":{"title":"Is it secure?","description":"The respect of personal data is a deep and strong commitment at Qwant. We work with our French banking partner MemoBank to ensure the highest security of all bank transactions."},"title":"Have a question? We've got answers!"}}},"signup":{"form":{"title":"Sign up","googleCta":"Sign up with Google","appleCta":"Sign up with Apple","or":"or","emailLabel":"Email","emailPlaceholder":"mary@example.com","passwordLabel":"Password","passwordHelperMessage":"Minimum 10 characters with at least one uppercase letter, one lowercase letter, one number and one special character","checkboxTerms":"I have read and accept the \u003Ca href='https:\u002F\u002Fabout.qwant.com\u002Flegal\u002Fqwant-search' target='_blank'\u003Eterms and conditions\u003C\u002Fa\u003E and the \u003Ca href='https:\u002F\u002Fabout.qwant.com\u002Flegal\u002Fconfidentialite' target='_blank'\u003Eprivacy policy\u003C\u002Fa\u003E","checkboxNewsletter":"I agree to receive the newsletter","submit":"Create an account","submitLanding":"Create an account with an email","connectionMessage":"Already have an account?","connectionLink":"Log in"}},"videos":{"copyright":"This video may be subject to copyright.","personal_data_title":"Information relating to your personal data","personal_data_description":"This video is not hosted by Qwant, which is not responsible for it's content or the personal data that may be used. The host of the video {{brand}} may, when it is displayed, access certain data such as your IP address and cookies, depending on its own \u003C0\u003Eprivacy policies\u003C\u002F0\u003E.","personal_data_remember":"Remember my choice and no longer display this message on this browser.","personal_data_accept":"watch the video","personal_data_cancel":"Cancel","playOnQwant":"Always play videos on Qwant.com","playOnQwantConfirm":"Are you sure ?","playOnQwantExplanations":"By disabling playback on Qwant.com, your videos will open in a new tab on the publisher's site (Dailymotion, Youtube…)","playOnQwantCancel":"Keep playing videos on Qwant.com","playOnQwantAccept":"Yes I'm sure"},"web":{"suggestTooltip":"This search suggestion is an advertisement for {{brand}}. If you click on this advertisement, you will be redirected to the advertiser's site: {{domain}}","ecoSuggest":{"suggestion":"Suggestion","ecoSuggestTooltip":"This suggestion is displayed when Qwant finds a more sustainable alternative that is likely to match your search."},"carousel":{"buttonAll":"Show all"},"shopping":{"landing":{"titleShoppingAds":"Shopping ads","popularCategories":"Most popular categories","legalSalesWarning":"The ads on this page may correspond to products that are not on sale. Check the merchant's website.","tooltipPriceDrop":"The products correspond to a selection of products whose price has recently fallen. For more offers, we invite you to specify your search in our dedicated shopping engine.","tooltipPopularity":"The products correspond to a selection of the most popular products. For more offers, we invite you to specify your search in our dedicated shopping engine.","tooltipCategory":"The products correspond to a selection of the most popular products in the category. For more offers, we invite you to specify your search in our dedicated shopping engine."},"buyProductNow":"Buy product now","useCode":"Use this discount code in the shopping cart","copyCode":"Press and hold to copy the code.","specialOffer":"Special offer","showProducts":"Show the products","mainCategory":"Main category","secondaryCategory":"Secondary category","seeMore":"Show the next {{number}}","seeLess":"Show less","allCategories":"All categories","min":"Min","max":"Max","ok":"OK","filter":"Filter","result":"Result","results":"Results \u003C0\u003E{{value}}\u003C\u002F0\u003E","noResult":"No product matches your request.","noResultSuggest":"We suggest removing some filters:","noResultQuery":"No product matches your query «{{query}}».","noResultTypo":"Check the spelling of your search","noResultBroader":"Use a less specific keyword","webResult":"Show web results","lessThan":"Less than","moreThan":"More than","between":"Between \u003C0\u002F\u003E and \u003C1\u002F\u003E","resetAll":"Reset all","allCategory":"All categories","tooltip":"The results presented on this page do not necessarily represent all products and services available on the Web. These are results for which Qwant is paid by Microsoft Bing on a CPC (\"cost per click\") basis. Qwant does not rank the Shopping offers by default; they are provided automatically by Bing Shopping based on the keywords entered. As with all of Qwant's services, we are committed to respecting your privacy when you search for products and services on our platform. The merchants from which you finalise your purchases have their own general terms and conditions of sale (applicable taxes, shipping costs, delivery options, etc.) which you should read before purchasing. The crossed-out prices are indicative information provided by the merchant when indexing its product data \u003C0 href=\"https:\u002F\u002Fabout.qwant.com\u002Fen\u002Flegal\u002Fclassement\u002F\"\u003ELearn more\u003C\u002F0\u003E","errors":{"priceRequired":"You need to fill one or both input above","priceNotANumber":"You need to use numbers","priceNegative":"The price can't be a negative number","priceMinMax":"The minimum price must be below the maximum price"},"filters":{"brands":"Brands","category":"Category","merchant":"Merchant","order":"Order","price":"Price"}},"news":{"title":"News on \u003C0\u003E{{value}}\u003C\u002F0\u003E","moreNews":"See more news","moreInUniverse":"See the other {{n}} articles","hideInUniverse":"Hide the other {{n}} articles"},"images":{"title":"Images of \u003C0\u003E{{value}}\u003C\u002F0\u003E","moreImages":"See more images"},"videos":{"title":"Videos of \u003C0\u003E{{value}}\u003C\u002F0\u003E","moreVideos":"See more videos"},"ads":{"microsoftMention":"Ads by Microsoft","qwantMention":"Ads by Qwant","microsoftToolTip":"Qwant takes care to preserve the confidentiality of your searches (\u003C0\u003ELearn more\u003C\u002F0\u003E). These ads from the Microsoft advertising network match the search terms you entered. The clicks are subject to \u003C1\u003EMicrosoft's privacy policy\u003C\u002F1\u003E.","ad":"Ad","from":"From {{ s }}","minOrder":"starting from {{s}} worth of purchases","morePrice":"Show {{ n }} prices from {{ price }}","code":"Code","clipboardCode":"The code was copied to your clipboard.","validity":"Validity","confidentiality":"Confidentiality","tooltip":"This sponsored content is published without transmission of personal data to the advertiser. Hyperlinks are provided by our partner whose Privacy policy applies when you click them.","seeMoreLinks":"See more links"},"productAds":{"title":"Products associated with {{value}}","titlePhone":"Products {{value}}","moreProducts":"See more products from {{value}}","moreProductsMobile":"See more products","adsMention":"Sponsored ads","adsMentionPhone":"Ad","promo":"Promotion"},"buttonShowMore":"Display more results","brandingBing":"Results by Microsoft Bing","relatedSearch":{"title":"To go further","titleSidebar":"Other searches"},"didYouMean":{"alteredQuery":"Includes results for \u003C0\u003E{{alteredQuery}}\u003C\u002F0\u003E","originalQuery":"Do you only want results for \u003C0\u003E{{originalQuery}}\u003C\u002F0\u003E?"},"report":"Click on a result to report it","adblockerModal":{"title":"Advertising keeps us free,\u003Cbr\u002F\u003E so play the game!","content":"Qwant offers a free search engine that respects your privacy. By blocking ads, you're blocking our only source of funding.","highlight":"To access your services, please disable your ad blocker!","howToCta":"How to disable my ad blocker?","deactivateCta":"I have disabled my ad blocker","helpTitle":"How to disable my ad blocker?","helpStep1":"Click on the ad blocker icon located at the top of your screen.","helpStep1Ex":"Examples of ad blocker icons:","helpStep1Sub1":"It's usually located in the top right-hand corner of your screen","helpStep1Sub2":"It's possible that a number partially covers the blocker icon","helpStep1Sub3":"If you use several blockers, make sure to disable all of them to access Qwant","helpStep2":"Follow the instructions provided by your blocker to disable it","helpStep3":"Click on the button below to take your changes into account:","helpMobileStep1":"Blocker disabling varies according to your browser (Firefox, Chrome, Safari...):","helpMobileStep2":"Open your phone or application settings","helpMobileStep2Or":"or","helpMobileStep2Bis":"Click on the icon (lock, shield, aA) to the left of the URL","helpMobileStep3":"Then click on the button below to take your changes into account: ","helpNeedHelpCta":"Need help ? Contact us","helpNeedHelpCtaUrl":"https:\u002F\u002Fabout.qwant.com\u002Fen\u002F"}},"upselling":{"download_tablet":"Download Qwant app for tablet and enjoy a european search engine that respects privacy.","download_mobile":"Download Qwant app for mobile and enjoy a european search engine that respects privacy.","ios_link":"https:\u002F\u002Fitunes.apple.com\u002Fus\u002Fapp\u002Fqwant\u002Fid924470452","android_link":"https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.qwant.liberty","junior_ios_link":"https:\u002F\u002Fapps.apple.com\u002Fus\u002Fapp\u002Fqwant-junior\u002Fid1318660239","ios_alt":"Download on the App Store","android_alt":"Get it on Google Play","download":"Download the app","pluginThanks":{"title":"The extension has been added to {{browser}} !","titleSecondary":"In detail what does this mean?","defaultSearchEngine":"Qwant is now your default search engine in the address bar","startPage":"Qwant will be displayed on the start page when you launch your browser","search":"Start a new search","mobile":"Continue on mobile"},"pluginSurvey":"https:\u002F\u002Ffr.surveymonkey.com\u002Fr\u002FKS9WPBC "}}};
                  initialLanguage = "en";
                  initialWhiteListLanguages = ["br","ca","co","de","en","es","eu","fr","it","nl","pl","pt","cimode"];
                  i18nNamespaces = ["account","alpha","common","drawers","errorpage","filters","footer","header","homepage","ia","images","junior","modules","report","reward","robots","settings","signup","upselling","videos","web"]
                  i18nNamespacesMapping = {"locales\u002Fbr\u002Faccount.json":"\u002Flocales\u002Fbr\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Falpha.json":"\u002Flocales\u002Fbr\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Fcommon.json":"\u002Flocales\u002Fbr\u002Fcommon.6c33f161dcb279662d6ca87d4ff9b24e.json","locales\u002Fbr\u002Fdrawers.json":"\u002Flocales\u002Fbr\u002Fdrawers.0d8ca2a729365e734aec0043bdb9ebc7.json","locales\u002Fbr\u002Ferrorpage.json":"\u002Flocales\u002Fbr\u002Ferrorpage.c0864410ebc0d5491aeab8c59f0718ce.json","locales\u002Fbr\u002Ffilters.json":"\u002Flocales\u002Fbr\u002Ffilters.4469fcf249f0bbbf6955d9300f2a54c9.json","locales\u002Fbr\u002Ffooter.json":"\u002Flocales\u002Fbr\u002Ffooter.da6fb7cf687a85ea1931954e01864df7.json","locales\u002Fbr\u002Fheader.json":"\u002Flocales\u002Fbr\u002Fheader.43a8dd5c1156632854e724143191214e.json","locales\u002Fbr\u002Fhomepage.json":"\u002Flocales\u002Fbr\u002Fhomepage.548fd5b8f363354dfc99fb31df8ac363.json","locales\u002Fbr\u002Fia.json":"\u002Flocales\u002Fbr\u002Fia.07eed66846e1a0f6bcaaf61e320f0c06.json","locales\u002Fbr\u002Fimages.json":"\u002Flocales\u002Fbr\u002Fimages.3c69e336cd11ac97c92305ed5e4e5096.json","locales\u002Fbr\u002Fjunior.json":"\u002Flocales\u002Fbr\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Fmodules.json":"\u002Flocales\u002Fbr\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Freport.json":"\u002Flocales\u002Fbr\u002Freport.ce2a24c6e48de34786133d46d9c523b6.json","locales\u002Fbr\u002Freward.json":"\u002Flocales\u002Fbr\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Frobots.json":"\u002Flocales\u002Fbr\u002Frobots.a35be9ac5086bfe9dda35a38109d8345.json","locales\u002Fbr\u002Fsettings.json":"\u002Flocales\u002Fbr\u002Fsettings.f7830d0e83068e0876f791c2c1f68fe7.json","locales\u002Fbr\u002Fsignup.json":"\u002Flocales\u002Fbr\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fbr\u002Fupselling.json":"\u002Flocales\u002Fbr\u002Fupselling.f23a938c9aad8060a07a8b10e481c8ae.json","locales\u002Fbr\u002Fvideos.json":"\u002Flocales\u002Fbr\u002Fvideos.e4a091c0595bf89959fd7e65403d9463.json","locales\u002Fbr\u002Fweb.json":"\u002Flocales\u002Fbr\u002Fweb.427c688236552cc397f2fb74e83b4e28.json","locales\u002Fca\u002Faccount.json":"\u002Flocales\u002Fca\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Falpha.json":"\u002Flocales\u002Fca\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Fcommon.json":"\u002Flocales\u002Fca\u002Fcommon.07600d3dd688d512f4687ae517a17229.json","locales\u002Fca\u002Fdrawers.json":"\u002Flocales\u002Fca\u002Fdrawers.e1f3534792603f768df90172b664c7a9.json","locales\u002Fca\u002Ferrorpage.json":"\u002Flocales\u002Fca\u002Ferrorpage.c0864410ebc0d5491aeab8c59f0718ce.json","locales\u002Fca\u002Ffilters.json":"\u002Flocales\u002Fca\u002Ffilters.2821d56083595f32bb142673fe16848f.json","locales\u002Fca\u002Ffooter.json":"\u002Flocales\u002Fca\u002Ffooter.772857597902c15b5da976176ad8c76f.json","locales\u002Fca\u002Fheader.json":"\u002Flocales\u002Fca\u002Fheader.2f4b61628da98888d0590eb8d943eed9.json","locales\u002Fca\u002Fhomepage.json":"\u002Flocales\u002Fca\u002Fhomepage.29aa26e09ced252f8a2c7aa358192281.json","locales\u002Fca\u002Fia.json":"\u002Flocales\u002Fca\u002Fia.f145032675715d328c724d9db4563515.json","locales\u002Fca\u002Fimages.json":"\u002Flocales\u002Fca\u002Fimages.706779ddaccc870460850e2494dca786.json","locales\u002Fca\u002Fjunior.json":"\u002Flocales\u002Fca\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Fmodules.json":"\u002Flocales\u002Fca\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Freport.json":"\u002Flocales\u002Fca\u002Freport.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Freward.json":"\u002Flocales\u002Fca\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Frobots.json":"\u002Flocales\u002Fca\u002Frobots.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Fsettings.json":"\u002Flocales\u002Fca\u002Fsettings.15203e84be1798846a6ffbd86a6ed619.json","locales\u002Fca\u002Fsignup.json":"\u002Flocales\u002Fca\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fca\u002Fupselling.json":"\u002Flocales\u002Fca\u002Fupselling.f23a938c9aad8060a07a8b10e481c8ae.json","locales\u002Fca\u002Fvideos.json":"\u002Flocales\u002Fca\u002Fvideos.a786faac46fea020656ddd003e11a4df.json","locales\u002Fca\u002Fweb.json":"\u002Flocales\u002Fca\u002Fweb.75df64eefb907d7a27675f1cb7faf462.json","locales\u002Fco\u002Faccount.json":"\u002Flocales\u002Fco\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Falpha.json":"\u002Flocales\u002Fco\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Fcommon.json":"\u002Flocales\u002Fco\u002Fcommon.a4ffafad8d8aad5343169f2948eb65e4.json","locales\u002Fco\u002Fdrawers.json":"\u002Flocales\u002Fco\u002Fdrawers.9a65da9e90f24d9896047971efe0f0e3.json","locales\u002Fco\u002Ferrorpage.json":"\u002Flocales\u002Fco\u002Ferrorpage.c0864410ebc0d5491aeab8c59f0718ce.json","locales\u002Fco\u002Ffilters.json":"\u002Flocales\u002Fco\u002Ffilters.9c3522024cf93abb6625e267972ec524.json","locales\u002Fco\u002Ffooter.json":"\u002Flocales\u002Fco\u002Ffooter.ca3a4e874f88ff764c5da84d895dc6d7.json","locales\u002Fco\u002Fheader.json":"\u002Flocales\u002Fco\u002Fheader.17377a577a1fba907444c85c7893b286.json","locales\u002Fco\u002Fhomepage.json":"\u002Flocales\u002Fco\u002Fhomepage.7fb448492b208a737831ac9d21325209.json","locales\u002Fco\u002Fia.json":"\u002Flocales\u002Fco\u002Fia.8bf7127319d9dd55dbd6486d7fcdcdc3.json","locales\u002Fco\u002Fimages.json":"\u002Flocales\u002Fco\u002Fimages.795870d2dfb94a8d5a84998c18a9ca76.json","locales\u002Fco\u002Fjunior.json":"\u002Flocales\u002Fco\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Fmodules.json":"\u002Flocales\u002Fco\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Freport.json":"\u002Flocales\u002Fco\u002Freport.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Freward.json":"\u002Flocales\u002Fco\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Frobots.json":"\u002Flocales\u002Fco\u002Frobots.917a885e115fb6aefc352d9ea291e0de.json","locales\u002Fco\u002Fsettings.json":"\u002Flocales\u002Fco\u002Fsettings.bc1455e57d9dde35981680e7bf741992.json","locales\u002Fco\u002Fsignup.json":"\u002Flocales\u002Fco\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fco\u002Fupselling.json":"\u002Flocales\u002Fco\u002Fupselling.f23a938c9aad8060a07a8b10e481c8ae.json","locales\u002Fco\u002Fvideos.json":"\u002Flocales\u002Fco\u002Fvideos.4552e2eaad67e61108c0905d43861530.json","locales\u002Fco\u002Fweb.json":"\u002Flocales\u002Fco\u002Fweb.df9fe8f311f02142dca457b8ac3b1789.json","locales\u002Fde\u002Faccount.json":"\u002Flocales\u002Fde\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fde\u002Falpha.json":"\u002Flocales\u002Fde\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fde\u002Fcommon.json":"\u002Flocales\u002Fde\u002Fcommon.652b35b2e2cc7a079d5e0bbcd9b15a3e.json","locales\u002Fde\u002Fdrawers.json":"\u002Flocales\u002Fde\u002Fdrawers.46f5af0ff82bcd60fc9a7590b006da1d.json","locales\u002Fde\u002Ferrorpage.json":"\u002Flocales\u002Fde\u002Ferrorpage.1d97e08d76852d2f30e51f1724c9ae2f.json","locales\u002Fde\u002Ffilters.json":"\u002Flocales\u002Fde\u002Ffilters.06e53912c17cfb669f81b2328aed609b.json","locales\u002Fde\u002Ffooter.json":"\u002Flocales\u002Fde\u002Ffooter.46a66f55715d00503dba9f6f686df290.json","locales\u002Fde\u002Fheader.json":"\u002Flocales\u002Fde\u002Fheader.34d294b510d55097173653607726c0a6.json","locales\u002Fde\u002Fhomepage.json":"\u002Flocales\u002Fde\u002Fhomepage.3235dcba4209d6b123be1c7ebbb58b55.json","locales\u002Fde\u002Fia.json":"\u002Flocales\u002Fde\u002Fia.002cdb68f22c27360f751fea9fea7d1d.json","locales\u002Fde\u002Fimages.json":"\u002Flocales\u002Fde\u002Fimages.f1904767176897c4cbfca551b6c535a8.json","locales\u002Fde\u002Fjunior.json":"\u002Flocales\u002Fde\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fde\u002Fmodules.json":"\u002Flocales\u002Fde\u002Fmodules.63ba6495e81ea7987ebcf20cdbd59173.json","locales\u002Fde\u002Freport.json":"\u002Flocales\u002Fde\u002Freport.d7815847a14bc6e1e78d71d599b8a278.json","locales\u002Fde\u002Freward.json":"\u002Flocales\u002Fde\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fde\u002Frobots.json":"\u002Flocales\u002Fde\u002Frobots.3cf49368e3329f2ca497efc3e09f8cb5.json","locales\u002Fde\u002Fsettings.json":"\u002Flocales\u002Fde\u002Fsettings.967d8ef298bf3f888f4bfa0c738c96ef.json","locales\u002Fde\u002Fsignup.json":"\u002Flocales\u002Fde\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fde\u002Fupselling.json":"\u002Flocales\u002Fde\u002Fupselling.e8cc7e33ed56d1bbe6866b58368161af.json","locales\u002Fde\u002Fvideos.json":"\u002Flocales\u002Fde\u002Fvideos.6509e644b434f7c0c99e7b7418de9e4b.json","locales\u002Fde\u002Fweb.json":"\u002Flocales\u002Fde\u002Fweb.a2b13d4ab18b33a1c36f08d4a7468ba4.json","locales\u002Fen\u002Faccount.json":"\u002Flocales\u002Fen\u002Faccount.358febc37c0e34e87ed17322e00a65b4.json","locales\u002Fen\u002Falpha.json":"\u002Flocales\u002Fen\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fen\u002Fcommon.json":"\u002Flocales\u002Fen\u002Fcommon.95817679658d7f30ef75c241098b2ce3.json","locales\u002Fen\u002Fdrawers.json":"\u002Flocales\u002Fen\u002Fdrawers.2b06a816d1fc451568d5c4b1ef180790.json","locales\u002Fen\u002Ferrorpage.json":"\u002Flocales\u002Fen\u002Ferrorpage.36ca021ca16e84a8d0a5e344ac937345.json","locales\u002Fen\u002Ffilters.json":"\u002Flocales\u002Fen\u002Ffilters.3b50eb5f7f009c8a6f9a12fcfdc84523.json","locales\u002Fen\u002Ffooter.json":"\u002Flocales\u002Fen\u002Ffooter.9703391ad5ff880503e0667e5e9673a7.json","locales\u002Fen\u002Fheader.json":"\u002Flocales\u002Fen\u002Fheader.76585ad62c4cf74c14ed1a0bbe6aabdf.json","locales\u002Fen\u002Fhomepage.json":"\u002Flocales\u002Fen\u002Fhomepage.6ddfc82b591758e6cd209e852b44aa1c.json","locales\u002Fen\u002Fia.json":"\u002Flocales\u002Fen\u002Fia.74cf6996b53b2b1bb01896e756496a3c.json","locales\u002Fen\u002Fimages.json":"\u002Flocales\u002Fen\u002Fimages.bda1382b2e5b9e93defa841c412811fc.json","locales\u002Fen\u002Fjunior.json":"\u002Flocales\u002Fen\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fen\u002Fmodules.json":"\u002Flocales\u002Fen\u002Fmodules.8a97433b342fa5c192c847aa7df6a58b.json","locales\u002Fen\u002Freport.json":"\u002Flocales\u002Fen\u002Freport.b81b19b650a7676f929829a54ffb6547.json","locales\u002Fen\u002Freward.json":"\u002Flocales\u002Fen\u002Freward.96f6abd410c9d199e13a3191eb97f8b7.json","locales\u002Fen\u002Frobots.json":"\u002Flocales\u002Fen\u002Frobots.54e0c6af5f73d4cc8b38a36c36414c7d.json","locales\u002Fen\u002Fsettings.json":"\u002Flocales\u002Fen\u002Fsettings.3fa1e80f6685e4d7c1406a0ff9bec723.json","locales\u002Fen\u002Fsignup.json":"\u002Flocales\u002Fen\u002Fsignup.fe9cc651a7a3939b466117718aa66679.json","locales\u002Fen\u002Fupselling.json":"\u002Flocales\u002Fen\u002Fupselling.83553fb7da247bb426bc148116b3fa5f.json","locales\u002Fen\u002Fvideos.json":"\u002Flocales\u002Fen\u002Fvideos.74c026c708aac14c3c34bb97972fd029.json","locales\u002Fen\u002Fweb.json":"\u002Flocales\u002Fen\u002Fweb.a7f0bf29c355e8f7ba51544d65bd9eee.json","locales\u002Fes\u002Faccount.json":"\u002Flocales\u002Fes\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fes\u002Falpha.json":"\u002Flocales\u002Fes\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fes\u002Fcommon.json":"\u002Flocales\u002Fes\u002Fcommon.93861c7a4488f92ee79b307c04bb6bc5.json","locales\u002Fes\u002Fdrawers.json":"\u002Flocales\u002Fes\u002Fdrawers.77d5dd88eb2014730cb22034ca5ce046.json","locales\u002Fes\u002Ferrorpage.json":"\u002Flocales\u002Fes\u002Ferrorpage.d0f2c506a5c31ecbcd364f187b70b4c7.json","locales\u002Fes\u002Ffilters.json":"\u002Flocales\u002Fes\u002Ffilters.2968569b890787437a636792b8879fdf.json","locales\u002Fes\u002Ffooter.json":"\u002Flocales\u002Fes\u002Ffooter.3c4e116bc31cfd4deb6b85e0325851cb.json","locales\u002Fes\u002Fheader.json":"\u002Flocales\u002Fes\u002Fheader.4c69145a698aba2f2a1df20110fabc30.json","locales\u002Fes\u002Fhomepage.json":"\u002Flocales\u002Fes\u002Fhomepage.fe7ae2352142f177a6db2c9482702cd4.json","locales\u002Fes\u002Fia.json":"\u002Flocales\u002Fes\u002Fia.0bb4b001e2f9caf83de9c62cc3135dee.json","locales\u002Fes\u002Fimages.json":"\u002Flocales\u002Fes\u002Fimages.fa9e6250dc7babe07ae0c3297446c0a2.json","locales\u002Fes\u002Fjunior.json":"\u002Flocales\u002Fes\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fes\u002Fmodules.json":"\u002Flocales\u002Fes\u002Fmodules.83a800232ca23d476cfd9015b09d7c2e.json","locales\u002Fes\u002Freport.json":"\u002Flocales\u002Fes\u002Freport.9ebf8bd17bcb2b310c960d3d349633ae.json","locales\u002Fes\u002Freward.json":"\u002Flocales\u002Fes\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fes\u002Frobots.json":"\u002Flocales\u002Fes\u002Frobots.c5171ae2a720fe195f41c13b810f048f.json","locales\u002Fes\u002Fsettings.json":"\u002Flocales\u002Fes\u002Fsettings.718da31837a5b9509c6b64c842a42ef8.json","locales\u002Fes\u002Fsignup.json":"\u002Flocales\u002Fes\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fes\u002Fupselling.json":"\u002Flocales\u002Fes\u002Fupselling.2f5e8b301c5875857027d5d31c174d80.json","locales\u002Fes\u002Fvideos.json":"\u002Flocales\u002Fes\u002Fvideos.ba762c47f77d82b835ac318bba8e400c.json","locales\u002Fes\u002Fweb.json":"\u002Flocales\u002Fes\u002Fweb.8ef462fae87d5bf75855bdb2a64ceda4.json","locales\u002Feu\u002Faccount.json":"\u002Flocales\u002Feu\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Falpha.json":"\u002Flocales\u002Feu\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Fcommon.json":"\u002Flocales\u002Feu\u002Fcommon.3a9efe604c86ff0f37f697ab50f9c57c.json","locales\u002Feu\u002Fdrawers.json":"\u002Flocales\u002Feu\u002Fdrawers.2efce8da92feb311d7fe05259c1b4d2d.json","locales\u002Feu\u002Ferrorpage.json":"\u002Flocales\u002Feu\u002Ferrorpage.c0864410ebc0d5491aeab8c59f0718ce.json","locales\u002Feu\u002Ffilters.json":"\u002Flocales\u002Feu\u002Ffilters.a680b92d1c3fafe374ba5b4245d859bc.json","locales\u002Feu\u002Ffooter.json":"\u002Flocales\u002Feu\u002Ffooter.bfb41b5790f10190ea53a59c873a0383.json","locales\u002Feu\u002Fheader.json":"\u002Flocales\u002Feu\u002Fheader.59ecc4ed6035a8330c564c7bb7e8d67b.json","locales\u002Feu\u002Fhomepage.json":"\u002Flocales\u002Feu\u002Fhomepage.9887b04e8f861d966e2cd7895cd0cb5c.json","locales\u002Feu\u002Fia.json":"\u002Flocales\u002Feu\u002Fia.c6294da27c8a8012b91dc98137b93a08.json","locales\u002Feu\u002Fimages.json":"\u002Flocales\u002Feu\u002Fimages.20c81074513e1cb723787f5fbf8b3ab1.json","locales\u002Feu\u002Fjunior.json":"\u002Flocales\u002Feu\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Fmodules.json":"\u002Flocales\u002Feu\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Freport.json":"\u002Flocales\u002Feu\u002Freport.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Freward.json":"\u002Flocales\u002Feu\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Frobots.json":"\u002Flocales\u002Feu\u002Frobots.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Fsettings.json":"\u002Flocales\u002Feu\u002Fsettings.57ed81984b72d31d0c3ae58ccf91bfed.json","locales\u002Feu\u002Fsignup.json":"\u002Flocales\u002Feu\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Feu\u002Fupselling.json":"\u002Flocales\u002Feu\u002Fupselling.f23a938c9aad8060a07a8b10e481c8ae.json","locales\u002Feu\u002Fvideos.json":"\u002Flocales\u002Feu\u002Fvideos.b5bb016593ef9da2048d69481e321693.json","locales\u002Feu\u002Fweb.json":"\u002Flocales\u002Feu\u002Fweb.8dd9228ebc79ff97410706b68cee7ab8.json","locales\u002Ffr\u002Faccount.json":"\u002Flocales\u002Ffr\u002Faccount.55a19b3151742a037cd2e23a4b2cf0ae.json","locales\u002Ffr\u002Falpha.json":"\u002Flocales\u002Ffr\u002Falpha.61aee2460c3ea3419127100c54749876.json","locales\u002Ffr\u002Fcommon.json":"\u002Flocales\u002Ffr\u002Fcommon.2c27f1c5e945da1680bb3d8c0f993bea.json","locales\u002Ffr\u002Fdrawers.json":"\u002Flocales\u002Ffr\u002Fdrawers.993c41454180ea284a915c9c6bf2884b.json","locales\u002Ffr\u002Ferrorpage.json":"\u002Flocales\u002Ffr\u002Ferrorpage.bed62535d3cf6ad5dd76f4acea9c0aa8.json","locales\u002Ffr\u002Ffilters.json":"\u002Flocales\u002Ffr\u002Ffilters.179f8df8c0278217982a41756d733465.json","locales\u002Ffr\u002Ffooter.json":"\u002Flocales\u002Ffr\u002Ffooter.a1c1a320b71c38c8a41eebe034c5609e.json","locales\u002Ffr\u002Fheader.json":"\u002Flocales\u002Ffr\u002Fheader.28a0776aef58a44b5072ad281f3b310b.json","locales\u002Ffr\u002Fhomepage.json":"\u002Flocales\u002Ffr\u002Fhomepage.fec59e287c043ac1bf71490123fa96d6.json","locales\u002Ffr\u002Fia.json":"\u002Flocales\u002Ffr\u002Fia.36563b564d6fca3024079fc2b8cc06ee.json","locales\u002Ffr\u002Fimages.json":"\u002Flocales\u002Ffr\u002Fimages.b6b4177a09b19388f1998d6d3c955c2f.json","locales\u002Ffr\u002Fjunior.json":"\u002Flocales\u002Ffr\u002Fjunior.3a106e4f68b08441cde18952f9ecdb80.json","locales\u002Ffr\u002Fmodules.json":"\u002Flocales\u002Ffr\u002Fmodules.e0aaa73e99c02b791cf71684c2b593ae.json","locales\u002Ffr\u002Freport.json":"\u002Flocales\u002Ffr\u002Freport.7d8ddb4a7b6a7d51921d7782771c880e.json","locales\u002Ffr\u002Freward.json":"\u002Flocales\u002Ffr\u002Freward.8b53c3d4ba478f8cd2954ebc504c3b0e.json","locales\u002Ffr\u002Frobots.json":"\u002Flocales\u002Ffr\u002Frobots.c594365c2bbfba9ae39ba09dc90d1b38.json","locales\u002Ffr\u002Fsettings.json":"\u002Flocales\u002Ffr\u002Fsettings.46aaf75cbf6d3b8dcac1a2251b40b7ad.json","locales\u002Ffr\u002Fsignup.json":"\u002Flocales\u002Ffr\u002Fsignup.4ab11feb6b9138fd3ff21fcde8f0d84e.json","locales\u002Ffr\u002Fupselling.json":"\u002Flocales\u002Ffr\u002Fupselling.7c3880c29b680887a7893175318850e5.json","locales\u002Ffr\u002Fvideos.json":"\u002Flocales\u002Ffr\u002Fvideos.a2a7fad56ac85341769fcd54cee9fd7e.json","locales\u002Ffr\u002Fweb.json":"\u002Flocales\u002Ffr\u002Fweb.23652a522b42e3c0c1e77db7b420ba1e.json","locales\u002Fit\u002Faccount.json":"\u002Flocales\u002Fit\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fit\u002Falpha.json":"\u002Flocales\u002Fit\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fit\u002Fcommon.json":"\u002Flocales\u002Fit\u002Fcommon.43bd6ed8f12156c29ef20d30d329677c.json","locales\u002Fit\u002Fdrawers.json":"\u002Flocales\u002Fit\u002Fdrawers.48b1bca8d3c34a6c0d3016ce91e1f5d3.json","locales\u002Fit\u002Ferrorpage.json":"\u002Flocales\u002Fit\u002Ferrorpage.f81d0015359f4cff93d3aa75799e9bf9.json","locales\u002Fit\u002Ffilters.json":"\u002Flocales\u002Fit\u002Ffilters.471a1dbf9415fe03105ae0c5f905f525.json","locales\u002Fit\u002Ffooter.json":"\u002Flocales\u002Fit\u002Ffooter.eba4abc4aa2d8c222afacb5a033c537d.json","locales\u002Fit\u002Fheader.json":"\u002Flocales\u002Fit\u002Fheader.ec8b3324114970e6f42ab9ade90f9074.json","locales\u002Fit\u002Fhomepage.json":"\u002Flocales\u002Fit\u002Fhomepage.4dc0c7e72aeb73b720faa33220b02b31.json","locales\u002Fit\u002Fia.json":"\u002Flocales\u002Fit\u002Fia.e76a1914cfaf482c0e6b1e3f2490e321.json","locales\u002Fit\u002Fimages.json":"\u002Flocales\u002Fit\u002Fimages.313f9a2ba1ecdd355b22eeedeaf7b20c.json","locales\u002Fit\u002Fjunior.json":"\u002Flocales\u002Fit\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fit\u002Fmodules.json":"\u002Flocales\u002Fit\u002Fmodules.1d71eb1f4457d80e785aad4b91079d8d.json","locales\u002Fit\u002Freport.json":"\u002Flocales\u002Fit\u002Freport.85ac2e078dc399cd4d0517414c4b4948.json","locales\u002Fit\u002Freward.json":"\u002Flocales\u002Fit\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fit\u002Frobots.json":"\u002Flocales\u002Fit\u002Frobots.7ae7a2bb9101636b3daea89ba62b3a38.json","locales\u002Fit\u002Fsettings.json":"\u002Flocales\u002Fit\u002Fsettings.3fac7654a397173f21b8b4bf6d1f46d1.json","locales\u002Fit\u002Fsignup.json":"\u002Flocales\u002Fit\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fit\u002Fupselling.json":"\u002Flocales\u002Fit\u002Fupselling.62a7a0a84d003f4132425688754765b7.json","locales\u002Fit\u002Fvideos.json":"\u002Flocales\u002Fit\u002Fvideos.f2ac79be2c8cb231df3c0c1d5f074749.json","locales\u002Fit\u002Fweb.json":"\u002Flocales\u002Fit\u002Fweb.a169282ed7de5f9d5e42ebb98e1850bc.json","locales\u002Fnl\u002Faccount.json":"\u002Flocales\u002Fnl\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Falpha.json":"\u002Flocales\u002Fnl\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Fcommon.json":"\u002Flocales\u002Fnl\u002Fcommon.b264532d5e4571c69e0e07ce0083fee8.json","locales\u002Fnl\u002Fdrawers.json":"\u002Flocales\u002Fnl\u002Fdrawers.cbe29e61187b8950da22e601ef035bc6.json","locales\u002Fnl\u002Ferrorpage.json":"\u002Flocales\u002Fnl\u002Ferrorpage.04a7201f98a33b735e1328a9c6dcf054.json","locales\u002Fnl\u002Ffilters.json":"\u002Flocales\u002Fnl\u002Ffilters.a31cd1c18cfdaa1499a0982e12bc428b.json","locales\u002Fnl\u002Ffooter.json":"\u002Flocales\u002Fnl\u002Ffooter.98840b68f8c8e8c04cfa0b58c8936d91.json","locales\u002Fnl\u002Fheader.json":"\u002Flocales\u002Fnl\u002Fheader.2c2cea073389ce4a7dc22fcaa0e21fe4.json","locales\u002Fnl\u002Fhomepage.json":"\u002Flocales\u002Fnl\u002Fhomepage.11794695e5a91e433b640cff748493a6.json","locales\u002Fnl\u002Fia.json":"\u002Flocales\u002Fnl\u002Fia.b65c4f7441a588c6c9550b37767a0e0b.json","locales\u002Fnl\u002Fimages.json":"\u002Flocales\u002Fnl\u002Fimages.56446d53181567fdbb47a8f162c5b767.json","locales\u002Fnl\u002Fjunior.json":"\u002Flocales\u002Fnl\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Fmodules.json":"\u002Flocales\u002Fnl\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Freport.json":"\u002Flocales\u002Fnl\u002Freport.5166bdaadc5904e7d42735c30984ba83.json","locales\u002Fnl\u002Freward.json":"\u002Flocales\u002Fnl\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Frobots.json":"\u002Flocales\u002Fnl\u002Frobots.843cbdf018cd6eb16f957bb3b0453b4f.json","locales\u002Fnl\u002Fsettings.json":"\u002Flocales\u002Fnl\u002Fsettings.477f6e2eab992b8c4316f52a11c0488d.json","locales\u002Fnl\u002Fsignup.json":"\u002Flocales\u002Fnl\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fnl\u002Fupselling.json":"\u002Flocales\u002Fnl\u002Fupselling.3dd02a372ce0e4092c7a238e513c0272.json","locales\u002Fnl\u002Fvideos.json":"\u002Flocales\u002Fnl\u002Fvideos.594d0afe0a2dbb24b23b98bb5d1d603c.json","locales\u002Fnl\u002Fweb.json":"\u002Flocales\u002Fnl\u002Fweb.f885e4a165b49c9bba30654b81c0eeac.json","locales\u002Fpl\u002Faccount.json":"\u002Flocales\u002Fpl\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Falpha.json":"\u002Flocales\u002Fpl\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Fcommon.json":"\u002Flocales\u002Fpl\u002Fcommon.59b8b79ae7a0933e6086315bd4954ac5.json","locales\u002Fpl\u002Fdrawers.json":"\u002Flocales\u002Fpl\u002Fdrawers.092f784d4914c3befd5928ab9472dcd2.json","locales\u002Fpl\u002Ferrorpage.json":"\u002Flocales\u002Fpl\u002Ferrorpage.b54759e1886b998375830ef8f0b51be2.json","locales\u002Fpl\u002Ffilters.json":"\u002Flocales\u002Fpl\u002Ffilters.ca0ce709b95fca716f0c4801e51a25de.json","locales\u002Fpl\u002Ffooter.json":"\u002Flocales\u002Fpl\u002Ffooter.9cd8a417fd57959a8d488c4e0f14b49a.json","locales\u002Fpl\u002Fheader.json":"\u002Flocales\u002Fpl\u002Fheader.1676ed16d6c6d646098414b6f7b81297.json","locales\u002Fpl\u002Fhomepage.json":"\u002Flocales\u002Fpl\u002Fhomepage.9b99ab99c890853c8db423b52f7981bd.json","locales\u002Fpl\u002Fia.json":"\u002Flocales\u002Fpl\u002Fia.67ec246200caca73d0c99ef57fbd66b7.json","locales\u002Fpl\u002Fimages.json":"\u002Flocales\u002Fpl\u002Fimages.ab4ccf038fdaec4f3b1b0de12303ccb4.json","locales\u002Fpl\u002Fjunior.json":"\u002Flocales\u002Fpl\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Fmodules.json":"\u002Flocales\u002Fpl\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Freport.json":"\u002Flocales\u002Fpl\u002Freport.4635a57cbcf59de28ec1e44dd90ad136.json","locales\u002Fpl\u002Freward.json":"\u002Flocales\u002Fpl\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Frobots.json":"\u002Flocales\u002Fpl\u002Frobots.955a4716904658e36acf0dd656446ca4.json","locales\u002Fpl\u002Fsettings.json":"\u002Flocales\u002Fpl\u002Fsettings.bdde3b891fec1e0825c1207ada56ec0f.json","locales\u002Fpl\u002Fsignup.json":"\u002Flocales\u002Fpl\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpl\u002Fupselling.json":"\u002Flocales\u002Fpl\u002Fupselling.d43346a35b7d262ab42aecb62796bf02.json","locales\u002Fpl\u002Fvideos.json":"\u002Flocales\u002Fpl\u002Fvideos.33ca5650aecb308f3bc552b39c9a2dfd.json","locales\u002Fpl\u002Fweb.json":"\u002Flocales\u002Fpl\u002Fweb.073f92f2fa27c7f5c58b8105a307671a.json","locales\u002Fpt\u002Faccount.json":"\u002Flocales\u002Fpt\u002Faccount.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Falpha.json":"\u002Flocales\u002Fpt\u002Falpha.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Fcommon.json":"\u002Flocales\u002Fpt\u002Fcommon.dee568940dec2b31771ab93d0c88c589.json","locales\u002Fpt\u002Fdrawers.json":"\u002Flocales\u002Fpt\u002Fdrawers.b0aef0d5a71c0945ae057d2962d2d0fc.json","locales\u002Fpt\u002Ferrorpage.json":"\u002Flocales\u002Fpt\u002Ferrorpage.3779611bfe87b4a2a4d8705edab8c925.json","locales\u002Fpt\u002Ffilters.json":"\u002Flocales\u002Fpt\u002Ffilters.391333197dfb63b30135095554087bb7.json","locales\u002Fpt\u002Ffooter.json":"\u002Flocales\u002Fpt\u002Ffooter.833a6c178b7d2ae255e00bdcaa78ab6d.json","locales\u002Fpt\u002Fheader.json":"\u002Flocales\u002Fpt\u002Fheader.21fd56dfd0a81410597729a02d5d8260.json","locales\u002Fpt\u002Fhomepage.json":"\u002Flocales\u002Fpt\u002Fhomepage.55acee7811abe82e2e64037dc53f0b2e.json","locales\u002Fpt\u002Fia.json":"\u002Flocales\u002Fpt\u002Fia.20cdd39f97b815753632550424686b12.json","locales\u002Fpt\u002Fimages.json":"\u002Flocales\u002Fpt\u002Fimages.9e35dbbca5021d98e2710aa33aa80c34.json","locales\u002Fpt\u002Fjunior.json":"\u002Flocales\u002Fpt\u002Fjunior.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Fmodules.json":"\u002Flocales\u002Fpt\u002Fmodules.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Freport.json":"\u002Flocales\u002Fpt\u002Freport.a9326ba3d0d11eb0efacf7123b04d3dd.json","locales\u002Fpt\u002Freward.json":"\u002Flocales\u002Fpt\u002Freward.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Frobots.json":"\u002Flocales\u002Fpt\u002Frobots.477af6e6f0334b53ba9b1941e4321625.json","locales\u002Fpt\u002Fsettings.json":"\u002Flocales\u002Fpt\u002Fsettings.77349e65131463fdd753e9e5c3204b01.json","locales\u002Fpt\u002Fsignup.json":"\u002Flocales\u002Fpt\u002Fsignup.8a80554c91d9fca8acb82f023de02f11.json","locales\u002Fpt\u002Fupselling.json":"\u002Flocales\u002Fpt\u002Fupselling.2ec100079420ed38eb1dce690318bc30.json","locales\u002Fpt\u002Fvideos.json":"\u002Flocales\u002Fpt\u002Fvideos.2f05062993dec435b8a26edb8a1f12ce.json","locales\u002Fpt\u002Fweb.json":"\u002Flocales\u002Fpt\u002Fweb.270fbd3802963f2c25a28611b5bfd461.json"}
                </script>
  <script id="__LOADABLE_REQUIRED_CHUNKS__" type="application/json">[]</script><script id="__LOADABLE_REQUIRED_CHUNKS___ext" type="application/json">{"namedChunks":[]}</script>
<script async="" data-chunk="app" src="/a61ec0921f734a0d5dee_runtime.Phoenix.js"></script>
<script async="" data-chunk="app" src="/eccc33be0ced324f778a_vendors~app.chunks.js"></script>
<script async="" data-chunk="app" src="/46a6c1fdc290b3b0cbd5_app.chunks.js"></script>
<script>(function(window, document, dataLayerName, id) {
window[dataLayerName]=window[dataLayerName]||[],window[dataLayerName].push({start:(new Date).getTime(),event:"stg.start"});var scripts=document.getElementsByTagName('script')[0],tags=document.createElement('script');
function stgCreateCookie(a,b,c){var d="";if(c){var e=new Date;e.setTime(e.getTime()+24*c*60*60*1e3),d="; expires="+e.toUTCString()}document.cookie=a+"="+b+d+"; path=/"}
var isStgDebug=(window.location.href.match("stg_debug")||document.cookie.match("stg_debug"))&&!window.location.href.match("stg_disable_debug");stgCreateCookie("stg_debug",isStgDebug?1:"",isStgDebug?14:-1);
var qP=[];dataLayerName!=="dataLayer"&&qP.push("data_layer_name="+dataLayerName),isStgDebug&&qP.push("stg_debug");var qPString=qP.length>0?("?"+qP.join("&")):"";
tags.async=!0,tags.src="https://k.qwant.com/containers/"+id+".js"+qPString,scripts.parentNode.insertBefore(tags,scripts);
!function(a,n,i){a[n]=a[n]||{};for(var c=0;c<i.length;c++)!function(i){a[n][i]=a[n][i]||{},a[n][i].api=a[n][i].api||function(){var a=[].slice.call(arguments,0);"string"==typeof a[0]&&window[dataLayerName].push({event:n+"."+i+":"+a[0],parameters:[].slice.call(arguments,1)})}}(i[c])}(window,"ppms",["tm","cm"]);
})(window, document, 'dataLayer', '98cbd59f-731c-4874-a402-04f51ed9069a')</script><script type="text/javascript">
    var _paq = _paq || [];
    _paq.push(['setTrackingSource', 'jstc_tm']);
    _paq.push(['setSecureCookie', 1]);
    _paq.push(['setCookieDomain', '.qwant.com']);
    _paq.push(['enableCrossDomainLinking']);
    _paq.push(['setDomains', ['.qwant.com', '.qwantjunior.com']]);
    (function(p,i,w,ik) {
        var g=ik.createElement('script'),s=ik.getElementsByTagName('script')[0];
        _paq.push(['setTrackerUrl', p]);
        _paq.push(['setSiteId', w]);
        g.type='text/javascript';g.async=true;g.defer=true;g.src=i;s.parentNode.insertBefore(g,s);
    })('https://k.qwant.com/2aecbbf86c74c1c2fb798e0a39f0678e','https://k.qwant.com/2aecbbf86c74c1c2fb798e0a39f0678e.js','98cbd59f-731c-4874-a402-04f51ed9069a',document)
</script></body></html>

================
File: debug_output/yahoo_analysis.txt
================
Analysis for yahoo
================================================================================

Potential containers found:
div.dd.algo: 0 elements found
div.algo-sr: 0 elements found
div.dd.algo.algo-sr: 0 elements found
article.webResult: 0 elements found
div.result: 0 elements found
div.web-result: 0 elements found
div.result: 0 elements found
div.search-result: 0 elements found
li.result: 0 elements found

Other potential elements:
h1: 1 elements found
  1. guce

================
File: debug_output/yahoo_content.html
================
<!DOCTYPE html><html dir="ltr" class="ltr  yahoo-page height100"><head>
    <title>Yahoo is part of the Yahoo family of brands</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover">
    <link rel="stylesheet" href="https://s.yimg.com/oa/build/css/site-ltr-1e589816.css">
    <link rel="icon" type="image/png" href="https://s.yimg.com/oa/build/images/favicons/yahoo.png">
    <style nonce="">:root,html[data-color-scheme=dark] [data-maintain-color],html[data-color-theme-enabled] [data-color-scheme=light],html[data-color-theme-enabled][data-color-scheme=light]{--yb-default-font-family:"Helvetica Neue", Helvetica, Tahoma, Geneva, Arial, sans-serif;--yb-fuji2-font-family:"YahooSans VF", YahooSans, "Yahoo Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;--yb-uh3-cond-font-family:"Yahoo Sans Cond", YahooSansCond, "Yahoo Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;--yb-font-regular:400;--yb-font-medium:500;--yb-font-bold:600;--yb-color-att-dark-blue:#0057b8;--yb-color-frontier-red:#c41230;--yb-color-rogers-red:#c41522;--yb-color-a11y-gray:#787679;--yb-barbie:#f80e5d;--yb-barney:#cc008c;--yb-batcave:#232a31;--yb-battleship:#5b636a;--yb-black:#000;--yb-blurple:#5d5eff;--yb-bob:#b0b9c1;--yb-bonsai:#008751;--yb-charcoal:#464e56;--yb-cobalt:#003abc;--yb-denim:#1a0dab;--yb-dirty-seagull:#e0e4e9;--yb-dolphin:#6e7780;--yb-dory:#0f69ff;--yb-gandalf:#979ea8;--yb-grape-jelly:#6001d2;--yb-gray-hair:#f0f3f5;--yb-hulk-pants:#7e1fff;--yb-inkwell:#1d2228;--yb-malbec:#39007d;--yb-marshmallow:#f5f8fa;--yb-midnight:#101518;--yb-mulberry:#5015b0;--yb-pebble:#c7cdd2;--yb-peeps:#7dcbff;--yb-ramones:#2c363f;--yb-sea-foam:#11d3cd;--yb-scooter:#0063eb;--yb-shark:#828a93;--yb-sky:#12a9ff;--yb-smurfette:#188fff;--yb-solo-cup:#eb0f29;--yb-starfish:#7759ff;--yb-swedish-fish:#ff333a;--yb-thanos:#907cff;--yb-turmeric:#ffa700;--yb-white:#fff;--yb-rgb-battleship:91 99 106;--yb-rgb-white:255 255 255;--yb-rgb-blurple:93 94 255;--yb-rgb-starfish:119 89 255;--yb-rgb-hulk-pants:126 31 255;--yb-rgb-grape-jelly:96 1 210;--yb-rgb-peeps:125 203 255;--yb-rgb-sky:18 169 255;--yb-rgb-dory:15 105 255;--yb-rgb-scooter:0 99 235;--yb-rgb-cobalt:0 58 188;--yb-rgb-sea-foam:17 211 205;--yb-battleship-fog:rgb(var(--yb-rgb-battleship) / 10%);--yb-white-fog:rgb(var(--yb-rgb-white) / 10%);--yb-blurple-fog:rgb(var(--yb-rgb-blurple) / 10%);--yb-starfish-fog:rgb(var(--yb-rgb-starfish) / 10%);--yb-hulk-pants-fog:rgb(var(--yb-rgb-hulk-pants) / 10%);--yb-grape-jelly-fog:rgb(var(--yb-rgb-grape-jelly) / 10%);--yb-peeps-fog:rgb(var(--yb-rgb-peeps) / 10%);--yb-sky-fog:rgb(var(--yb-rgb-sky) / 10%);--yb-dory-fog:rgb(var(--yb-rgb-dory) / 10%);--yb-scooter-fog:rgb(var(--yb-rgb-scooter) / 10%);--yb-cobalt-fog:rgb(var(--yb-rgb-cobalt) / 10%);--yb-sea-foam-fog:rgb(var(--yb-rgb-sea-foam) / 10%);--yb-hulk-pants-accent:rgb(var(--yb-rgb-hulk-pants) / 50%);--yb-grape-jelly-accent:rgb(var(--yb-rgb-grape-jelly) / 50%);--yb-sky-accent:rgb(var(--yb-rgb-sky) / 50%);--yb-logo-brand:var(--yb-grape-jelly);--yb-logo-property:var(--yb-batcave);--yb-finance-logo-brand:var(--yb-grape-jelly);--yb-text-primary:var(--yb-batcave);--yb-text-secondary:var(--yb-battleship);--yb-text-mail-primary:var(--yb-grape-jelly);--yb-text-mail-hover:var(--yb-mulberry);--yb-background-color:var(--yb-white);--yb-l2-background-color:var(--yb-marshmallow);--yb-popover-background:var(--uh-popover-background, var(--yb-white));--yb-tab-focus-accent:var(--yb-grape-jelly-accent);--yb-selected-item-background:var(--yb-marshmallow);--yb-sidenav-close-btn-background:var(--yb-marshmallow);--yb-sidenav-btn-color-hover:var(--yb-grape-jelly);--yb-sidenav-btn-color-active:var(--yb-dirty-seagull);--yb-sidenav-btn-text-active:var(--yb-batcave);--yb-sidenav-finance-plus-icon:var(--yb-svg-icon-color-non-l2);--yb-sidenav-bg:var(--yb-background-color);--yb-moremenu-finance-plus-icon:var(--yb-svg-icon-color-non-l2);--yb-profile-avatar-bg:var(--uh-profile-avatar-bg, var(--yb-gray-hair));--yb-profile-panel-hover:var(--uh-profile-panel-hover-bg, var(--yb-dirty-seagull));--yb-profile-alphatar-background:var(--yb-gray-hair);--yb-profile-alphatar-background-pressed:var(--yb-white);--yb-signin-border-color:var(--yb-dirty-seagull);--yb-mail-border-color:var(--yb-grape-jelly);--yb-unread-container-bg:rgb(var(--yb-rgb-grape-jelly) / 5%);--yb-profile-character-hover:var(--yb-white);--yb-profile-pressed-state:var(--yb-bob);--yb-profile-character-pressed-state-bg:var(--yb-dirty-seagull);--yb-profile-character-pressed-state-text:var(--yb-batcave);--yb-profile-account-status-container-bg:var(--yb-battleship-fog);--yb-searchbox-bg:var(--yb-gray-hair);--yb-search-btn-hover:#5409b2;--yb-search-faux-icon:var(--yb-batcave);--yb-search-input-box-shadow:0 0 1px 0 rgb(0 0 0 / 0%), 0 1px 0 0 var(--yb-dirty-seagull);--yb-search-assist-primary:var(--yb-batcave);--yb-search-assist-secondary:var(--yb-dolphin);--yb-search-assist-history:#6e329d;--yb-search-assist-history-pc:var(--yb-grape-jelly);--yb-search-assist-back-btn:var(--yb-dory);--yb-search-assist-item-hover-background:var(--yb-marshmallow);--yb-elevation3-box-shadow:0 4px 8px 0 rgb(0 0 0 / 10%), 0 0 1px 0 rgb(0 0 0 / 10%);--yb-elevation4-box-shadow:0 4px 16px 0 rgb(0 0 0 / 20%), 0 0 2px 0 rgb(0 0 0 / 5%);--yb-l2-news-background:linear-gradient(0deg, rgb(255 255 255 / 100%) 0%, rgb(248 250 251 / 100%) 100%);--yb-current-account-fog:var(--yb-dory-fog);--yb-editions-modal-outline:var(--yb-dirty-seagull);--yb-editions-text:var(--yb-dolphin);--yb-cobrand-logos-divider:var(--yb-dirty-seagull);--yb-l2-background:var(--uh-l2-background, var(--yb-l2-background-color));--yb-search-carat:var(--uh-search-carat-color, var(--yb-grape-jelly));--yb-l2-divider-color:var(--uh-l2-divider-color, var(--yb-gray-hair));--yb-l2-text-color:var(--uh-l2-text-color, var(--yb-batcave));--yb-default-font:var(--uh-font-family, var(--yb-default-font-family));--yb-fuji2-font:var(--uh-font-family, var(--yb-fuji2-font-family));--yb-uh3-cond-font:var(--uh-font-family, var(--yb-uh3-cond-font-family));--yb-outline:4px solid var(--uh-tab-focus-color, var(--yb-tab-focus-accent));--yb-search-btn-color:var(--uh-search-btn-color, var(--yb-search-carat));--yb-search-btn-hover-color:var(--uh-search-btn-hover-color, var(--yb-search-btn-hover));--yb-text-hover-color:var(--uh-text-hover-color, var(--yb-sidenav-btn-color-hover));--yb-profile-panel-hover-text:var(--uh-text-hover-color, var(--yb-grape-jelly));--yb-searchbox-transition:border-radius 0s 0.2s ease-out, background-color 0s 0.2s ease-out, box-shadow 0.2s ease-out, padding-left 50ms 150ms ease-out;--yb-property-ruler-color:var(--uh-property-ruler-color, var(--yb-grape-jelly));--yb-svg-icon-color:var(--uh-icon-color, var(--yb-grape-jelly));--yb-svg-icon-color-non-l2:var(--uh-icon-color-non-l2, var(--yb-grape-jelly) );--yb-svg-icon-color-selected:var(--uh-icon-color-selected, var(--yb-white));--yb-mail-bubble-color:var(--uh-mail-bubble-color, var(--yb-grape-jelly));--yb-mail-indicator:var(--yb-profile-panel-hover-text);--yb-mail-indicator-border:1px solid var(--yb-background-color);--yb-mail-count:var(--yb-text-primary);--yb-tap-color:var(--uh-text-hover-color, var(--yb-text-primary));--yb-text-pressed-color:var(--uh-text-pressed-color, var(--yb-mulberry));--yb-l2-margin:var(--uh-l2-margin);--yb-text-shadow:none;--yb-nav-color:var(--yb-text-secondary);--yb-sports-l2-dropdown-hover-bg:#e6e6e6;--yb-sports-l2-dropdown-hover-color:var(--yb-black);--yb-sports-l2-dropdown-focus-bg:#ecf8ff;--yb-nav-selected-color:var(--yb-text-primary);--yb-topnav-bg:var(--yb-batcave);--yb-back-button-fill:var(--yb-batcave);--yb-sa-stock-up:var(--yb-bonsai);--yb-sa-stock-down:var(--yb-solo-cup);--yb-sa-flight-label-border:1px solid var(--yb-dirty-seagull);--yb-sa-flight-label-positive:var(--yb-bonsai);--yb-sa-flight-label-negative:var(--yb-solo-cup);--yb-popover-border:1px solid #d8dade;--yb-popover-border-radius:4px;--yb-popover-shadow:0 2px 8px 0 rgb(0 0 0 / 36%);--yb-yns-title:var(--batcave);--yb-l2-nav-selected:var(--yb-grape-jelly);--yb-l2-nav-dropdown-focus:var(--yb-text-hover-color);--yb-mail-icon-text:var(--yb-batcave);--yb-mail-signin-link:#0078ff;--yb-light-img-logo-display:block;--yb-dark-img-logo-display:none;--yb-account-item-border:#d8dade;--yb-account-item-hover-bg:rgb(227 236 248);--yb-account-info-bg:#ededf3;--yb-account-menu-item:var(--yb-white);--yb-account-link:var(--yb-smurfette);--yb-account-text:#26282a;--yb-editions-button:var(--yb-marshmallow);--yb-editions-modal-background:var(--yb-white);--yb-mobile-search-carat:var(--uh-search-carat-color, var(--yb-dory));--yb-dialpad:var(--yb-black);--yb-dialpad-label-text:#1b1b1b;--yb-dialpad-regular:#1d1d1d;--yb-dialpad-focus-background:var(--uh-dialpad-focus-background, #F1F2FF);--yb-dialpad-hover:rgba(43, 53, 218, 1);--yb-dialpad-outline:rgba(43, 53, 217, 0.45);--yb-dialpad-icon:#626262;--yb-dialpad-icon-hover:var(--uh-dialpad-icon-hover, #1d1d1d);--yb-dialpad-icon-backplate:var(--uh-dialpad-icon-backplate, rgb(19 19 19 / 10%));--yb-poweredby-container-bg:var(--yb-marshmallow);--yb-poweredby-text:var(--yb-black);--yb-l1-selected-color:var(--uh-l1-selected-color, var(--yb-text-primary));--yb-l1-selected-font-weight:var(--uh-l1-selected-font-weight, var(--yb-font-bold));--yb-l1-selected-hover-color:var(--uh-l1-selected-hover-color, var(--yb-text-primary));--yb-visual-viewport-height:100vh;--yb-sa-height-max:auto;--yb-sa-height-min:auto}html[data-color-theme-enabled][data-color-scheme=dark],html[data-color-theme-enabled] [data-color-scheme=dark]{--yb-sea-foam-fog:rgb(var(--yb-rgb-sea-foam) / 20%);--yb-cobalt-fog:rgb(var(--yb-rgb-cobalt) / 30%);--yb-scooter-fog:rgb(var(--yb-rgb-scooter) / 30%);--yb-dory-fog:rgb(var(--yb-rgb-dory) / 30%);--yb-sky-fog:rgb(var(--yb-rgb-sky) / 30%);--yb-peeps-fog:rgb(var(--yb-rgb-peeps) / 30%);--yb-grape-jelly-fog:rgb(var(--yb-rgb-grape-jelly) / 30%);--yb-hulk-pants-fog:rgb(var(--yb-rgb-hulk-pants) / 30%);--yb-starfish-fog:rgb(var(--yb-rgb-starfish) / 30%);--yb-blurple-fog:rgb(var(--yb-rgb-blurple) / 30%);--yb-logo-brand:var(--yb-white);--yb-logo-property:rgb(255 255 255 / 70%);--yb-finance-logo-brand:#B896E1;--yb-text-primary:var(--yb-gray-hair);--yb-text-secondary:var(--yb-bob);--yb-text-mail-primary:var(--yb-sky);--yb-text-mail-hover:var(--yb-sky);--yb-background-color:var(--yb-midnight);--yb-l2-background-color:transparent;--yb-popover-background:var(--uh-popover-background, var(--yb-batcave));--yb-tab-focus-accent:var(--yb-sky-accent);--yb-selected-item-background:var(--yb-inkwell);--yb-sidenav-close-btn-background:var(--yb-batcave);--yb-sidenav-btn-color-hover:var(--yb-sky);--yb-sidenav-btn-color-active:var(--yb-inkwell);--yb-sidenav-btn-text-active:var(--yb-bob);--yb-sidenav-finance-plus-icon:var(--yb-white);--yb-moremenu-finance-plus-icon:var(--yb-white);--yb-profile-avatar-bg:var(--uh-profile-avatar-bg, var(--yb-ramones));--yb-profile-panel-hover:var(--uh-profile-panel-hover-bg, var(--yb-ramones));--yb-profile-alphatar-background:var(--yb-ramones);--yb-profile-alphatar-background-pressed:var(--yb-batcave);--yb-signin-border-color:var(--yb-gandalf);--yb-mail-border-color:var(--yb-sky);--yb-profile-character-hover:var(--yb-midnight);--yb-profile-pressed-state:var(--yb-battleship);--yb-profile-character-pressed-state-bg:var(--yb-inkwell);--yb-profile-character-pressed-state-text:var(--yb-bob);--yb-profile-account-status-container-bg:var(--yb-white-fog);--yb-searchbox-bg:var(--yb-batcave);--yb-search-btn-hover:var(--yb-dory);--yb-search-faux-icon:var(--yb-marshmallow);--yb-search-input-box-shadow:0 0 1px 0 rgb(0 0 0 / 0%), 0 1px 0 0 var(--yb-midnight);--yb-search-assist-primary:var(--yb-marshmallow);--yb-search-assist-secondary:var(--yb-bob);--yb-search-assist-history:var(--yb-thanos);--yb-search-assist-history-pc:#be8fff;--yb-search-assist-back-btn:var(--yb-sky);--yb-search-assist-item-hover-background:var(--yb-ramones);--yb-elevation3-box-shadow:0 4px 8px 0 rgb(0 0 0 / 90%), 0 0 1px 0 rgb(0 0 0 / 92%);--yb-elevation4-box-shadow:0 4px 16px 0 rgb(0 0 0 / 80%), 0 0 2px 0 rgb(0 0 0 / 95%);--yb-l2-news-background:var(--yb-midnight);--yb-current-account-fog:var(--yb-white-fog);--yb-mail-count:var(--yb-sky);--yb-sports-l2-dropdown-hover-bg:var(--yb-selected-item-background);--yb-sports-l2-dropdown-hover-color:var(--yb-text-hover-color);--yb-sports-l2-dropdown-focus-bg:var(--yb-selected-item-background);--yb-topnav-bg:var(--yb-starfish);--yb-back-button-fill:var(--yb-white);--yb-sa-stock-up:#21d87d;--yb-sa-stock-down:#fc7a6e;--yb-sa-flight-label-border:1px solid var(--yb-marshmallow);--yb-sa-flight-label-positive:#1ac567;--yb-sa-flight-label-negative:#ff5257;--yb-popover-border:none;--yb-popover-border-radius:8px;--yb-popover-shadow:0 4px 8px 0 rgb(0 0 0 / 9%), 0 0 1px 0 rgb(0 0 0 / 9%);--yb-yns-title:var(--yb-marshmallow);--yb-l2-nav-selected:var(--yb-white);--yb-l2-nav-dropdown-focus:var(--yb-white);--yb-mail-icon-text:var(--yb-thanos);--yb-mail-signin-link:var(--yb-gray-hair);--yb-light-img-logo-display:none;--yb-dark-img-logo-display:block;--yb-account-item-border:var(--yb-inkwell);--yb-account-item-hover-bg:var(--yb-gandalf);--yb-account-info-bg:transparent;--yb-account-menu-item:var(--yb-inkwell);--yb-account-link:var(--yb-account-text);--yb-account-text:var(--yb-gray-hair);--yb-editions-button:var(--yb-selected-item-background);--yb-editions-modal-background:var(--yb-inkwell);--yb-editions-modal-outline:var(--yb-battleship);--yb-editions-text:var(--yb-gandalf);--yb-cobrand-logos-divider:var(--yb-gandalf);--yb-unread-container-bg:#06334d;--yb-l2-background:var(--uh-l2-background, var(--yb-l2-background-color));--yb-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-l2-divider-color:var(--uh-l2-divider-color, var(--yb-sky));--yb-l2-text-color:var(--uh-l2-text-color, var(--yb-text-primary));--yb-default-font:var(--uh-font-family, var(--yb-default-font-family));--yb-fuji2-font:var(--uh-font-family, var(--yb-fuji2-font-family));--yb-uh3-cond-font:var(--uh-font-family, var(--yb-uh3-cond-font-family));--yb-outline:4px solid var(--uh-tab-focus-color, var(--yb-tab-focus-accent));--yb-search-btn-color:var(--uh-search-btn-color, var(--yb-search-carat));--yb-search-btn-hover-color:var(--uh-search-btn-hover-color, var(--yb-search-btn-hover));--yb-text-hover-color:var(--uh-text-hover-color, var(--yb-sidenav-btn-color-hover));--yb-profile-panel-hover-text:var(--uh-text-hover-color, var(--yb-sky));--yb-property-ruler-color:var(--uh-property-ruler-color, var(--yb-sky));--yb-svg-icon-color:var(--uh-icon-color, var(--yb-white));--yb-svg-icon-color-non-l2:var(--uh-icon-color-non-l2, var(--yb-white));--yb-svg-icon-color-selected:var(--uh-icon-color-selected, var(--yb-batcave));--yb-mail-bubble-color:var(--uh-mail-bubble-color, var(--yb-sky));--yb-tap-color:var(--uh-text-hover-color, var(--yb-text-primary));--yb-text-pressed-color:var(--uh-text-pressed-color, #1289ff);--yb-l2-margin:var(--uh-l2-margin);--yb-mobile-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-dialpad:var(--yb-white);--yb-dialpad-label-text:#F0F3F5;--yb-dialpad-regular:var(--yb-bob);--yb-dialpad-focus-background:var(--uh-dialpad-focus-background, #414364);--yb-dialpad-hover:#96A1FF;--yb-dialpad-icon:#ffffff;--yb-dialpad-icon-hover:var(--uh-dialpad-icon-hover, #ffffff);--yb-dialpad-icon-backplate:var(--uh-dialpad-icon-backplate, rgb(255 255 255 / 10%));--yb-poweredby-container-bg:var(--yb-batcave);--yb-poweredby-text:var(--yb-white);--yb-l1-selected-color:var(--uh-l1-selected-color, var(--yb-text-primary));--yb-l1-selected-font-weight:var(--uh-l1-selected-font-weight, var(--yb-font-bold));--yb-l1-selected-hover-color:var(--uh-l1-selected-hover-color, var(--yb-text-primary))}html[data-color-theme-enabled][data-color-scheme=transparent],html[data-color-theme-enabled] [data-color-scheme=transparent]{--yb-sea-foam-fog:rgb(var(--yb-rgb-sea-foam) / 20%);--yb-cobalt-fog:rgb(var(--yb-rgb-cobalt) / 30%);--yb-scooter-fog:rgb(var(--yb-rgb-scooter) / 30%);--yb-dory-fog:rgb(var(--yb-rgb-dory) / 30%);--yb-sky-fog:rgb(var(--yb-rgb-sky) / 30%);--yb-peeps-fog:rgb(var(--yb-rgb-peeps) / 30%);--yb-grape-jelly-fog:rgb(var(--yb-rgb-grape-jelly) / 30%);--yb-hulk-pants-fog:rgb(var(--yb-rgb-hulk-pants) / 30%);--yb-starfish-fog:rgb(var(--yb-rgb-starfish) / 30%);--yb-blurple-fog:rgb(var(--yb-rgb-blurple) / 30%);--yb-logo-brand:var(--yb-white);--yb-logo-property:rgb(255 255 255 / 70%);--yb-finance-logo-brand:#B896E1;--yb-text-primary:var(--yb-gray-hair);--yb-text-secondary:var(--yb-bob);--yb-text-mail-primary:var(--yb-sky);--yb-text-mail-hover:var(--yb-sky);--yb-background-color:rgba(16, 21, 24, 0.5);--yb-l2-background-color:transparent;--yb-popover-background:var(--uh-popover-background, var(--yb-batcave));--yb-tab-focus-accent:var(--yb-sky-accent);--yb-selected-item-background:var(--yb-inkwell);--yb-sidenav-close-btn-background:var(--yb-batcave);--yb-sidenav-btn-color-hover:var(--yb-sky);--yb-sidenav-btn-color-active:var(--yb-inkwell);--yb-sidenav-btn-text-active:var(--yb-bob);--yb-sidenav-finance-plus-icon:var(--yb-white);--yb-sidenav-bg:rgba(16, 21, 24, 0.6);--yb-moremenu-finance-plus-icon:var(--yb-white);--yb-profile-avatar-bg:var(--uh-profile-avatar-bg, var(--yb-ramones));--yb-profile-panel-hover:var(--uh-profile-panel-hover-bg, var(--yb-ramones));--yb-profile-alphatar-background:var(--yb-ramones);--yb-profile-alphatar-background-pressed:var(--yb-batcave);--yb-signin-border-color:var(--yb-gandalf);--yb-mail-border-color:var(--yb-sky);--yb-profile-character-hover:var(--yb-midnight);--yb-profile-pressed-state:var(--yb-battleship);--yb-profile-character-pressed-state-bg:var(--yb-inkwell);--yb-profile-character-pressed-state-text:var(--yb-bob);--yb-profile-account-status-container-bg:var(--yb-white-fog);--yb-searchbox-bg:rgba(35, 42, 49, 0.50);--yb-search-btn-hover:var(--yb-dory);--yb-search-faux-icon:var(--yb-marshmallow);--yb-search-input-box-shadow:0 0 1px 0 rgb(0 0 0 / 0%), 0 1px 0 0 var(--yb-midnight);--yb-search-assist-primary:var(--yb-marshmallow);--yb-search-assist-secondary:var(--yb-bob);--yb-search-assist-history:var(--yb-thanos);--yb-search-assist-history-pc:#be8fff;--yb-search-assist-back-btn:var(--yb-sky);--yb-search-assist-item-hover-background:var(--yb-ramones);--yb-elevation3-box-shadow:none;--yb-elevation4-box-shadow:0 4px 16px 0 rgb(0 0 0 / 80%), 0 0 2px 0 rgb(0 0 0 / 95%);--yb-l2-news-background:initial;--yb-current-account-fog:var(--yb-white-fog);--yb-mail-indicator:var(--yb-batcave);--yb-mail-indicator-border:1px solid var(--yb-white);--yb-mail-count:var(--yb-white);--yb-text-shadow:0px 0px 1px rgba(0, 0, 0, 0.50), 0px 2px 4px rgba(0, 0, 0, 0.40);--yb-nav-color:var(--yb-text-primary);--yb-sports-l2-dropdown-hover-bg:var(--yb-selected-item-background);--yb-sports-l2-dropdown-hover-color:var(--yb-text-hover-color);--yb-nav-selected-color:var(--yb-white);--yb-sports-l2-dropdown-focus-bg:var(--yb-selected-item-background);--yb-topnav-bg:var(--yb-starfish);--yb-back-button-fill:var(--yb-white);--yb-sa-stock-up:#21d87d;--yb-sa-stock-down:#fc7a6e;--yb-sa-flight-label-border:1px solid var(--yb-marshmallow);--yb-sa-flight-label-positive:#1ac567;--yb-sa-flight-label-negative:#ff5257;--yb-popover-border:none;--yb-popover-border-radius:8px;--yb-popover-shadow:0 4px 8px 0 rgb(0 0 0 / 9%), 0 0 1px 0 rgb(0 0 0 / 9%);--yb-yns-title:var(--yb-marshmallow);--yb-l2-nav-selected:var(--yb-white);--yb-l2-nav-dropdown-focus:var(--yb-white);--yb-mail-icon-text:var(--yb-thanos);--yb-mail-signin-link:var(--yb-gray-hair);--yb-light-img-logo-display:none;--yb-dark-img-logo-display:block;--yb-account-item-border:var(--yb-inkwell);--yb-account-item-hover-bg:var(--yb-gandalf);--yb-account-info-bg:transparent;--yb-account-menu-item:var(--yb-inkwell);--yb-account-link:var(--yb-account-text);--yb-account-text:var(--yb-gray-hair);--yb-editions-button:var(--yb-selected-item-background);--yb-editions-modal-background:var(--yb-inkwell);--yb-cobrand-logos-divider:var(--yb-gandalf);--yb-icon-filter:drop-shadow(0 1px 2px rgb(0 0 0 / 40%));--yb-transparent-popover-background:rgba(16, 21, 24, 0.8);--yb-transparent-popover-backdrop-filter:blur(4px);--yb-transparent-popover-box-shadow:0 4px 8px 0 rgb(0 0 0 / 10%), 0 0 1px 0 rgb(0 0 0 / 10%);--yb-unread-container-bg:#06334d;--yb-l2-background:var(--uh-l2-background, var(--yb-l2-background-color));--yb-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-l2-divider-color:var(--uh-l2-divider-color, var(--yb-sky));--yb-l2-text-color:var(--uh-l2-text-color, var(--yb-text-primary));--yb-default-font:var(--uh-font-family, var(--yb-default-font-family));--yb-fuji2-font:var(--uh-font-family, var(--yb-fuji2-font-family));--yb-uh3-cond-font:var(--uh-font-family, var(--yb-uh3-cond-font-family));--yb-outline:4px solid var(--uh-tab-focus-color, var(--yb-tab-focus-accent));--yb-search-btn-color:var(--uh-search-btn-color, var(--yb-search-carat));--yb-search-btn-hover-color:var(--uh-search-btn-hover-color, var(--yb-search-btn-hover));--yb-text-hover-color:var(--uh-text-hover-color, var(--yb-sidenav-btn-color-hover));--yb-profile-panel-hover-text:var(--uh-text-hover-color, var(--yb-sky));--yb-property-ruler-color:var(--uh-property-ruler-color, var(--yb-sky));--yb-svg-icon-color:var(--uh-icon-color, var(--yb-white));--yb-svg-icon-color-non-l2:var(--uh-icon-color-non-l2, var(--yb-white));--yb-svg-icon-color-selected:var(--uh-icon-color-selected, var(--yb-batcave));--yb-mail-bubble-color:var(--uh-mail-bubble-color, var(--yb-sky));--yb-tap-color:var(--uh-text-hover-color, var(--yb-text-primary));--yb-text-pressed-color:var(--uh-text-pressed-color, #1289ff);--yb-l2-margin:var(--uh-l2-margin);--yb-mobile-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-l1-selected-color:var(--uh-l1-selected-color, var(--yb-text-primary));--yb-l1-selected-font-weight:var(--uh-l1-selected-font-weight, var(--yb-font-bold));--yb-l1-selected-hover-color:var(--uh-l1-selected-hover-color, var(--yb-text-primary))}@media (prefers-color-scheme:dark){html[data-color-theme-enabled]{--yb-sea-foam-fog:rgb(var(--yb-rgb-sea-foam) / 20%);--yb-cobalt-fog:rgb(var(--yb-rgb-cobalt) / 30%);--yb-scooter-fog:rgb(var(--yb-rgb-scooter) / 30%);--yb-dory-fog:rgb(var(--yb-rgb-dory) / 30%);--yb-sky-fog:rgb(var(--yb-rgb-sky) / 30%);--yb-peeps-fog:rgb(var(--yb-rgb-peeps) / 30%);--yb-grape-jelly-fog:rgb(var(--yb-rgb-grape-jelly) / 30%);--yb-hulk-pants-fog:rgb(var(--yb-rgb-hulk-pants) / 30%);--yb-starfish-fog:rgb(var(--yb-rgb-starfish) / 30%);--yb-blurple-fog:rgb(var(--yb-rgb-blurple) / 30%);--yb-logo-brand:var(--yb-white);--yb-logo-property:rgb(255 255 255 / 70%);--yb-finance-logo-brand:#B896E1;--yb-text-primary:var(--yb-gray-hair);--yb-text-secondary:var(--yb-bob);--yb-text-mail-primary:var(--yb-sky);--yb-text-mail-hover:var(--yb-sky);--yb-background-color:var(--yb-midnight);--yb-l2-background-color:transparent;--yb-popover-background:var(--uh-popover-background, var(--yb-batcave));--yb-tab-focus-accent:var(--yb-sky-accent);--yb-selected-item-background:var(--yb-inkwell);--yb-sidenav-close-btn-background:var(--yb-batcave);--yb-sidenav-btn-color-hover:var(--yb-sky);--yb-sidenav-btn-color-active:var(--yb-inkwell);--yb-sidenav-btn-text-active:var(--yb-bob);--yb-sidenav-finance-plus-icon:var(--yb-white);--yb-moremenu-finance-plus-icon:var(--yb-white);--yb-profile-avatar-bg:var(--uh-profile-avatar-bg, var(--yb-ramones));--yb-profile-panel-hover:var(--uh-profile-panel-hover-bg, var(--yb-ramones));--yb-profile-alphatar-background:var(--yb-ramones);--yb-profile-alphatar-background-pressed:var(--yb-batcave);--yb-signin-border-color:var(--yb-gandalf);--yb-mail-border-color:var(--yb-sky);--yb-profile-character-hover:var(--yb-midnight);--yb-profile-pressed-state:var(--yb-battleship);--yb-profile-character-pressed-state-bg:var(--yb-inkwell);--yb-profile-character-pressed-state-text:var(--yb-bob);--yb-profile-account-status-container-bg:var(--yb-white-fog);--yb-searchbox-bg:var(--yb-batcave);--yb-search-btn-hover:var(--yb-dory);--yb-search-faux-icon:var(--yb-marshmallow);--yb-search-input-box-shadow:0 0 1px 0 rgb(0 0 0 / 0%), 0 1px 0 0 var(--yb-midnight);--yb-search-assist-primary:var(--yb-marshmallow);--yb-search-assist-secondary:var(--yb-bob);--yb-search-assist-history:var(--yb-thanos);--yb-search-assist-history-pc:#be8fff;--yb-search-assist-back-btn:var(--yb-sky);--yb-search-assist-item-hover-background:var(--yb-ramones);--yb-elevation3-box-shadow:0 4px 8px 0 rgb(0 0 0 / 90%), 0 0 1px 0 rgb(0 0 0 / 92%);--yb-elevation4-box-shadow:0 4px 16px 0 rgb(0 0 0 / 80%), 0 0 2px 0 rgb(0 0 0 / 95%);--yb-l2-news-background:var(--yb-midnight);--yb-current-account-fog:var(--yb-white-fog);--yb-mail-count:var(--yb-sky);--yb-sports-l2-dropdown-hover-bg:var(--yb-selected-item-background);--yb-sports-l2-dropdown-hover-color:var(--yb-text-hover-color);--yb-sports-l2-dropdown-focus-bg:var(--yb-selected-item-background);--yb-topnav-bg:var(--yb-starfish);--yb-back-button-fill:var(--yb-white);--yb-sa-stock-up:#21d87d;--yb-sa-stock-down:#fc7a6e;--yb-sa-flight-label-border:1px solid var(--yb-marshmallow);--yb-sa-flight-label-positive:#1ac567;--yb-sa-flight-label-negative:#ff5257;--yb-popover-border:none;--yb-popover-border-radius:8px;--yb-popover-shadow:0 4px 8px 0 rgb(0 0 0 / 9%), 0 0 1px 0 rgb(0 0 0 / 9%);--yb-yns-title:var(--yb-marshmallow);--yb-l2-nav-selected:var(--yb-white);--yb-l2-nav-dropdown-focus:var(--yb-white);--yb-mail-icon-text:var(--yb-thanos);--yb-mail-signin-link:var(--yb-gray-hair);--yb-light-img-logo-display:none;--yb-dark-img-logo-display:block;--yb-account-item-border:var(--yb-inkwell);--yb-account-item-hover-bg:var(--yb-gandalf);--yb-account-info-bg:transparent;--yb-account-menu-item:var(--yb-inkwell);--yb-account-link:var(--yb-account-text);--yb-account-text:var(--yb-gray-hair);--yb-editions-button:var(--yb-selected-item-background);--yb-editions-modal-background:var(--yb-inkwell);--yb-editions-modal-outline:var(--yb-battleship);--yb-editions-text:var(--yb-gandalf);--yb-cobrand-logos-divider:var(--yb-gandalf);--yb-unread-container-bg:#06334d;--yb-l2-background:var(--uh-l2-background, var(--yb-l2-background-color));--yb-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-l2-divider-color:var(--uh-l2-divider-color, var(--yb-sky));--yb-l2-text-color:var(--uh-l2-text-color, var(--yb-text-primary));--yb-default-font:var(--uh-font-family, var(--yb-default-font-family));--yb-fuji2-font:var(--uh-font-family, var(--yb-fuji2-font-family));--yb-uh3-cond-font:var(--uh-font-family, var(--yb-uh3-cond-font-family));--yb-outline:4px solid var(--uh-tab-focus-color, var(--yb-tab-focus-accent));--yb-search-btn-color:var(--uh-search-btn-color, var(--yb-search-carat));--yb-search-btn-hover-color:var(--uh-search-btn-hover-color, var(--yb-search-btn-hover));--yb-text-hover-color:var(--uh-text-hover-color, var(--yb-sidenav-btn-color-hover));--yb-profile-panel-hover-text:var(--uh-text-hover-color, var(--yb-sky));--yb-property-ruler-color:var(--uh-property-ruler-color, var(--yb-sky));--yb-svg-icon-color:var(--uh-icon-color, var(--yb-white));--yb-svg-icon-color-non-l2:var(--uh-icon-color-non-l2, var(--yb-white));--yb-svg-icon-color-selected:var(--uh-icon-color-selected, var(--yb-batcave));--yb-mail-bubble-color:var(--uh-mail-bubble-color, var(--yb-sky));--yb-tap-color:var(--uh-text-hover-color, var(--yb-text-primary));--yb-text-pressed-color:var(--uh-text-pressed-color, #1289ff);--yb-l2-margin:var(--uh-l2-margin);--yb-mobile-search-carat:var(--uh-search-carat-color, var(--yb-sky));--yb-dialpad:var(--yb-white);--yb-dialpad-label-text:#F0F3F5;--yb-dialpad-regular:var(--yb-bob);--yb-dialpad-focus-background:var(--uh-dialpad-focus-background, #414364);--yb-dialpad-hover:#96A1FF;--yb-dialpad-icon:#ffffff;--yb-dialpad-icon-hover:var(--uh-dialpad-icon-hover, #ffffff);--yb-dialpad-icon-backplate:var(--uh-dialpad-icon-backplate, rgb(255 255 255 / 10%));--yb-poweredby-container-bg:var(--yb-batcave);--yb-poweredby-text:var(--yb-white);--yb-l1-selected-color:var(--uh-l1-selected-color, var(--yb-text-primary));--yb-l1-selected-font-weight:var(--uh-l1-selected-font-weight, var(--yb-font-bold));--yb-l1-selected-hover-color:var(--uh-l1-selected-hover-color, var(--yb-text-primary))}html[data-color-theme-enabled] [data-maintain-color]{--yb-barbie:#f80e5d;--yb-barney:#cc008c;--yb-batcave:#232a31;--yb-battleship:#5b636a;--yb-black:#000;--yb-blurple:#5d5eff;--yb-bob:#b0b9c1;--yb-bonsai:#008751;--yb-charcoal:#464e56;--yb-cobalt:#003abc;--yb-denim:#1a0dab;--yb-dirty-seagull:#e0e4e9;--yb-dolphin:#6e7780;--yb-dory:#0f69ff;--yb-gandalf:#979ea8;--yb-grape-jelly:#6001d2;--yb-gray-hair:#f0f3f5;--yb-hulk-pants:#7e1fff;--yb-inkwell:#1d2228;--yb-malbec:#39007d;--yb-marshmallow:#f5f8fa;--yb-midnight:#101518;--yb-mulberry:#5015b0;--yb-pebble:#c7cdd2;--yb-peeps:#7dcbff;--yb-ramones:#2c363f;--yb-sea-foam:#11d3cd;--yb-scooter:#0063eb;--yb-shark:#828a93;--yb-sky:#12a9ff;--yb-smurfette:#188fff;--yb-solo-cup:#eb0f29;--yb-starfish:#7759ff;--yb-swedish-fish:#ff333a;--yb-thanos:#907cff;--yb-turmeric:#ffa700;--yb-white:#fff;--yb-rgb-battleship:91 99 106;--yb-rgb-white:255 255 255;--yb-rgb-blurple:93 94 255;--yb-rgb-starfish:119 89 255;--yb-rgb-hulk-pants:126 31 255;--yb-rgb-grape-jelly:96 1 210;--yb-rgb-peeps:125 203 255;--yb-rgb-sky:18 169 255;--yb-rgb-dory:15 105 255;--yb-rgb-scooter:0 99 235;--yb-rgb-cobalt:0 58 188;--yb-rgb-sea-foam:17 211 205;--yb-battleship-fog:rgb(var(--yb-rgb-battleship) / 10%);--yb-white-fog:rgb(var(--yb-rgb-white) / 10%);--yb-blurple-fog:rgb(var(--yb-rgb-blurple) / 10%);--yb-starfish-fog:rgb(var(--yb-rgb-starfish) / 10%);--yb-hulk-pants-fog:rgb(var(--yb-rgb-hulk-pants) / 10%);--yb-grape-jelly-fog:rgb(var(--yb-rgb-grape-jelly) / 10%);--yb-peeps-fog:rgb(var(--yb-rgb-peeps) / 10%);--yb-sky-fog:rgb(var(--yb-rgb-sky) / 10%);--yb-dory-fog:rgb(var(--yb-rgb-dory) / 10%);--yb-scooter-fog:rgb(var(--yb-rgb-scooter) / 10%);--yb-cobalt-fog:rgb(var(--yb-rgb-cobalt) / 10%);--yb-sea-foam-fog:rgb(var(--yb-rgb-sea-foam) / 10%);--yb-hulk-pants-accent:rgb(var(--yb-rgb-hulk-pants) / 50%);--yb-grape-jelly-accent:rgb(var(--yb-rgb-grape-jelly) / 50%);--yb-sky-accent:rgb(var(--yb-rgb-sky) / 50%);--yb-logo-brand:var(--yb-grape-jelly);--yb-logo-property:var(--yb-batcave);--yb-finance-logo-brand:var(--yb-grape-jelly);--yb-text-primary:var(--yb-batcave);--yb-text-secondary:var(--yb-battleship);--yb-text-mail-primary:var(--yb-grape-jelly);--yb-text-mail-hover:var(--yb-mulberry);--yb-background-color:var(--yb-white);--yb-l2-background-color:var(--yb-marshmallow);--yb-popover-background:var(--uh-popover-background, var(--yb-white));--yb-tab-focus-accent:var(--yb-grape-jelly-accent);--yb-selected-item-background:var(--yb-marshmallow);--yb-sidenav-close-btn-background:var(--yb-marshmallow);--yb-sidenav-btn-color-hover:var(--yb-grape-jelly);--yb-sidenav-btn-color-active:var(--yb-dirty-seagull);--yb-sidenav-btn-text-active:var(--yb-batcave);--yb-sidenav-finance-plus-icon:var(--yb-svg-icon-color-non-l2);--yb-sidenav-bg:var(--yb-background-color);--yb-moremenu-finance-plus-icon:var(--yb-svg-icon-color-non-l2);--yb-profile-avatar-bg:var(--uh-profile-avatar-bg, var(--yb-gray-hair));--yb-profile-panel-hover:var(--uh-profile-panel-hover-bg, var(--yb-dirty-seagull));--yb-profile-alphatar-background:var(--yb-gray-hair);--yb-profile-alphatar-background-pressed:var(--yb-white);--yb-signin-border-color:var(--yb-dirty-seagull);--yb-mail-border-color:var(--yb-grape-jelly);--yb-unread-container-bg:rgb(var(--yb-rgb-grape-jelly) / 5%);--yb-profile-character-hover:var(--yb-white);--yb-profile-pressed-state:var(--yb-bob);--yb-profile-character-pressed-state-bg:var(--yb-dirty-seagull);--yb-profile-character-pressed-state-text:var(--yb-batcave);--yb-profile-account-status-container-bg:var(--yb-battleship-fog);--yb-searchbox-bg:var(--yb-gray-hair);--yb-search-btn-hover:#5409b2;--yb-search-faux-icon:var(--yb-batcave);--yb-search-input-box-shadow:0 0 1px 0 rgb(0 0 0 / 0%), 0 1px 0 0 var(--yb-dirty-seagull);--yb-search-assist-primary:var(--yb-batcave);--yb-search-assist-secondary:var(--yb-dolphin);--yb-search-assist-history:#6e329d;--yb-search-assist-history-pc:var(--yb-grape-jelly);--yb-search-assist-back-btn:var(--yb-dory);--yb-search-assist-item-hover-background:var(--yb-marshmallow);--yb-elevation3-box-shadow:0 4px 8px 0 rgb(0 0 0 / 10%), 0 0 1px 0 rgb(0 0 0 / 10%);--yb-elevation4-box-shadow:0 4px 16px 0 rgb(0 0 0 / 20%), 0 0 2px 0 rgb(0 0 0 / 5%);--yb-l2-news-background:linear-gradient(0deg, rgb(255 255 255 / 100%) 0%, rgb(248 250 251 / 100%) 100%);--yb-current-account-fog:var(--yb-dory-fog);--yb-editions-modal-outline:var(--yb-dirty-seagull);--yb-editions-text:var(--yb-dolphin);--yb-cobrand-logos-divider:var(--yb-dirty-seagull);--yb-l2-background:var(--uh-l2-background, var(--yb-l2-background-color));--yb-search-carat:var(--uh-search-carat-color, var(--yb-grape-jelly));--yb-l2-divider-color:var(--uh-l2-divider-color, var(--yb-gray-hair));--yb-l2-text-color:var(--uh-l2-text-color, var(--yb-batcave));--yb-default-font:var(--uh-font-family, var(--yb-default-font-family));--yb-fuji2-font:var(--uh-font-family, var(--yb-fuji2-font-family));--yb-uh3-cond-font:var(--uh-font-family, var(--yb-uh3-cond-font-family));--yb-outline:4px solid var(--uh-tab-focus-color, var(--yb-tab-focus-accent));--yb-search-btn-color:var(--uh-search-btn-color, var(--yb-search-carat));--yb-search-btn-hover-color:var(--uh-search-btn-hover-color, var(--yb-search-btn-hover));--yb-text-hover-color:var(--uh-text-hover-color, var(--yb-sidenav-btn-color-hover));--yb-profile-panel-hover-text:var(--uh-text-hover-color, var(--yb-grape-jelly));--yb-searchbox-transition:border-radius 0s 0.2s ease-out, background-color 0s 0.2s ease-out, box-shadow 0.2s ease-out, padding-left 50ms 150ms ease-out;--yb-property-ruler-color:var(--uh-property-ruler-color, var(--yb-grape-jelly));--yb-svg-icon-color:var(--uh-icon-color, var(--yb-grape-jelly));--yb-svg-icon-color-non-l2:var(--uh-icon-color-non-l2, var(--yb-grape-jelly) );--yb-svg-icon-color-selected:var(--uh-icon-color-selected, var(--yb-white));--yb-mail-bubble-color:var(--uh-mail-bubble-color, var(--yb-grape-jelly));--yb-mail-indicator:var(--yb-profile-panel-hover-text);--yb-mail-indicator-border:1px solid var(--yb-background-color);--yb-mail-count:var(--yb-text-primary);--yb-tap-color:var(--uh-text-hover-color, var(--yb-text-primary));--yb-text-pressed-color:var(--uh-text-pressed-color, var(--yb-mulberry));--yb-l2-margin:var(--uh-l2-margin);--yb-text-shadow:none;--yb-nav-color:var(--yb-text-secondary);--yb-sports-l2-dropdown-hover-bg:#e6e6e6;--yb-sports-l2-dropdown-hover-color:var(--yb-black);--yb-sports-l2-dropdown-focus-bg:#ecf8ff;--yb-nav-selected-color:var(--yb-text-primary);--yb-topnav-bg:var(--yb-batcave);--yb-back-button-fill:var(--yb-batcave);--yb-sa-stock-up:var(--yb-bonsai);--yb-sa-stock-down:var(--yb-solo-cup);--yb-sa-flight-label-border:1px solid var(--yb-dirty-seagull);--yb-sa-flight-label-positive:var(--yb-bonsai);--yb-sa-flight-label-negative:var(--yb-solo-cup);--yb-popover-border:1px solid #d8dade;--yb-popover-border-radius:4px;--yb-popover-shadow:0 2px 8px 0 rgb(0 0 0 / 36%);--yb-yns-title:var(--batcave);--yb-l2-nav-selected:var(--yb-grape-jelly);--yb-l2-nav-dropdown-focus:var(--yb-text-hover-color);--yb-mail-icon-text:var(--yb-batcave);--yb-mail-signin-link:#0078ff;--yb-light-img-logo-display:block;--yb-dark-img-logo-display:none;--yb-account-item-border:#d8dade;--yb-account-item-hover-bg:rgb(227 236 248);--yb-account-info-bg:#ededf3;--yb-account-menu-item:var(--yb-white);--yb-account-link:var(--yb-smurfette);--yb-account-text:#26282a;--yb-editions-button:var(--yb-marshmallow);--yb-editions-modal-background:var(--yb-white);--yb-mobile-search-carat:var(--uh-search-carat-color, var(--yb-dory));--yb-dialpad:var(--yb-black);--yb-dialpad-label-text:#1b1b1b;--yb-dialpad-regular:#1d1d1d;--yb-dialpad-focus-background:var(--uh-dialpad-focus-background, #F1F2FF);--yb-dialpad-hover:rgba(43, 53, 218, 1);--yb-dialpad-outline:rgba(43, 53, 217, 0.45);--yb-dialpad-icon:#626262;--yb-dialpad-icon-hover:var(--uh-dialpad-icon-hover, #1d1d1d);--yb-dialpad-icon-backplate:var(--uh-dialpad-icon-backplate, rgb(19 19 19 / 10%));--yb-poweredby-container-bg:var(--yb-marshmallow);--yb-poweredby-text:var(--yb-black);--yb-l1-selected-color:var(--uh-l1-selected-color, var(--yb-text-primary));--yb-l1-selected-font-weight:var(--uh-l1-selected-font-weight, var(--yb-font-bold));--yb-l1-selected-hover-color:var(--uh-l1-selected-hover-color, var(--yb-text-primary));--yb-visual-viewport-height:100vh;--yb-sa-height-max:auto;--yb-sa-height-min:auto}}.use-homepage-blue{--yb-search-btn-color:var(--yb-dory);--yb-outline:4px solid var(--yb-dory);--yb-search-btn-hover-color:var(--yb-scooter);--yb-text-hover-color:var(--yb-dory);--yb-mail-count:var(--yb-dory);--yb-mail-indicator:var(--yb-dory);--yb-profile-panel-hover-text:var(--yb-dory);--yb-logo-brand:var(--yb-batcave);--yb-logo-property:rgb(35 42 49 / 70%);--yb-search-carat:var(--yb-dory);--yb-text-pressed-color:var(--yb-scooter)}.use-homepage-blue-v2{--yb-profile-avatar-bg:#ecf7ff;--yb-searchbox-bg:#ecf7ff}.ybar-property-finance{--yb-mail-border-color:var(--uh-mail-bubble-color);--yb-text-mail-primary:var(--uh-mail-bubble-color);--yb-text-mail-hover:var(--uh-mail-bubble-color)}._yb_5t6xy._yb_1u9bsx1,._yb_3zjksb._yb_1u9bsx1{--yb-text-hover-color:var(--yb-color-att-dark-blue);--yb-search-btn-color:var(--yb-color-att-dark-blue);--yb-search-btn-hover-color:var(--yb-color-att-dark-blue);--yb-profile-panel-hover-text:var(--yb-color-att-dark-blue);--yb-mail-border-color:var(--yb-color-att-dark-blue);--yb-text-mail-primary:var(--yb-color-att-dark-blue);--yb-text-mail-hover:var(--yb-color-att-dark-blue)}._yb_1bwhbi8._yb_iswvcq,._yb_1bqr3cv._yb_iswvcq{--yb-text-hover-color:var(--yb-color-rogers-red);--yb-search-btn-color:var(--yb-color-rogers-red);--yb-search-btn-hover-color:var(--yb-color-rogers-red);--yb-profile-panel-hover-text:var(--yb-color-rogers-red);--yb-mail-border-color:var(--yb-color-rogers-red);--yb-text-mail-primary:var(--yb-color-rogers-red);--yb-text-mail-hover:var(--yb-color-rogers-red)}
/*! Copyright 2017 Yahoo Holdings, Inc. All rights reserved. */
template{display:none}._yb_bbmou4{font-family:"Helvetica Neue",Helvetica,Tahoma,Geneva,Arial,sans-serif;font-family:var(--yb-default-font);font-weight:400;font-weight:var(--yb-font-regular);font-stretch:normal;direction:ltr;display:block;box-sizing:border-box;text-align:start;-webkit-font-smoothing:antialiased;z-index:1000;overflow-anchor:none}.ybar-ytheme-crunch._yb_bbmou4,.ybar-ytheme-fuji2._yb_bbmou4{font-family:"YahooSans VF",YahooSans,"Yahoo Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-family:var(--yb-fuji2-font)}html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch{text-shadow:none;text-shadow:var(--yb-text-shadow)}html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch button,html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch ._yb_1muppqd,html[data-color-theme-enabled][data-color-scheme=transparent] #ybar-nav-placement{text-shadow:none}html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch svg{filter:var(--yb-icon-filter)}html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch button svg,html[data-color-theme-enabled][data-color-scheme=transparent] .ybar-ytheme-crunch ._yb_1muppqd svg,html[data-color-theme-enabled][data-color-scheme=transparent] #ybar-nav-placement svg{filter:none}#ybar._yb_v1r5ph{margin:0 auto}._yb_bbmou4 ._yb_16kwvy4{display:flex;flex-direction:column}.ybar-ytheme-crunch #ybar-inner-wrap{background:#fff;background:var(--yb-background-color)}._yb_1u6ljkh{display:flex;justify-content:center}._yb_dzr3yz{display:flex;justify-content:flex-start;align-items:center;width:100%;min-width:0;max-width:1920px;box-sizing:border-box;transition:margin .2s ease-out,opacity .15s linear .2s;opacity:1}.ybar-ytheme-crunch ._yb_dzr3yz{max-width:calc(100% - 32px);max-width:var(--uh-max-width, calc(100% - 32px))}.typing .ybar-ytheme-crunch ._yb_16kwvy4{transition:margin .2s ease-out}.ybar-ytheme-fuji2 ._yb_dzr3yz{max-width:1340px;padding:0 20px;transition:margin .2s ease-out,opacity .15s linear .2s,padding .4s}.ybar-property-sports._yb_115wtas #ybar-navigation{max-width:100%;padding:0}.ybar-sticky #ybar._yb_115wtas #ybar-inner-wrap{left:0}.ybar-ytheme-fuji2._yb_2erz1k ._yb_dzr3yz,.ybar-ytheme-fuji2._yb_2erz1k ._yb_1smugqe ._yb_dzr3yz{padding:0;margin:0}.ybar-ytheme-fuji2._yb_2erz1k ._yb_1u6ljkh._yb_1emv3g7,.ybar-ytheme-fuji2._yb_2erz1k ._yb_1u6ljkh._yb_1smugqe{padding:0 20px;transition:padding .4s}@media screen and (min-width:1020px){.ybar-ytheme-fuji2 ._yb_dzr3yz{padding:0 40px}.ybar-ytheme-fuji2._yb_2erz1k ._yb_1u6ljkh._yb_1emv3g7,.ybar-ytheme-fuji2._yb_2erz1k ._yb_1u6ljkh._yb_1smugqe{padding:0 40px}}.ybar-ytheme-fuji2._yb_1sik2rh ._yb_dzr3yz{padding:0;max-width:100%}.ybar-ytheme-fuji2._yb_jrobl8._yb_2erz1k ._yb_dzr3yz{max-width:1264px;min-width:0}._yb_1jtlmql ._yb_dzr3yz,.ybar-ytheme-fuji2._yb_ist0jp ._yb_1jtlmql ._yb_dzr3yz,.ybar-ytheme-fuji2._yb_2erz1k ._yb_1jtlmql ._yb_dzr3yz{padding:0;position:relative;display:none}.ybar-ytheme-fuji2 ._yb_1jtlmql ._yb_dzr3yz{display:flex}.ybar-ytheme-fuji2.ybar-property-mail.fuji2-dialpad ._yb_1jtlmql{display:none}._yb_1s3151i{background:#232a31;background:var(--yb-topnav-bg);flex:1}.ybar-dark ._yb_1s3151i{background:#464e56;background:var(--yb-charcoal)}.ybar-dark ._yb_vp1vt8 ._yb_1s3151i{background-color:#7e1fff;background-color:var(--yb-hulk-pants)}.ybar-ytheme-fuji2 ._yb_1jtlmql{overflow:hidden}@media screen and (max-width:1340px){.ybar-ytheme-fuji2 ._yb_1jtlmql{width:100%;min-width:1032px}.ybar-ytheme-fuji2 ._yb_1s3151i{display:none}}._yb_wutdic{min-width:0;padding:0;height:84px}._yb_v5t4r9 ._yb_wutdic,._yb_1os1r4w ._yb_wutdic,._yb_v1r5ph ._yb_wutdic,._yb_1q0vcon ._yb_wutdic,._yb_1fg69p4 ._yb_wutdic,._yb_69p0bm ._yb_wutdic,._yb_zfzvr2 ._yb_wutdic{padding:0 64px 0 50px}._yb_v9nhk7._yb_1u6ljkh._yb_1muppqd{padding:0 16px;margin-bottom:8px;justify-content:center;width:auto}._yb_ist0jp ._yb_v9nhk7._yb_1u6ljkh._yb_1muppqd,.ybar-property-generic ._yb_v9nhk7._yb_1u6ljkh._yb_1muppqd,.ybar-property-homepage ._yb_v9nhk7._yb_1u6ljkh._yb_1muppqd{margin-bottom:16px}._yb_1smugqe ._yb_dzr3yz{height:34px;padding-left:24px}.ybar-ytheme-crunch ._yb_1smugqe._yb_l2-news{background:linear-gradient(0deg,rgb(255 255 255/100%) 0,rgb(248 250 251/100%) 100%);background:var(--yb-l2-news-background)}.ybar-ytheme-crunch ._yb_1smugqe._yb_mjszbe{background:#f5f8fa;background:var(--yb-l2-background)}.ybar-ytheme-crunch ._yb_1smugqe._yb_cg7fqk{box-shadow:0 -1px 0 #f0f3f5;box-shadow:0 -1px 0 var(--yb-l2-divider-color)}.ybar-ytheme-crunch ._yb_1smugqe._yb_15sv7cz{background-color:#6001d2;background-color:var(--yb-grape-jelly)}.ybar-ytheme-crunch.ybar-property-finance ._yb_1smugqe{background-color:#f5f8fa;background-color:var(--yb-l2-background)}.ybar-ytheme-fuji2 ._yb_wutdic{height:72px}.ybar-ytheme-fuji2._yb_1sik2rh._yb_189cmx2 ._yb_wutdic{height:84px}._yb_ist0jp ._yb_wutdic,._yb_2erz1k ._yb_wutdic{height:80px;padding:5px 0 7px;box-sizing:content-box}#ybar.ybar-ytheme-crunch.ybar-property-homepage._yb_phn8ti._yb_1u9bsx1,#ybar.ybar-ytheme-crunch._yb_phn8ti{--uh-visible-height:112px;height:112px}#ybar.ybar-ytheme-crunch.ybar-property-finance._yb_phn8ti{--uh-visible-height:117px;height:117px}#ybar.ybar-ytheme-crunch.ybar-property-finance._yb_phn8ti._yb_kx18b1{--uh-visible-height:113px;height:113px}#ybar.ybar-ytheme-crunch.ybar-property-homepage._yb_phn8ti,#ybar.ybar-ytheme-crunch,.modal-open #ybar.ybar-ytheme-crunch,.modal-open #ybar.ybar-ytheme-crunch.ybar-property-homepage._yb_phn8ti._yb_1u9bsx1,#ybar.ybar-ytheme-crunch ._yb_wutdic{--uh-visible-height:64px;height:64px;padding:0}.ybar-ytheme-fuji2 ._yb_1smugqe ._yb_dzr3yz,.ybar-ytheme-fuji2 ._yb_wutdic{padding:0 20px;box-sizing:border-box}.ybar-ytheme-crunch ._yb_1smugqe ._yb_dzr3yz{height:48px;padding:0}.ybar-ytheme-crunch.ybar-property-finance:not(._yb_kx18b1) ._yb_1smugqe ._yb_dzr3yz{height:50px}@media screen and (min-width:1020px){.ybar-ytheme-fuji2 ._yb_1smugqe ._yb_dzr3yz,.ybar-ytheme-fuji2 ._yb_wutdic{padding:0 40px}}.ybar-ytheme-fuji2._yb_1sik2rh ._yb_wutdic{padding:0}.modal-open ._yb_1smugqe,.ybar-hide-navigation ._yb_1smugqe{overflow:hidden}.ybar-hide-navigation .ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe{overflow:unset}.ybar-hide-navigation #ybar ._yb_1smugqe._yb_hwx3um>._yb_dzr3yz{margin-top:-82px}.modal-open #ybar ._yb_1smugqe>._yb_dzr3yz,.ybar-hide-navigation #ybar ._yb_1smugqe>._yb_dzr3yz{opacity:0;margin-top:-60px}.ybar-ytheme-crunch._yb_kx18b1 ._yb_1wmqq67{margin:0;height:1px;background-color:#f0f3f5;background-color:var(--yb-gray-hair)}.ybar-ytheme-crunch:not(._yb_kx18b1)._yb_rq7mm4 ._yb_16kwvy4{border-bottom:#f0f3f5 3px solid;border-bottom:var(--yb-l2-divider-color) 3px solid}.ybar-ytheme-crunch ._yb_15sv7cz #ybar-navigation{height:49px}.ybar-hide-navigation #ybar.ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe>._yb_dzr3yz{opacity:1;margin-top:0}.ybar-hide-navigation #ybar ._yb_19s5ae1{opacity:0;margin-top:-42px}.modal-open ._yb_1jtlmql>._yb_dzr3yz,.ybar-hide-topnavigation ._yb_1jtlmql>._yb_dzr3yz{margin-top:-39px}@media screen and (max-width:1340px){.ybar-ytheme-fuji2 ._yb_1jtlmql{width:100%;min-width:1032px}.ybar-ytheme-fuji2._yb_rq7mm4._yb_19dmi0p ._yb_1jtlmql{min-width:initial}.ybar-ytheme-fuji2 ._yb_1s3151i{display:none}}@media screen and (min-width:1020px){.ybar-ytheme-fuji2 ._yb_ist0jp ._yb_wutdic ._yb_2qgpj,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_wutdic ._yb_2qgpj{width:320px;justify-content:flex-end}}@supports (display:grid){@media screen and (max-width:1019px){#ybar.ybar-ytheme-fuji2 ._yb_wutdic{grid-column-gap:20px}}.ybar-ytheme-fuji2 ._yb_wutdic{display:grid;grid-template-columns:[main-start] repeat(9,minmax(0,1fr)) [main-end] repeat(3,minmax(0,1fr));grid-template-rows:auto;grid-column-gap:32px}#ybar.ybar-ytheme-fuji2.ybar-property-mail ._yb_wutdic{display:flex;-moz-column-gap:normal;column-gap:normal}.ybar-ytheme-fuji2 ._yb_wutdic>div{grid-row-start:1}.ybar-ytheme-fuji2 ._yb_1muppqd{grid-column:main;justify-self:end;width:calc(100% - 240px)}.ybar-ytheme-fuji2._yb_2erz1k ._yb_1muppqd{width:calc(100% - 220px)}.ybar-ytheme-fuji2._yb_2erz1k._yb_5t6xy._yb_1u9bsx1 ._yb_1muppqd,.ybar-ytheme-fuji2._yb_2erz1k._yb_3zjksb._yb_1u9bsx1 ._yb_1muppqd,.ybar-ytheme-fuji2._yb_2erz1k._yb_3zjksb._yb_z83zjv ._yb_1muppqd,.ybar-ytheme-fuji2._yb_2erz1k._yb_1bwhbi8._yb_iswvcq ._yb_1muppqd,.ybar-ytheme-fuji2._yb_2erz1k._yb_1bqr3cv._yb_iswvcq ._yb_1muppqd{width:calc(100% - 240px)}.ybar-ytheme-crunch ._yb_wutdic>._yb_26wpdh,.ybar-ytheme-fuji2 ._yb_wutdic>._yb_26wpdh{grid-column-start:main-start;z-index:1}.ybar-ytheme-fuji2 ._yb_wutdic ._yb_2qgpj,.ybar-ytheme-fuji2.ybar-property-generic ._yb_wutdic ._yb_2qgpj,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_wutdic ._yb_2qgpj{grid-column:main-end/-1;justify-self:end;width:auto}.ybar-ytheme-fuji2 ._yb_wutdic ._yb_y280k9{grid-column-start:main-start}}@supports (display:grid){@media screen and (max-width:1023px){#ybar.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_wutdic{grid-template-columns:[main-start] repeat(5,minmax(0,1fr)) [main-end toolbar-start]repeat(1,minmax(0,1fr)) [toolbar-end]}#ybar.ybar-ytheme-crunch:not(._yb_rq7mm4) :not(._yb_1qomz0q)>._yb_wutdic{grid-column-gap:24px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1w5vwjh{display:none}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_11pef5i{align-items:center;display:flex;height:36px;margin-right:12px;margin-left:-8px;padding:0 8px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1qomz0q ._yb_11pef5i{margin-right:8px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1qomz0q ._yb_11pef5i:has(._yb_19mvr2h:focus-visible),.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_11pef5i:hover{background-color:#f5f8fa;background-color:var(--yb-sidenav-close-btn-background);border-radius:100px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_11pef5i:active{background-color:#e0e4e9;background-color:var(--yb-sidenav-btn-color-active);border-radius:100px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1qomz0q ._yb_19mvr2h:focus-visible svg path,.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_11pef5i:hover ._yb_19mvr2h svg path{fill:#6001d2;fill:var(--yb-text-hover-color)}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_11pef5i:active ._yb_19mvr2h svg path{fill:#232a31;fill:var(--yb-sidenav-btn-text-active)}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1muppqd{max-width:unset;min-width:193px;width:100%;padding-right:139px}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_19mvr2h:focus-visible{outline:4px solid rgb(96 1 210/50%);outline:var(--yb-outline);border-radius:1px;outline-offset:6px}.ybar-ytheme-crunch:not(._yb_rq7mm4) ._yb_1qomz0q ._yb_19mvr2h:focus-visible{border-radius:100px}}@media screen and (max-width:1049px){#ybar.ybar-ytheme-crunch._yb_kx18b1 ._yb_wutdic{grid-template-columns:[main-start] repeat(3,minmax(0,1fr)) [main-end space-start] repeat(1,minmax(0,1fr)) [space-end nav-start]repeat(1,minmax(0,1fr)) [nav-end toolbar-start]repeat(1,minmax(250px,1fr)) [toolbar-end];grid-column-gap:1rem}.ybar-ytheme-crunch._yb_kx18b1 ._yb_1w5vwjh{grid-column-start:6}.ybar-ytheme-crunch._yb_kx18b1 ._yb_11pef5i,.ybar-ytheme-crunch.ybar-property-finance ._yb_1qomz0q ._yb_11pef5i{align-items:center;display:flex;height:36px;margin-right:10px;padding:0 9px 2px}#ybar.ybar-ytheme-crunch._yb_rq7mm4._yb_phn8ti{height:67px}#ybar.ybar-ytheme-crunch._yb_rq7mm4._yb_phn8ti._yb_kx18b1{height:64px}.ybar-hide-navigation #ybar.ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe>._yb_dzr3yz,#ybar.ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe>._yb_dzr3yz{opacity:0;margin-top:-60px}.ybar-hide-navigation .ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe,.ybar-ytheme-crunch._yb_rq7mm4 ._yb_1smugqe{overflow:hidden}.ybar-ytheme-crunch._yb_kx18b1 ._yb_uy5fkg{grid-column:1/span 5}.ybar-ytheme-crunch._yb_kx18b1 ._yb_11pef5i:hover{background-color:#f5f8fa;background-color:var(--yb-marshmallow);border-radius:100px}.ybar-ytheme-crunch._yb_rq7mm4 ._yb_1muppqd{max-width:632px;min-width:193px;width:calc(100% - 174px);margin-right:19px}}@media screen and (max-width:767px){#ybar.ybar-ytheme-crunch._yb_kx18b1,#ybar.ybar-ytheme-crunch._yb_kx18b1._yb_phn8ti{height:92px}#ybar.ybar-ytheme-crunch :not(._yb_1qomz0q)>._yb_wutdic{grid-column-gap:20px}#ybar.ybar-ytheme-crunch._yb_kx18b1 ._yb_wutdic{height:32px;margin:8px 16px 0;padding-bottom:84px}.ybar-ytheme-crunch._yb_kx18b1 ._yb_1muppqd{position:absolute;top:48px;max-width:100vw;width:calc(100vw - 88px)}.ybar-ytheme-crunch ._yb_uy5fkg{grid-column:1/span 5}.ybar-ytheme-crunch._yb_rq7mm4:not(._yb_kx18b1) ._yb_1muppqd{min-width:100px}}.ybar-ytheme-crunch :not(._yb_1qomz0q)>._yb_wutdic{display:grid;grid-template-columns:[main-start] repeat(11,minmax(0,1fr)) [main-end toolbar-start]repeat(1,minmax(0,1fr)) [toolbar-end];grid-template-rows:auto;grid-column-gap:32px}.ybar-ytheme-crunch._yb_kx18b1 ._yb_wutdic{grid-template-columns:[main-start] repeat(7,minmax(0,1fr)) [main-end space-start] repeat(1,minmax(0,1fr)) [space-end nav-start]repeat(4,minmax(0,1fr)) [nav-end toolbar-start]repeat(1,minmax(250px,1fr)) [toolbar-end]}._yb_uy5fkg{align-items:center;display:flex;flex-wrap:nowrap;grid-column:1/span 6}.ybar-ytheme-crunch ._yb_uy5fkg{transition:width .15s;width:inherit}._yb_1w5vwjh{display:flex;justify-content:flex-end}.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_1w5vwjh{grid-column:10}._yb_kx18b1 ._yb_1w5vwjh{grid-column-start:12}.ybar-ytheme-crunch ._yb_wutdic>div{grid-row-start:1}.ybar-ytheme-crunch ._yb_1muppqd{width:auto;min-width:193px}.ybar-ytheme-crunch ._yb_wutdic>._yb_26wpdh{grid-column-start:main-start;z-index:1}.ybar-ytheme-crunch ._yb_wutdic ._yb_2qgpj{grid-column:toolbar-start;width:100%;justify-content:flex-end}}.ybar-ytheme-crunch._yb_1jtdxyl ._yb_1emv3g7:not(._yb_1qomz0q) ._yb_11pef5i,._yb_11pef5i{display:none}._yb_19mvr2h{background:0 0;display:inline-block;border:0;margin:0;padding:0;height:20px;width:20px}._yb_19mvr2h:hover svg path{fill:#6001d2;fill:var(--yb-text-hover-color)}._yb_19mvr2h svg{display:inline-block;vertical-align:baseline}._yb_19mvr2h svg path{fill:#232a31;fill:var(--yb-text-primary)}._yb_v5t4r9 ._yb_wutdic{padding-left:54px}._yb_1ahofbt ._yb_wutdic{width:1020px}._yb_1os1r4w ._yb_wutdic{background:#6302de}._yb_1os1r4w._yb_2y1n8n ._yb_wutdic{background:0 0}._yb_1os1r4w._yb_189cmx2 ._yb_wutdic,._yb_1os1r4w._yb_1knq4zo ._yb_wutdic,._yb_1os1r4w._yb_5xpw6f ._yb_wutdic,._yb_1os1r4w._yb_td6sjk ._yb_wutdic{background:#000;background:var(--yb-black)}._yb_1os1r4w._yb_3w2bsd ._yb_wutdic{background:#2b2c2f}._yb_1os1r4w._yb_okuc2 ._yb_wutdic{background:#333}._yb_1os1r4w._yb_116dmfv ._yb_wutdic{background:#2b2d32}._yb_1o9isxs._yb_1996gte ._yb_wutdic{background:#6302de}._yb_1os1r4w._yb_g7a2wu ._yb_wutdic{background:#222}._yb_1os1r4w._yb_1nnw83b ._yb_wutdic{background:#0a4ea3}._yb_1os1r4w._yb_m0uu5w ._yb_wutdic{background:#0a0a0a}._yb_1os1r4w._yb_13gzied ._yb_wutdic{background:#fff;background:var(--yb-white)}._yb_1os1r4w._yb_pi28zo ._yb_wutdic{background:#1e4e9d}._yb_1os1r4w._yb_elmbj ._yb_wutdic{background:linear-gradient(303deg,#00d301,#36c275 50%,#00a562)}._yb_1os1r4w._yb_c5xir8 ._yb_wutdic{background:#36465d}._yb_26wpdh{display:flex;width:142px;min-width:142px}._yb_ist0jp ._yb_26wpdh,._yb_2erz1k ._yb_26wpdh{height:58px;width:205px;min-width:205px;margin-top:10px;margin-left:15px}.ybar-ytheme-crunch ._yb_wutdic ._yb_26wpdh{height:auto;width:auto;min-width:-moz-fit-content;min-width:fit-content;margin:0}._yb_1sik2rh ._yb_26wpdh{justify-content:center;min-width:192px}@media screen and (max-width:1024px){._yb_ist0jp ._yb_26wpdh,._yb_2erz1k ._yb_26wpdh{width:90px;min-width:90px;height:27px}}.ybar-ytheme-fuji2 ._yb_wutdic ._yb_26wpdh{height:auto;width:166px;min-width:166px;margin-right:20px;margin-top:0;margin-left:0;transition:min-width .4s,width .4s}.ybar-ytheme-fuji2._yb_1sik2rh ._yb_wutdic ._yb_26wpdh{margin-right:0}@media screen and (min-width:1020px){.ybar-ytheme-fuji2 ._yb_wutdic ._yb_26wpdh{width:220px;min-width:220px}}.ybar-ytheme-fuji2.ybar-property-mail ._yb_26wpdh{width:192px;min-width:192px}@media screen and (min-width:1440px){._yb_1sik2rh ._yb_26wpdh,.ybar-ytheme-fuji2._yb_1sik2rh ._yb_26wpdh{max-width:224px;width:14%}}._yb_1muppqd{display:flex;flex:1}._yb_1sik2rh ._yb_1muppqd{flex:initial}._yb_1muppqd #mail-search{flex:1}._yb_69p0bm:not(.ybar-ytheme-crunch) ._yb_1muppqd{display:none}#ybar.ybar-searchbox-assist-fullscreen #ybar-inner-wrap{position:initial}._yb_19s5ae1{margin:0 auto;padding:0 40px;width:1340px;max-width:100%;box-sizing:border-box;height:42px;display:flex;opacity:1;transition:margin .2s ease-out,opacity .15s linear .2s}._yb_1v4azts{overflow:hidden}._yb_15yb1e4{width:220px;margin-right:20px;flex-shrink:0}@media screen and (max-width:1019px){._yb_19s5ae1{padding:0 20px;transition:padding .4s}._yb_1hrqc53{width:143px;margin-left:105px;flex-shrink:0}}._yb_2qgpj{margin-left:auto;display:flex;align-items:center}.ybar-ytheme-crunch ._yb_2qgpj{margin:0}.ybar-ytheme-crunch ._yb_1qomz0q ._yb_2qgpj._yb_1mkycac{gap:10px}._yb_1sik2rh ._yb_2qgpj{padding-right:32px}.ybar-ytheme-crunch._yb_rq7mm4 ._yb_2qgpj{gap:12px}.ybar-ytheme-fuji2._yb_ist0jp ._yb_2qgpj,.ybar-ytheme-fuji2._yb_2erz1k ._yb_2qgpj{margin-right:0}._yb_2qgpj>div{margin-left:32px;white-space:nowrap}.ybar-ytheme-crunch ._yb_1qomz0q ._yb_1bud7df,.ybar-ytheme-crunch ._yb_1qomz0q ._yb_26w2jb{margin-left:0}.ybar-ytheme-crunch:not(.ybar-property-finance)._yb_19dqzcm ._yb_1qomz0q ._yb_26w2jb{width:60px;display:flex;justify-content:flex-end}.ybar-ytheme-crunch ._yb_1qomz0q ._yb_az9x9b{margin-left:16px}.ybar-ytheme-crunch ._yb_az9x9b,.ybar-ytheme-crunch._yb_19dqzcm ._yb_1qomz0q ._yb_az9x9b,.ybar-ytheme-crunch.ybar-mail-v3 ._yb_1qomz0q ._yb_2qgpj ._yb_az9x9b,.ybar-ytheme-crunch.ybar-mail-v3._yb_19dqzcm ._yb_1qomz0q ._yb_2qgpj ._yb_az9x9b{margin-left:12px}.ybar-ytheme-crunch.ybar-property-finance.ybar-mail-v3 ._yb_1qomz0q ._yb_2qgpj ._yb_az9x9b,.ybar-ytheme-crunch.ybar-property-finance._yb_19dqzcm ._yb_1qomz0q ._yb_az9x9b{margin-left:0}.ybar-ytheme-crunch ._yb_2qgpj>div{display:inline-block}@media screen and (max-width:600px){.ybar-ytheme-fuji2 ._yb_2qgpj{display:none}}@media screen and (min-width:1344px){.ybar-ytheme-crunch ._yb_wutdic ._yb_26wpdh{margin-left:0}}._yb_1bwhbi8._yb_iswvcq ._yb_2qgpj ._yb_1bud7df{display:none}._yb_2qgpj ._yb_zndw9d{max-width:250px}@media screen and (max-width:768px){:not(._yb_1qomz0q) ._yb_2qgpj>div{margin-left:24px}._yb_v5t4r9 ._yb_wutdic{height:54px;padding:0 24px 0 20px}._yb_1os1r4w ._yb_wutdic{height:50px;padding:0}._yb_v5t4r9 ._yb_wutdic,._yb_1os1r4w ._yb_wutdic{justify-content:center;position:relative}._yb_v5t4r9._yb_okuc2 ._yb_2qgpj,._yb_v5t4r9._yb_1996gte ._yb_2qgpj,._yb_v5t4r9._yb_m0uu5w ._yb_2qgpj,._yb_1os1r4w ._yb_2qgpj{position:absolute;right:24px}._yb_v5t4r9 ._yb_26wpdh,._yb_1os1r4w ._yb_26wpdh{width:auto;min-width:auto}._yb_189cmx2 ._yb_26wpdh{height:18px}._yb_1996gte ._yb_26wpdh,._yb_116dmfv ._yb_26wpdh{height:24px}._yb_1nnw83b ._yb_26wpdh{height:15px}._yb_2y1n8n ._yb_26wpdh{height:25px;width:64px}._yb_1knq4zo ._yb_26wpdh{height:22px}._yb_1os1r4w._yb_pi28zo ._yb_26wpdh,._yb_elmbj ._yb_26wpdh{height:20px}.ybar-property-finance ._yb_1qomz0q ._yb_uy5fkg ._yb_1muppqd{padding-right:0}}._yb_14tgfka{display:block}._yb_1sik2rh ._yb_1u6ljkh{max-width:none}._yb_1sik2rh ._yb_wutdic{padding:0;max-width:none}._yb_1sik2rh ._yb_wutdic ._yb_1muppqd{height:48px;margin:0;min-width:496px;padding:0;width:44%}._yb_1sik2rh._yb_19dmi0p ._yb_wutdic>._yb_26wpdh,._yb_1sik2rh._yb_17dx6fk ._yb_wutdic>._yb_26wpdh,._yb_1sik2rh._yb_156l1ls ._yb_wutdic>._yb_26wpdh,._yb_1sik2rh._yb_ozcu3o ._yb_wutdic>._yb_26wpdh{width:224px;min-width:224px}._yb_1sik2rh ._yb_wutdic ._yb_2qgpj{padding-right:32px}._yb_rq7mm4._yb_19dmi0p ._yb_16kwvy4{background:#fff;background:var(--yb-white)}._yb_1sik2rh ._yb_1s3151i{display:none}.ybar-ytheme-fuji2.ybar-property-mail ._yb_2t4frf{display:none}.ybar-ytheme-fuji2.ybar-property-mail.fuji2-dialpad ._yb_2t4frf{display:block}.ybar-amp,.ybar-amp .ybar-row{min-width:initial;max-width:initial;padding-right:0}#ybar._yb_50ho25{height:84px}#ybar.ybar-ytheme-fuji2.ybar-property-mail.fuji2-dialpad._yb_50ho25{height:72px}#ybar.ybar-ytheme-fuji2._yb_50ho25{height:111px}#ybar.ybar-ytheme-fuji2.ybar-property-generic._yb_50ho25{height:123px}#ybar.ybar-ytheme-fuji2._yb_phn8ti{height:104px}#ybar._yb_phn8ti,#ybar._yb_50ho25._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-homepage._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-generic._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-mail.fuji2-dialpad._yb_50ho25._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-generic._yb_50ho25._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-homepage._yb_50ho25._yb_phn8ti{height:114px}.ybar-ytheme-crunch.ybar-property-homepage._yb_phn8ti:not(._yb_1u9bsx1) ._yb_1smugqe{display:none}#ybar.ybar-ytheme-fuji2._yb_50ho25._yb_phn8ti{height:143px}.modal-open #ybar.ybar-ytheme-fuji2._yb_50ho25._yb_phn8ti{height:72px}#ybar.ybar-ytheme-fuji2.ybar-property-generic.ybar-show-homepage-topnavigation._yb_50ho25._yb_phn8ti,#ybar.ybar-ytheme-fuji2.ybar-property-homepage.ybar-show-homepage-topnavigation._yb_50ho25._yb_phn8ti{height:155px}#ybar.ybar-property-generic._yb_phn8ti,#ybar.ybar-property-homepage._yb_phn8ti{height:126px}#ybar.ybar-ytheme-fuji2.ybar-property-generic._yb_50ho25._yb_qezay3{height:165px}#ybar.ybar-ytheme-fuji2._yb_50ho25._yb_phn8ti._yb_qezay3{height:185px}#ybar.ybar-ytheme-fuji2._yb_50ho25._yb_phn8ti._yb_qezay3._yb_rq7mm4._yb_19dmi0p{height:203px}.modal-open .ybar-sticky #ybar.ybar-ytheme-fuji2._yb_2erz1k{height:92px!important}.modal-open .ybar-sticky #ybar.ybar-ytheme-fuji2._yb_2erz1k{height:80px!important}@media screen and (orientation:portrait){html.Reader-open ._yb_1muppqd{display:none}html.Reader-open ._yb_b7aa7v{display:inline-block}._yb_26qcwt{display:inline-block}._yb_2718zi{display:none}}#ybar input[type=hidden]{visibility:hidden}.ybar-show-outline{outline-offset:2px;outline:3px solid #0f69ff;outline:3px solid var(--yb-dory)}.ybar-hide-outline{outline:0!important}.ybar-ytheme-crunch .ybar-show-outline:focus{outline-offset:5px;outline:4px solid rgb(96 1 210/50%);outline:var(--yb-outline);border-radius:1px}._yb_bbmou4 :focus{outline:solid #0f69ff 2px;outline:solid var(--yb-dory) 2px}._yb_bbmou4 :focus:not(:focus-visible){outline:0}.ybar-theme-dark ._yb_bbmou4 :focus{outline-color:#12a9ff;outline-color:var(--yb-sky)}.ybar-theme-dark ._yb_bbmou4 :focus:not(:focus-visible){outline:0}body.typing .ybar-ytheme-fuji2[data-ovrly-bkt=darker] ._yb_1u6ljkh._yb_1smugqe{background-color:rgb(16 24 21/70%);pointer-events:none}body.typing .ybar-ytheme-fuji2[data-ovrly-bkt=light] ._yb_1u6ljkh._yb_1smugqe{background-color:#fff;background-color:var(--yb-white);opacity:.2;pointer-events:none}.ybar-page-is-scrolled:not(.ybar-hide-navigation) body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] ._yb_1vxyy3,:not(.ybar-page-is-scrolled) body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] ._yb_1vxyy3{background-color:#101518;background-color:var(--yb-midnight);height:64px;height:var(--uh-visible-height, 64px);opacity:.6;position:fixed;width:100%;z-index:1}.ybar-page-is-scrolled body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] ._yb_1smugqe,:not(.ybar-page-is-scrolled) body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] #ybar-inner-wrap{pointer-events:none}:not(.ybar-page-is-scrolled) body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] #ybar-inner-wrap #ybar-search-box-container{pointer-events:auto}.ybar-ytheme-crunch ._yb_1u6ljkh{margin:0}@media screen and (min-width:768px){.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_dzr3yz{max-width:calc(100% - 39px);max-width:var(--uh-max-width, calc(100% - 39px))}}@media screen and (min-width:1024px){.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_dzr3yz{max-width:calc(100% - 40px);max-width:var(--uh-max-width, calc(100% - 40px))}.ybar-ytheme-crunch.ybar-property-finance:not(._yb_kx18b1) ._yb_dzr3yz{margin-left:12px;margin-left:var(--uh-row-margin-left, 12px);margin-right:0;margin-right:var(--uh-row-margin-right, 0)}}@media screen and (min-width:1050px){.ybar-ytheme-crunch.property-finance:not(._yb_kx18b1) ._yb_dzr3yz{max-width:calc(100% - 36px);max-width:var(--uh-max-width, calc(100% - 36px))}}@media screen and (min-width:1050px){.ybar-ytheme-crunch._yb_kx18b1 ._yb_dzr3yz{margin-left:calc((100vw - 1440px)/2);margin-right:calc((100vw - 1440px)/2)}}@media screen and (max-width:1049px){.ybar-ytheme-crunch.ybar-property-finance ._yb_1qomz0q ._yb_dzr3yz{max-width:calc(100% - 28px);max-width:var(--uh-max-width, calc(100% - 28px));margin-left:3px;margin-left:var(--uh-row-margin-left, 3px);margin-right:0;margin-right:var(--uh-row-margin-right, 0)}}@media screen and (min-width:1280px){.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_dzr3yz{max-width:min(1264px,calc(100% - 40px));max-width:var(--uh-max-width, min(1264px, calc(100% - 40px)))}.ybar-ytheme-crunch.ybar-property-finance ._yb_dzr3yz{max-width:calc(100% - 36px);max-width:var(--uh-max-width, calc(100% - 36px))}}@media screen and (min-width:1440px){.ybar-ytheme-crunch:not(._yb_kx18b1) ._yb_dzr3yz{max-width:1264px;max-width:var(--uh-max-width, 1264px)}.ybar-ytheme-crunch.ybar-property-finance ._yb_dzr3yz{max-width:1404px;max-width:var(--uh-max-width, 1404px)}}._yb_1qomz0q ._yb_wutdic ._yb_2qgpj{width:auto}:not(.ybar-page-is-scrolled) body.typing .ybar-ytheme-crunch[data-ovrly-bkt=midnight60] #ybar-inner-wrap ._yb_1qomz0q ._yb_uy5fkg{width:inherit}._yb_19dqzcm ._yb_1qomz0q ._yb_1w5vwjh{margin-left:0}@media screen and (max-width:1023px){._yb_1qomz0q :not(._yb_rq7mm4) ._yb_1muppqd{padding-right:0}.ybar-property-finance ._yb_1qomz0q ._yb_1muppqd{padding-right:40px}._yb_1qomz0q ._yb_1w5vwjh,._yb_1qomz0q ._yb_1muppqd,._yb_19dqzcm ._yb_1qomz0q ._yb_1muppqd{margin-right:24px}.ybar-mail-v5 ._yb_1qomz0q ._yb_1muppqd{margin-right:46px}._yb_kx18b1 ._yb_1qomz0q ._yb_dzr3yz{max-width:calc(100% - 23px)}._yb_kx18b1 ._yb_1qomz0q ._yb_11pef5i{margin-right:10px}._yb_kx18b1 ._yb_1qomz0q ._yb_26wpdh{margin-right:10px}}@media screen and (min-width:1024px){._yb_1qomz0q ._yb_1w5vwjh{margin-right:40px}._yb_1qomz0q ._yb_1muppqd{margin-right:40px}._yb_19dqzcm ._yb_1qomz0q ._yb_1muppqd{margin-right:40px}._yb_kx18b1 ._yb_1qomz0q ._yb_uy5fkg{margin-left:12px}._yb_kx18b1 ._yb_1qomz0q ._yb_26wpdh{margin-right:10px}._yb_kx18b1 ._yb_1qomz0q ._yb_dzr3yz{max-width:calc(100% - 25px)}._yb_kx18b1 ._yb_1qomz0q ._yb_1muppqd{margin-right:48px}}@media screen and (min-width:1280px){._yb_1qomz0q ._yb_1w5vwjh{margin-right:56px}.ybar-property-finance ._yb_1qomz0q ._yb_1w5vwjh{margin-right:56px}._yb_1qomz0q ._yb_1muppqd{margin-right:56px}.ybar-property-finance ._yb_1qomz0q ._yb_1muppqd{margin-right:60px}._yb_19dqzcm ._yb_1qomz0q ._yb_1muppqd{margin-right:56px}._yb_kx18b1 ._yb_1qomz0q ._yb_1w5vwjh{margin-right:0}._yb_kx18b1 ._yb_1qomz0q ._yb_1muppqd{margin-right:70px}._yb_kx18b1 ._yb_1qomz0q ._yb_dzr3yz{max-width:calc(100% - 24px)}}@media screen and (min-width:1440px){.ybar-property-finance ._yb_1qomz0q ._yb_1w5vwjh,._yb_1qomz0q ._yb_1w5vwjh{margin-right:64px}.ybar-property-finance ._yb_1qomz0q ._yb_1muppqd,._yb_19dqzcm ._yb_1qomz0q ._yb_1muppqd,._yb_1qomz0q ._yb_1muppqd{margin-right:64px}.ybar-property-finance:not(._yb_g6ro8m,._yb_13pabky,._yb_1e2sz6e) ._yb_1qomz0q ._yb_1muppqd{max-width:740px}._yb_kx18b1 ._yb_1qomz0q ._yb_1muppqd{margin-right:78px}._yb_kx18b1 ._yb_1qomz0q ._yb_1w5vwjh{margin-right:46px}}._yb_1qomz0q #ybarAccountMenu{padding:0}._yb_18dd21{color:red}.ybar-sticky #ybar-inner-wrap{position:fixed;z-index:20;width:100%;transition:box-shadow .2s ease-out}.ybar-page-is-scrolled body:not(.uh-disable-bottom-box-shadow) .ybar-sticky #ybar-inner-wrap{box-shadow:rgb(0 0 0/40%) 0 0 10px 0}.ybar-sticky .ybar-ytheme-crunch.ybar-property-finance #ybar-inner-wrap{transition:box-shadow .5s ease-in-out;top:0}._yb_1s8ibak,._yb_1b9x91s ._yb_1jc4gg0,._yb_fajdfd,._yb_t3vv1p,._yb_1jc4gg0,._yb_mkdxrx,.ybar-ytheme-fuji2 ._yb_mkdxrx,._yb_tyjfd1,._yb_1xyb1po,._yb_wvwmz5,._yb_12p4kq1,._yb_1utz9cx,._yb_1xs54pa,._yb_1qxcmf5,._yb_1856sns,._yb_19gmgo9,._yb_7zky42,._yb_66i12g,._yb_1jc3ac5,._yb_wklvr4,.ybar-ytheme-fuji2 ._yb_fajdfd,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_fajdfd,._yb_laz8r0,._yb_7dxmux,._yb_l06g4f,._yb_p92pzg,._yb_19xr1yw,._yb_14v0pqj,._yb_1jugtd5,._yb_iva9fe,._yb_ycmex2,._yb_18m475z,._yb_106tojv,._yb_v10t20,._yb_13ix2cd,._yb_1ipstdz,._yb_1mre8d0,._yb_1g07l37,._yb_1ogiuyw,._yb_1knjkik,._yb_alkw6r,._yb_uuu0ny,._yb_1yhgbi0,._yb_lkxfo3,._yb_dcvoaw,._yb_1vifz6d,._yb_1qkoi2y,._yb_745sfo,._yb_nrk6cq,._yb_alfv4i,._yb_sstvpn,._yb_702g33,._yb_prtnec,._yb_1c7ti4i,._yb_1qlxi9,._yb_2w8yu1,._yb_1phjup6,._yb_137fl4z,._yb_1ig6q1v,._yb_1bxd6y2,._yb_1fg4gb1,._yb_g65rpo,._yb_1jpak4i,._yb_1ipqnqk,._yb_1gkesjf,._yb_1dfeie,._yb_128o2yp{background-image:url(https://s.yimg.com/kr/assets/spritify-sprite-dark-fd484ded-615432bc.png);background-size:32px 1713px;background-repeat:no-repeat}._yb_1s8ibak,._yb_1b9x91s ._yb_1jc4gg0{background-position:0 -1582px;width:24px;height:24px}._yb_fajdfd,._yb_t3vv1p,._yb_1jc4gg0{background-position:0 -1611px;width:24px;height:24px}._yb_mkdxrx{background-position:0 -1524px;width:24px;height:24px}.ybar-ytheme-fuji2 ._yb_mkdxrx{background-position:0 -1640px;width:32px;height:32px}._yb_tyjfd1{background-position:0 -1553px;width:24px;height:24px}._yb_1xyb1po{background-position:0 -1677px;width:32px;height:36px}.ybar-light ._yb_1s8ibak,.ybar-light ._yb_1b9x91s ._yb_1jc4gg0,.ybar-light ._yb_fajdfd,.ybar-light ._yb_t3vv1p,.ybar-light ._yb_1jc4gg0,.ybar-light .ybar-property-homepage ._yb_fajdfd,.ybar-light ._yb_mkdxrx,.ybar-light .ybar-ytheme-fuji2 ._yb_mkdxrx,.ybar-light ._yb_tyjfd1,.ybar-light ._yb_1xyb1po{background-image:url(https://s.yimg.com/kr/assets/spritify-sprite-light-fd484ded-e3dce7a4.png);background-size:32px 1740px;background-repeat:no-repeat}.ybar-light ._yb_1s8ibak,.ybar-light ._yb_1b9x91s ._yb_1jc4gg0{background-position:0 -1609px;width:24px;height:24px}.ybar-light ._yb_fajdfd,.ybar-light ._yb_t3vv1p,.ybar-light ._yb_1jc4gg0{background-position:0 -1638px;width:24px;height:24px}.ybar-light .ybar-property-homepage ._yb_fajdfd{background-position:0 -1524px;width:27px;height:20px}.ybar-light ._yb_mkdxrx{background-position:0 -1549px;width:24px;height:26px}.ybar-light .ybar-ytheme-fuji2 ._yb_mkdxrx{background-position:0 -1667px;width:32px;height:32px}.ybar-light ._yb_tyjfd1{background-position:0 -1580px;width:24px;height:24px}.ybar-light ._yb_1xyb1po{background-position:0 -1704px;width:32px;height:36px}._yb_wvwmz5{background-position:0 -1188px;width:24px;height:24px}._yb_12p4kq1{background-position:0 -1245px;width:13px;height:12px}._yb_1utz9cx{background-position:0 -1291px;width:18px;height:18px}._yb_1xs54pa{background-position:0 -1314px;width:18px;height:18px}._yb_1qxcmf5{background-position:0 -1337px;width:18px;height:16px}._yb_1856sns{background-position:0 -1262px;width:24px;height:24px}._yb_19gmgo9{background-position:0 -1358px;width:24px;height:24px}._yb_7zky42{background-position:0 -1387px;width:12px;height:12px}._yb_66i12g{background-position:0 -1434px;width:16px;height:16px}._yb_1jc3ac5{background-position:0 -1455px;width:18px;height:18px}._yb_wklvr4{background-position:0 -1478px;width:18px;height:18px}.ybar-ytheme-fuji2 ._yb_fajdfd,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_fajdfd{background-position:0 -1404px;width:23px;height:25px}._yb_laz8r0{background-position:0 -99px;width:28px;height:28px}._yb_7dxmux{background-position:0 -132px;width:28px;height:28px}._yb_l06g4f,._yb_p92pzg{background-position:0 -165px;width:28px;height:28px}._yb_19xr1yw,._yb_14v0pqj{background-position:0 -66px;width:28px;height:28px}._yb_1jugtd5,._yb_iva9fe{background-position:0 -231px;width:28px;height:28px}._yb_ycmex2{background-position:0 -33px;width:28px;height:28px}._yb_18m475z{background-position:0 -198px;width:28px;height:28px}._yb_106tojv,._yb_v10t20{background-position:0 0;width:28px;height:28px}._yb_13ix2cd{background-position:0 -297px;width:28px;height:28px}._yb_1ipstdz,._yb_1mre8d0{background-position:0 -264px;width:28px;height:28px}._yb_1g07l37{background-position:0 -429px;width:28px;height:28px}._yb_1ogiuyw{background-position:0 -495px;width:28px;height:28px}._yb_1knjkik{background-position:0 -462px;width:28px;height:28px}._yb_alkw6r{background-position:0 -396px;width:28px;height:28px}._yb_uuu0ny{background-position:0 -594px;width:28px;height:28px}._yb_1yhgbi0{background-position:0 -528px;width:28px;height:28px}._yb_lkxfo3{background-position:0 -561px;width:28px;height:28px}._yb_dcvoaw{background-position:0 -363px;width:28px;height:28px}._yb_1vifz6d{background-position:0 -330px;width:28px;height:28px}._yb_1qkoi2y{background-position:0 -627px;width:28px;height:28px}._yb_745sfo{background-position:0 -660px;width:28px;height:28px}._yb_nrk6cq{background-position:0 -693px;width:28px;height:28px}._yb_alfv4i{background-position:0 -726px;width:28px;height:28px}._yb_sstvpn{background-position:0 -759px;width:28px;height:28px}._yb_702g33{background-position:0 -792px;width:28px;height:28px}._yb_prtnec{background-position:0 -825px;width:28px;height:28px}._yb_1c7ti4i{background-position:0 -858px;width:28px;height:28px}._yb_1qlxi9{background-position:0 -891px;width:28px;height:28px}._yb_2w8yu1{background-position:0 -924px;width:28px;height:28px}._yb_1phjup6{background-position:0 -957px;width:28px;height:28px}._yb_137fl4z{background-position:0 -990px;width:28px;height:28px}._yb_1ig6q1v{background-position:0 -1155px;width:28px;height:28px}._yb_1bxd6y2{background-position:0 -1023px;width:28px;height:28px}._yb_1fg4gb1,._yb_g65rpo{background-position:0 -1056px;width:28px;height:28px}._yb_1jpak4i{background-position:0 -1089px;width:28px;height:28px}._yb_1ipqnqk{background-position:0 -1122px;width:28px;height:28px}._yb_1gkesjf{background-position:0 -1501px;width:18px;height:18px}._yb_1dfeie{background-position:0 -1217px;width:14px;height:9px}._yb_128o2yp{background-position:0 -1231px;width:14px;height:9px}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2),only screen and (min-resolution:192dpi),only screen and (min-resolution:2dppx){._yb_1s8ibak,._yb_1b9x91s ._yb_1jc4gg0,._yb_fajdfd,._yb_t3vv1p,._yb_1jc4gg0,._yb_mkdxrx,.ybar-ytheme-fuji2 ._yb_mkdxrx,._yb_tyjfd1,._yb_wvwmz5,._yb_12p4kq1,._yb_1utz9cx,._yb_1xs54pa,._yb_1qxcmf5,._yb_19gmgo9,._yb_7zky42,._yb_66i12g,._yb_1jc3ac5,._yb_wklvr4,.ybar-ytheme-fuji2 ._yb_fajdfd,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_fajdfd,._yb_laz8r0,._yb_7dxmux,._yb_l06g4f,._yb_19xr1yw,._yb_1jugtd5,._yb_ycmex2,._yb_18m475z,._yb_106tojv,._yb_13ix2cd,._yb_1ipstdz,._yb_1g07l37,._yb_1ogiuyw,._yb_1knjkik,._yb_alkw6r,._yb_uuu0ny,._yb_1yhgbi0,._yb_lkxfo3,._yb_dcvoaw,._yb_1vifz6d,._yb_1qkoi2y,._yb_745sfo,._yb_nrk6cq,._yb_alfv4i,._yb_sstvpn,._yb_702g33,._yb_prtnec,._yb_1c7ti4i,._yb_1qlxi9,._yb_2w8yu1,._yb_1phjup6,._yb_137fl4z,._yb_1ig6q1v,._yb_1bxd6y2,._yb_1fg4gb1,._yb_g65rpo,._yb_1jpak4i,._yb_1ipqnqk,._yb_1gkesjf,._yb_1dfeie,._yb_128o2yp{background-image:url(https://s.yimg.com/kr/assets/spritify-sprite-dark-2x-fd484ded-89f6b234.png);background-size:32px 1672px;background-repeat:no-repeat}._yb_1s8ibak,._yb_1b9x91s ._yb_1jc4gg0{background-position:0 -1541px;width:24px;height:24px}._yb_fajdfd,._yb_t3vv1p,._yb_1jc4gg0{background-position:0 -1570px;width:24px;height:24px}._yb_mkdxrx{background-position:0 -1483px;width:24px;height:24px}.ybar-ytheme-fuji2 ._yb_mkdxrx{background-position:0 -1599px;width:32px;height:32px}._yb_tyjfd1{background-position:0 -1512px;width:24px;height:24px}.ybar-light ._yb_1s8ibak,.ybar-light ._yb_1b9x91s ._yb_1jc4gg0,.ybar-light ._yb_fajdfd,.ybar-light ._yb_t3vv1p,.ybar-light ._yb_1jc4gg0,.ybar-light .ybar-property-homepage ._yb_fajdfd,.ybar-light ._yb_mkdxrx,.ybar-light .ybar-ytheme-fuji2 ._yb_mkdxrx,.ybar-light ._yb_tyjfd1{background-image:url(https://s.yimg.com/kr/assets/spritify-sprite-light-2x-fd484ded-374cd76d.png);background-size:32px 1699px;background-repeat:no-repeat}.ybar-light ._yb_1s8ibak,.ybar-light ._yb_1b9x91s ._yb_1jc4gg0{background-position:0 -1568px;width:24px;height:24px}.ybar-light ._yb_fajdfd,.ybar-light ._yb_t3vv1p,.ybar-light ._yb_1jc4gg0{background-position:0 -1597px;width:24px;height:24px}.ybar-light .ybar-property-homepage ._yb_fajdfd{background-position:0 -1483px;width:27px;height:20px}.ybar-light ._yb_mkdxrx{background-position:0 -1508px;width:24px;height:26px}.ybar-light .ybar-ytheme-fuji2 ._yb_mkdxrx{background-position:0 -1626px;width:32px;height:32px}.ybar-light ._yb_tyjfd1{background-position:0 -1539px;width:24px;height:24px}._yb_wvwmz5{background-position:0 -1188px;width:24px;height:24px}._yb_12p4kq1{background-position:0 -1245px;width:13px;height:12px}._yb_1utz9cx{background-position:0 -1262px;width:18px;height:18px}._yb_1xs54pa{background-position:0 -1285px;width:18px;height:18px}._yb_1qxcmf5{background-position:0 -1308px;width:18px;height:16px}._yb_19gmgo9{background-position:0 -1329px;width:12px;height:12px}._yb_7zky42{background-position:0 -1346px;width:12px;height:12px}._yb_66i12g{background-position:0 -1393px;width:16px;height:16px}._yb_1jc3ac5{background-position:0 -1414px;width:18px;height:18px}._yb_wklvr4{background-position:0 -1437px;width:18px;height:18px}.ybar-ytheme-fuji2 ._yb_fajdfd,.ybar-ytheme-fuji2.ybar-property-homepage ._yb_fajdfd{background-position:0 -1363px;width:23px;height:25px}._yb_laz8r0{background-position:0 -99px;width:28px;height:28px}._yb_7dxmux{background-position:0 -132px;width:28px;height:28px}._yb_l06g4f{background-position:0 -165px;width:28px;height:28px}._yb_19xr1yw{background-position:0 -66px;width:28px;height:28px}._yb_1jugtd5{background-position:0 -231px;width:28px;height:28px}._yb_ycmex2{background-position:0 -33px;width:28px;height:28px}._yb_18m475z{background-position:0 -198px;width:28px;height:28px}._yb_106tojv{background-position:0 0;width:28px;height:28px}._yb_13ix2cd{background-position:0 -297px;width:28px;height:28px}._yb_1ipstdz{background-position:0 -264px;width:28px;height:28px}._yb_1g07l37{background-position:0 -429px;width:28px;height:28px}._yb_1ogiuyw{background-position:0 -495px;width:28px;height:28px}._yb_1knjkik{background-position:0 -462px;width:28px;height:28px}._yb_alkw6r{background-position:0 -396px;width:28px;height:28px}._yb_uuu0ny{background-position:0 -594px;width:28px;height:28px}._yb_1yhgbi0{background-position:0 -528px;width:28px;height:28px}._yb_lkxfo3{background-position:0 -561px;width:28px;height:28px}._yb_dcvoaw{background-position:0 -363px;width:28px;height:28px}._yb_1vifz6d{background-position:0 -330px;width:28px;height:28px}._yb_1qkoi2y{background-position:0 -627px;width:28px;height:28px}._yb_745sfo{background-position:0 -660px;width:28px;height:28px}._yb_nrk6cq{background-position:0 -693px;width:28px;height:28px}._yb_alfv4i{background-position:0 -726px;width:28px;height:28px}._yb_sstvpn{background-position:0 -759px;width:28px;height:28px}._yb_702g33{background-position:0 -792px;width:28px;height:28px}._yb_prtnec{background-position:0 -825px;width:28px;height:28px}._yb_1c7ti4i{background-position:0 -858px;width:28px;height:28px}._yb_1qlxi9{background-position:0 -891px;width:28px;height:28px}._yb_2w8yu1{background-position:0 -924px;width:28px;height:28px}._yb_1phjup6{background-position:0 -957px;width:28px;height:28px}._yb_137fl4z{background-position:0 -990px;width:28px;height:28px}._yb_1ig6q1v{background-position:0 -1155px;width:28px;height:28px}._yb_1bxd6y2{background-position:0 -1023px;width:28px;height:28px}._yb_1fg4gb1,._yb_g65rpo{background-position:0 -1056px;width:28px;height:28px}._yb_1jpak4i{background-position:0 -1089px;width:28px;height:28px}._yb_1ipqnqk{background-position:0 -1122px;width:28px;height:28px}._yb_1gkesjf{background-position:0 -1460px;width:18px;height:18px}._yb_1dfeie{background-position:0 -1217px;width:14px;height:9px}._yb_128o2yp{background-position:0 -1231px;width:14px;height:9px}}._yb_1s7oh70{display:flex;align-items:0;font-size:0;height:100%}._yb_1ekgad8._yb_1s7oh70,._yb_nqixwx._yb_1s7oh70{width:100%}.ybar-ytheme-crunch ._yb_1s7oh70{width:auto}.ybar-ytheme-fuji2 ._yb_1s7oh70{max-height:24px;transition:height .4s}.ybar-ytheme-fuji2 ._yb_1ekgad8._yb_1s7oh70,.ybar-ytheme-fuji2 ._yb_nqixwx._yb_1s7oh70{margin-top:8px;max-height:45px}@media screen and (min-width:1020px){.ybar-ytheme-fuji2 ._yb_1s7oh70{max-height:32px}.ybar-ytheme-fuji2 ._yb_1ekgad8._yb_1s7oh70,.ybar-ytheme-fuji2 ._yb_nqixwx._yb_1s7oh70{margin-top:6px;max-height:56px}}.ybar-ytheme-fuji2 ._yb_1lf3kkk._yb_1s7oh70{width:auto;max-height:40px}._yb_1s7oh70:focus{outline-offset:2px}._yb_ftk0fa{align-self:flex-start;max-height:100%;max-width:100%}@media screen and (min-width:768px){._yb_ftk0fa{max-height:40px}}._yb_nqixwx ._yb_ftk0fa{height:100%;max-height:100%}.ybar-ytheme-fuji2 ._yb_ftk0fa{height:auto;width:auto;max-height:100%;max-width:100%;flex-shrink:0;-o-object-fit:contain;object-fit:contain;-o-object-position:left;object-position:left}.ybar-ytheme-fuji2._yb_1lf3kkk ._yb_ftk0fa{-o-object-position:center;object-position:center}.ybar-ytheme-crunch ._yb_9ow7t3 ._yb_ftk0fa{max-height:24px}._yb_1near09{display:block;display:var(--yb-light-img-logo-display)}._yb_1s7rouz{display:none;display:var(--yb-dark-img-logo-display)}.ybar-dark ._yb_1s7rouz{display:block}.ybar-dark ._yb_1near09,.ybar-ytheme-crunch ._yb_1s7rouz,.ybar-light ._yb_1s7rouz{display:none}.ybar-amp ._yb_1s7oh70{display:block;margin:auto;padding:10px 0;text-align:center}@media screen and (max-width:768px){._yb_miwkng ._yb_ftk0fa,._yb_19jntx5 ._yb_ftk0fa{height:100%;max-height:32px}}._yb_ovs6in{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}._yb_1mrxhn3{display:flex;align-items:center}._yb_aqhy15{width:1px;height:20px;background-color:#e0e4e9;background-color:var(--yb-cobrand-logos-divider);margin:0 8px}._yb_1mrxhn3 svg{width:auto;height:100%}._yb_1mrxhn3 a._yb_4wfnek,._yb_1mrxhn3 ._yb_6nnjs4{height:24px}._yb_1mrxhn3 ._yb_2y654h{height:20px}._yb_1mrxhn3 a._yb_w9fh6r{height:18px}</style>
    <style nonce="">#consent-page #ybar div{background: #fff;padding-left: 0}.btn {padding: 15px;font-size:20px;min-width: 30%;}.btn.primary{background-color: #0f69ff;color: #fff;cursor: pointer;}</style>
</head>
<body id="tcf2-layer1" class="no-touch blur-preview-tpl wizard tcf-2 yahoo eu-localized en-GB js">
<script nonce="">
    if ('classList' in document.body) {
        document.body.classList.add('js');
        document.body.classList.remove('no-js');
    }
</script>
<div id="consent-page" class="theme-2 v4 brandtype-yahoo ">
    <div class="consent-overlay">
        <div class="container con-container is-reject-all-enabled" aria-labelledby="consent-title" aria-describedby="consent-text">
            <div class="con-wizard">
                <form method="post" class="consent-form" action="">
                <div class="wizard-header"><div class="consent-brand-logo"><div id="ybar" role="banner" data-spaceid="" data-testid="" data-version="3.10.48" data-issinglerowheader="false" data-issinglerowsearchbox="" class="ybar-ytheme-classic  ybar-property-guce  ybar-variant-yahoo _yb_bbmou4 _yb_jrobl8 _yb_1os1r4w    ybar-light       ybar-track-link-views          "> <script id="ybarConfig" type="text/x-template">
        {}
    </script>  <div id="ybar-inner-wrap" class="_yb_16kwvy4 "><div class="_yb_1vxyy3"></div>          <div class="_yb_1u6ljkh _yb_1emv3g7"><div class="_yb_dzr3yz _yb_wutdic">   <div class="_yb_26wpdh"><h1 class="_yb_ovs6in">guce</h1>     <a href="https://uk.yahoo.com/" target="_self" id="ybar-logo" class="_yb_1s7oh70  _yb_19jntx5    " data-ylk="slk:guce;elm:logo;sec:ybar;subsec:logo;itc:0;">             <img class="_yb_ftk0fa _yb_1near09" src="https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_p_bestfit_frontpage.png" srcset="https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_p_bestfit_frontpage.png 1x, https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_p_bestfit_frontpage_2x.png 2x" title="" aria-hidden="true" alt=""><img class="_yb_ftk0fa _yb_1s7rouz" src="https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_w_bestfit_frontpage.png" srcset="https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_w_bestfit_frontpage.png 1x, https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_w_bestfit_frontpage_2x.png 2x" title="" aria-hidden="true" alt="">          guce    </a>  </div>    <div role="toolbar" class="_yb_2qgpj ybar-menu-hover-open"> </div></div></div>  </div></div></div></div>
                <div class="wizard-body">
                    <div class="consent-text" id="consent-text">
                        <div class="content-section first">
                            <p>    We, Yahoo, are part of the <span tabindex="0" aria-label="Yahoo family of brands" aria-describedby="consent-yahoo-tooltip" class="info hover touched-once" data-tooltip="The sites and apps that we own and operate, including Yahoo and AOL, and our digital advertising service, Yahoo Advertising."><span class="info-popup"><span class="info-popup-content"><span class="info-popup-heading">Yahoo family of brands</span><img src="../static/images/close.svg" alt=""><span id="consent-yahoo-tooltip" class="info-popup-description">The sites and apps that we own and operate, including Yahoo and AOL, and our digital advertising service, Yahoo Advertising.</span></span></span>Yahoo</span> family of brands.
</p>
                            <div>    When you use our sites and apps, we use <span tabindex="0" aria-label="Cookies" aria-describedby="consent-cookie-tooltip" class="info hover" data-tooltip="Cookies (including similar technologies such as web storage) allow the operators of websites and apps to store and read information from your device. Learn more in our <a href='/redirect?to=https%3A%2F%2Flegal.yahoo.com%2Fie%2Fen%2Fyahoo%2Fprivacy%2Fcookies%2Findex.html&amp;brandDomain=&amp;brandId=yahoo&amp;tos=eu&amp;step=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6&amp;userType=NON_REG' target='_blank'>cookie policy</a>."><span class="info-popup"><span class="info-popup-content"><span class="info-popup-heading">Cookies</span><img src="../static/images/close.svg" alt=""><span id="consent-cookie-tooltip" class="info-popup-description">Cookies (including similar technologies such as web storage) allow the operators of websites and apps to store and read information from your device. Learn more in our <a href="/redirect?to=https%3A%2F%2Flegal.yahoo.com%2Fie%2Fen%2Fyahoo%2Fprivacy%2Fcookies%2Findex.html&amp;brandDomain=&amp;brandId=yahoo&amp;tos=eu&amp;step=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6&amp;userType=NON_REG" target="_blank">cookie policy</a>.</span></span></span>cookies</span> to:
</div>
                            <ul class="content-list">
                                <li class="list-item">provide our sites and apps to you</li>
                                <li class="list-item">authenticate users, apply security measures, and prevent spam and abuse, and</li>
                                <li class="list-item">measure your use of our sites and apps</li>
                            </ul>
                        </div>
                        <div class="content-section">
                            <div>    If you click '<strong>Accept all</strong>', we and <a href="/v2/partners-list?sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" target="_blank">our partners</a>, including 238 who are part of the IAB Transparency &amp; Consent Framework, will also store and/or access information on a device (in other words, use cookies) and use precise geolocation data and other personal data such as IP address and browsing and search data, for personalised advertising and content, advertising and content measurement and audience research and services development.
</div>
                                <p>    If you do not want us and our partners to use cookies and personal data for these additional purposes, click '<strong>Reject all</strong>'.
</p>
                            <p>    If you would like to customise your choices, click '<strong>Manage privacy settings</strong>'.
</p>
                            <p>    You can withdraw your consent or change your choices at any time by clicking on the 'Privacy &amp; cookie settings' or 'Privacy dashboard' links on our sites and apps. Find out more about how we use your personal data in our <a href="/redirect?to=https%3A%2F%2Flegal.yahoo.com%2Fie%2Fen%2Fyahoo%2Fprivacy%2Findex.html&amp;brandDomain=&amp;brandId=yahoo&amp;tos=eu&amp;step=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6&amp;userType=NON_REG" target="_blank">privacy policy</a> and <a href="/redirect?to=https%3A%2F%2Flegal.yahoo.com%2Fie%2Fen%2Fyahoo%2Fprivacy%2Fcookies%2Findex.html&amp;brandDomain=&amp;brandId=yahoo&amp;tos=eu&amp;step=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6&amp;userType=NON_REG" target="_blank">cookie policy</a>.
</p>
                        </div>
                    </div>
                    <div class="actions couple">
    <input type="hidden" name="csrfToken" value="LmxhE88" style="">
    <input type="hidden" name="sessionId" value="3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" style="">
    <input type="hidden" name="originalDoneUrl" value="https://search.yahoo.com/search?p=FontLab&amp;guccounter=1" style="">
    <input type="hidden" name="namespace" value="yahoo" style="">
    <button type="submit" data-beacon="/beacon?tag=TCF2&amp;step=Layer1-AcceptAll&amp;brandDomain=search.yahoo.com&amp;brandBid=&amp;userType=nonreg&amp;sdk=false&amp;tos=en-GB&amp;country=PL&amp;x=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" class="btn secondary accept-all " name="agree" value="agree" data-ylk="slk:accept-all;elm:consent;sec:general_consent;subsec:guce;itc:1;outcm:consent-layer1_click">Accept all</button>
        <button type="submit" data-beacon="/beacon?tag=TCF2&amp;step=Layer1-RejectAll&amp;brandDomain=search.yahoo.com&amp;brandBid=&amp;userType=nonreg&amp;sdk=false&amp;tos=en-GB&amp;country=PL&amp;x=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" class="btn secondary reject-all" name="reject" value="reject" data-ylk="slk:reject-all;elm:consent;sec:general_consent;subsec:guce;itc:1;outcm:consent-layer1_click">Reject all</button>
    <a href="/v2/partners?sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" class="btn secondary mng-btn manage-settings" role="button" data-ylk="slk:manage-privacy-settings;elm:setting;sec:general_consent;subsec:guce;itc:1;outcm:consent-layer1_click">Manage privacy settings</a>
                    </div>
                </div>
                </form>
                <div class="scroll-down-wrapper">
                    <button id="scroll-down-btn" class="btn">
                        <span class="scroll-down-arrow"></span>Go to end
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="https://s.yimg.com/oa/build/js/site-820ed71c.js" nonce=""></script>
    <img class="beacon hidden" src="/beacon?tag=TCF2&amp;step=Layer1-View&amp;brandDomain=search.yahoo.com&amp;brandBid=&amp;userType=nonreg&amp;sdk=false&amp;tos=en-GB&amp;country=PL&amp;x=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6">
    <input type="hidden" data-impressionbeaconjs="/beacon?tag=TCF2&amp;step=Layer1-View-Js&amp;brandDomain=search.yahoo.com&amp;brandBid=&amp;userType=nonreg&amp;sdk=false&amp;tos=en-GB&amp;country=PL&amp;x=&amp;sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6" style="">
<noscript>
    <img class="beacon hidden" src="/beacon?tag=code72&step=Layer1-View&sessionId=3_cc-session_7f1945f4-bcb0-4d8f-b35c-290f1b848dd6">
</noscript>
    <script nonce="" src="https://s.yimg.com/ss/rapid-3.53.30.js"> </script>
    <script nonce="">
              var custKeys = {
                      outcm : "consent-layer1_imp",
                      mrkt : "gb",
                      lang : "en-GB",
                      pt : "utility",
                      pct : "story",
                      ver : "java",
                      dmi_consent: "false",
                      site : "www.yahoo.com"
              };
              var rapidConfigs = {
                      spaceid : "1197812781",
                      keys : custKeys,
                      anonymized : "true",
              };
              var rapidInstance = new YAHOO.i13n.Rapid(rapidConfigs);
    </script>
</body></html>

================
File: resources/brave/brave_image.md
================
[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Search Image Search API

Brave Search API is a REST API to query Brave Search and get back search
results from the web. The following sections describe how to curate requests,
including parameters and headers, to Brave Search API and get a JSON response
back.

> To try the API on a Free plan, you’ll still need to subscribe — you simply
> won’t be charged. Once subscribed, you can get an API key in the [API Keys
> section](/app/keys).

## Endpoints

Brave Search API exposes multiple endpoints for specific types of data, based
on the level of your subscription. If you don’t see the endpoint you’re
interested in, you may need to change your subscription.

Brave Image Search API is currently available at the following endpoint and
exposes an API to get images from the web relevant to the query.

    
    
    https://api.search.brave.com/res/v1/images/search
    
    

## Example

Get started immediately with CURL. An example request will look something like
this:

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/images/search?q=munich&safesearch=strict&count=20&search_lang=en&country=us&spellcheck=1" \
      -H "Accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "X-Subscription-Token: <YOUR_API_KEY>"
    

## Next Steps

To learn what parameters are available and what responses can be expected
while querying Brave Search, please review the following pages:

  * [Query Parameters](/app/documentation/image-search/query)
  * [Request Headers](/app/documentation/image-search/request-headers)
  * [Response Headers](/app/documentation/image-search/response-headers)
  * [Response Objects](/app/documentation/image-search/responses)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Image Search API

## Query Parameters

#### # Image Search API

This table lists the query parameters supported by the Image Search API. Some
are required, but most are optional.

Parameter| Required| Type| Default| Description  
---|---|---|---|---  
q| true| string| |  The user’s search query term. Query can not be empty. Maximum of 400 characters and 50 words in the query.  
country| false| string| US|  The search query country, where the results come
from. The country string is limited to 2 character country codes of supported
countries. For a list of supported values, see [Country
Codes](/app/documentation/image-search/codes#country-codes).  
search_lang| false| string| en|  The search language preference. The 2 or more
character language code for which the search results are provided. For a list
of possible values, see [Language Codes](/app/documentation/image-
search/codes#language-codes).  
count| false| number| 50|  The number of search results returned in response.
The maximum is `100`. The actual number delivered may be less than requested.  
safesearch| false| string| strict|  Filters search results for adult content.
The following values are supported:

  * `off`: No filtering is done.
  * `strict`: Drops all adult content from search results.

  
spellcheck| false| bool| 1|  Whether to spellcheck provided query. If the
spellchecker is enabled, the modified query is always used for search. The
modified query can be found in `altered` key from the
[query](/app/documentation/image-search/responses#Query) response model.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Image Search API

## Request Headers

#### Image Search API Request Headers

This table lists the request headers supported by the Image Search API, most
of which are optional.

Header| Required| Name| Description  
---|---|---|---  
Accept| false| Accept|  The default supported media type is `application/json`  
Accept-Encoding| false| Accept Encoding|  The supported compression type is
`gzip`.  
Api-Version| false| Web Search API Version|  The Brave Web Search API version
to use. This is denoted by the format `YYYY-MM-DD`. The latest version is used
by default, and the previous ones can be found in the [API Changelog](./api-
changelog).  
Cache-Control| false| Cache Control|  Search will return cached web search
results by default. To prevent caching set the Cache-Control header to `no-
cache`. This is currently done as best effort.  
User-Agent| false| User Agent|  The user agent of the client sending the
request. Search can utilize the user agent to provide a different experience
depending on the client sending the request. The user agent should follow the
commonly used browser agent strings on each platform. For more information on
curating user agents, see [RFC 9110](https://www.rfc-
editor.org/rfc/rfc9110.html#name-user-agent). User agent string examples by
platform:

  * **Android** : Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36
  * **iOS** : Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1
  * **macOS** : Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
  * **Windows** : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/

  
X-Subscription-Token| true| Authentication token|  The secret token for the
subscribed plan to authenticate the request. Can be obtained from [API
Keys](/app/keys).

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Image Search API

## Response Headers

#### Global

This table lists the response headers supported by the Image Search API.

Header| Name| Description  
---|---|---  
X-RateLimit-Limit| Rate Limit|  Rate limits associated with the requested
plan. An example rate limit `X-RateLimit-Limit: 1, 15000` means 1 request per
second and 15000 requests per month.  
X-RateLimit-Policy| Rate Limit Policy|  Rate limit policies currently
associated with the requested plan. An example policy `X-RateLimit-Policy:
1;w=1, 15000;w=2592000` means a limit of 1 request over a 1 second window and
15000 requests over a month window. The windows are always given in seconds.  
X-RateLimit-Remaining| Rate Limit Remaining|  Remaining quota units associated
with the expiring limits. An example remaining limit `X-RateLimit-Remaining:
1, 1000` indicates the API is able to be accessed once during the current
second, and 1000 times over the current month. **Note** : Only successful
requests are counted and billed.  
X-RateLimit-Reset| Rate Limit Reset|  The number of seconds until the quota
associated with the expiring limits resets. An example reset limit
`X-RateLimit-Reset: 1, 1419704` means a single request can be done again in a
second and in 1419704 seconds the full monthly quota associated with the plan
will be available again.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Image Search API

## Response Objects

#### # ImageSearchApiResponse

Top level response model for successful Image Search API requests. The API can
also respond back with an error response based on invalid subscription keys
and rate limit events.

Field| Type| Description  
---|---|---  
type| "images"| The type of search API result. The value is always images.  
query| Query| Image search query string.  
results| list [ ImageResult ]| The list of image results for the given query.  
  
#### # Query

A model representing information gathered around the requested query.

Field| Type| Description  
---|---|---  
original| string| The original query that was requested.  
altered| string| The altered query by the spellchecker. This is the query that
is used to search.  
spellcheck_off| bool| Whether the spell checker is enabled or disabled.  
show_strict_warning| string| The value is True if the lack of results is due
to a 'strict' safesearch setting. Adult content relevant to the query was
found, but was blocked by safesearch.  
  
#### # ImageResult

A model representing an image result for the requested query.

Field| Type| Description  
---|---|---  
type| image_result| The type of image search API result. The value is always
image_result.  
title| string| The title of the image.  
url| string| The original page url where the image was found.  
source| string| The source domain where the image was found.  
page_fetched| string| The iso date time when the page was last fetched. The
format is YYYY-MM-DDTHH:MM:SSZ  
thumbnail| Thumbnail| The thumbnail for the image.  
properties| Properties| Metadata for the image.  
meta_url| MetaUrl| Aggregated information on the url associated with the image
search result.  
  
#### # Thumbnail

Aggregated details representing the image thumbnail

Field| Type| Description  
---|---|---  
src| string| The served url of the image.  
  
#### # Properties

Metadata on an image.

Field| Type| Description  
---|---|---  
url| string| The image URL.  
placeholder| string| The lower resolution placeholder image url.  
  
#### # MetaUrl

Aggregated information about a url.

Field| Type| Description  
---|---|---  
scheme| string| The protocol scheme extracted from the url.  
netloc| string| The network location part extracted from the url.  
hostname| string| The lowercased domain name extracted from the url.  
favicon| string| The favicon used for the url.  
path| string| The hierarchical path of the url useful as a display string.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

## Codes

#### [#](/app/documentation/image-search/query#country) Country Codes

This table lists the country codes supported by the `country` parameter.

Country| Code  
---|---  
All Regions| ALL  
Argentina| AR  
Australia| AU  
Austria| AT  
Belgium| BE  
Brazil| BR  
Canada| CA  
Chile| CL  
Denmark| DK  
Finland| FI  
France| FR  
Germany| DE  
Hong Kong| HK  
India| IN  
Indonesia| ID  
Italy| IT  
Japan| JP  
Korea| KR  
Malaysia| MY  
Mexico| MX  
Netherlands| NL  
New Zealand| NZ  
Norway| NO  
Peoples Republic of China| CN  
Poland| PL  
Portugal| PT  
Republic of the Philippines| PH  
Russia| RU  
Saudi Arabia| SA  
South Africa| ZA  
Spain| ES  
Sweden| SE  
Switzerland| CH  
Taiwan| TW  
Turkey| TR  
United Kingdom| GB  
United States| US  
  
#### [#](/app/documentation/image-search/query#language) Language Codes

This table lists the language codes supported by the `search_lang` parameter.

Language| Code  
---|---  
Arabic| ar  
Basque| eu  
Bengali| bn  
Bulgarian| bg  
Catalan| ca  
Chinese Simplified| zh-hans  
Chinese Traditional| zh-hant  
Croatian| hr  
Czech| cs  
Danish| da  
Dutch| nl  
English| en  
English United Kingdom| en-gb  
Estonian| et  
Finnish| fi  
French| fr  
Galician| gl  
German| de  
Gujarati| gu  
Hebrew| he  
Hindi| hi  
Hungarian| hu  
Icelandic| is  
Italian| it  
Japanese| jp  
Kannada| kn  
Korean| ko  
Latvian| lv  
Lithuanian| lt  
Malay| ms  
Malayalam| ml  
Marathi| mr  
Norwegian Bokmål| nb  
Polish| pl  
Portuguese Brazil| pt-br  
Portuguese Portugal| pt-pt  
Punjabi| pa  
Romanian| ro  
Russian| ru  
Serbian Cyrylic| sr  
Slovak| sk  
Slovenian| sl  
Spanish| es  
Swedish| sv  
Tamil| ta  
Telugu| te  
Thai| th  
Turkish| tr  
Ukrainian| uk  
Vietnamese| vi

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Search API Changelog - Images

This changelog lists all updates to the Brave Image Search API in
chronological order.

### 2023-08-09

  * Initial release of the Image Search API.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search)

[ Get Started](/app/documentation/image-search/get-started)[ Query
Parameters](/app/documentation/image-search/query)[ Request
Headers](/app/documentation/image-search/request-headers)[ Response
Headers](/app/documentation/image-search/response-headers)[ Response
Objects](/app/documentation/image-search/responses)[
Codes](/app/documentation/image-search/codes)[ API
Changelog](/app/documentation/image-search/api-changelog)[ How to
Guides](/app/documentation/image-search/guides)

[ Video Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# A simple guide to handle missing and small image results

##### Brave Search Image API

There are two limitations of the Brave Search Image API:

  * the image results could be pointing to urls that cannot be resolved (404)
  * the image dimensions `width` and `height` are not provided ahead of time.

We’ve worked around the very same limitations to build our image search
vertical at [search.brave.com/images](https://search.brave.com/images?q=cats).
This guide is a simpler version of the same approach.

Our project structure will be this:

    
    
    index.js
    public/
        images.html
        styles.css
    

To get started, let’s create a folder for our image search page as well as
create the files we will need later on:

    
    
    mkdir img-search && cd img-search
    mkdir public
    touch public/images.html
    touch public/styles.css
    

We’ll use a simple [node.js express server](https://expressjs.com/) to call
the API. So let’s go ahead and install it as a dependency (our only one).

    
    
    npm install express --save
    

The following `index.js` is our server, and will be handling the API calls. It
has to be done through a server environment so that there are no Cross-Origin
Resource Sharing ([CORS](https://developer.mozilla.org/en-
US/docs/Web/HTTP/CORS)) issues.

#### index.js

    
    
    const express = require('express');
    const app = express();
    const port = 4000;
    
    app.use(express.static('public'));
    
    const API_KEY = '<YOUR_API_KEY>';
    const API_PATH = 'https://api.search.brave.com/res/v1/images/search';
    
    app.get('/api/images', async (req, res) => {
      try {
        const params = new URLSearchParams({
          q: req.query.q,
          count: 20,
          search_lang: 'en',
          country: 'us',
          spellcheck: 1,
        });
        const response = await fetch(`${API_PATH}?${params}`, {
          headers: {
            'x-subscription-token': API_KEY,
            accept: 'application/json',
          },
        });
        const data = await response.json();
        res.json(data);
        return;
      } catch (err) {
        console.log(err);
      }
      res.status(500).send('Internal Server Error');
    });
    
    app.listen(port, () => {
      console.log(`Example app listening on port ${port}`);
    });
    

Now that we have our server, let’s focus on the client side scripts needed to
load image outside of the DOM, to learn if they exist, and what the `width`
and `height` is.

#### public/images.html

    
    
    <html>
      <head>
        <title>Image Search</title>
        <link rel="stylesheet" href="/styles.css" />
      </head>
      <body>
        <script lang="javascript">
          async function fetchImages(query) {
            const params = new URLSearchParams({ q: query });
            const response = await fetch(`/api/images?${params}`);
            return await response.json();
            return data;
          }
    
          function renderImages(images) {
            const imagesContainer = document.getElementById('images');
            imagesContainer.innerHTML = '';
            images.forEach(({ image }) => {
              const figElement = document.createElement('figure');
    
              const imgElement = document.createElement('img');
              imgElement.src = image.thumbnail.src;
              imgElement.alt = image.title;
              imgElement.width = image.thumbnail.width;
              imgElement.height = image.thumbnail.height;
    
              const figCaptionElement = document.createElement('figcaption');
              figCaptionElement.innerHTML =
                `<div class="dimensions">${image.thumbnail.width} x ${image.thumbnail.height}</div>` +
                image.title;
    
              figElement.appendChild(imgElement);
              figElement.appendChild(figCaptionElement);
    
              imagesContainer.appendChild(figElement);
            });
          }
    
          function loadImage(result) {
            return new Promise((resolve, reject) => {
              const img = new Image();
              img.crossOrigin = 'anonymous';
              img.onload = (e) => {
                if (e.target) {
                  const image = e.target;
                  const width = image.naturalWidth;
                  const height = image.naturalHeight;
    
                  // Filter images that are too small
                  if (width < 275 || height < 275) {
                    console.error('[Img] Image too small', result);
                    reject(result);
                    return;
                  }
    
                  // Fill missing info; use the size the image will be scaled into instead of actual size
                  result.thumbnail.width = width;
                  result.thumbnail.height = height;
    
                  resolve(result);
                } else {
                  console.error('[Img] onLoad returned no image', result);
                  reject(result);
                }
              };
              img.onerror = (e) => {
                console.error('[Img] onError loading img', e);
                reject(result);
              };
              img.onabort = (e) => {
                console.error('[Img] onAbort loading img', e);
                reject(result);
              };
              img.src = result.thumbnail.src;
            });
          }
    
          async function load(query) {
            // Load images from API
            const response = await fetchImages(query);
            const loadedImages = [];
            let i = 0;
            const count = 5;
            const initialPromises = [];
    
            // Load the first 5 images in parallel
            for (let i = 0; i < count; i++) {
              initialPromises.push(async () => {
                const result = response.results[i];
                try {
                  const image = await loadImage(result);
                  loadedImages.push({
                    image,
                  });
                } catch (err) {
                  // pass
                }
              });
            }
    
            // Wait for the first 5 images to resolve
            await Promise.all(initialPromises);
    
            // Load images sequentially until there is 5 results, then show them.
            while (loadedImages.length < 5 || i >= response.results.length) {
              const result = response.results[i];
              try {
                const image = await loadImage(result);
                loadedImages.push({
                  image,
                });
              } catch (err) {
                // pass
              }
              i++;
            }
    
            renderImages(loadedImages);
          }
        </script>
        <div id="search">
          <input type="text" id="query" value="" onchan />
          <button onclick="load(document.getElementById('query').value)">Search</button>
        </div>
        <div id="images"></div>
      </body>
    </html>
    

The approach here, is to load images outside of the DOM, 5 at a time (which
you can configure), and images that we manage successfully, and are larger
than a given size (`width > 275 || height > 275` in the example), we show in
the DOM.

Lastly, we need some styles to make sure what we see does not look too bad:

### styles.css

    
    
    #images {
      display: flex;
      flex-wrap: wrap;
      gap: 20px;
      max-width: 1000px;
      margin: 2rem auto;
      justify-content: center;
    }
    #search {
      display: flex;
      gap: 1rem;
      align-items: center;
      width: 600px;
      margin: auto;
    }
    #search input {
      width: 100%;
      padding: 10px 20px;
      border-radius: 12px;
      outline: none;
      border: solid 1px #d3d3d3;
      background: #f3f3f3;
    }
    button {
      cursor: pointer;
      padding: 10px 20px;
      border-radius: 12px;
      outline: none;
      border: solid 1px #d3d3d3;
      background: #f3f3f3;
    }
    button:hover {
      background: #111;
      color: #fff;
    }
    figure {
      border: solid 1px #d3d3d3;
      display: flex;
      flex-flow: column;
      padding: 5px 5px 10px 5px;
      max-width: 220px;
      gap: 1rem;
      border-radius: 12px;
      margin: 0;
    }
    
    img {
      max-width: 220px;
      max-height: 150px;
      object-fit: contain;
      border-radius: 12px;
    }
    
    figcaption {
      display: flex;
      text-align: center;
      font-family: sans-serif;
      font-size: 14px;
      flex-direction: column;
      gap: 5px;
      align-items: center;
    }
    figcaption .dimensions {
      font-size: 12px;
      color: blue;
      background: #e7e7fc;
      padding: 5px 10px;
      border-radius: 12px;
      width: fit-content;
    }
    

And we’re ready to go. You can now run the project:

    
    
    node index.js
    

Open `localhost:4000/images.html` in the browser, and start searching.

![Image Search Client](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/img-search-client.Yjc8cU7X.png)

================
File: resources/brave/brave_news.md
================
[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave News Search API

Brave Search API is a REST API to query Brave Search and get back search
results from the web. The following sections describe how to curate requests,
including parameters and headers, to Brave Search API and get a JSON response
back.

> To try the API on a Free plan, you’ll still need to subscribe — you simply
> won’t be charged. Once subscribed, you can get an API key in the [API Keys
> section](/app/keys).

## Endpoints

Brave Search API exposes multiple endpoints for specific types of data, based
on the level of your subscription. If you don’t see the endpoint you’re
interested in, you may need to change your subscription.

Brave News Search API is currently available at the following endpoint and
exposes an API to get news from the web relevant to the query.

    
    
    https://api.search.brave.com/res/v1/news/search
    

## Example

Get started immediately with CURL. An example request will look something like
this:

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/news/search?q=munich&count=10&country=us&search_lang=en&spellcheck=1" \
      -H "Accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "X-Subscription-Token: <YOUR_API_KEY>"
    

## Next Steps

To learn what parameters are available and what responses can be expected
while querying Brave Search, please review the following pages:

  * [Query Parameters](/app/documentation/news-search/query)
  * [Request Headers](/app/documentation/news-search/request-headers)
  * [Response Headers](/app/documentation/news-search/response-headers)
  * [Response Objects](/app/documentation/news-search/responses)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave News Search API

## Query Parameters

#### # News Search API

This table lists the query parameters supported by the News Search API. Some
are required, but most are optional.

Parameter| Required| Type| Default| Description  
---|---|---|---|---  
q| true| string| |  The user’s search query term. Query can not be empty. Maximum of 400 characters and 50 words in the query.  
country| false| string| US|  The search query country, where the results come
from. The country string is limited to 2 character country codes of supported
countries. For a list of supported values, see [Country
Codes](/app/documentation/news-search/codes#country-codes).  
search_lang| false| string| en|  The search language preference. The 2 or more
character language code for which the search results are provided. For a list
of possible values, see [Language Codes](/app/documentation/news-
search/codes#language-codes).  
ui_lang| false| string| en-US|  User interface language preferred in response.
Usually of the format ‘<language_code>-<country_code>’. For more, see [RFC
9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-language). For a
list of supported values, see [UI Language Codes](/app/documentation/news-
search/codes#market-codes).  
count| false| number| 20|  The number of search results returned in response.
The maximum is `50`. The actual number delivered may be less than requested.
Combine this parameter with `offset` to paginate search results.  
offset| false| number| 0|  The zero based offset that indicates number of
search results per page (count) to skip before returning the result. The
maximum is `9`. The actual number delivered may be less than requested based
on the query. In order to paginate results use this parameter together with
`count`. For example, if your user interface displays 20 search results per
page, set `count` to `20` and offset to `0` to show the first page of results.
To get subsequent pages, increment `offset` by 1 (e.g. 0, 1, 2). The results
may overlap across multiple pages.  
spellcheck| false| bool| 1|  Whether to spellcheck provided query. If the
spellchecker is enabled, the modified query is always used for search. The
modified query can be found in `altered` key from the
[query](/app/documentation/news-search/responses#Query) response model.  
safesearch| false| string| moderate|  Filters search results for adult
content. The following values are supported:

  * `off` \- No filtering.
  * `moderate` \- Filter out explicit content.
  * `strict` \- Filter out explicit and suggestive content.

  
freshness| false| string| |  Filters search results by when they were discovered. The following values are supported: \- `pd`: Discovered within the last 24 hours. \- `pw`: Discovered within the last 7 Days. \- `pm`: Discovered within the last 31 Days. \- `py`: Discovered within the last 365 Days… \- `YYYY-MM-DDtoYYYY-MM-DD`: timeframe is also supported by specifying the date range e.g. `2022-04-01to2022-07-30`.  
extra_snippets| false| bool| |  A snippet is an excerpt from a page you get as a result of the query, and extra_snippets allow you to get up to 5 additional, alternative excerpts. Only available under `Free AI`, `Base AI`, `Pro AI`, `Base Data`, `Pro Data` and `Custom plans`.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave News Search API

## Request Headers

#### News Search API Request Headers

This table lists the request headers supported by the News Search API, most of
which are optional.

Header| Required| Name| Description  
---|---|---|---  
Accept| false| Accept|  The default supported media type is `application/json`  
Accept-Encoding| false| Accept Encoding|  The supported compression type is
`gzip`.  
Api-Version| false| Web Search API Version|  The Brave Web Search API version
to use. This is denoted by the format `YYYY-MM-DD`. The latest version is used
by default, and the previous ones can be found in the [API Changelog](./api-
changelog).  
Cache-Control| false| Cache Control|  Search will return cached web search
results by default. To prevent caching set the Cache-Control header to `no-
cache`. This is currently done as best effort.  
User-Agent| false| User Agent|  The user agent of the client sending the
request. Search can utilize the user agent to provide a different experience
depending on the client sending the request. The user agent should follow the
commonly used browser agent strings on each platform. For more information on
curating user agents, see [RFC 9110](https://www.rfc-
editor.org/rfc/rfc9110.html#name-user-agent). User agent string examples by
platform:

  * **Android** : Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36
  * **iOS** : Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1
  * **macOS** : Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
  * **Windows** : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/

  
X-Subscription-Token| true| Authentication token|  The secret token for the
subscribed plan to authenticate the request. Can be obtained from [API
Keys](/app/keys).

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave News Search API

## Response Headers

#### Global

This table lists the response headers supported by the News Search API.

Header| Name| Description  
---|---|---  
X-RateLimit-Limit| Rate Limit|  Rate limits associated with the requested
plan. An example rate limit `X-RateLimit-Limit: 1, 15000` means 1 request per
second and 15000 requests per month.  
X-RateLimit-Policy| Rate Limit Policy|  Rate limit policies currently
associated with the requested plan. An example policy `X-RateLimit-Policy:
1;w=1, 15000;w=2592000` means a limit of 1 request over a 1 second window and
15000 requests over a month window. The windows are always given in seconds.  
X-RateLimit-Remaining| Rate Limit Remaining|  Remaining quota units associated
with the expiring limits. An example remaining limit `X-RateLimit-Remaining:
1, 1000` indicates the API is able to be accessed once during the current
second, and 1000 times over the current month. **Note** : Only successful
requests are counted and billed.  
X-RateLimit-Reset| Rate Limit Reset|  The number of seconds until the quota
associated with the expiring limits resets. An example reset limit
`X-RateLimit-Reset: 1, 1419704` means a single request can be done again in a
second and in 1419704 seconds the full monthly quota associated with the plan
will be available again.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave News Search API

## Response Objects

#### # NewsSearchApiResponse

Top level response model for successful News Search API requests. The API can
also respond back with an error response based on invalid subscription keys
and rate limit events.

Field| Type| Description  
---|---|---  
type| "news"| The type of search API result. The value is always news.  
query| Query| News search query string.  
results| list [ NewsResult ]| The list of news results for the given query.  
  
#### # Query

A model representing information gathered around the requested query.

Field| Type| Description  
---|---|---  
original| string| The original query that was requested.  
altered| string| The altered query by the spellchecker. This is the query that
is used to search if any.  
cleaned| string| The cleaned noramlized query by the spellchecker. This is the
query that is used to search if any.  
spellcheck_off| bool| Whether the spell checker is enabled or disabled.  
show_strict_warning| bool| The value is True if the lack of results is due to
a 'strict' safesearch setting. Adult content relevant to the query was found,
but was blocked by safesearch.  
  
#### # NewsResult

A model representing a news result for the requested query.

Field| Type| Description  
---|---|---  
type| news_result| The type of news search API result. The value is always
news_result.  
url| string| The source url of the news article.  
title| string| The title of the news article.  
description| string| The description for the news article.  
age| string| A human readable representation of the page age.  
page_age| string| The page age found from the source web page.  
page_fetched| string| The iso date time when the page was last fetched. The
format is YYYY-MM-DDTHH:MM:SSZ  
breaking| bool| Whether the result includes breaking news.  
thumbnail| Thumbnail| The thumbnail for the news article.  
meta_url| MetaUrl| Aggregated information on the url associated with the news
search result.  
extra_snippets| list [ string ]| A list of extra alternate snippets for the
news search result.  
  
#### # Thumbnail

Aggregated details representing the news thumbnail

Field| Type| Description  
---|---|---  
src| string| The served url of the thumbnail associated with the news article.  
original| string| The original url of the thumbnail associated with the news
article.  
  
#### # MetaUrl

Aggregated information about a url.

Field| Type| Description  
---|---|---  
scheme| string| The protocol scheme extracted from the url.  
netloc| string| The network location part extracted from the url.  
hostname| string| The lowercased domain name extracted from the url.  
favicon| string| The favicon used for the url.  
path| string| The hierarchical path of the url useful as a display string.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave News Search API

## Codes

#### [#](/app/documentation/news-search/query#country) Country Codes

This table lists the country codes supported by the `country` parameter.

Country| Code  
---|---  
All Regions| ALL  
Argentina| AR  
Australia| AU  
Austria| AT  
Belgium| BE  
Brazil| BR  
Canada| CA  
Chile| CL  
Denmark| DK  
Finland| FI  
France| FR  
Germany| DE  
Hong Kong| HK  
India| IN  
Indonesia| ID  
Italy| IT  
Japan| JP  
Korea| KR  
Malaysia| MY  
Mexico| MX  
Netherlands| NL  
New Zealand| NZ  
Norway| NO  
Peoples Republic of China| CN  
Poland| PL  
Portugal| PT  
Republic of the Philippines| PH  
Russia| RU  
Saudi Arabia| SA  
South Africa| ZA  
Spain| ES  
Sweden| SE  
Switzerland| CH  
Taiwan| TW  
Turkey| TR  
United Kingdom| GB  
United States| US  
  
#### [#](/app/documentation/news-search/query#language) Language Codes

This table lists the language codes supported by the `search_lang` parameter.

Language| Code  
---|---  
Arabic| ar  
Basque| eu  
Bengali| bn  
Bulgarian| bg  
Catalan| ca  
Chinese Simplified| zh-hans  
Chinese Traditional| zh-hant  
Croatian| hr  
Czech| cs  
Danish| da  
Dutch| nl  
English| en  
English United Kingdom| en-gb  
Estonian| et  
Finnish| fi  
French| fr  
Galician| gl  
German| de  
Gujarati| gu  
Hebrew| he  
Hindi| hi  
Hungarian| hu  
Icelandic| is  
Italian| it  
Japanese| jp  
Kannada| kn  
Korean| ko  
Latvian| lv  
Lithuanian| lt  
Malay| ms  
Malayalam| ml  
Marathi| mr  
Norwegian Bokmål| nb  
Polish| pl  
Portuguese Brazil| pt-br  
Portuguese Portugal| pt-pt  
Punjabi| pa  
Romanian| ro  
Russian| ru  
Serbian Cyrylic| sr  
Slovak| sk  
Slovenian| sl  
Spanish| es  
Swedish| sv  
Tamil| ta  
Telugu| te  
Thai| th  
Turkish| tr  
Ukrainian| uk  
Vietnamese| vi  
  
#### [#](/app/documentation/news-search/query#market-code) Market Codes

This table lists the country language codes supported by the `ui_lang`
parameter.

Country| Language| Code  
---|---|---  
Argentina| Spanish| es-AR  
Australia| English| en-AU  
Austria| German| de-AT  
Belgium| Dutch| nl-BE  
Belgium| French| fr-BE  
Brazil| Portuguese| pt-BR  
Canada| English| en-CA  
Canada| French| fr-CA  
Chile| Spanish| es-CL  
Denmark| Danish| da-DK  
Finland| Finnish| fi-FI  
France| French| fr-FR  
Germany| German| de-DE  
Hong Kong SAR| Traditional Chinese| zh-HK  
India| English| en-IN  
Indonesia| English| en-ID  
Italy| Italian| it-IT  
Japan| Japanese| ja-JP  
Korea| Korean| ko-KR  
Malaysia| English| en-MY  
Mexico| Spanish| es-MX  
Netherlands| Dutch| nl-NL  
New Zealand| English| en-NZ  
Norway| Norwegian| no-NO  
People's republic of China| Chinese| zh-CN  
Poland| Polish| pl-PL  
Republic of the Philippines| English| en-PH  
Russia| Russian| ru-RU  
South Africa| English| en-ZA  
Spain| Spanish| es-ES  
Sweden| Swedish| sv-SE  
Switzerland| French| fr-CH  
Switzerland| German| de-CH  
Taiwan| Traditional Chinese| zh-TW  
Turkey| Turkish| tr-TR  
United Kingdom| English| en-GB  
United States| English| en-US  
United States| Spanish| es-US

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search)

[ Get Started](/app/documentation/news-search/get-started)[ Query
Parameters](/app/documentation/news-search/query)[ Request
Headers](/app/documentation/news-search/request-headers)[ Response
Headers](/app/documentation/news-search/response-headers)[ Response
Objects](/app/documentation/news-search/responses)[
Codes](/app/documentation/news-search/codes)[ API
Changelog](/app/documentation/news-search/api-changelog)

[ Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Search API Changelog - News

This changelog lists all updates to the Brave News Search API in chronological
order.

### 2023-08-15

  * Add news search.

================
File: resources/brave/brave_video.md
================
[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Video Search API

Brave Search API is a REST API to query Brave Search and get back search
results from the web. The following sections describe how to curate requests,
including parameters and headers, to Brave Search API and get a JSON response
back.

> To try the API on a Free plan, you’ll still need to subscribe — you simply
> won’t be charged. Once subscribed, you can get an API key in the [API Keys
> section](/app/keys).

## Endpoints

Brave Search API exposes multiple endpoints for specific types of data, based
on the level of your subscription. If you don’t see the endpoint you’re
interested in, you may need to change your subscription.

Brave Video Search API is currently available at the following endpoint and
exposes an API to get videos from the web relevant to the query.

    
    
    https://api.search.brave.com/res/v1/videos/search
    

## Example

Get started immediately with CURL. An example request will look something like
this:

    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/videos/search?q=munich&count=10&country=us&search_lang=en&spellcheck=1" \
      -H "Accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "X-Subscription-Token: <YOUR_API_KEY>"
    

## Next Steps

To learn what parameters are available and what responses can be expected
while querying Brave Search, please review the following pages:

  * [Query Parameters](/app/documentation/video-search/query)
  * [Request Headers](/app/documentation/video-search/request-headers)
  * [Response Headers](/app/documentation/video-search/response-headers)
  * [Response Objects](/app/documentation/video-search/responses)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Video Search API

## Query Parameters

#### # Video Search API

This table lists the query parameters supported by the Video Search API. Some
are required, but most are optional.

Parameter| Required| Type| Default| Description  
---|---|---|---|---  
q| true| string| |  The user’s search query term. Query can not be empty. Maximum of 400 characters and 50 words in the query.  
country| false| string| US|  The search query country, where the results come
from. The country string is limited to 2 character country codes of supported
countries. For a list of supported values, see [Country
Codes](/app/documentation/video-search/codes#country-codes).  
search_lang| false| string| en|  The search language preference. The 2 or more
character language code for which the search results are provided. For a list
of possible values, see [Language Codes](/app/documentation/video-
search/codes#language-codes).  
ui_lang| false| string| en-US|  User interface language preferred in response.
Usually of the format ‘<language_code>-<country_code>’. For more, see [RFC
9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-language). For a
list of supported values, see [UI Language Codes](/app/documentation/video-
search/codes#market-codes).  
count| false| number| 20|  The number of search results returned in response.
The maximum is `50`. The actual number delivered may be less than requested.
Combine this parameter with `offset` to paginate search results.  
offset| false| number| 0|  The zero based offset that indicates number of
search results per page (count) to skip before returning the result. The
maximum is `9`. The actual number delivered may be less than requested based
on the query. In order to paginate results use this parameter together with
`count`. For example, if your user interface displays 20 search results per
page, set `count` to `20` and offset to `0` to show the first page of results.
To get subsequent pages, increment `offset` by 1 (e.g. 0, 1, 2). The results
may overlap across multiple pages.  
spellcheck| false| bool| 1|  Whether to spellcheck provided query. If the
spellchecker is enabled, the modified query is always used for search. The
modified query can be found in `altered` key from the
[query](/app/documentation/video-search/responses#Query) response model.  
safesearch| false| string| moderate|  Filters search results for adult
content. The following values are supported:

  * `off` \- No filtering.
  * `moderate` \- Filter out explicit content.
  * `strict` \- Filter out explicit and suggestive content.

  
freshness| false| string| |  Filters search results by when they were discovered. The following values are supported: \- `pd`: Discovered within the last 24 hours. \- `pw`: Discovered within the last 7 Days. \- `pm`: Discovered within the last 31 Days. \- `py`: Discovered within the last 365 Days… \- `YYYY-MM-DDtoYYYY-MM-DD`: timeframe is also supported by specifying the date range e.g. `2022-04-01to2022-07-30`.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Video Search API

## Request Headers

#### Video Search API Request Headers

This table lists the request headers supported by the Video Search API, most
of which are optional.

Header| Required| Name| Description  
---|---|---|---  
Accept| false| Accept|  The default supported media type is `application/json`  
Accept-Encoding| false| Accept Encoding|  The supported compression type is
`gzip`.  
Api-Version| false| Web Search API Version|  The Brave Web Search API version
to use. This is denoted by the format `YYYY-MM-DD`. The latest version is used
by default, and the previous ones can be found in the [API Changelog](./api-
changelog).  
Cache-Control| false| Cache Control|  Search will return cached web search
results by default. To prevent caching set the Cache-Control header to `no-
cache`. This is currently done as best effort.  
User-Agent| false| User Agent|  The user agent of the client sending the
request. Search can utilize the user agent to provide a different experience
depending on the client sending the request. The user agent should follow the
commonly used browser agent strings on each platform. For more information on
curating user agents, see [RFC 9110](https://www.rfc-
editor.org/rfc/rfc9110.html#name-user-agent). User agent string examples by
platform:

  * **Android** : Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36
  * **iOS** : Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1
  * **macOS** : Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
  * **Windows** : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/

  
X-Subscription-Token| true| Authentication token|  The secret token for the
subscribed plan to authenticate the request. Can be obtained from [API
Keys](/app/keys).

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Video Search API

## Response Headers

#### Global

This table lists the response headers supported by the Video Search API.

Header| Name| Description  
---|---|---  
X-RateLimit-Limit| Rate Limit|  Rate limits associated with the requested
plan. An example rate limit `X-RateLimit-Limit: 1, 15000` means 1 request per
second and 15000 requests per month.  
X-RateLimit-Policy| Rate Limit Policy|  Rate limit policies currently
associated with the requested plan. An example policy `X-RateLimit-Policy:
1;w=1, 15000;w=2592000` means a limit of 1 request over a 1 second window and
15000 requests over a month window. The windows are always given in seconds.  
X-RateLimit-Remaining| Rate Limit Remaining|  Remaining quota units associated
with the expiring limits. An example remaining limit `X-RateLimit-Remaining:
1, 1000` indicates the API is able to be accessed once during the current
second, and 1000 times over the current month. **Note** : Only successful
requests are counted and billed.  
X-RateLimit-Reset| Rate Limit Reset|  The number of seconds until the quota
associated with the expiring limits resets. An example reset limit
`X-RateLimit-Reset: 1, 1419704` means a single request can be done again in a
second and in 1419704 seconds the full monthly quota associated with the plan
will be available again.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Video Search API

## Response Objects

#### # VideoSearchApiResponse

Top level response model for successful Video Search API requests. The API can
also respond back with an error response based on invalid subscription keys
and rate limit events.

Field| Type| Description  
---|---|---  
type| "videos"| The type of search API result. The value is always video.  
query| Query| Video search query string.  
results| list [ VideoResult ]| The list of video results for the given query.  
  
#### # Query

A model representing information gathered around the requested query.

Field| Type| Description  
---|---|---  
original| string| The original query that was requested.  
altered| string| The altered query by the spellchecker. This is the query that
is used to search if any.  
cleaned| string| The cleaned noramlized query by the spellchecker. This is the
query that is used to search if any.  
spellcheck_off| bool| Whether the spell checker is enabled or disabled.  
show_strict_warning| string| The value is True if the lack of results is due
to a 'strict' safesearch setting. Adult content relevant to the query was
found, but was blocked by safesearch.  
  
#### # VideoResult

A model representing a video result for the requested query.

Field| Type| Description  
---|---|---  
type| video_result| The type of video search API result. The value is always
video_result.  
url| string| The source url of the video.  
title| string| The title of the video.  
description| string| The description for the video.  
age| string| A human readable representation of the page age.  
page_age| string| The page age found from the source web page.  
page_fetched| string| The iso date time when the page was last fetched. The
format is YYYY-MM-DDTHH:MM:SSZ  
thumbnail| Thumbnail| The thumbnail for the video.  
video| VideoData| Metadata for the video.  
meta_url| MetaUrl| Aggregated information on the url associated with the video
search result.  
  
#### # Thumbnail

Aggregated details representing the video thumbnail

Field| Type| Description  
---|---|---  
src| string| The served url of the thumbnail associated with the video.  
original| string| The original url of the thumbnail associated with the video.  
  
#### # VideoData

A model representing metadata gathered for a video.

Field| Type| Description  
---|---|---  
duration| string| A time string representing the duration of the video.  
views| int| The number of views of the video.  
creator| string| The creator of the video.  
publisher| string| The publisher of the video.  
requires_subscription| bool| Whether the video requires a subscription.  
tags| list [ string ]| A list of tags relevant to the video.  
author| Profile| A list of profiles associated with the video.  
  
#### # Profile

A profile of an entity associated with the video.

Field| Type| Description  
---|---|---  
name| string| The name of the profile.  
long_name| string| The long name of the profile.  
url| string| The original url where the profile is available.  
img| string| The served image url representing the profile.  
  
#### # MetaUrl

Aggregated information about a url.

Field| Type| Description  
---|---|---  
scheme| string| The protocol scheme extracted from the url.  
netloc| string| The network location part extracted from the url.  
hostname| string| The lowercased domain name extracted from the url.  
favicon| string| The favicon used for the url.  
path| string| The hierarchical path of the url useful as a display string.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Video Search API

## Codes

#### [#](/app/documentation/video-search/query#country) Country Codes

This table lists the country codes supported by the `country` parameter.

Country| Code  
---|---  
All Regions| ALL  
Argentina| AR  
Australia| AU  
Austria| AT  
Belgium| BE  
Brazil| BR  
Canada| CA  
Chile| CL  
Denmark| DK  
Finland| FI  
France| FR  
Germany| DE  
Hong Kong| HK  
India| IN  
Indonesia| ID  
Italy| IT  
Japan| JP  
Korea| KR  
Malaysia| MY  
Mexico| MX  
Netherlands| NL  
New Zealand| NZ  
Norway| NO  
Peoples Republic of China| CN  
Poland| PL  
Portugal| PT  
Republic of the Philippines| PH  
Russia| RU  
Saudi Arabia| SA  
South Africa| ZA  
Spain| ES  
Sweden| SE  
Switzerland| CH  
Taiwan| TW  
Turkey| TR  
United Kingdom| GB  
United States| US  
  
#### [#](/app/documentation/video-search/query#language) Language Codes

This table lists the language codes supported by the `search_lang` parameter.

Language| Code  
---|---  
Arabic| ar  
Basque| eu  
Bengali| bn  
Bulgarian| bg  
Catalan| ca  
Chinese Simplified| zh-hans  
Chinese Traditional| zh-hant  
Croatian| hr  
Czech| cs  
Danish| da  
Dutch| nl  
English| en  
English United Kingdom| en-gb  
Estonian| et  
Finnish| fi  
French| fr  
Galician| gl  
German| de  
Gujarati| gu  
Hebrew| he  
Hindi| hi  
Hungarian| hu  
Icelandic| is  
Italian| it  
Japanese| jp  
Kannada| kn  
Korean| ko  
Latvian| lv  
Lithuanian| lt  
Malay| ms  
Malayalam| ml  
Marathi| mr  
Norwegian Bokmål| nb  
Polish| pl  
Portuguese Brazil| pt-br  
Portuguese Portugal| pt-pt  
Punjabi| pa  
Romanian| ro  
Russian| ru  
Serbian Cyrylic| sr  
Slovak| sk  
Slovenian| sl  
Spanish| es  
Swedish| sv  
Tamil| ta  
Telugu| te  
Thai| th  
Turkish| tr  
Ukrainian| uk  
Vietnamese| vi  
  
#### [#](/app/documentation/video-search/query#market-code) Market Codes

This table lists the country language codes supported by the `ui_lang`
parameter.

Country| Language| Code  
---|---|---  
Argentina| Spanish| es-AR  
Australia| English| en-AU  
Austria| German| de-AT  
Belgium| Dutch| nl-BE  
Belgium| French| fr-BE  
Brazil| Portuguese| pt-BR  
Canada| English| en-CA  
Canada| French| fr-CA  
Chile| Spanish| es-CL  
Denmark| Danish| da-DK  
Finland| Finnish| fi-FI  
France| French| fr-FR  
Germany| German| de-DE  
Hong Kong SAR| Traditional Chinese| zh-HK  
India| English| en-IN  
Indonesia| English| en-ID  
Italy| Italian| it-IT  
Japan| Japanese| ja-JP  
Korea| Korean| ko-KR  
Malaysia| English| en-MY  
Mexico| Spanish| es-MX  
Netherlands| Dutch| nl-NL  
New Zealand| English| en-NZ  
Norway| Norwegian| no-NO  
People's republic of China| Chinese| zh-CN  
Poland| Polish| pl-PL  
Republic of the Philippines| English| en-PH  
Russia| Russian| ru-RU  
South Africa| English| en-ZA  
Spain| Spanish| es-ES  
Sweden| Swedish| sv-SE  
Switzerland| French| fr-CH  
Switzerland| German| de-CH  
Taiwan| Traditional Chinese| zh-TW  
Turkey| Turkish| tr-TR  
United Kingdom| English| en-GB  
United States| English| en-US  
United States| Spanish| es-US

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search) [ Summarizer
Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search)

[ Get Started](/app/documentation/video-search/get-started)[ Query
Parameters](/app/documentation/video-search/query)[ Request
Headers](/app/documentation/video-search/request-headers)[ Response
Headers](/app/documentation/video-search/response-headers)[ Response
Objects](/app/documentation/video-search/responses)[
Codes](/app/documentation/video-search/codes)[ API
Changelog](/app/documentation/video-search/api-changelog)

[ News Search](/app/documentation/news-search) [
Suggest](/app/documentation/suggest) [
Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Search API Changelog - Videos

This changelog lists all updates to the Brave Video Search API in
chronological order.

### 2023-08-15

  * Add video search.

================
File: resources/brave/brave.md
================
[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Web Search API - Changelog

This changelog outlines all significant changes to the Brave Web Search API in
chronological order.

### 2023-01-01

  * Add Brave Web Search API resource.

### 2023-04-14

  * Change `SearchResult` restaurant property to `location`.

### 2023-10-11

  * Add `spellcheck` flag.

# Local Search API - Changelog

This changelog outlines all significant changes to the Brave Local Search API
in chronological order.

### 2024-06-11

  * Add Brave Local Search API resource.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Web Search API

## Codes

#### [#](/app/documentation/web-search/query#country) Country Codes

This table lists the country codes supported by the `country` parameter.

Country| Code  
---|---  
All Regions| ALL  
Argentina| AR  
Australia| AU  
Austria| AT  
Belgium| BE  
Brazil| BR  
Canada| CA  
Chile| CL  
Denmark| DK  
Finland| FI  
France| FR  
Germany| DE  
Hong Kong| HK  
India| IN  
Indonesia| ID  
Italy| IT  
Japan| JP  
Korea| KR  
Malaysia| MY  
Mexico| MX  
Netherlands| NL  
New Zealand| NZ  
Norway| NO  
Peoples Republic of China| CN  
Poland| PL  
Portugal| PT  
Republic of the Philippines| PH  
Russia| RU  
Saudi Arabia| SA  
South Africa| ZA  
Spain| ES  
Sweden| SE  
Switzerland| CH  
Taiwan| TW  
Turkey| TR  
United Kingdom| GB  
United States| US  
  
#### [#](/app/documentation/web-search/query#language) Language Codes

This table lists the language codes supported by the `search_lang` parameter.

Language| Code  
---|---  
Arabic| ar  
Basque| eu  
Bengali| bn  
Bulgarian| bg  
Catalan| ca  
Chinese Simplified| zh-hans  
Chinese Traditional| zh-hant  
Croatian| hr  
Czech| cs  
Danish| da  
Dutch| nl  
English| en  
English United Kingdom| en-gb  
Estonian| et  
Finnish| fi  
French| fr  
Galician| gl  
German| de  
Gujarati| gu  
Hebrew| he  
Hindi| hi  
Hungarian| hu  
Icelandic| is  
Italian| it  
Japanese| jp  
Kannada| kn  
Korean| ko  
Latvian| lv  
Lithuanian| lt  
Malay| ms  
Malayalam| ml  
Marathi| mr  
Norwegian Bokmål| nb  
Polish| pl  
Portuguese Brazil| pt-br  
Portuguese Portugal| pt-pt  
Punjabi| pa  
Romanian| ro  
Russian| ru  
Serbian Cyrylic| sr  
Slovak| sk  
Slovenian| sl  
Spanish| es  
Swedish| sv  
Tamil| ta  
Telugu| te  
Thai| th  
Turkish| tr  
Ukrainian| uk  
Vietnamese| vi  
  
#### [#](/app/documentation/web-search/query#market-code) Market Codes

This table lists the country language codes supported by the `ui_lang`
parameter.

Country| Language| Code  
---|---|---  
Argentina| Spanish| es-AR  
Australia| English| en-AU  
Austria| German| de-AT  
Belgium| Dutch| nl-BE  
Belgium| French| fr-BE  
Brazil| Portuguese| pt-BR  
Canada| English| en-CA  
Canada| French| fr-CA  
Chile| Spanish| es-CL  
Denmark| Danish| da-DK  
Finland| Finnish| fi-FI  
France| French| fr-FR  
Germany| German| de-DE  
Hong Kong SAR| Traditional Chinese| zh-HK  
India| English| en-IN  
Indonesia| English| en-ID  
Italy| Italian| it-IT  
Japan| Japanese| ja-JP  
Korea| Korean| ko-KR  
Malaysia| English| en-MY  
Mexico| Spanish| es-MX  
Netherlands| Dutch| nl-NL  
New Zealand| English| en-NZ  
Norway| Norwegian| no-NO  
People's republic of China| Chinese| zh-CN  
Poland| Polish| pl-PL  
Republic of the Philippines| English| en-PH  
Russia| Russian| ru-RU  
South Africa| English| en-ZA  
Spain| Spanish| es-ES  
Sweden| Swedish| sv-SE  
Switzerland| French| fr-CH  
Switzerland| German| de-CH  
Taiwan| Traditional Chinese| zh-TW  
Turkey| Turkish| tr-TR  
United Kingdom| English| en-GB  
United States| English| en-US  
United States| Spanish| es-US

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

# Brave Web Search API

## Introduction

Brave Web Search API is a REST API to query Brave Search and get back search
results from the web. The following sections describe how to curate requests,
including parameters and headers, to Brave Web Search API and get a JSON
response back.

> To try the API on a Free plan, you’ll still need to subscribe — you simply
> won’t be charged. Once subscribed, you can get an API key in the [API Keys
> section](/app/keys).

## Endpoints

Brave Search API exposes multiple endpoints for specific types of data, based
on the level of your subscription. If you don’t see the endpoint you’re
interested in, you may need to change your subscription.

    
    
    https://api.search.brave.com/res/v1/web/search
    

## Example

A request has to be made to the web search endpoint. An example CURL request
is given below.

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/web/search?q=brave+search" \
      -H "Accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "X-Subscription-Token: <YOUR_API_KEY>"
    

The response specification for Web Search API can be seen in the
[WebSearchApiResponse](/app/documentation/web-
search/responses#WebSearchApiResponse) model.

## Next Steps

To learn what parameters are available and what responses can be expected
while querying Brave Web Search API, please review the following pages:

  * [Query Parameters](/app/documentation/web-search/query#WebSearchAPIQueryParameters)
  * [Request Headers](/app/documentation/web-search/request-headers#WebSearchAPIRequestHeaders)
  * [Response Headers](/app/documentation/web-search/response-headers)
  * [Response Objects](/app/documentation/web-search/responses)

# Brave Local Search API

## Introduction

Brave Local Search API provides enrichments for location search results.

> Access to Local API is available through the [Pro
> plans](/app/subscriptions/subscribe?tab=normal).

## Endpoints

Brave Local Search API is currently available at the following endpoints and
exposes an API to get extra information about a location, including pictures
and related web results.

    
    
    https://api.search.brave.com/res/v1/local/pois
    

The endpoint supports batching and retrieval of extra information of up to 20
locations with a single request.

The local API also includes an endpoint to get an AI generated description for
a location.

    
    
    https://api.search.brave.com/res/v1/local/descriptions
    

## Example

An initial request has to be made to web search endpoint with a given query.
An example CURL request is given below.

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/web/search?q=greek+restaurants+in+san+francisco" \
      -H "Accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "X-Subscription-Token: <YOUR_API_KEY>"
    

If the query returns a list of locations, as in this case, each location
result has an [id field](/app/documentation/web-
search/responses#LocationResult), which is a temporary ID that can be used to
retrieve extra information about the location. An example from the locations
result is given below.

    
    
    {
      "locations": {
        "results": [
          {
            "id": "1520066f3f39496780c5931d9f7b26a6",
            "title": "Pangea Banquet Mediterranean Food"
          },
          {
            "id": "d00b153c719a427ea515f9eacf4853a2",
            "title": "Park Mediterranean Grill"
          },
          {
            "id": "4b943b378725432aa29f019def0f0154",
            "title": "The Halal Mediterranean Co."
          }
        ]
      }
    }
    

The `id` value can be used to further fetch extra information about the
location. An example request is given below.

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/local/pois?ids=1520066f3f39496780c5931d9f7b26a6&ids=d00b153c719a427ea515f9eacf4853a2" \
      -H "accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "x-subscription-token: <YOUR_API_KEY>"
    

An AI generated description associated with a location can be further fetched
using the example below.

    
    
    
    curl -s --compressed "https://api.search.brave.com/res/v1/local/descriptions?ids=1520066f3f39496780c5931d9f7b26a6&ids=d00b153c719a427ea515f9eacf4853a2" \
      -H "accept: application/json" \
      -H "Accept-Encoding: gzip" \
      -H "x-subscription-token: <YOUR_API_KEY>"
    

The response specification for Local Search API can be seen in the
[LocalPoiSearchApiResponse](/app/documentation/web-
search/responses#LocalPoiSearchApiResponse) and
[LocalDescriptionsSearchApiResponse](/app/documentation/web-
search/responses#LocalDescriptionsSearchApiResponse) models.

## Next Steps

To learn what parameters are available and what responses can be expected
while querying Brave Web Search API, please review the following pages:

  * [Query Parameters](/app/documentation/web-search/query#LocalSearchAPIQueryParameters)
  * [Request Headers](/app/documentation/web-search/request-headers#LocalSearchAPIRequestHeaders)
  * [Response Headers](/app/documentation/web-search/response-headers)
  * [Response Objects](/app/documentation/web-search/responses)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Web Search API

## Query Parameters

#### # Web Search API

This table lists the query parameters supported by the Web Search API. Some
are required, but most are optional.

Parameter| Required| Type| Default| Description  
---|---|---|---|---  
q| true| string| |  The user’s search query term. Query can not be empty. Maximum of 400 characters and 50 words in the query.  
country| false| string| US|  The search query country, where the results come
from. The country string is limited to 2 character country codes of supported
countries. For a list of supported values, see [Country
Codes](/app/documentation/web-search/codes#country-codes).  
search_lang| false| string| en|  The search language preference. The 2 or more
character language code for which the search results are provided. For a list
of possible values, see [Language Codes](/app/documentation/web-
search/codes#language-codes).  
ui_lang| false| string| en-US|  User interface language preferred in response.
Usually of the format ‘<language_code>-<country_code>’. For more, see [RFC
9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-language). For a
list of supported values, see [UI Language Codes](/app/documentation/web-
search/codes#market-codes).  
count| false| number| 20|  The number of search results returned in response.
The maximum is `20`. The actual number delivered may be less than requested.
Combine this parameter with `offset` to paginate search results.  
offset| false| number| 0|  The zero based offset that indicates number of
search results per page (count) to skip before returning the result. The
maximum is `9`. The actual number delivered may be less than requested based
on the query. In order to paginate results use this parameter together with
`count`. For example, if your user interface displays 20 search results per
page, set `count` to `20` and offset to `0` to show the first page of results.
To get subsequent pages, increment `offset` by 1 (e.g. 0, 1, 2). The results
may overlap across multiple pages.  
safesearch| false| string| moderate|  Filters search results for adult
content. The following values are supported:

  * `off`: No filtering is done.
  * `moderate`: Filters explicit content, like images and videos, but allows adult domains in the search results.
  * `strict`: Drops all adult content from search results.

  
freshness| false| string| |  Filters search results by when they were discovered. The following values are supported: \- `pd`: Discovered within the last 24 hours. \- `pw`: Discovered within the last 7 Days. \- `pm`: Discovered within the last 31 Days. \- `py`: Discovered within the last 365 Days… \- `YYYY-MM-DDtoYYYY-MM-DD`: timeframe is also supported by specifying the date range e.g. `2022-04-01to2022-07-30`.  
text_decorations| false| bool| 1|  Whether display strings (e.g. result
snippets) should include decoration markers (e.g. highlighting characters).  
spellcheck| false| bool| 1|  Whether to spellcheck provided query. If the
spellchecker is enabled, the modified query is always used for search. The
modified query can be found in `altered` key from the
[query](/app/documentation/web-search/responses#Query) response model.  
result_filter| false| string| |  A comma delimited string of result types to include in the search response. Not specifying this parameter will return back all result types in search response where data is available and a plan with the corresponding option is subscribed. The response always includes query and type to identify any query modifications and response type respectively. Available result filter values are: \- discussions \- faq \- infobox \- news \- query \- summarizer \- videos \- web \- locations Example result filter param `result_filter=discussions`, `videos` returns only `discussions`, and videos responses. Another example where only location results are required, set the `result_filter` param to `result_filter=locations`.  
goggles_id| false| string| |  Goggles act as a custom re-ranking on top of Brave’s search index. For more details, refer to the [Goggles repository](https://github.com/brave/goggles-quickstart). This parameter is deprecated. Please use the goggles parameter.  
goggles| false| string| |  Goggles act as a custom re-ranking on top of Brave’s search index. The parameter supports both a url where the Goggle is hosted or the definition of the goggle. For more details, refer to the [Goggles repository](https://github.com/brave/goggles-quickstart).  
units| false| string| |  The measurement units. If not provided, units are derived from search country. Possible values are: \- `metric`: The standardized measurement system \- `imperial`: The British Imperial system of units.  
extra_snippets| false| bool| |  A snippet is an excerpt from a page you get as a result of the query, and extra_snippets allow you to get up to 5 additional, alternative excerpts. Only available under `Free AI`, `Base AI`, `Pro AI`, `Base Data`, `Pro Data` and `Custom plans`.  
summary| false| bool| |  This parameter enables summary key generation in web search results. This is required for summarizer to be enabled.  
  

You can also optimise your search query by using [search
operators](https://search.brave.com/help/operators).

#### # Local Search API

This table lists the query parameters supported by the Local Search API. Some
are required, but most are optional.

Parameter| Required| Type| Default| Description  
---|---|---|---|---  
ids| true| list[string]| |  Unique identifier for the location. Ids can not be empty. Maximum of 20 ids per request. The parameter can be repeated to query for multiple ids.  
search_lang| false| string| en|  The search language preference. The 2 or more
character language code for which the search results are provided. For a list
of possible values, see [Language Codes](/app/documentation/web-
search/codes#language-codes).  
ui_lang| false| string| en-US|  User interface language preferred in response.
Usually of the format ‘<language_code>-<country_code>’. For more, see [RFC
9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-language). For a
list of supported values, see [UI Language Codes](/app/documentation/web-
search/codes#market-codes).  
units| false| string| |  The measurement units. If not provided, units are derived from search country. Possible values are: \- `metric`: The standardized measurement system \- `imperial`: The British Imperial system of units.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Web Search API

## Request Headers

#### # Web Search API Request Headers

This table lists the request headers supported by the Web Search API. Most are
optional, but note that sending more information in headers (such as client
location) will improve search results.

Header| Required| Name| Description  
---|---|---|---  
Accept| false| Accept|  The default supported media type is `application/json`  
Accept-Encoding| false| Accept Encoding|  The supported compression type is
`gzip`.  
Api-Version| false| Web Search API Version|  The Brave Web Search API version
to use. This is denoted by the format `YYYY-MM-DD`. The latest version is used
by default, and the previous ones can be found in the [API Changelog](./api-
changelog).  
Cache-Control| false| Cache Control|  Search will return cached web search
results by default. To prevent caching set the Cache-Control header to `no-
cache`. This is currently done as best effort.  
User-Agent| false| User Agent|  The user agent of the client sending the
request. Search can utilize the user agent to provide a different experience
depending on the client sending the request. The user agent should follow the
commonly used browser agent strings on each platform. For more information on
curating user agents, see [RFC 9110](https://www.rfc-
editor.org/rfc/rfc9110.html#name-user-agent). User agent string examples by
platform:

  * **Android** : Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36
  * **iOS** : Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1
  * **macOS** : Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
  * **Windows** : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/

  
X-Loc-Lat| false| Latitude|  The latitude of the client’s geographical
location in degrees, to provide relevant local results. The latitiude must be
greater than or equal to -90.0 degrees and less than or equal to +90.0
degrees.  
X-Loc-Long| false| Longitude|  The longitude of the client’s geographical
location in degrees, to provide relevant local results. The longitude must be
greater than or equal to -180.0 degrees and less than or equal to +180.0
degrees.  
X-Loc-Timezone| false| Timezone|  The IANA timezone for the client’s device,
for example `America/New_York`. For complete list of IANA timezones and
location mappings see [IANA Database](https://www.iana.org/time-zones) and
[Geonames Database](https://download.geonames.org/export/dump/).  
X-Loc-City| false| City Name|  The generic name of the client city.  
X-Loc-State| false| State Code|  The code representing the client’s
state/region, can be up to 3 characters long. The region is the first-level
subdivision (the broadest or least specific) of the [ISO
3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) code.  
X-Loc-State-Name| false| State Name|  The name of the client’s state/region.
The region is the first-level subdivision (the broadest or least specific) of
the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) code.  
X-Loc-Country| false| Country Code|  The two letter code for the client’s
country. For a list of country codes, see [ISO 3166-1
alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)  
X-Loc-Postal-Code| false| Postal Code|  The postal code of the client’s
location.  
X-Subscription-Token| true| Authentication token|  The secret token for the
subscribed plan to authenticate the request. Can be obtained from [API
Keys](/app/keys).  
  
#### # Local Search API Request Headers

This table lists the request headers supported by the Local Search API, most
of which are optional.

Header| Required| Name| Description  
---|---|---|---  
Accept| false| Accept|  The default supported media type is `application/json`  
Accept-Encoding| false| Accept Encoding|  The supported compression type is
`gzip`.  
Api-Version| false| Web Search API Version|  The Brave Web Search API version
to use. This is denoted by the format `YYYY-MM-DD`. The latest version is used
by default, and the previous ones can be found in the [API Changelog](./api-
changelog).  
Cache-Control| false| Cache Control|  Search will return cached web search
results by default. To prevent caching set the Cache-Control header to `no-
cache`. This is currently done as best effort.  
User-Agent| false| User Agent|  The user agent of the client sending the
request. Search can utilize the user agent to provide a different experience
depending on the client sending the request. The user agent should follow the
commonly used browser agent strings on each platform. For more information on
curating user agents, see [RFC 9110](https://www.rfc-
editor.org/rfc/rfc9110.html#name-user-agent). User agent string examples by
platform:

  * **Android** : Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36
  * **iOS** : Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1
  * **macOS** : Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
  * **Windows** : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/

  
X-Subscription-Token| true| Authentication token|  The secret token for the
subscribed plan to authenticate the request. Can be obtained from [API
Keys](/app/keys).

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Web Search API

## Response Headers

#### Global

This table lists the response headers supported by the Web Search API.

Header| Name| Description  
---|---|---  
X-RateLimit-Limit| Rate Limit|  Rate limits associated with the requested
plan. An example rate limit `X-RateLimit-Limit: 1, 15000` means 1 request per
second and 15000 requests per month.  
X-RateLimit-Policy| Rate Limit Policy|  Rate limit policies currently
associated with the requested plan. An example policy `X-RateLimit-Policy:
1;w=1, 15000;w=2592000` means a limit of 1 request over a 1 second window and
15000 requests over a month window. The windows are always given in seconds.  
X-RateLimit-Remaining| Rate Limit Remaining|  Remaining quota units associated
with the expiring limits. An example remaining limit `X-RateLimit-Remaining:
1, 1000` indicates the API is able to be accessed once during the current
second, and 1000 times over the current month. **Note** : Only successful
requests are counted and billed.  
X-RateLimit-Reset| Rate Limit Reset|  The number of seconds until the quota
associated with the expiring limits resets. An example reset limit
`X-RateLimit-Reset: 1, 1419704` means a single request can be done again in a
second and in 1419704 seconds the full monthly quota associated with the plan
will be available again.

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard)

[![Brave](https://cdn.search.brave.com/search-
api/web/v1/client/_app/immutable/assets/brave-
logo.BytqdRrN.svg)](/app/dashboard) [ Documentation](/app/documentation)

[ Web Search](/app/documentation/web-search)

[ Get Started](/app/documentation/web-search/get-started)[ Query
Parameters](/app/documentation/web-search/query)[ Request
Headers](/app/documentation/web-search/request-headers)[ Response
Headers](/app/documentation/web-search/response-headers)[ Response
Objects](/app/documentation/web-search/responses)[
Codes](/app/documentation/web-search/codes)[ API
Changelog](/app/documentation/web-search/api-changelog)

[ Summarizer Search](/app/documentation/summarizer-search) [ Image
Search](/app/documentation/image-search) [ Video
Search](/app/documentation/video-search) [ News
Search](/app/documentation/news-search) [ Suggest](/app/documentation/suggest)
[ Spellcheck](/app/documentation/spellcheck) [
General](/app/documentation/general)

[Login](/login) [Register](/register)

###### Brave Web Search API

## Response Objects

#### # WebSearchApiResponse

Top level response model for successful Web Search API requests. The response
will include the relevant keys based on the plan subscribed, query relevance
or applied result_filter as a query parameter. The API can also respond back
with an error response based on invalid subscription keys and rate limit
events.

Field| Type| Required| Description  
---|---|---|---  
type| "search"| true|  The type of web search API result. The value is always
search.  
discussions| Discussions| false|  Discussions clusters aggregated from forum
posts that are relevant to the query.  
faq| FAQ| false|  Frequently asked questions that are relevant to the search
query.  
infobox| GraphInfobox| false|  Aggregated information on an entity showable as
an infobox.  
locations| Locations| false|  Places of interest (POIs) relevant to location
sensitive queries.  
mixed| MixedResponse| false|  Preferred ranked order of search results.  
news| News| false|  News results relevant to the query.  
query| Query| false|  Search query string and its modifications that are used
for search.  
videos| Videos| false|  Videos relevant to the query.  
web| Search| false|  Web search results relevant to the query.  
summarizer| Summarizer| false|  Summary key to get summary results for the
query.  
  
#### # LocalPoiSearchApiResponse

Top level response model for successful Local Search API request to get extra
information for locations. The response will include a list of location
results corresponding to the ids in the request. The API can also respond back
with an error response in cases like too many ids being requested, invalid
subscription keys, and rate limit events. Access to Local Search API requires
a subscription to a Pro plan.

Field| Type| Required| Description  
---|---|---|---  
type| "local_pois"| true|  The type of local POI search API result. The value
is always local_pois.  
results| list [ LocationResult ]| false|  Location results matching the ids in
the request.  
  
#### # LocalDescriptionsSearchApiResponse

Top level response model for successful Local Search API request to get AI
generated description for locations. The response includes a list of generated
descriptions corresponding to the ids in the request. The API can also respond
back with an error response in cases like too many ids being requested,
invalid subscription keys, and rate limit events. Access to Local Search API
requires a subscription to a Pro plan.

Field| Type| Required| Description  
---|---|---|---  
type| "local_descriptions"| true|  The type of local description search API
result. The value is always local_descriptions.  
results| list [ LocationDescription ]| false|  Location descriptions matching
the ids in the request.  
  
#### # Query

A model representing information gathered around the requested query.

Field| Type| Required| Description  
---|---|---|---  
original| string| true|  The original query that was requested.  
show_strict_warning| bool| false|  Whether there is more content available for
query, but the response was restricted due to safesearch.  
altered| string| false|  The altered query for which the search was performed.  
safesearch| bool| false|  Whether safesearch was enabled.  
is_navigational| bool| false|  Whether the query is a navigational query to a
domain.  
is_geolocal| bool| false|  Whether the query has location relevance.  
local_decision| string| false|  Whether the query was decided to be location
sensitive.  
local_locations_idx| int| false|  The index of the location.  
is_trending| bool| false|  Whether the query is trending.  
is_news_breaking| bool| false|  Whether the query has news breaking articles
relevant to it.  
ask_for_location| bool| false|  Whether the query requires location
information for better results.  
language| Language| false|  The language information gathered from the query.  
spellcheck_off| bool| false|  Whether the spellchecker was off.  
country| string| false|  The country that was used.  
bad_results| bool| false|  Whether there are bad results for the query.  
should_fallback| bool| false|  Whether the query should use a fallback.  
lat| string| false|  The gathered location latitutde associated with the
query.  
long| string| false|  The gathered location longitude associated with the
query.  
postal_code| string| false|  The gathered postal code associated with the
query.  
city| string| false|  The gathered city associated with the query.  
state| string| false|  The gathered state associated with the query.  
header_country| string| false|  The country for the request origination.  
more_results_available| bool| false|  Whether more results are available for
the given query.  
custom_location_label| string| false|  Any custom location labels attached to
the query.  
reddit_cluster| string| false|  Any reddit cluster associated with the query.  
  
#### # Discussions

A model representing a discussion cluster relevant to the query.

Field| Type| Required| Description  
---|---|---|---  
type| "search"| true|  The type identifying a discussion cluster. Currently
the value is always search.  
results| list [ DiscussionResult ]| true|  A list of discussion results.  
mutated_by_goggles| bool| true|  Whether the discussion results are changed by
a Goggle. False by default.  
  
#### # DiscussionResult (SearchResult)

A discussion result. These are forum posts and discussions that are relevant
to the search query.

Field| Type| Required| Description  
---|---|---|---  
type| "discussion"| true|  The discussion result type identifier. The value is
always discussion.  
data| ForumData| false|  The enriched aggregated data for the relevant forum
post.  
  
#### # ForumData

Defines a result from a discussion forum.

Field| Type| Required| Description  
---|---|---|---  
forum_name| string| true|  The name of the forum.  
num_answers| int| false|  The number of answers to the post.  
score| string| false|  The score of the post on the forum.  
title| string| false|  The title of the post on the forum.  
question| string| false|  The question asked in the forum post.  
top_comment| string| false|  The top-rated comment under the forum post.  
  
#### # FAQ

Frequently asked questions relevant to the search query term.

Field| Type| Required| Description  
---|---|---|---  
type| "faq"| true|  The FAQ result type identifier. The value is always faq.  
results| list [ QA ]| true|  A list of aggregated question answer results
relevant to the query.  
  
#### # QA

A question answer result.

Field| Type| Required| Description  
---|---|---|---  
question| string| true|  The question being asked.  
answer| string| true|  The answer to the question.  
title| string| true|  The title of the post.  
url| string| true|  The url pointing to the post.  
meta_url| MetaUrl| false|  Aggregated information about the url.  
  
#### # MetaUrl

Aggregated information about a url.

Field| Type| Required| Description  
---|---|---|---  
scheme| string| true|  The protocol scheme extracted from the url.  
netloc| string| true|  The network location part extracted from the url.  
hostname| string| false|  The lowercased domain name extracted from the url.  
favicon| string| true|  The favicon used for the url.  
path| string| true|  The hierarchical path of the url useful as a display
string.  
  
#### # Search

A model representing a collection of web search results.

Field| Type| Required| Description  
---|---|---|---  
type| "search"| true|  A type identifying web search results. The value is
always search.  
results| list [ SearchResult ]| true|  A list of search results.  
family_friendly| bool| true|  Whether the results are family friendly.  
  
#### # SearchResult (Result)

Aggregated information on a web search result, relevant to the query.

Field| Type| Required| Description  
---|---|---|---  
type| "search_result"| true|  A type identifying a web search result. The
value is always search_result.  
subtype| "generic"| true|  A sub type identifying the web search result type.  
is_live| bool| true|  Whether the web search result is currently live. Default
value is False.  
deep_results| DeepResult| false|  Gathered information on a web search result.  
schemas| list [ list ]| false|  A list of schemas (structured data) extracted
from the page. The schemas try to follow
[schema.org](https://schema.org/docs/schemas.html) and will return anything we
can extract from the HTML that can fit into these models.  
meta_url| MetaUrl| false|  Aggregated information on the url associated with
the web search result.  
thumbnail| Thumbnail| false|  The thumbnail of the web search result.  
age| string| false|  A string representing the age of the web search result.  
language| string| true|  The main language on the web search result.  
location| LocationResult| false|  The location details if the query relates to
a restaurant.  
video| VideoData| false|  The video associated with the web search result.  
movie| MovieData| false|  The movie associated with the web search result.  
faq| FAQ| false|  Any frequently asked questions associated with the web
search result.  
qa| QAPage| false|  Any question answer information associated with the web
search result page.  
book| Book| false|  Any book information associated with the web search result
page.  
rating| Rating| false|  Rating found for the web search result page.  
article| Article| false|  An article found for the web search result page.  
product| ProductReview| false|  The main product and a review that is found on
the web search result page.  
product_cluster| list [ ProductReview ]| false|  A list of products and
reviews that are found on the web search result page.  
cluster_type| string| false|  A type representing a cluster. The value can be
product_cluster.  
cluster| list [ Result ]| false|  A list of web search results.  
creative_work| CreativeWork| false|  Aggregated information on the creative
work found on the web search result.  
music_recording| MusicRecording| false|  Aggregated information on music
recording found on the web search result.  
review| Review| false|  Aggregated information on the review found on the web
search result.  
software| Software| false|  Aggregated information on a software product found
on the web search result page.  
recipe| Recipe| false|  Aggregated information on a recipe found on the web
search result page.  
organization| Organization| false|  Aggregated information on a organization
found on the web search result page.  
content_type| string| false|  The content type associated with the search
result page.  
extra_snippets| list [ string ]| false|  A list of extra alternate snippets
for the web search result.  
  
#### # Result

A model representing a web search result.

Field| Type| Required| Description  
---|---|---|---  
title| string| true|  The title of the web page.  
url| string| true|  The url where the page is served.  
is_source_local| bool| true|  
is_source_both| bool| true|  
description| string| false|  A description for the web page.  
page_age| string| false|  A date representing the age of the web page.  
page_fetched| string| false|  A date representing when the web page was last
fetched.  
profile| Profile| false|  A profile associated with the web page.  
language| string| false|  A language classification for the web page.  
family_friendly| bool| true|  Whether the web page is family friendly.  
  
#### # AbstractGraphInfobox (Result)

Shared aggregated information on an entity from a knowledge graph.

Field| Type| Required| Description  
---|---|---|---  
type| "infobox"| true|  The infobox result type identifier. The value is
always infobox.  
position| int| true|  The position on a search result page.  
label| string| false|  Any label associated with the entity.  
category| string| false|  Category classification for the entity.  
long_desc| string| false|  A longer description for the entity.  
thumbnail| Thumbnail| false|  The thumbnail associated with the entity.  
attributes| list [ list [ string ] ]| false|  A list of attributes about the
entity.  
profiles| list [ Profile ] | list [ DataProvider ]| false|  The profiles associated with the entity.  
website_url| string| false|  The official website pertaining to the entity.  
ratings| list [ Rating ]| false|  Any ratings given to the entity.  
providers| list [ DataProvider ]| false|  A list of data sources for the
entity.  
distance| Unit| false|  A unit representing quantity relevant to the entity.  
images| list [ Thumbnail ]| false|  A list of images relevant to the entity.  
movie| MovieData| false|  Any movie data relevant to the entity. Appears only
when the result is a movie.  
  
#### # GenericInfobox (AbstractGraphInfobox)

Aggregated information on a generic entity from a knowledge graph.

Field| Type| Required| Description  
---|---|---|---  
subtype| "generic"| true|  The infobox subtype identifier. The value is always
generic.  
found_in_urls| list [ string ]| false|  List of urls where the entity was
found.  
  
#### # EntityInfobox (AbstractGraphInfobox)

Aggregated information on an entity from a knowledge graph.

Field| Type| Required| Description  
---|---|---|---  
subtype| "entity"| true|  The infobox subtype identifier. The value is always
entity.  
  
#### # QAInfobox (AbstractGraphInfobox)

A question answer infobox.

Field| Type| Required| Description  
---|---|---|---  
subtype| "code"| true|  The infobox subtype identifier. The value is always
code.  
data| QAPage| true|  The question and relevant answer.  
meta_url| MetaUrl| false|  Detailed information on the page containing the
question and relevant answer.  
  
#### # InfoboxWithLocation (AbstractGraphInfobox)

An infobox with location.

Field| Type| Required| Description  
---|---|---|---  
subtype| "location"| true|  The infobox subtype identifier. The value is
always location.  
is_location| bool| true|  Whether the entity a location.  
coordinates| list [ float ]| false|  The coordinates of the location.  
zoom_level| int| true|  The map zoom level.  
location| LocationResult| false|  The location result.  
  
#### # InfoboxPlace (AbstractGraphInfobox)

An infobox for a place, such as a business.

Field| Type| Required| Description  
---|---|---|---  
subtype| "place"| true|  The infobox subtype identifier. The value is always
place.  
location| LocationResult| true|  The location result.  
  
#### # GraphInfobox

Aggregated information on an entity shown as an infobox.

Field| Type| Required| Description  
---|---|---|---  
type| "graph"| true|  The type identifier for infoboxes. The value is always
graph.  
results| GenericInfoboxQAInfoboxInfoboxPlaceInfoboxWithLocationEntityInfobox|
true|  A list of infoboxes associated with the query.  
  
#### # QAPage

Aggreated result from a question answer page.

Field| Type| Required| Description  
---|---|---|---  
question| string| true|  The question that is being asked.  
answer| Answer| true|  An answer to the question.  
  
#### # Answer

A response representing an answer to a question on a forum.

Field| Type| Required| Description  
---|---|---|---  
text| string| true|  The main content of the answer.  
author| string| false|  The name of the author of the answer.  
upvoteCount| int| false|  Number of upvotes on the answer.  
downvoteCount| int| false|  The number of downvotes on the answer.  
  
#### # Thumbnail

Aggregated details representing a picture thumbnail.

Field| Type| Required| Description  
---|---|---|---  
src| string| true|  The served url of the picture thumbnail.  
original| string| false|  The original url of the image.  
  
#### # LocationWebResult (Result)

A model representing a web result related to a location.

Field| Type| Required| Description  
---|---|---|---  
meta_url| MetaUrl| true|  Aggregated information about the url.  
  
#### # LocationResult (Result)

A result that is location relevant.

Field| Type| Required| Description  
---|---|---|---  
type| "location_result"| true|  Location result type identifier. The value is
always location_result.  
id| string| false|  A Temporary id associated with this result, which can be
used to retrieve extra information about the location. It remains valid for 8
hours…  
provider_url| string| true|  The complete url of the provider.  
coordinates| list [ float ]| false|  A list of coordinates associated with the
location. This is a lat long represented as a floating point.  
zoom_level| int| true|  The zoom level on the map.  
thumbnail| Thumbnail| false|  The thumbnail associated with the location.  
postal_address| PostalAddress| false|  The postal address associated with the
location.  
opening_hours| OpeningHours| false|  The opening hours, if it is a business,
associated with the location .  
contact| Contact| false|  The contact of the business associated with the
location.  
price_range| string| false|  A display string used to show the price
classification for the business.  
rating| Rating| false|  The ratings of the business.  
distance| Unit| false|  The distance of the location from the client.  
profiles| list [ DataProvider ]| false|  Profiles associated with the
business.  
reviews| Reviews| false|  Aggregated reviews from various sources relevant to
the business.  
pictures| PictureResults| false|  A bunch of pictures associated with the
business.  
action| Action| false|  An action to be taken.  
serves_cuisine| list [ string ]| false|  A list of cuisine categories served.  
categories| list [ string ]| false|  A list of categories.  
icon_category| string| false|  An icon category.  
results| LocationWebResult| false|  Web results related to this location.  
timezone| string| false|  IANA timezone identifier.  
timezone_offset| string| false|  The utc offset of the timezone.  
  
#### # LocationDescription

AI generated description of a location result.

Field| Type| Required| Description  
---|---|---|---  
type| "local_description"| true|  The type of a location description. The
value is always local_description.  
id| string| true|  A Temporary id of the location with this description.  
description| string| false|  AI generated description of the location with the
given id.  
  
#### # Locations

A model representing location results.

Field| Type| Required| Description  
---|---|---|---  
type| "locations"| true|  Location type identifier. The value is always
locations.  
results| list [ LocationResult ]| true|  An aggregated list of location
sensitive results.  
  
#### # MixedResponse

The ranking order of results on a search result page.

Field| Type| Required| Description  
---|---|---|---  
type| "mixed"| true|  The type representing the model mixed. The value is
always mixed.  
main| list [ ResultReference ]| false|  The ranking order for the main section
of the search result page.  
top| list [ ResultReference ]| false|  The ranking order for the top section
of the search result page.  
side| list [ ResultReference ]| false|  The ranking order for the side section
of the search result page.  
  
#### # ResultReference

The ranking order of results on a search result page.

Field| Type| Required| Description  
---|---|---|---  
type| string| true|  The type of the result.  
index| int| false|  The 0th based index where the result should be placed.  
all| bool| true|  Whether to put all the results from the type at specific
position.  
  
#### # Videos

A model representing video results.

Field| Type| Required| Description  
---|---|---|---  
type| videos| true|  The type representing the videos. The value is always
videos.  
results| list [ VideoResult ]| true|  A list of video results.  
mutated_by_goggles| bool| false|  Whether the video results are changed by a
Goggle. False by default.  
  
#### # News

A model representing news results.

Field| Type| Required| Description  
---|---|---|---  
type| news| true|  The type representing the news. The value is always news.  
results| list [ NewsResult ]| true|  A list of news results.  
mutated_by_goggles| bool| false|  Whether the news results are changed by a
Goggle. False by default.  
  
#### # NewsResult (Result)

A model representing news results.

Field| Type| Required| Description  
---|---|---|---  
meta_url| MetaUrl| false|  The aggregated information on the url representing
a news result  
source| string| false|  The source of the news.  
breaking| bool| true|  Whether the news result is currently a breaking news.  
is_live| bool| true|  Whether the news result is currently live.  
thumbnail| Thumbnail| false|  The thumbnail associated with the news result.  
age| string| false|  A string representing the age of the news article.  
extra_snippets| list [ string ]| false|  A list of extra alternate snippets
for the news search result.  
  
#### # PictureResults

A model representing a list of pictures.

Field| Type| Required| Description  
---|---|---|---  
viewMoreUrl| string| false|  A url to view more pictures.  
results| list [ Thumbnail ]| true|  A list of thumbnail results.  
  
#### # Action

A model representing an action to be taken.

Field| Type| Required| Description  
---|---|---|---  
type| string| true|  The type representing the action.  
url| string| true|  A url representing the action to be taken.  
  
#### # PostalAddress

A model representing a postal address of a location

Field| Type| Required| Description  
---|---|---|---  
type| "PostalAddress"| true|  The type identifying a postal address. The value
is always PostalAddress.  
country| string| false|  The country associated with the location.  
postalCode| string| false|  The postal code associated with the location.  
streetAddress| string| false|  The street address associated with the
location.  
addressRegion| string| false|  The region associated with the location. This
is usually a state.  
addressLocality| string| false|  The address locality or subregion associated
with the location.  
displayAddress| string| true|  The displayed address string.  
  
#### # OpeningHours

Opening hours of a bussiness at a particular location.

Field| Type| Required| Description  
---|---|---|---  
current_day| list [ DayOpeningHours ]| false|  The current day opening hours.
Can have two sets of opening hours.  
days| list [ list [ DayOpeningHours ] ]| false|  The opening hours for the
whole week.  
  
#### # DayOpeningHours

A model representing the opening hours for a particular day for a business at
a particular location.

Field| Type| Required| Description  
---|---|---|---  
abbr_name| string| true|  A short string representing the day of the week.  
full_name| string| true|  A full string representing the day of the week.  
opens| string| true|  A 24 hr clock time string for the opening time of the
business on a particular day.  
closes| string| true|  A 24 hr clock time string for the closing time of the
business on a particular day.  
  
#### # Contact

A model representing contact information for an entity.

Field| Type| Required| Description  
---|---|---|---  
email| string| false|  The email address.  
telephone| string| false|  The telephone number.  
  
#### # DataProvider

A model representing the data provider associated with the entity.

Field| Type| Required| Description  
---|---|---|---  
type| "external"| true|  The type representing the source of data. This is
usually external.  
name| string| true|  The name of the data provider. This can be a domain.  
url| string| true|  The url where the information is coming from.  
long_name| string| false|  The long name for the data provider.  
img| string| false|  The served url for the image data.  
  
#### # Profile

A profile of an entity.

Field| Type| Required| Description  
---|---|---|---  
name| string| true|  The name of the profile.  
long_name| string| true|  The long name of the profile.  
url| string| false|  The original url where the profile is available.  
img| string| false|  The served image url representing the profile.  
  
#### # Unit

A model representing a unit of measurement.

Field| Type| Required| Description  
---|---|---|---  
value| float| true|  The quantity of the unit.  
units| string| true|  The name of the unit associated with the quantity.  
  
#### # MovieData

Aggregated data for a movie result.

Field| Type| Required| Description  
---|---|---|---  
name| string| false|  Name of the movie.  
description| string| false|  A short plot summary for the movie.  
url| string| false|  A url serving a movie profile page.  
thumbnail| Thumbnail| false|  A thumbnail for a movie poster.  
release| string| false|  The release date for the movie.  
directors| list [ Person ]| false|  A list of people responsible for directing
the movie.  
actors| list [ Person ]| false|  A list of actors in the movie.  
rating| Rating| false|  Rating provided to the movie from various sources.  
duration| string| false|  The runtime of the movie. The format is HH:MM:SS.  
genre| list [ string ]| false|  List of genres in which the movie can be
classified.  
query| string| false|  The query that resulted in the movie result.  
  
#### # Thing

A model describing a generic thing.

Field| Type| Required| Description  
---|---|---|---  
type| "thing"| true|  A type identifying a thing. The value is always thing.  
name| string| true|  The name of the thing.  
url| string| false|  A url for the thing.  
thumbnail| Thumbnail| false|  Thumbnail associated with the thing.  
  
#### # Person (Thing)

A model describing a person entity.

Field| Type| Required| Description  
---|---|---|---  
type| "person"| true|  A type identifying a person. The value is always
person.  
  
#### # Rating

The rating associated with an entity.

Field| Type| Required| Description  
---|---|---|---  
ratingValue| float| true|  The current value of the rating.  
bestRating| float| true|  Best rating received.  
reviewCount| int| false|  The number of reviews associated with the rating.  
profile| Profile| false|  The profile associated with the rating.  
is_tripadvisor| bool| true|  Whether the rating is coming from Tripadvisor.  
  
#### # Book

A model representing a book result.

Field| Type| Required| Description  
---|---|---|---  
title| string| true|  The title of the book.  
author| list [ Person ]| true|  The author of the book.  
date| string| false|  The publishing date of the book.  
price| Price| false|  The price of the book.  
pages| int| false|  The number of pages in the book.  
publisher| Person| false|  The publisher of the book.  
rating| Rating| false|  A gathered rating from different sources associated
with the book.  
  
#### # Price

A model representing the price for an entity.

Field| Type| Required| Description  
---|---|---|---  
price| string| true|  The price value in a given currency.  
price_currency| string| true|  The current of the price value.  
  
#### # Article

A model representing an article.

Field| Type| Required| Description  
---|---|---|---  
author| list [ Person ]| false|  The author of the article.  
date| string| false|  The date when the article was published.  
publisher| Organization| false|  The name of the publisher for the article.  
thumbnail| Thumbnail| false|  A thumbnail associated with the article.  
isAccessibleForFree| bool| false|  Whether the article is free to read or is
behind a paywall.  
  
#### # ContactPoint (Thing)

A way to contact an entity.

Field| Type| Required| Description  
---|---|---|---  
type| "contact_point"| true|  A type string identifying a contact point. The
value is always contact_point.  
telephone| string| false|  The telephone number of the entity.  
email| string| false|  The email address of the entity.  
  
#### # Organization (Thing)

An entity responsible for another entity.

Field| Type| Required| Description  
---|---|---|---  
type| "organization"| true|  A type string identifying an organization. The
value is always organization.  
contact_points| list [ ContactPoint ]| false|  A list of contact points for
the organization.  
  
#### # HowTo

Aggregated information on a how to.

Field| Type| Required| Description  
---|---|---|---  
text| string| true|  The how to text.  
name| string| false|  A name for the how to.  
url| string| false|  A url associated with the how to.  
image| list [ string ]| false|  A list of image urls associated with the how
to.  
  
#### # Recipe

Aggregated information on a recipe.

Field| Type| Required| Description  
---|---|---|---  
title| string| true|  The title of the recipe.  
description| string| true|  The description of the recipe.  
thumbnail| Thumbnail| true|  A thumbnail associated with the recipe.  
url| string| true|  The url of the web page where the recipe was found.  
domain| string| true|  The domain of the web page where the recipe was found.  
favicon| string| true|  The url for the favicon of the web page where the
recipe was found.  
time| string| false|  The total time required to cook the recipe.  
prep_time| string| false|  The preparation time for the recipe.  
cook_time| string| false|  The cooking time for the recipe.  
ingredients| string| false|  Ingredients required for the recipe.  
instructions| list [ HowTo ]| false|  List of instructions for the recipe.  
servings| int| false|  How many people the recipe serves.  
calories| int| false|  Calorie count for the recipe.  
rating| Rating| false|  Aggregated information on the ratings associated with
the recipe.  
recipeCategory| string| false|  The category of the recipe.  
recipeCuisine| string| false|  The cuisine classification for the recipe.  
video| VideoData| false|  Aggregated information on the cooking video
associated with the recipe.  
  
#### # Product

A model representing a product.

Field| Type| Required| Description  
---|---|---|---  
type| "Product"| true|  A string representing a product type. The value is
always product.  
name| string| true|  The name of the product.  
category| string| false|  The category of the product.  
price| string| true|  The price of the product.  
thumbnail| Thumbnail| true|  A thumbnail associated with the product.  
description| string| false|  The description of the product.  
offers| list [ Offer ]| false|  A list of offers available on the product.  
rating| Rating| false|  A rating associated with the product.  
  
#### # Offer

An offer associated with a product.

Field| Type| Required| Description  
---|---|---|---  
url| string| true|  The url where the offer can be found.  
priceCurrency| string| true|  The currency in which the offer is made.  
price| string| true|  The price of the product currently on offer.  
  
#### # Review

A model representing a review for an entity.

Field| Type| Required| Description  
---|---|---|---  
type| "review"| true|  A string representing review type. This is always
review.  
name| string| true|  The review title for the review.  
thumbnail| Thumbnail| true|  The thumbnail associated with the reviewer.  
description| string| true|  A description of the review (the text of the
review itself).  
rating| Rating| true|  The ratings associated with the review.  
  
#### # Reviews

The reviews associated with an entity.

Field| Type| Required| Description  
---|---|---|---  
results| list [ TripAdvisorReview ]| true|  A list of trip advisor reviews for
the entity.  
viewMoreUrl| string| true|  A url to a web page where more information on the
result can be seen.  
reviews_in_foreign_language| bool| true|  Any reviews available in a foreign
language.  
  
#### # TripAdvisorReview

A model representing a Tripadvisor review.

Field| Type| Required| Description  
---|---|---|---  
title| string| true|  The title of the review.  
description| string| true|  A description seen in the review.  
date| string| true|  The date when the review was published.  
rating| Rating| true|  A rating given by the reviewer.  
author| Person| true|  The author of the review.  
review_url| string| true|  A url link to the page where the review can be
found.  
language| string| true|  The language of the review.  
  
#### # CreativeWork

A creative work relevant to the query. An example can be enriched metadata for
an app.

Field| Type| Required| Description  
---|---|---|---  
name| string| true|  The name of the creative work.  
thumbnail| Thumbnail| true|  A thumbnail associated with the creative work.  
rating| Rating| false|  A rating that is given to the creative work.  
  
#### # MusicRecording

Result classified as a music label or a song.

Field| Type| Required| Description  
---|---|---|---  
name| string| true|  The name of the song or album.  
thumbnail| Thumbnail| false|  A thumbnail associated with the music.  
rating| Rating| false|  The rating of the music.  
  
#### # Software

A model representing a software entity.

Field| Type| Required| Description  
---|---|---|---  
name| string| false|  The name of the software product.  
author| string| false|  The author of software product.  
version| string| false|  The latest version of the software product.  
codeRepository| string| false|  The code repository where the software product
is currently available or maintained.  
homepage| string| false|  The home page of the software product.  
datePublisher| string| false|  The date when the software product was
published.  
is_npm| bool| false|  Whether the software product is available on npm.  
is_pypi| bool| false|  Whether the software product is available on pypi.  
stars| int| false|  The number of stars on the repository.  
forks| int| false|  The numbers of forks of the repository.  
ProgrammingLanguage| string| false|  The programming language spread on the
software product.  
  
#### # DeepResult

Aggregated deep results from news, social, videos and images.

Field| Type| Required| Description  
---|---|---|---  
news| list [ NewsResult ]| false|  A list of news results associated with the
result.  
buttons| list [ ButtonResult ]| false|  A list of buttoned results associated
with the result.  
videos| list [ VideoResult ]| false|  Videos associated with the result.  
images| list [ Image ]| false|  Images associated with the result.  
  
#### # VideoResult (Result)

A model representing a video result.

Field| Type| Required| Description  
---|---|---|---  
type| "video_result"| true|  The type identifying the video result. The value
is always video_result.  
video| VideoData| true|  Meta data for the video.  
meta_url| MetaUrl| false|  Aggregated information on the URL  
thumbnail| Thumbnail| false|  The thumbnail of the video.  
age| string| false|  A string representing the age of the video.  
  
#### # VideoData

A model representing metadata gathered for a video.

Field| Type| Required| Description  
---|---|---|---  
duration| string| false|  A time string representing the duration of the
video. The format can be HH:MM:SS or MM:SS.  
views| string| false|  The number of views of the video.  
creator| string| false|  The creator of the video.  
publisher| string| false|  The publisher of the video.  
thumbnail| Thumbnail| false|  A thumbnail associated with the video.  
tags| list [ string ]| false|  A list of tags associated with the video.  
author| Profile| false|  Author of the video.  
requires_subscription| bool| false|  Whether the video requires a subscription
to watch.  
  
#### # ButtonResult

A result which can be used as a button.

Field| Type| Required| Description  
---|---|---|---  
type| "button_result"| true|  A type identifying button result. The value is
always button_result.  
title| string| true|  The title of the result.  
url| string| true|  The url for the button result.  
  
#### # Image

A model describing an image

Field| Type| Required| Description  
---|---|---|---  
thumbnail| Thumbnail| true|  The thumbnail associated with the image.  
url| string| false|  The url of the image.  
properties| ImageProperties| false|  Metadata on the image.  
  
#### # Language

A model representing a language.

Field| Type| Required| Description  
---|---|---|---  
main| string| true|  The main language seen in the string.  
  
#### # ImageProperties

Metadata on an image.

Field| Type| Required| Description  
---|---|---|---  
url| string| true|  The original image URL.  
resized| string| true|  The url for a better quality resized image.  
placeholder| string| true|  The placeholder image url.  
height| int| false|  The image height.  
width| int| false|  The image width.  
format| string| false|  The image format.  
content_size| string| false|  The image size.  
  
#### # Summarizer

Details on getting the summary.

Field| Type| Required| Description  
---|---|---|---  
type| "summarizer"| true|  The value is always summarizer.  
key| string| true|  The key for the summarizer API.

================
File: resources/pplx/pplx_urls.txt
================
https://docs.perplexity.ai/guides/getting-started
https://docs.perplexity.ai/guides/model-cards
https://docs.perplexity.ai/guides/pricing
https://docs.perplexity.ai/guides/structured-outputs
https://docs.perplexity.ai/guides/prompt-guide
https://docs.perplexity.ai/guides/bots
https://docs.perplexity.ai/api-reference/chat-completions

================
File: resources/pplx/pplx.md
================
[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Initial Setup

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Initial Setup

Register and make a successful API request

##

​

Registration

  * Start by visiting the [API Settings page](https://www.perplexity.ai/pplx-api)

  * Register your credit card to get started

This step will not charge your credit card. It just stores payment information
for later API usage.

##

​

Generate an API key

  * Every API call needs a valid API key

The API key is a long-lived access token that can be used until it is manually
refreshed or deleted.

Send the API key as a bearer token in the Authorization header with each API
request.

When you run out of credits, your API keys will be blocked until you add to
your credit balance. You can avoid this by configuring “Automatic Top Up”,
which refreshes your balance whenever you drop below $2.

##

​

Make your API call

  * The API is conveniently OpenAI client-compatible for easy integration with existing applications.

cURL

    
    
    curl --location 'https://api.perplexity.ai/chat/completions' \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --header 'Authorization: Bearer {API_KEY}' \
    --data '{
      "model": "sonar-pro ",
      "messages": [
        {
          "role": "system",
          "content": "Be precise and concise."
        },
        {
          "role": "user",
          "content": "How many stars are there in our galaxy?"
        }
      ]
    }'
    

python

    
    
    from openai import OpenAI
    
    YOUR_API_KEY = "INSERT API KEY HERE"
    
    messages = [
        {
            "role": "system",
            "content": (
                "You are an artificial intelligence assistant and you need to "
                "engage in a helpful, detailed, polite conversation with a user."
            ),
        },
        {   
            "role": "user",
            "content": (
                "How many stars are in the universe?"
            ),
        },
    ]
    
    client = OpenAI(api_key=YOUR_API_KEY, base_url="https://api.perplexity.ai")
    
    # chat completion without streaming
    response = client.chat.completions.create(
        model="sonar-pro",
        messages=messages,
    )
    print(response)
    
    # chat completion with streaming
    response_stream = client.chat.completions.create(
        model="sonar-pro",
        messages=messages,
        stream=True,
    )
    for response in response_stream:
        print(response)
    

[Supported Models](/guides/model-cards)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

On this page

  * Registration
  * Generate an API key
  * Make your API call

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Supported Models

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Supported Models

Model| Context Length| Model Type  
---|---|---  
`sonar-deep-research`| 128k| Chat Completion  
`sonar-reasoning-pro`| 128k| Chat Completion  
`sonar-reasoning`| 128k| Chat Completion  
`sonar-pro`| 200k| Chat Completion  
`sonar`| 128k| Chat Completion  
`r1-1776`| 128k| Chat Completion  
  
  1. `sonar-reasoning-pro` and `sonar-pro` have a max output token limit of 8k
  2. The reasoning models output CoTs in their responses as well
  3. `r1-1776` is an offline chat model that does not use our search subsystem

[Initial Setup](/guides/getting-started)[Pricing](/guides/pricing)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Pricing

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Pricing

Model| Input Tokens (Per Million Tokens)| Reasoning Tokens (Per Million
Tokens)| Output Tokens (Per Million Tokens)| Price per 1000 searches  
---|---|---|---|---  
`sonar-deep-research`| $2| $3| $8| $5  
`sonar-reasoning-pro`| $2| -| $8| $5  
`sonar-reasoning`| $1| -| $5| $5  
`sonar-pro`| $3| -| $15| $5  
`sonar`| $1| -| $1| $5  
`r1-1776`| $2| -| $8| -  
  
`r1-1776` is an offline chat model that does not use our search subsystem

##

​

Pricing Breakdown

Detailed Pricing Breakdown for Sonar Deep Research

**Input Tokens**

  1. Input tokens are priced at $2/1M tokens

  2. Input tokens comprise of Prompt tokens (user prompt) + Citation tokens (these are processed tokens from running searches)

**Search Queries**

  1. Deep Research runs multiple searches to conduct exhaustive research

  2. Searches are priced at $5/1000 searches

  3. A request that does 30 searches will cost $0.15 in this step.

**Reasoning Tokens**

  1. Reasoning is a distinct step in Deep Research since it does extensive automated reasoning through all the material it gathers during its research phase

  2. Reasoning tokens here are a bit different than the CoTs in the answer - these are tokens that we use to reason through the research material prior to generating the outputs via the CoTs.

  3. Reasoning tokens are priced at $3/1M tokens

**Output Tokens**

  1. Output tokens (Completion tokens) are priced at $8/1M tokens

**Total Price**

Your total price per request finally is a sum of the above 4 components

Detailed Pricing Breakdown for Sonar Reasoning Pro and Sonar Pro

**Input Tokens**

  1. Input tokens are priced at $2/1M tokens and $3/1M tokens respectively

  2. Input tokens comprise of Prompt tokens (user prompt) + Citation tokens (these are processed tokens from running searches)

**Search Queries**

  1. To give detailed answers, both the Pro APIs also run multiple searches on top of the user prompt where necessary for more exhaustive information retrieval

  2. Searches are priced at $5/1000 searches

  3. A request that does 3 searches will cost $0.015 in this step

**Output Tokens**

  1. Output tokens (Completion tokens) are priced at $8/1M tokens and $15/1M tokens respectively

**Total Price**

Your total price per request finally is a sum of the above 3 components

Detailed Pricing Breakdown for Sonar Reasoning and Sonar

**Input Tokens**

  1. Input tokens are priced at $1/1M tokens for both

  2. Input tokens comprise of Prompt tokens (user prompt)

**Search Queries**

  1. Each request does 1 search priced at $5/1000 searches

**Output Tokens**

  1. Output tokens (Completion tokens) are priced at $5/1M tokens and $1/1M tokens respectively

**Total Price**

Your total price per request finally is a sum of the above 2 components

[Supported Models](/guides/model-cards)[Rate Limits and Usage
Tiers](/guides/usage-tiers)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Structured Outputs Guide

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Structured Outputs Guide

Structured outputs is currently a beta feature and only available to users in
Tier-3

##

​

Overview

We currently support two types of structured outputs: **JSON Schema** and
**Regex**. LLM responses will work to match the specified format, except for
the following cases:

  * The output exceeds `max_tokens`

Enabling the structured outputs can be done by adding a `response_format`
field in the request:

**JSON Schema**

  * `response_format: { type: "json_schema", json_schema: {"schema": object} }` .

  * The schema should be a valid JSON schema object.

**Regex** (only avilable for `sonar` right now)

  * `response_format: { type: "regex", regex: {"regex": str} }` .

  * The regex is a regular expression string.

We recommend to give the LLM some hints about the output format in the
prompts.

The first request with a new JSON Schema or Regex expects to incur delay on
the first token. Typically, it takes 10 to 30 seconds to prepare the new
schema. Once the schema has been prepared, the subsequent requests will not
see such delay.

##

​

Examples

###

​

1\. Get a response in JSON format

**Request**

python

    
    
    import requests
    from pydantic import BaseModel
    
    class AnswerFormat(BaseModel):
        first_name: str
        last_name: str
        year_of_birth: int
        num_seasons_in_nba: int
    
    url = "https://api.perplexity.ai/chat/completions"
    headers = {"Authorization": "Bearer YOUR_API_KEY"}
    payload = {
        "model": "sonar",
        "messages": [
            {"role": "system", "content": "Be precise and concise."},
            {"role": "user", "content": (
                "Tell me about Michael Jordan. "
                "Please output a JSON object containing the following fields: "
                "first_name, last_name, year_of_birth, num_seasons_in_nba. "
            )},
        ],
        "response_format": {
    		    "type": "json_schema",
            "json_schema": {"schema": AnswerFormat.model_json_schema()},
        },
    }
    response = requests.post(url, headers=headers, json=payload).json()
    print(response["choices"][0]["message"]["content"])
    

**Response**

    
    
    {"first_name":"Michael","last_name":"Jordan","year_of_birth":1963,"num_seasons_in_nba":15}
    

###

​

2\. Use a regex to output the format

**Request**

python

    
    
    import requests
    
    url = "https://api.perplexity.ai/chat/completions"
    headers = {"Authorization": "Bearer YOUR_API_KEY"}
    payload = {
        "model": "sonar",
        "messages": [
            {"role": "system", "content": "Be precise and concise."},
            {"role": "user", "content": "What is the IPv4 address of OpenDNS DNS server?"},
        ],
        "response_format": {
    		    "type": "regex",
            "regex": {"regex": r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"},
        },
    }
    response = requests.post(url, headers=headers, json=payload).json()
    print(response["choices"][0]["message"]["content"])
    

**Response**

    
    
    208.67.222.222
    

##

​

Best Practices

###

​

Generating responses in a JSON Format

For Python users, we recommend using the Pydantic library to [generate JSON
schema](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_json_schema).

**Unsupported JSON Schemas**

Recursive JSON schema is not supported. As a result of that, unconstrained
objects are not supported either. Here’s a few example of unsupported schemas:

    
    
    # UNSUPPORTED!
    
    from typing import Any
    
    class UnconstrainedDict(BaseModel):
       unconstrained: dict[str, Any]
    
    class RecursiveJson(BaseModel):
       value: str
       child: list["RecursiveJson"]
    

###

​

Generating responses using a regex

**Supported Regex**

  * Characters: `\d`, `\w`, `\s` , `.`
  * Character classes: `[0-9A-Fa-f]` , `[^x]`
  * Quantifiers: `*`, `?` , `+`, `{3}`, `{2,4}` , `{3,}`
  * Alternation: `|`
  * Group: `( ... )`
  * Non-capturing group: `(?: ... )`
  * Positive lookahead: `(?= ... )`
  * Negative lookahead: `(?! ... )`

**Unsupported Regex**

  * Contents of group: `\1`
  * Anchors: `^`, `$`, `\b`
  * Positive look-behind: `(?<= ... )`
  * Negative look-behind: `(?<! ... )`
  * Recursion: `(?R)`

[Rate Limits and Usage Tiers](/guides/usage-tiers)[Prompt
Guide](/guides/prompt-guide)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

On this page

  * Overview
  * Examples
  * 1\. Get a response in JSON format
  * 2\. Use a regex to output the format
  * Best Practices
  * Generating responses in a JSON Format
  * Generating responses using a regex

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Prompt Guide

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Prompt Guide

##

​

System Prompt

You can use the system prompt to provide instructions related to style, tone,
and language of the response.

The real-time search component of our models does not attend to the system
prompt.

**Example of a system prompt**

    
    
    You are a helpful AI assistant.
    
    Rules:
    1. Provide only the final answer. It is important that you do not include any explanation on the steps below.
    2. Do not show the intermediate steps information.
    
    Steps:
    1. Decide if the answer should be a brief sentence or a list of suggestions.
    2. If it is a list of suggestions, first, write a brief and natural introduction based on the original query.
    3. Followed by a list of suggestions, each suggestion should be split by two newlines.
    

##

​

User Prompt

You should use the user prompt to pass in the actual query for which you need
an answer for. The user prompt will be used to kick off a real-time web search
to make sure the answer has the latest and the most relevant information
needed.

**Example of a user prompt**

    
    
    What are the best sushi restaurants in the world currently?
    

[Structured Outputs Guide](/guides/structured-outputs)[Perplexity
Crawlers](/guides/bots)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Guides

Perplexity Crawlers

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Guides

  * [Initial Setup](/guides/getting-started)
  * [Supported Models](/guides/model-cards)
  * [Pricing](/guides/pricing)
  * [Rate Limits and Usage Tiers](/guides/usage-tiers)
  * [Structured Outputs Guide](/guides/structured-outputs)
  * [Prompt Guide](/guides/prompt-guide)
  * [Perplexity Crawlers](/guides/bots)

Guides

# Perplexity Crawlers

We strive to improve our service every day by delivering the best search
experience possible. To achieve this, we collect data using web crawlers
(“robots”) and user agents that gather and index information from the
internet, operating either automatically or in response to user requests.
Webmasters can use the following robots.txt tags to manage how their sites and
content interact with Perplexity. Each setting works independently, and it may
take up to 24 hours for our systems to reflect changes.

User Agent| Description  
---|---  
PerplexityBot| `PerplexityBot` is designed to surface and link websites in
search results on Perplexity. It is not used to crawl content for AI
foundation models. To ensure your site appears in search results, we recommend
allowing `PerplexityBot` in your site’s `robots.txt` file and permitting
requests from our published IP ranges listed below.  
  
Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko;
compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)`  
  
Published IP addresses: <https://www.perplexity.com/perplexitybot.json>  
Perplexity‑User| `Perplexity-User` supports user actions within Perplexity.
When users ask Perplexity a question, it might visit a web page to help
provide an accurate answer and include a link to the page in its response.
`Perplexity-User` controls which sites these user requests can access. It is
not used for web crawling or to collect content for training AI foundation
models.  
  
Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko;
compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)`  
  
Published IP addresses: <https://www.perplexity.com/perplexity-user.json>  
  
Since a user requested the fetch, this fetcher generally ignores robots.txt
rules.  
  
[Prompt Guide](/guides/prompt-guide)

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

[Perplexity home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/SonarByPerplexity.svg)![dark
logo](https://mintlify.s3.us-
west-1.amazonaws.com/perplexity/logo/Sonar_Wordmark_Light.svg)](/home.mdx)

Search docs

  * [Playground](https://labs.perplexity.ai/)
  * [Playground](https://labs.perplexity.ai/)

Search...

Navigation

Perplexity API

Chat Completions

[Home](/home)[Guides](/guides/getting-started)[API Reference](/api-
reference/chat-completions)[Changelog](/changelog/changelog)[System
Status](/system-status/system-
status)[FAQ](/faq/faq)[Discussions](/discussions/discussions)

##### Perplexity API

  * [POSTChat Completions](/api-reference/chat-completions)

Perplexity API

# Chat Completions

Generates a model’s response for the given chat conversation.

POST

/

chat

/

completions

Try it

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request POST \
      --url https://api.perplexity.ai/chat/completions \
      --header 'Authorization: Bearer <token>' \
      --header 'Content-Type: application/json' \
      --data '{
      "model": "sonar",
      "messages": [
        {
          "role": "system",
          "content": "Be precise and concise."
        },
        {
          "role": "user",
          "content": "How many stars are there in our galaxy?"
        }
      ],
      "max_tokens": 123,
      "temperature": 0.2,
      "top_p": 0.9,
      "search_domain_filter": null,
      "return_images": false,
      "return_related_questions": false,
      "search_recency_filter": "<string>",
      "top_k": 0,
      "stream": false,
      "presence_penalty": 0,
      "frequency_penalty": 1,
      "response_format": null
    }'

200

422

    
    
    {
      "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "model": "sonar",
      "object": "chat.completion",
      "created": 1724369245,
      "citations": [
        "https://www.astronomy.com/science/astro-for-kids-how-many-stars-are-there-in-space/",
        "https://www.esa.int/Science_Exploration/Space_Science/Herschel/How_many_stars_are_there_in_the_Universe",
        "https://www.space.com/25959-how-many-stars-are-in-the-milky-way.html",
        "https://www.space.com/26078-how-many-stars-are-there.html",
        "https://en.wikipedia.org/wiki/Milky_Way"
      ],
      "choices": [
        {
          "index": 0,
          "finish_reason": "stop",
          "message": {
            "role": "assistant",
            "content": "The number of stars in the Milky Way galaxy is estimated to be between 100 billion and 400 billion stars. The most recent estimates from the Gaia mission suggest that there are approximately 100 to 400 billion stars in the Milky Way, with significant uncertainties remaining due to the difficulty in detecting faint red dwarfs and brown dwarfs."
          },
          "delta": {
            "role": "assistant",
            "content": ""
          }
        }
      ],
      "usage": {
        "prompt_tokens": 14,
        "completion_tokens": 70,
        "total_tokens": 84
      }
    }

#### Authorizations

​

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is
your auth token.

#### Body

application/json

​

model

string

required

The name of the model that will complete your prompt. Refer to [Supported
Models](https://docs.perplexity.ai/guides/model-cards) to find all the models
offered.

​

messages

object[]

required

A list of messages comprising the conversation so far.

Show child attributes

​

messages.content

string

required

The contents of the message in this turn of conversation.

​

messages.role

enum<string>

required

The role of the speaker in this turn of conversation. After the (optional)
system message, user and assistant roles should alternate with `user` then
`assistant`, ending in `user`.

Available options:

`system`,

`user`,

`assistant`

​

max_tokens

integer

The maximum number of completion tokens returned by the API. The number of
tokens requested in `max_tokens` plus the number of prompt tokens sent in
messages must not exceed the context window token limit of model requested. If
left unspecified, then the model will generate tokens until either it reaches
its stop token or the end of its context window.

​

temperature

number

default:

0.2

The amount of randomness in the response, valued between 0 inclusive and 2
exclusive. Higher values are more random, and lower values are more
deterministic.

Required range: `0 < x < 2`

​

top_p

number

default:

0.9

The nucleus sampling threshold, valued between 0 and 1 inclusive. For each
subsequent token, the model considers the results of the tokens with top_p
probability mass. We recommend either altering top_k or top_p, but not both.

Required range: `0 < x < 1`

​

search_domain_filter

any[]

Given a list of domains, limit the citations used by the online model to URLs
from the specified domains. Currently limited to only 3 domains for
whitelisting and blacklisting. For **blacklisting** add a `-` to the beginning
of the domain string. **Only available in certain tiers** \- refer to our
usage tiers [here](https://docs.perplexity.ai/guides/usage-tiers).

​

return_images

boolean

default:

false

Determines whether or not a request to an online model should return images.
**Only available in certain tiers** \- refer to our usage tiers
[here](https://docs.perplexity.ai/guides/usage-tiers).

​

return_related_questions

boolean

default:

false

Determines whether or not a request to an online model should return related
questions.**Only available in certain tiers** \- refer to our usage tiers
[here](https://docs.perplexity.ai/guides/usage-tiers).

​

search_recency_filter

string

Returns search results within the specified time interval - does not apply to
images. Values include `month`, `week`, `day`, `hour`.

​

top_k

number

default:

0

The number of tokens to keep for highest top-k filtering, specified as an
integer between 0 and 2048 inclusive. If set to 0, top-k filtering is
disabled. We recommend either altering top_k or top_p, but not both.

Required range: `0 < x < 2048`

​

stream

boolean

default:

false

Determines whether or not to incrementally stream the response with [server-
sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-
sent_events/Using_server-sent_events#event_stream_format) with `content-type:
text/event-stream`.

​

presence_penalty

number

default:

0

A value between -2.0 and 2.0. Positive values penalize new tokens based on
whether they appear in the text so far, increasing the model's likelihood to
talk about new topics. Incompatible with `frequency_penalty`.

Required range: `-2 < x < 2`

​

frequency_penalty

number

default:

1

A multiplicative penalty greater than 0. Values greater than 1.0 penalize new
tokens based on their existing frequency in the text so far, decreasing the
model's likelihood to repeat the same line verbatim. A value of 1.0 means no
penalty. Incompatible with `presence_penalty`.

Required range: `x > 0`

​

response_format

object

Enable structured outputs with a JSON or Regex schema. Refer to the guide
[here](https://docs.perplexity.ai/guides/structured-outputs) for more
information on how to use this parameter. **Only available in certain tiers**
\- refer to our usage tiers [here](https://docs.perplexity.ai/guides/usage-
tiers).

#### Response

200

200422

application/json

application/jsontext/event-stream

OK

​

id

string

An ID generated uniquely for each response.

​

model

string

The model used to generate the response.

​

object

string

The object type, which always equals `chat.completion`.

​

created

integer

The Unix timestamp (in seconds) of when the completion was created.

​

citations

any[]

Citations for the generated answer.

​

choices

object[]

The list of completion choices the model generated for the input prompt.

Show child attributes

​

choices.index

integer

​

choices.finish_reason

enum<string>

The reason the model stopped generating tokens. Possible values include `stop`
if the model hit a natural stopping point, or `length` if the maximum number
of tokens specified in the request was reached.

Available options:

`stop`,

`length`

​

choices.message

object

The message generated by the model.

Show child attributes

​

choices.message.content

string

required

The contents of the message in this turn of conversation.

​

choices.message.role

enum<string>

required

The role of the speaker in this turn of conversation. After the (optional)
system message, user and assistant roles should alternate with `user` then
`assistant`, ending in `user`.

Available options:

`system`,

`user`,

`assistant`

​

choices.delta

object

The incrementally streamed next tokens. Only meaningful when `stream = true`.

Show child attributes

​

choices.delta.content

string

required

The contents of the message in this turn of conversation.

​

choices.delta.role

enum<string>

required

The role of the speaker in this turn of conversation. After the (optional)
system message, user and assistant roles should alternate with `user` then
`assistant`, ending in `user`.

Available options:

`system`,

`user`,

`assistant`

​

usage

object

Usage statistics for the completion request.

Show child attributes

​

usage.prompt_tokens

integer

The number of tokens provided in the request prompt.

​

usage.completion_tokens

integer

The number of tokens generated in the response output.

​

usage.total_tokens

integer

The total number of tokens used in the chat completion (prompt + completion).

[twitter](https://twitter.com/perplexity_ai)[linkedin](https://www.linkedin.com/company/perplexity-
ai/)[discord](https://discord.com/invite/perplexity-
ai)[website](https://labs.perplexity.ai/)

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request POST \
      --url https://api.perplexity.ai/chat/completions \
      --header 'Authorization: Bearer <token>' \
      --header 'Content-Type: application/json' \
      --data '{
      "model": "sonar",
      "messages": [
        {
          "role": "system",
          "content": "Be precise and concise."
        },
        {
          "role": "user",
          "content": "How many stars are there in our galaxy?"
        }
      ],
      "max_tokens": 123,
      "temperature": 0.2,
      "top_p": 0.9,
      "search_domain_filter": null,
      "return_images": false,
      "return_related_questions": false,
      "search_recency_filter": "<string>",
      "top_k": 0,
      "stream": false,
      "presence_penalty": 0,
      "frequency_penalty": 1,
      "response_format": null
    }'

200

422

    
    
    {
      "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "model": "sonar",
      "object": "chat.completion",
      "created": 1724369245,
      "citations": [
        "https://www.astronomy.com/science/astro-for-kids-how-many-stars-are-there-in-space/",
        "https://www.esa.int/Science_Exploration/Space_Science/Herschel/How_many_stars_are_there_in_the_Universe",
        "https://www.space.com/25959-how-many-stars-are-in-the-milky-way.html",
        "https://www.space.com/26078-how-many-stars-are-there.html",
        "https://en.wikipedia.org/wiki/Milky_Way"
      ],
      "choices": [
        {
          "index": 0,
          "finish_reason": "stop",
          "message": {
            "role": "assistant",
            "content": "The number of stars in the Milky Way galaxy is estimated to be between 100 billion and 400 billion stars. The most recent estimates from the Gaia mission suggest that there are approximately 100 to 400 billion stars in the Milky Way, with significant uncertainties remaining due to the difficulty in detecting faint red dwarfs and brown dwarfs."
          },
          "delta": {
            "role": "assistant",
            "content": ""
          }
        }
      ],
      "usage": {
        "prompt_tokens": 14,
        "completion_tokens": 70,
        "total_tokens": 84
      }
    }

================
File: resources/you/you_news.md
================
[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

API Guide

News API

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### API Guide

  * [Smart API](/api-modes/smart-api)
  * [Research API](/api-modes/research-api)
  * [Search API](/api-modes/search-api)
  * [News API](/api-modes/news-api)

##### Custom

  * [Custom APIs](/api-modes/custom-api)

API Guide

# News API

##

​

Stay Informed with the Latest Global News

When interacting with news results, LLMs are currently facing challlenges:

## Lack of News-Specific Filtering

LLMs lack the capability to focus exclusively on real-time news updates,
limiting their relevance for time-sensitive information.

## Limited Recency Filtering

Models are generally unable to filter news based on specific timeframes,
preventing users from accessing the most relevant information for them.

With our **News API** , we ensure you have reliable insights into global news
and events, keeping you informed about the latest stories and developments
worldwide

## Access to Live News

Our API integrates live news data, providing long snippets from trusted
sources, complete with URLs for verification.

## Customizable Recency and Region

For news results, users can filter data by timeframes such as the past day,
week, or month, enabling access to the insights you need.

## Uniquely Long Snippets

Ensure your responses are trustworthy and contain the information you need.

##

​

Use Cases

## Stay Up to Date

  

Current Developments in Key Areas of Interest

query.py

    
    
    import requests
    
    url = "https://api.ydc-index.io/news"
    
    query = {"query":"Latest News on Chipmakers"}
    
    headers = {"X-API-Key": "YOUR_API_KEY"}
    
    response = requests.request("GET", url, headers=headers, params=query)
    
    print(response.text)
    

Response

    
    
    {
    "news": {
    "query": {
      "original": "Latest News on Chipmakers",
      "show_strict_warning": false,
      "spellcheck_off": false
    },
    "results": [
      {
        "age": "4 days ago",
        "description": "The country that was once the world’s largest producer of semiconductors has embarked on a quest to return to the top.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› opinion  › articles  › 2024-12-12  › japan-chipmakers-gamble-the-future-of-semiconductors-on-the-past",
          "scheme": "https"
        },
        "page_age": "2024-12-12T22:37:49",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/qlX4Mz061puuwMyZm1FuXEbSGXuCbqjHIypccDoXGqw/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2lYTWNFSDBjMFli/OC92MS8xMjAweDgw/MC5qcGc"
        },
        "title": "Japan Chipmakers Gamble the Future of Semiconductors on the Past - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/opinion/articles/2024-12-12/japan-chipmakers-gamble-the-future-of-semiconductors-on-the-past"
      },
      {
        "age": "2 weeks ago",
        "description": "Chinese companies should buy locally instead, four of the country's top industry associations said.",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› technology  › chinese-firms-should-diversify-chip-sources-internet-society-china-says-2024-12-03",
          "scheme": "https"
        },
        "page_age": "2024-12-04T12:28:42",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/BuXIjhV4mQs66s0tgItvuiy4x3EBC-ZpqgaeQsLvF-Y/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi9S/WlRXVE9YSkNCUDVS/RzM3RURQRERMWTdM/US5qcGc_YXV0aD02/YTI3MDBmMjJhMGJj/Y2I4NzE0OTM4M2Qz/YTZlODkyODg4YWI4/YTk4MTUwMmI2NGQ1/MDNlNDZmZDY0YjVl/MjRkJmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "US chips are 'no longer safe,' Chinese industry bodies say in latest trade salvo | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/technology/chinese-firms-should-diversify-chip-sources-internet-society-china-says-2024-12-03/"
      },
      {
        "age": "2 weeks ago",
        "description": "Microchip Technology Inc. is pausing its application for US semiconductor subsidies, making it the first known company to step back from a program designed to revitalize American chipmaking.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › articles  › 2024-12-03  › microchip-pauses-chips-act-application-after-scaling-back-plans",
          "scheme": "https"
        },
        "page_age": "2024-12-03T22:47:04",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/va8gs8bDTD44dQtxAjHvM8dB9Trdl_puEs2DlPWJlRM/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2llQThZQ3hjNXFp/TS92MC8xMjAweDgw/MC5qcGc"
        },
        "title": "Microchip Pauses Chips Act Application Amid Inventory Woes - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/articles/2024-12-03/microchip-pauses-chips-act-application-after-scaling-back-plans"
      },
      {
        "age": "2 weeks ago",
        "description": "The Chinese government has slammed America’s introduction of fresh export controls on US-made semiconductors that Washington fears Beijing could use to make the next generation of weapons and artificial intelligence (AI) systems.",
        "meta_url": {
          "hostname": "www.cnn.com",
          "netloc": "cnn.com",
          "path": "› 2024  › 12  › 02  › tech  › china-us-chips-new-restrictions-intl-hnk  › index.html",
          "scheme": "https"
        },
        "page_age": "2024-12-03T02:18:13",
        "source_name": "CNN",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/Q7u2YWA5NPRkhPy3LpctiPU11jkmoP6uYjggAeJ4J6s/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9tZWRp/YS5jbm4uY29tL2Fw/aS92MS9pbWFnZXMv/c3RlbGxhci9wcm9k/L2FwMjQyOTE1NDEy/Njk1OTEtY29weS5q/cGc_Yz0xNng5JnE9/d184MDAsY19maWxs"
        },
        "title": "AI and semiconductors: China hits out at latest US effort to block Beijing’s access to chip technology | CNN Business",
        "type": "news_result",
        "url": "https://www.cnn.com/2024/12/02/tech/china-us-chips-new-restrictions-intl-hnk/index.html"
      },
      {
        "age": "2 weeks ago",
        "description": "The US will launch its third crackdown in three years on China's semiconductor industry on Monday, restricting exports to 140 companies.",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› technology  › latest-us-strike-chinas-chips-hits-semiconductor-toolmakers-2024-12-02",
          "scheme": "https"
        },
        "page_age": "2024-12-03T01:14:17",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/UQxYf9pHn51WR53MNkbaa9ieeQZStKI64CetvaW6Tt4/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi9E/VlRNTERBWkRWSkk3/RTdDUzZJUEtEUVRV/RS5qcGc_YXV0aD0x/OGZkYzAxZmNlZmEx/ZDk4MjIxODFhYTY0/YzA2YTBjNWFjMDk4/YWIxMmM2NzBjZmRh/NDlmYmRkY2Y2MDNh/ZjY0JmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "Latest US clampdown on China's chips hits semiconductor toolmakers | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/technology/latest-us-strike-chinas-chips-hits-semiconductor-toolmakers-2024-12-02/"
      },
      {
        "age": "3 weeks ago",
        "description": "There’s been a sea change among tech investors during the past month: Software stocks are hot, while semiconductor makers are not.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › articles  › 2024-11-26  › software-is-in-chips-are-out-as-traders-position-for-trump-era",
          "scheme": "https"
        },
        "page_age": "2024-11-26T12:01:25",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/LxYcJMko0ujutqhct8xx6kD_wc32kwIH0BJJTPle4cM/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2k3aDhSbUZuMjcy/US92MC8xMjAweDgw/MC5qcGc"
        },
        "title": "Software Is In, Chips Are Out as Traders Position for Trump Era - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/articles/2024-11-26/software-is-in-chips-are-out-as-traders-position-for-trump-era"
      },
      {
        "age": "4 weeks ago",
        "description": "Understanding how AI impacts business. The latest news on advancements in artificial intelligence, how to use AI, and how to invest in AI.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› ai",
          "scheme": "https"
        },
        "page_age": "2024-11-21T21:05:04",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/m7Jfen96xPtekEXCptzbwN1D52cE6auJKE9sP5DajpU/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/Ymxvb21iZXJnLmNv/bS9haQ"
        },
        "title": "AI - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/ai"
      },
      {
        "age": "1 month ago",
        "description": "The Biden administration is trying to shore up its CHIPS Act funding agreements before Donald Trump takes office.",
        "meta_url": {
          "hostname": "www.businessinsider.com",
          "netloc": "businessinsider.com",
          "path": "› chips-act-funding-biden-administration-trump-tariffs-repeal-2024-11",
          "scheme": "https"
        },
        "page_age": "2024-11-19T09:15:01",
        "source_name": "Business Insider",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/_16b6eIPhruMXBpV8ovQHxtj5qc_0nTGW5SHlHYseAg/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pLmlu/c2lkZXIuY29tLzY3/M2JiM2Y0ZmEwMTQw/Y2RkNTY0Mjk5ZT93/aWR0aD0xMjAwJmZv/cm1hdD1qcGVn"
        },
        "title": "The Biden administration is scrambling to send billions to chipmakers before Trump takes over",
        "type": "news_result",
        "url": "https://www.businessinsider.com/chips-act-funding-biden-administration-trump-tariffs-repeal-2024-11"
      },
      {
        "age": "1 month ago",
        "description": "JONATHAN: NVIDIA IS HUGE SO WE ALL HAVE EXPOSURE TO IT ONE WAY OR ANOTHER. EXPLAIN THE STORY THIS MORNING, REPORTING THE CHIPMAKER IS FACING A DESIGN SNACK FOR THE BLACKWELL CHIPS. WE SEE THAT DROPPING IN AND OUT OF THE NEWS REPEATEDLY, SHAKING UP THE STOCK FROM TIME TO TIME.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › videos  › 2024-11-18  › chipmakers-hope-for-a-boost-from-nvidia-earnigns-video",
          "scheme": "https"
        },
        "page_age": "2024-11-18T14:17:33",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/BzYM6UHOgK9rvTWBxa_JK-buc5-4LfUelVxMrd_tl6A/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2lCejhkVm53dEVo/WS92My8tMXgtMS5q/cGc"
        },
        "title": "Watch Chipmakers Hope for a Boost From Nvidia Earnings - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/videos/2024-11-18/chipmakers-hope-for-a-boost-from-nvidia-earnigns-video"
      },
      {
        "age": "1 month ago",
        "description": "Nov 17 (Reuters) - Nvidia's (NVDA.O), ... reported on Sunday. The Blackwell graphics processing units overheat when connected together in server racks designed to hold up to 72 chips, the report said, citing sources familiar with the issue. The chipmaker has asked its suppliers ...",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› technology  › artificial-intelligence  › new-nvidia-ai-chips-face-issue-with-overheating-servers-information-reports-2024-11-17",
          "scheme": "https"
        },
        "page_age": "2024-11-17T22:36:10",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/16Jgf2p3zxsmMnQUzOrP7EhvynVj9rnuSDEGYINQ-HQ/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi9W/VFhIVkFJM1ZCT1lU/QVFSRzdOQlZMNUVJ/SS5qcGc_YXV0aD1m/ODQxZmExMzY3ODMz/ZGRjMmJhMTQ5MzJi/YTQ5Yzc2ZmY2MTNm/NmI0MWI3ZjM3Y2Yx/ZDU5ZDZiZjA2ZjYw/ZjJhJmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "New Nvidia AI chips overheating in servers, the Information reports | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/technology/artificial-intelligence/new-nvidia-ai-chips-face-issue-with-overheating-servers-information-reports-2024-11-17/"
      },
      {
        "age": "November 8, 2024",
        "description": "China hardliners in Congress are calling on the world's foremost semiconductor equipment makers - KLA , LAM , Applied Materials , Tokyo Electron and ASML - to provide details of their sales to China.",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› technology  › us-lawmakers-press-top-chip-equipment-makers-details-china-sales-2024-11-08",
          "scheme": "https"
        },
        "page_age": "2024-11-08T18:05:21",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/UQxYf9pHn51WR53MNkbaa9ieeQZStKI64CetvaW6Tt4/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi9E/VlRNTERBWkRWSkk3/RTdDUzZJUEtEUVRV/RS5qcGc_YXV0aD0x/OGZkYzAxZmNlZmEx/ZDk4MjIxODFhYTY0/YzA2YTBjNWFjMDk4/YWIxMmM2NzBjZmRh/NDlmYmRkY2Y2MDNh/ZjY0JmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "US lawmakers press top chip equipment makers for details on China sales | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/technology/us-lawmakers-press-top-chip-equipment-makers-details-china-sales-2024-11-08/"
      },
      {
        "age": "November 8, 2024",
        "description": "The Biden administration is racing to complete Chips Act agreements with companies like Intel Corp. and Samsung Electronics Co., aiming to shore up one of its signature initiatives before President-elect Donald Trump enters the White House.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › articles  › 2024-11-08  › trump-s-win-sets-off-race-to-complete-chips-act-subsidy-deals",
          "scheme": "https"
        },
        "page_age": "2024-11-08T01:42:07",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/ei0BLNvbyDZ0k8vGo3QdI7Pm8QtABfzqpfz0ucNHOa0/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2l4T25CbS4zdFhq/Yy92MC8xMjAweDgw/MC5qcGc"
        },
        "title": "Trump’s Win Has Biden Rushing to Finalize Chips Act Deals With Intel, Samsung - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/articles/2024-11-08/trump-s-win-sets-off-race-to-complete-chips-act-subsidy-deals"
      },
      {
        "age": "November 4, 2024",
        "description": "Intel has fallen so far so fast that the chipmaker's stock price is no longer having an impact on the Dow Jones Industrial Average.",
        "meta_url": {
          "hostname": "www.cnbc.com",
          "netloc": "cnbc.com",
          "path": "› 2024  › 11  › 04  › the-dow-needs-nvidia-because-intel-plunge-made-semis-underrepresented.html",
          "scheme": "https"
        },
        "page_age": "2024-11-04T20:59:19",
        "source_name": "CNBC",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/1uMlnbYCbjdLfqxeP9fQOibcd2dVPGJwIDWZ65jYr8k/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWFn/ZS5jbmJjZm0uY29t/L2FwaS92MS9pbWFn/ZS8xMDgwMzI5OTIt/MTcyNjEwNzgwMzAw/NS1nZXR0eWltYWdl/cy0yMTU1MTI3Mzc5/LU5WSURJQV9IVUFO/Ry5qcGVnP3Y9MTcz/MjE5ODI4OCZhbXA7/dz0xOTIwJmFtcDto/PTEwODA"
        },
        "title": "The Dow needs Nvidia to give chipmakers representation in index after Intel's plunge",
        "type": "news_result",
        "url": "https://www.cnbc.com/2024/11/04/the-dow-needs-nvidia-because-intel-plunge-made-semis-underrepresented.html"
      },
      {
        "age": "October 30, 2024",
        "description": "Global stock indexes edged lower on Wednesday as a disappointing forecast from Advanced Micro Devices weighed on chipmakers, while gold prices rose to a record high as uncertainty ahead of next week's U.S. presidential election drove safe-haven demand.",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› markets  › global-markets-wrapup-1-2024-10-30",
          "scheme": "https"
        },
        "page_age": "2024-10-30T21:05:08",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/nzLyG1gwaIEPPDPWvUB6P6_z5aoPvHTWttuhFJ-AZZ4/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi9O/MkJQN0VHM1RGT0dI/REFMSlFGVDNJRTZa/WS5qcGc_YXV0aD0z/YmE1ZmUyZGZkYzkx/MjAzZmU0YzVjZWE2/MWNhNmJiNjUzYTc0/ZjhlMjQxMjEzNDAx/NTUzYTYyMWZiODdm/M2E3JmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "Stocks fall with chipmakers, gold hits record high | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/markets/global-markets-wrapup-1-2024-10-30/"
      },
      {
        "age": "October 30, 2024",
        "description": "OpenAI is working with Broadcom and TSMC to build its first in-house chip designed to support its artificial intelligence systems, while adding AMD chips alongside Nvidia chips to meet its surging infrastructure demands, sources told Reuters.",
        "meta_url": {
          "hostname": "www.reuters.com",
          "netloc": "reuters.com",
          "path": "› technology  › artificial-intelligence  › openai-builds-first-chip-with-broadcom-tsmc-scales-back-foundry-ambition-2024-10-29",
          "scheme": "https"
        },
        "page_age": "2024-10-30T15:30:09",
        "source_name": "reuters.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/JfpxYjJ_YO4fhT-Ejlkn0j1V4oqVpLdCQ7LIqyAlBOM/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/cmV1dGVycy5jb20v/cmVzaXplci92Mi83/M0I1NTRIS0JCTUZI/S0tNTE82RlZFVTNH/US5qcGc_YXV0aD04/NDlhODM1MDIwZGVj/YjBhMjI1ZDM5MGVk/YmE4NzI0YTNkMWYz/YzI2ZmE1YjM4OGMy/ZWU1Y2NkNWVkZmU3/YWYzJmFtcDtoZWln/aHQ9MTAwNSZhbXA7/d2lkdGg9MTkyMCZh/bXA7cXVhbGl0eT04/MCZhbXA7c21hcnQ9/dHJ1ZQ"
        },
        "title": "Exclusive: OpenAI builds first chip with Broadcom and TSMC, scales back foundry ambition | Reuters",
        "type": "news_result",
        "url": "https://www.reuters.com/technology/artificial-intelligence/openai-builds-first-chip-with-broadcom-tsmc-scales-back-foundry-ambition-2024-10-29/"
      },
      {
        "age": "October 16, 2024",
        "description": "A rally in semiconductor names and strong economic data sent stocks higher on Thursday.",
        "meta_url": {
          "hostname": "www.cnbc.com",
          "netloc": "cnbc.com",
          "path": "› 2024  › 10  › 16  › stock-market-today-live-updates.html",
          "scheme": "https"
        },
        "page_age": "2024-10-16T22:02:35",
        "source_name": "CNBC",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/3z4hAEdUIDVi62nmwGTixjpwr8RNndn7RzgS7AzkBpU/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWFn/ZS5jbmJjZm0uY29t/L2FwaS92MS9pbWFn/ZS8xMDgwNDQ3MjUt/MTcyODM5Nzg5MDg1/NC1nZXR0eWltYWdl/cy0yMTc3NDM3MDE5/LW1zMV8xNzQ0X3ln/cXlwem9oLmpwZWc_/dj0xNzI5MTgxMTAz/JmFtcDt3PTE5MjAm/YW1wO2g9MTA4MA"
        },
        "title": "Dow closes at fresh record, Nasdaq ends higher as chipmakers rally: Live updates",
        "type": "news_result",
        "url": "https://www.cnbc.com/2024/10/16/stock-market-today-live-updates.html"
      },
      {
        "age": "October 16, 2024",
        "description": "ASML’s surprise results have implications for the overall chip industry. But first...",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › newsletters  › 2024-10-16  › asml-s-surprise-results-signal-uncertain-future-for-some-chipmakers",
          "scheme": "https"
        },
        "page_age": "2024-10-16T11:05:28",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/CCtgpMYTTo_tqrCUjHj2hE4j33_v3pN_12gPUXztUOk/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2k1QnRoejdlb1Zt/TS92MS8xMjAweDgw/MC5qcGc"
        },
        "title": "ASML’s Surprise Results Signal Uncertain Future for Some Chipmakers - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/newsletters/2024-10-16/asml-s-surprise-results-signal-uncertain-future-for-some-chipmakers"
      },
      {
        "age": "October 16, 2024",
        "description": "ASML Holding NV has lost more than €60 billion ($65.3 billion) in market value since it reported weak orders for its chipmaking machines, forcing investors to reevaluate the health of the industry.",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › articles  › 2024-10-16  › asml-s-tumble-fuels-questions-about-chip-industry-s-prospects",
          "scheme": "https"
        },
        "page_age": "2024-10-16T10:36:26",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/FRs8PrWQma_nu8Z4wCUNX20wYoNYhRPA5K8oYZWYcL0/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2k2dUkwNDdXTWpC/OC92MC8xMjAweDgw/MC5qcGc"
        },
        "title": "ASML’s Plunge Shows the Diverging Fortunes of Chipmakers From AI - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/articles/2024-10-16/asml-s-tumble-fuels-questions-about-chip-industry-s-prospects"
      },
      {
        "age": "October 16, 2024",
        "description": "Chip stocks fell Tuesday. ASML slashed its guidance for 2025, and the sector mulled reports of more potential restrictions on chip exports from some US firms.",
        "meta_url": {
          "hostname": "ca.finance.yahoo.com",
          "netloc": "ca.finance.yahoo.com",
          "path": "› news  › chipmakers-tumble-asml-forecast-cut-030444530.html",
          "scheme": "https"
        },
        "page_age": "2024-10-16T03:04:44",
        "source_name": "ca.finance.yahoo.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/a2VYr800beR71JP283brHdStO-voqPux2jfJuPjnnuw/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9zLnlp/bWcuY29tL255L2Fw/aS9yZXMvMS4yL1ho/OU5CUEk1WEFLR2Np/S3puREk1TmctLS9Z/WEJ3YVdROWFHbG5h/R3hoYm1SbGNqdDNQ/VEV5TURBN2FEMDVN/REEtL2h0dHBzOi8v/bWVkaWEuemVuZnMu/Y29tL2VuL2J1c2lu/ZXNzX2luc2lkZXJf/YXJ0aWNsZXNfODg4/LzEzMjI5YmQ0OWEz/NjhmYzQ4YmViZWZl/ZjUwZTcwMjU4"
        },
        "title": "Chipmakers tumble as ASML forecast cut issues a growth warning to the sector",
        "type": "news_result",
        "url": "https://ca.finance.yahoo.com/news/chipmakers-tumble-asml-forecast-cut-030444530.html"
      },
      {
        "age": "October 15, 2024",
        "description": "Manage your newsletter preferences anytime here. ASML Holding’s shares plunged the most in 26 years after it booked only about half the orders analysts expected, a startling slowdown for the Dutch company, maker of the world’s most advanced chip-making machines and one of the bellwethers ...",
        "meta_url": {
          "hostname": "www.bloomberg.com",
          "netloc": "bloomberg.com",
          "path": "› news  › newsletters  › 2024-10-15  › asml-shares-plunge-amid-strange-times-for-chipmakers-like-intel-samsung",
          "scheme": "https"
        },
        "page_age": "2024-10-15T22:14:46",
        "source_name": "Bloomberg L.P.",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/iQL7-057RrQw0oDsHMrzhHX5ksoVJeP0D_tecxHpO1E/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9hc3Nl/dHMuYndieC5pby9p/bWFnZXMvdXNlcnMv/aXFqV0hCRmRmeElV/L2lhaWNjSmhPMTc4/US92MC8xMjAweDgw/MC5qcGc"
        },
        "title": "ASML Shares Plunge Amid Strange Times for Chipmakers Like Intel, Samsung - Bloomberg",
        "type": "news_result",
        "url": "https://www.bloomberg.com/news/newsletters/2024-10-15/asml-shares-plunge-amid-strange-times-for-chipmakers-like-intel-samsung"
      }
    ],
    "type": "news"
    }
    }
    

Country-specific Industry Overviews

query.py

    
    
    import requests
    
    url = "https://api.ydc-index.io/news"
    
    querystring = {"query":"News on the Chemical Industry", "country":"IN"}
    
    headers = {"X-API-Key": "YOUR_API_KEY"}
    
    response = requests.request("GET", url, headers=headers, params=querystring)
    
    print(response.text)
    

reponse

    
    
    {
    "news": {
    "query": {
      "original": "Chemical Industry",
      "show_strict_warning": false,
      "spellcheck_off": false
    },
    "results": [
      {
        "age": "2 weeks ago",
        "description": "On December 3 2024 Sudarshan Chemical Industries a midcap company in the dyes and pigments industry saw a 5 02 increase in its stock outperforming the sector by 2 7 This marks the fourth consecutive day of gains with a total increase of 11 34 in the past four days The stock is currently trading ...",
        "meta_url": {
          "hostname": "www.marketsmojo.com",
          "netloc": "marketsmojo.com",
          "path": "› news  › stocks-in-action  › sudarshan-chemical-industries-stock-sees-positive-trend-outperforms-sector-and-market-308679",
          "scheme": "https"
        },
        "page_age": "2024-12-03T05:30:02",
        "source_name": "marketsmojo.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/YiUpk2EMKEHCCGwC57406-c57F3JKfEZr6r3jUKE_jk/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pLm1h/cmtldHNtb2pvLmNv/bS9uZXdzaW1nLzIw/MjQvMTIvU3VkYXJz/aGFuQ2hlbWljX3By/aWNlUmVsYXRlZGZh/Y3RvcnNfMjMxNjI5/LnBuZw"
        },
        "title": "Sudarshan Chemical Industries' Stock Sees Positive Trend, Outperforms Sector and Market",
        "type": "news_result",
        "url": "https://www.marketsmojo.com/news/stocks-in-action/sudarshan-chemical-industries-stock-sees-positive-trend-outperforms-sector-and-market-308679"
      },
      {
        "age": "2 weeks ago",
        "description": "Chemical industry in Tamil Nadu faces challenges, seeks government support for cracker project, growth projections shared at Chemvision 2024.",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› news  › national  › tamil-nadu  › chemical-industry-calls-for-cracker-project-to-boost-growth-in-tamil-nadu  › article68927363.ece",
          "scheme": "https"
        },
        "page_age": "2024-12-02T15:30:31",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/MbaLnkSns7korT9MlnYjmNHGa1WUAhQ3UWPKsATH8sw/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly90aC1p/LnRoZ2ltLmNvbS9w/dWJsaWMvaW5jb21p/bmcvNnppYXh2L2Fy/dGljbGU2ODkzOTQ1/Ni5lY2UvYWx0ZXJu/YXRlcy9MQU5EU0NB/UEVfMTIwMC9CVlJf/NDQ1NS5KUEc"
        },
        "title": "Chemical industry calls for cracker project to boost growth in Tamil Nadu - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/news/national/tamil-nadu/chemical-industry-calls-for-cracker-project-to-boost-growth-in-tamil-nadu/article68927363.ece"
      },
      {
        "age": "2 weeks ago",
        "description": "Paradeep Phosphates Limited has taken the planned shutdown of the ammonia and urea plants at Goa",
        "meta_url": {
          "hostname": "www.indianchemicalnews.com",
          "netloc": "indianchemicalnews.com",
          "path": "› general  › briefs-paradeep-phosphates-and-upl-24269",
          "scheme": "https"
        },
        "page_age": "2024-12-02T14:35:03",
        "source_name": "indianchemicalnews.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/Vl4q-rbHKGG5hwNVyuoaLx_Igp-MdbrerzkvrrHSwGQ/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/aW5kaWFuY2hlbWlj/YWxuZXdzLmNvbS9w/dWJsaWMvdXBsb2Fk/cy9uZXdzLzIwMjQv/MTIvMjQyNjkvVVBM/X2xvZ29fb3JpZ2lu/YWwuanBn"
        },
        "title": "Briefs: Paradeep Phosphates and UPL",
        "type": "news_result",
        "url": "https://www.indianchemicalnews.com/general/briefs-paradeep-phosphates-and-upl-24269"
      },
      {
        "age": "2 weeks ago",
        "description": "Press release - Exactitude Consultancy - Crop Protection Chemicals Market Detailed Industry Report Analysis 2024-2032 | BASF, Syngenta, Bayer Crop Science - published on openPR.com",
        "meta_url": {
          "hostname": "www.openpr.com",
          "netloc": "openpr.com",
          "path": "› news  › 3766044  › crop-protection-chemicals-market-detailed-industry-report",
          "scheme": "https"
        },
        "page_age": "2024-12-02T10:46:15",
        "source_name": "openpr.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/pAlDpCwJjcEf6Ypm-K1Tl8JBCNjyRa73ZfUkRYZwVXU/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9jZG4u/b3Blbi1wci5jb20v/TC9jL0xjMDIxNTQ3/NjdfZy5qcGc"
        },
        "title": "Crop Protection Chemicals Market Detailed Industry Report Analysis 2024-2032 | BASF, Syngenta, Bayer Crop Science",
        "type": "news_result",
        "url": "https://www.openpr.com/news/3766044/crop-protection-chemicals-market-detailed-industry-report"
      },
      {
        "age": "5 days ago",
        "description": "CII Visakhapatnam to organise conference on Industrial & Chemical Safety from December 12",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› news  › cities  › Visakhapatnam  › cii-visakhapatnam-to-organise-conference-on-industrial-chemical-safety-from-december-12  › article68973107.ece",
          "scheme": "https"
        },
        "page_age": "2024-12-11T12:18:13",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/llajowBpmgWaVpuUx0Kw-DZmR0pl3GHEUnH8UFCou-g/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/dGhlaGluZHUuY29t/L3RoZW1lL2ltYWdl/cy9vZy1pbWFnZS5w/bmc"
        },
        "title": "CII Visakhapatnam to organise conference on Industrial & Chemical Safety from December 12 - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/news/cities/Visakhapatnam/cii-visakhapatnam-to-organise-conference-on-industrial-chemical-safety-from-december-12/article68973107.ece"
      },
      {
        "age": "3 weeks ago",
        "description": "CII Tamil Nadu Chemvision 2024 highlights sustainability, safety, investment opportunities, and capability building in the chemical industry.",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› news  › national  › tamil-nadu  › cii-tamil-nadu-chemvision-2024-to-be-held-on-november-29  › article68923289.ece",
          "scheme": "https"
        },
        "page_age": "2024-11-28T17:55:13",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/llajowBpmgWaVpuUx0Kw-DZmR0pl3GHEUnH8UFCou-g/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/dGhlaGluZHUuY29t/L3RoZW1lL2ltYWdl/cy9vZy1pbWFnZS5w/bmc"
        },
        "title": "CII Tamil Nadu Chemvision 2024 to be held on November 29 - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/news/national/tamil-nadu/cii-tamil-nadu-chemvision-2024-to-be-held-on-november-29/article68923289.ece"
      },
      {
        "age": "1 month ago",
        "description": "Fire officials said the incident occurred when chemical sludge, which was awaiting transport to a cement factory, caught fire. Firefighters doused the flames before fire could spread to the main unit. The reactor and boilers, which are key components of the chemical industry, were not damaged ...",
        "meta_url": {
          "hostname": "timesofindia.indiatimes.com",
          "netloc": "timesofindia.indiatimes.com",
          "path": "› city  › hyderabad  › massive-fire-erupts-at-chemical-facility-near-hyderabad-no-casualties-reported  › articleshow  › 115369330.cms",
          "scheme": "https"
        },
        "page_age": "2024-11-16T19:01:00",
        "source_name": "timesofindia.indiatimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/2lwy_RjV_cNso39qFr6pfrjPykcR3cRKhHnm_Z6LzJI/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9zdGF0/aWMudG9paW1nLmNv/bS90aHVtYi9tc2lk/LTExNTM2OTMyNyx3/aWR0aC0xMDcwLGhl/aWdodC01ODAsaW1n/c2l6ZS01NjQ2MCxy/ZXNpemVtb2RlLTc1/LG92ZXJsYXktdG9p/X3N3LHB0LTMyLHlf/cGFkLTQwL3Bob3Rv/LmpwZw"
        },
        "title": "Massive Fire Erupts at Chemical Facility Near Hyderabad, No Casualties Reported | - Times of India",
        "type": "news_result",
        "url": "https://timesofindia.indiatimes.com/city/hyderabad/massive-fire-erupts-at-chemical-facility-near-hyderabad-no-casualties-reported/articleshow/115369330.cms"
      },
      {
        "age": "October 24, 2024",
        "description": "সম্প্রতি যে সংস্থা দেশের সেরা কোম্পানির পুরস্কার (তালিকাভুক্ত কোম্পানির মধ্যে) পেয়েছে, সেটিই সিঙ্গুরে ২২০ কোটি ...",
        "meta_url": {
          "hostname": "bangla.hindustantimes.com",
          "netloc": "bangla.hindustantimes.com",
          "path": "› pictures  › big-investment-for-singur-himadri-speciality-chemical-limited-to-invest-rs-220-crore-for-31729757880342.html",
          "scheme": "https"
        },
        "page_age": "2024-10-24T08:29:45",
        "source_name": "bangla.hindustantimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/P2qC9UIGEGMbr_jLcGcbrqITQpUIY6NaltTu8DBiEB8/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWFn/ZXMuaGluZHVzdGFu/dGltZXMuY29tL2Jh/bmdsYS9pbWcvMjAy/NC8xMC8yNC82MDB4/MzM4L0lORElBLVNU/RUVMLTBfMTcyOTc1/Nzg3MTk5NF8xNzI5/NzU4NTg1MDQ4LkpQ/Rw"
        },
        "title": "₹220 cr investment at Singur: সিঙ্গুরে ২২০ কোটি টাকার বিনিয়োগ আসছে! লগ্নি করছে দেশের সেরা হওয়া সংস্থা, কী হবে? - Big investment for Singur, Himadri Speciality Chemical limited to invest ₹220 crore for - ছবিঘর নিউজ",
        "type": "news_result",
        "url": "https://bangla.hindustantimes.com/pictures/big-investment-for-singur-himadri-speciality-chemical-limited-to-invest-rs-220-crore-for-31729757880342.html"
      },
      {
        "age": "September 16, 2024",
        "description": "Texas chemical plant explosion: Firefighters were battling a pipeline fire in suburban Houston that sparked grass fires and burned power poles on Monday",
        "meta_url": {
          "hostname": "www.hindustantimes.com",
          "netloc": "hindustantimes.com",
          "path": "› world-news  › us-news  › texas-chemical-plant-explosion-evacuations-ordered-in-la-porte-amid-roaring-pipeline-fire-101726503834727.html",
          "scheme": "https"
        },
        "page_age": "2024-09-16T16:28:49",
        "source_name": "Hindustan Times",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/faaxK__lNPrgy_h2x4S1uacJIB8EVkgmD37qsgKPHl8/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/aGluZHVzdGFudGlt/ZXMuY29tL2h0LWlt/Zy9pbWcvMjAyNC8w/OS8xNi8xNjAweDkw/MC9URVhBUy1DQVRU/TEUtLTFfMTY4MTQ1/MTc1NjI3MF8xNjgx/NDUxNzU2MjcwXzE3/MjY1MDM5MTIyNDUu/SlBH"
        },
        "title": "Texas chemical plant explosion: Evacuations ordered in La Porte amid roaring pipeline fire - Hindustan Times",
        "type": "news_result",
        "url": "https://www.hindustantimes.com/world-news/us-news/texas-chemical-plant-explosion-evacuations-ordered-in-la-porte-amid-roaring-pipeline-fire-101726503834727.html"
      },
      {
        "age": "September 13, 2024",
        "description": "Gas leak reported at chemical company in Ambernath, Thane district; fire brigade officials on scene, awaiting further details.",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› news  › national  › maharashtra  › gas-leak-at-chemical-factory-in-thanes-ambernath  › article68637090.ece",
          "scheme": "https"
        },
        "page_age": "2024-09-13T01:43:07",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/llajowBpmgWaVpuUx0Kw-DZmR0pl3GHEUnH8UFCou-g/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/dGhlaGluZHUuY29t/L3RoZW1lL2ltYWdl/cy9vZy1pbWFnZS5w/bmc"
        },
        "title": "Gas leak at chemical factory in Thane’s Ambernath - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/news/national/maharashtra/gas-leak-at-chemical-factory-in-thanes-ambernath/article68637090.ece"
      },
      {
        "age": "August 31, 2024",
        "description": "Discover the vast chemical armory of plants like garlic, used for centuries in diets and medicine for human health.",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› sci-tech  › the-chemical-treasury-in-garlic  › article68559174.ece",
          "scheme": "https"
        },
        "page_age": "2024-08-31T15:40:00",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/llajowBpmgWaVpuUx0Kw-DZmR0pl3GHEUnH8UFCou-g/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/dGhlaGluZHUuY29t/L3RoZW1lL2ltYWdl/cy9vZy1pbWFnZS5w/bmc"
        },
        "title": "The chemical treasury in garlic - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/sci-tech/the-chemical-treasury-in-garlic/article68559174.ece"
      },
      {
        "age": "August 26, 2024",
        "description": "And are there such more requests from the industry pending for the ministry to look at? Ajay Joshi: We will see a lot more anti-dumping duties, as well as a lot more minimum import support price initiatives that will be rendered from the Indian government to Indian chemical players.",
        "meta_url": {
          "hostname": "m.economictimes.com",
          "netloc": "m.economictimes.com",
          "path": "› markets  › expert-view  › more-anti-dumping-duties-to-support-local-indian-chemical-companies-ajay-joshi  › articleshow  › 112801519.cms",
          "scheme": "https"
        },
        "page_age": "2024-08-26T10:40:02",
        "source_name": "m.economictimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/36FKJ7dAKQRbme3CqO47lQcFO4VHz03KPSoqn-Eqxi0/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWcu/ZXRpbWcuY29tL3Ro/dW1iL21zaWQtMTEy/ODAxNTI4LHdpZHRo/LTEyMDAsaGVpZ2h0/LTYzMCxpbWdzaXpl/LTQwNTQsb3Zlcmxh/eS1ldG1hcmtldHMv/YXJ0aWNsZXNob3cu/anBn"
        },
        "title": "chemical companies: More anti-dumping duties to support local Indian chemical companies: Ajay Joshi - The Economic Times",
        "type": "news_result",
        "url": "https://m.economictimes.com/markets/expert-view/more-anti-dumping-duties-to-support-local-indian-chemical-companies-ajay-joshi/articleshow/112801519.cms"
      },
      {
        "age": "August 24, 2024",
        "description": "Producers of PFAS chemicals and semiconductors, a key part of most electronics, have formed a group that develops industry-friendly science aimed at heading off regulation as facilities release high levels of toxic waste, documents seen by the Guardian show.",
        "meta_url": {
          "hostname": "www.theguardian.com",
          "netloc": "theguardian.com",
          "path": "› environment  › article  › 2024  › aug  › 24  › pfas-toxic-waste-pollution-regulation-lobbying",
          "scheme": "https"
        },
        "page_age": "2024-08-24T13:00:33",
        "source_name": "The Guardian",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/0W30teYhY65K0E8fmkhQaOgOuJ6qSCa1DspIcofMITQ/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pLmd1/aW0uY28udWsvaW1n/L21lZGlhL2QwMzc3/ODczZjBjM2VlNjcw/YzljODNhNDgzMjU2/YzQ1MjljMzZjY2Qv/MF8yMzJfNjk2MF80/MTc2L21hc3Rlci82/OTYwLmpwZz93aWR0/aD0xMjAwJmhlaWdo/dD02MzAmcXVhbGl0/eT04NSZhdXRvPWZv/cm1hdCZmaXQ9Y3Jv/cCZvdmVybGF5LWFs/aWduPWJvdHRvbSUy/Q2xlZnQmb3Zlcmxh/eS13aWR0aD0xMDBw/Jm92ZXJsYXktYmFz/ZTY0PUwybHRaeTl6/ZEdGMGFXTXZiM1ps/Y214aGVYTXZkR2N0/WkdWbVlYVnNkQzV3/Ym1jJmVuYWJsZT11/cHNjYWxlJnM9NTRl/M2VkMjAzNzNmNjJh/Njg0ZTNhYzM0NTA5/ODgxOTI"
        },
        "title": "Industry acts to head off regulation on PFAS pollution from semiconductors | PFAS | The Guardian",
        "type": "news_result",
        "url": "https://www.theguardian.com/environment/article/2024/aug/24/pfas-toxic-waste-pollution-regulation-lobbying"
      },
      {
        "age": "August 6, 2024",
        "description": "Imported chemicals, reagents, and ... chemicals and are vital to experimental research across nearly every domain of scientific research. They comprise oxidisers, corrosive acids, and compressed gas, that are used by researchers to conduct experiments and even make new products. Outside of research settings, the medical diagnostics industry is run on ...",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› news  › national  › why-was-customs-duty-hike-imposed-for-lab-chemicals-explained  › article68489881.ece",
          "scheme": "https"
        },
        "page_age": "2024-08-06T03:00:00",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/XnRTEq-045V-3-yqQmZzNL2CXz7nfE9uB3A4EvvK_ek/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly90aC1p/LnRoZ2ltLmNvbS9w/dWJsaWMvaW5jb21p/bmcvM2QycmNkL2Fy/dGljbGU2ODQ4OTg5/NC5lY2UvYWx0ZXJu/YXRlcy9MQU5EU0NB/UEVfMTIwMC9JTUdf/UE8yMl9MYWJfMl8x/X0xVQlRLVkxOLmpw/Zw"
        },
        "title": "Why was a customs duty hike imposed for lab chemicals? | Explained - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/news/national/why-was-customs-duty-hike-imposed-for-lab-chemicals-explained/article68489881.ece"
      },
      {
        "age": "July 30, 2024",
        "description": "Scientists alarmed by 150% hike in customs duty on laboratory chemicals, sparking concerns over research funding and accessibility.",
        "meta_url": {
          "hostname": "www.thehindu.com",
          "netloc": "thehindu.com",
          "path": "› sci-tech  › science  › 150-customs-duty-on-lab-chemicals-alarms-scientists  › article68465158.ece",
          "scheme": "https"
        },
        "page_age": "2024-07-30T23:18:00",
        "source_name": "The Hindu",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/efUVKzr_CvwMR3CIlcnSh_yOGKOwJkoPdM38OGSPIlg/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly90aC1p/LnRoZ2ltLmNvbS9w/dWJsaWMvaW5jb21p/bmcvNHUzdWs1L2Fy/dGljbGU2ODQ2NjE4/NS5lY2UvYWx0ZXJu/YXRlcy9MQU5EU0NB/UEVfMTIwMC9QTzE5/X0xhYl9zYW1wbGVz/LmpwZw"
        },
        "title": "150% customs duty on lab chemicals alarms scientists - The Hindu",
        "type": "news_result",
        "url": "https://www.thehindu.com/sci-tech/science/150-customs-duty-on-lab-chemicals-alarms-scientists/article68465158.ece"
      },
      {
        "age": "July 15, 2024",
        "description": "Union Budget 2024: The agrochemical sector in India is pushing for an increase in import duties to combat the influx of chemicals from China. Industry experts are advocating for tariffs to level the playing field for domestic players and address the trade deficit.",
        "meta_url": {
          "hostname": "m.economictimes.com",
          "netloc": "m.economictimes.com",
          "path": "› news  › economy  › policy  › budget-2024-agro-chemical-sector-seeks-hike-in-import-duties  › articleshow  › 111736462.cms",
          "scheme": "https"
        },
        "page_age": "2024-07-15T18:35:05",
        "source_name": "m.economictimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/D0Ec-qSM1b3xUV5kKHPGOuFehxSUBw2KwKBFAyJ6zC8/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWcu/ZXRpbWcuY29tL3Ro/dW1iL21zaWQtMTEx/NzM2NDg4LHdpZHRo/LTEyMDAsaGVpZ2h0/LTYzMCxpbWdzaXpl/LTEwMTEwNCxvdmVy/bGF5LWVjb25vbWlj/dGltZXMvcGhvdG8u/anBn"
        },
        "title": "Budget 2024: Agro-chemical sector seeks hike in import duties - The Economic Times",
        "type": "news_result",
        "url": "https://m.economictimes.com/news/economy/policy/budget-2024-agro-chemical-sector-seeks-hike-in-import-duties/articleshow/111736462.cms"
      },
      {
        "age": "June 26, 2024",
        "description": "“These stocks have either reversed from a long-term support or made a multiyear breakout retest which make them quite safe as compared to the stocks which are witnessing a breakout which can fail if the markets correct,” said InCreds VP, Gaurav Bissa, in a client note.",
        "meta_url": {
          "hostname": "m.economictimes.com",
          "netloc": "m.economictimes.com",
          "path": "› markets  › stocks  › news  › brokerage-view-chemical-stocks-ripe-for-fresh-up-cycle  › articleshow  › 111270903.cms",
          "scheme": "https"
        },
        "page_age": "2024-06-26T09:05:03",
        "source_name": "m.economictimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/GqRtEiyviXDP6MguofYwO3jl4EWYZYJl6Wyj_EaGV30/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWcu/ZXRpbWcuY29tL3Ro/dW1iL21zaWQtMTEx/MjcwODg2LHdpZHRo/LTEyMDAsaGVpZ2h0/LTYzMCxpbWdzaXpl/LTQ4NjQwLG92ZXJs/YXktZXRtYXJrZXRz/L3Bob3RvLmpwZw"
        },
        "title": "chemical stocks: Brokerage View: Chemical stocks ripe for fresh up-cycle - The Economic Times",
        "type": "news_result",
        "url": "https://m.economictimes.com/markets/stocks/news/brokerage-view-chemical-stocks-ripe-for-fresh-up-cycle/articleshow/111270903.cms"
      },
      {
        "age": "June 3, 2024",
        "description": "Regulating chemicals one-by-one has allowed the tobacco industry to skirt menthol bans by creating new additives with similar effects but unclear safety profiles",
        "meta_url": {
          "hostname": "www.scientificamerican.com",
          "netloc": "scientificamerican.com",
          "path": "› article  › how-tobacco-companies-use-chemistry-to-get-around-menthol-bans",
          "scheme": "https"
        },
        "page_age": "2024-06-03T13:00:00",
        "source_name": "Scientific American",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/72rWK2FjUyLGTVKABZyKNSK-9aPPMcc4KVbkuSR30xw/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9zdGF0/aWMuc2NpZW50aWZp/Y2FtZXJpY2FuLmNv/bS9kYW0vbS8xNGEw/NDEyODM4ZGRkMTMv/b3JpZ2luYWwvMlJF/NDBLNl9XRUIuanBn/P3c9MTIwMA"
        },
        "title": "How Tobacco Companies Use Chemistry to Get around Menthol Bans | Scientific American",
        "type": "news_result",
        "url": "https://www.scientificamerican.com/article/how-tobacco-companies-use-chemistry-to-get-around-menthol-bans/"
      },
      {
        "age": "May 30, 2024",
        "description": "The plastic industry is pitching chemical recycling as a great new hope in the battle against the plastic pollution crisis. Experts say not so fast",
        "meta_url": {
          "hostname": "www.cnn.com",
          "netloc": "cnn.com",
          "path": "› 2024  › 05  › 30  › climate  › chemical-recycling-plastic-pollution-climate  › index.html",
          "scheme": "https"
        },
        "page_age": "2024-05-30T08:00:15",
        "source_name": "CNN",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/JKOPReSeEiqJBpPyB9W_qKvTxxtYi24wM8W2UP76JII/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9tZWRp/YS5jbm4uY29tL2Fw/aS92MS9pbWFnZXMv/c3RlbGxhci9wcm9k/L2dldHR5aW1hZ2Vz/LTEyNTg1MTE4NDUu/anBnP2M9MTZ4OSZx/PXdfODAwLGNfZmls/bA"
        },
        "title": "The plastics industry says chemical recycling could help banish pollution. It’s ‘an illusion,’ critics say | CNN",
        "type": "news_result",
        "url": "https://www.cnn.com/2024/05/30/climate/chemical-recycling-plastic-pollution-climate/index.html"
      },
      {
        "age": "May 25, 2024",
        "description": "India's Petroleum, Chemical, and Petrochemical Investment Regions (PCPIRs) are expected to attract investments worth USD 420 billion, reflecting the sector's robust potential. Additionally, the establishment of seven Central Institutes of Petrochemicals Engineering & Technology (CIPET) and the Institute of Pesticide Formulation Technology (IPFT) will drive skill development, ensuring a skilled workforce to support the industry...",
        "meta_url": {
          "hostname": "m.economictimes.com",
          "netloc": "m.economictimes.com",
          "path": "› industry  › indl-goods  › svs  › chem-  › -fertilisers  › indias-chemicals-market-to-hit-29-7-bn-in-2024-set-for-steady-growth-with-3-26-cagr-through-2029  › articleshow  › 110418837.cms",
          "scheme": "https"
        },
        "page_age": "2024-05-25T07:30:02",
        "source_name": "m.economictimes.com",
        "thumbnail": {
          "src": "https://you.com/proxy?url=https://imgs.news.you.com/KNb5Pm02ITThd3icECdte7bUxKtEz53cELFDWN7YRh8/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9pbWcu/ZXRpbWcuY29tL3Ro/dW1iL21zaWQtMTEw/NDE4ODU2LHdpZHRo/LTEyMDAsaGVpZ2h0/LTYzMCxpbWdzaXpl/LTI0MDc0LG92ZXJs/YXktZWNvbm9taWN0/aW1lcy9hcnRpY2xl/c2hvdy5qcGc"
        },
        "title": "chemicals market: India's chemicals market to hit $29.7 bn in 2024, set for steady growth with 3.26% CAGR through 2029 - The Economic Times",
        "type": "news_result",
        "url": "https://m.economictimes.com/industry/indl-goods/svs/chem-/-fertilisers/indias-chemicals-market-to-hit-29-7-bn-in-2024-set-for-steady-growth-with-3-26-cagr-through-2029/articleshow/110418837.cms"
      }
    ],
    "type": "news"
    }
    }
    

##

​

Explore further

## [Quickstart](/docs/quickstart)## [API Reference](/api-reference)

[Search API](/api-modes/search-api)[Custom APIs](/api-modes/custom-api)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

On this page

  * Stay Informed with the Latest Global News
  * Use Cases
  * Explore further

[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

API Reference

News

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### API Reference

  * [POSTSmart API](/api-reference/smart)
  * [POSTResearch API](/api-reference/research)
  * [GETSearch](/api-reference/search)
  * [GETNews](/api-reference/news)

API Reference

# News

GET

/

news

Try it

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request GET \
      --url https://chat-api.you.com/news \
      --header 'X-API-Key: <api-key>'

200

    
    
    {
      "news": {
        "results": [
          {
            "url": "https://news.you.com",
            "title": "Breaking News about the World's Greatest Search Engine!",
            "description": "Search on YDC for the news",
            "type": "news",
            "age": "18 hours ago",
            "page_age": "2 days",
            "breaking": false,
            "page_fetched": "2023-10-12T23:00:00Z",
            "thumbnail": {
              "original": "https://reuters.com/news.jpg"
            },
            "meta_url": {
              "scheme": "https",
              "netloc": "reuters.com",
              "hostname": "www.reuters.com",
              "path": "› 2023  › 10  › 18  › politics  › inflation  › index.html"
            }
          }
        ]
      }
    }

**Before You Get Started**

To register for usage of our News API, please reach out via email at
[api@you.com](mailto:api@you.com).

#### Authorizations

​

X-API-Key

string

header

required

#### Query Parameters

​

query

string

required

Search query used to retrieve relevant results from index

​

count

integer

Specifies the maximum number of web results to return. Range `1 ≤
num_web_results ≤ 20`.

​

offset

integer

Indicates the `offset` for pagination. The `offset` is calculated in multiples
of `num_web_results`. For example, if `num_web_results = 5` and `offset = 1`,
results 5–10 will be returned. Range `0 ≤ offset ≤ 9`.

​

country

string

Country Code, one of `['AR', 'AU', 'AT', 'BE', 'BR', 'CA', 'CL', 'DK', 'FI',
'FR', 'DE', 'HK', 'IN', 'ID', 'IT', 'JP', 'KR', 'MY', 'MX', 'NL', 'NZ', 'NO',
'CN', 'PL', 'PT', 'PH', 'RU', 'SA', 'ZA', 'ES', 'SE', 'CH', 'TW', 'TR', 'GB',
'US']`.

​

search_lang

string

Language codes, one of `['ar', 'eu', 'bn', 'bg', 'ca', 'Simplified',
'Traditional', 'hr', 'cs', 'da', 'nl', 'en', 'United', 'et', 'fi', 'fr', 'gl',
'de', 'gu', 'he', 'hi', 'hu', 'is', 'it', 'jp', 'kn', 'ko', 'lv', 'lt', 'ms',
'ml', 'mr', 'Bokmål', 'pl', 'Brazil', 'Portugal', 'pa', 'ro', 'ru', 'Cyrylic',
'sk', 'sl', 'es', 'sv', 'ta', 'te', 'th', 'tr', 'uk', 'vi']`.

​

ui_lang

string

User interface language for the response, one of `['es-AR', 'en-AU', 'de-AT',
'nl-BE', 'fr-BE', 'pt-BR', 'en-CA', 'fr-CA', 'es-CL', 'da-DK', 'fi-FI', 'fr-
FR', 'de-DE', 'SAR', 'en-IN', 'en-ID', 'it-IT', 'ja-JP', 'ko-KR', 'en-MY',
'es-MX', 'nl-NL', 'English', 'no-NO', 'of', 'pl-PL', 'the', 'ru-RU',
'English', 'es-ES', 'sv-SE', 'fr-CH', 'de-CH', 'Chinese', 'tr-TR', 'English',
'English', 'Spanish']`.

​

safesearch

string

Configures the safesearch filter for content moderation. `off` \- no filtering
applied.`moderate` \- moderate content filtering (default). `strict` \- strict
content filtering.

​

spellcheck

boolean

Determine whether the `query` requires spell-checking. default is `true`.

​

recency

enum<string>

Specify the desired recency for the requested articles.

Available options:

`day`,

`week`,

`month`,

`year`

#### Response

200 - application/json

A JSON object containing array of news results

​

news

object

Show child attributes

​

news.results

object[]

Show child attributes

​

news.results.url

string

​

news.results.title

string

​

news.results.description

string

​

news.results.type

string

​

news.results.age

string

​

news.results.page_age

string

​

news.results.breaking

boolean

​

news.results.page_fetched

string

​

news.results.thumbnail

object

Show child attributes

​

news.results.thumbnail.original

string

​

news.results.meta_url

object

Show child attributes

​

news.results.meta_url.scheme

string

​

news.results.meta_url.netloc

string

​

news.results.meta_url.hostname

string

​

news.results.meta_url.path

string

[Search](/api-reference/search)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request GET \
      --url https://chat-api.you.com/news \
      --header 'X-API-Key: <api-key>'

200

    
    
    {
      "news": {
        "results": [
          {
            "url": "https://news.you.com",
            "title": "Breaking News about the World's Greatest Search Engine!",
            "description": "Search on YDC for the news",
            "type": "news",
            "age": "18 hours ago",
            "page_age": "2 days",
            "breaking": false,
            "page_fetched": "2023-10-12T23:00:00Z",
            "thumbnail": {
              "original": "https://reuters.com/news.jpg"
            },
            "meta_url": {
              "scheme": "https",
              "netloc": "reuters.com",
              "hostname": "www.reuters.com",
              "path": "› 2023  › 10  › 18  › politics  › inflation  › index.html"
            }
          }
        ]
      }
    }

================
File: resources/you/you_news.txt
================
https://documentation.you.com/api-modes/news-api
https://documentation.you.com/api-reference/news

================
File: resources/you/you.md
================
Loading...

[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

Initial Setup

Quickstart

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### Initial Setup

  * [Quickstart](/docs/quickstart)

##### More Examples

  * [Open Source Examples](/docs/opensource-examples)

Initial Setup

# Quickstart

##

​

Introduction

Welcome to the Quickstart Guide for integrating comprehensive, high-quality
answers with precise and reliable citations using our [Smart](/api-
modes/smart-api), [Research](/api-modes/research-api), [Search](/api-
modes/search-api) and [News](/api-modes/news-api) APIs. This guide will walk
you through the initial setup and provide you with sample code to perform
searches and retrieve results.

##

​

Step 1: Set Up Your API Key

**Before You Get Started**

To use the You.com Smart, Research, Search and News LLM endpoints, you can get
an API key through the self-serve portal at
[api.you.com](https://api.you.com). For support, please reach out via email at
[api@you.com](mailto:api@you.com).

Replace `X-API-Key` in the code with your actual API key:

API Key

    
    
    YOUR_API_KEY = "your_actual_api_key_here"
    

##

​

Step 2: Write the Search Function

Create a function to interact with the Research API:

  * Smart API
  * Research API
  * Search API
  * News API

Learn more about the [Smart API ](/api-modes/smart-api).

smart_api.py

    
    
    import requests
    
    def get_smart_results(query):
        headers = {"X-API-Key": YOUR_API_KEY}
        params = {"query": query, "instructions": instructions}
        return requests.get(
            "https://chat-api.you.com/smart?query={query}",
            params=params,
            headers=headers,
        ).json()
    

Use the function to search for AI snippets related to a specific topic:

  * Smart API
  * Research API
  * Search API
  * News API

smart_results.py

    
    
    get_smart_results("Who won the Nobel Prize in Physics in 2024?")
    

Answer

answer

    
    
    {
    "answer":"#### The 2024 Nobel Prize in Physics\n\n
    The 2024 Nobel Prize in Physics was awarded jointly to **John J. Hopfield**
    and **Geoffrey E. Hinton** \"for foundational discoveries and inventions that
    enable machine learning with artificial neural networks\".
    [[1]](https://www.nobelprize.org/prizes/physics/2024/summary/) [[2]](https://www.nobelprize.org/prizes/physics/2024/press-release/)\n\n      
    Hopfield and Hinton are pioneers in the field of artificial intelligence and
    machine learning. Their work in the 1980s laid the groundwork for the development of
    modern neural networks and deep learning algorithms, which are now widely used in
    various applications.
    [[3]](https://www.nobelprize.org/prizes/physics/2024/popular-information/) [[4]](https://spectrum.ieee.org/nobel-prize-in-physics)\n\n
    Specifically, Hopfield created a structure that can store and reconstruct information, while Hinton
    invented a method that can autonomously find properties in data, which are key
    innovations that make artificial intelligence work.
    [[5]](https://www.weforum.org/stories/2024/10/nobel-prize-winners-2024/)\n\n        
    The Nobel Prize committee recognized their \"foundational discoveries
    and inventions that enable machine learning with artificial neural networks\",
    highlighting how their work has been instrumental in the rapid progress of AI and machine
    learning in recent years.
    [[1]](https://www.nobelprize.org/prizes/physics/2024/summary/) [[2]](https://www.nobelprize.org/prizes/physics/2024/press-release/)"     
    
    "search_results":[
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/summary/",
    "name":"The Nobel Prize in Physics 2024 - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/press-release/",
    "name":"Press release: The Nobel Prize in Physics 2024 - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/",
    "name":"Nobel Prize in Physics",
    "snippet":"The Nobel Prize medal. ... A slide rule that physics laureate Toshihide Maskawa used as a high school student.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/all-nobel-prizes-2024/",
    "name":"All Nobel Prizes 2024 - NobelPrize.org",
    "snippet":"Ill. Niklas Elmehed © Nobel Prize Outreach · This year’s laureates used tools from physics to construct methods that helped lay the foundation for today’s powerful machine learning. John Hopfield created a structure that can store and reconstruct information.",
    "metadata":"None"
    },
    {
    "url":"https://www.aps.org/about/news/2024/10/nobel-physics-2024-winners",
    "name":"APS congratulates 2024 Nobel Prize winners",
    "snippet":"The latest news and announcements about APS and the global physics community.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/popular-information/",
    "name":"The Nobel Prize in Physics 2024 - Popular science background - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://time.com/7065011/nobel-prize-2024-winners/",
    "name":"These Are the Winners of the 2024 Nobel Prizes",
    "snippet":"Victor Ambros and Gary Ruvkun were on Monday awarded the 2024 Nobel Prize in Physiology or Medicine for their discovery of microRNAs, a class of small molecules essential for gene regulation. Their research has uncovered how these microRNAs influence cellular behavior and contribute to various ...",
    "metadata":"None"
    },
    {
    "url":"https://www.reuters.com/science/hopfield-hinton-win-2024-nobel-prize-physics-2024-10-08/",
    "name":"Nobel physics prize 2024 won by AI pioneers John Hopfield and Geoffrey Hinton | Reuters",
    "snippet":"[1/6]John J Hopfield and Geoffrey E Hinton are awarded this year's Nobel Prize in Physics, announced at a press conference at the Royal Swedish Academy of Sciences in Stockholm, Sweden October 8, 2024.",
    "metadata":"None"
    },
    {
    "url":"https://www.weforum.org/stories/2024/10/nobel-prize-winners-2024/",
    "name":"These are the Nobel Prize winners of 2024 | World Economic Forum",
    "snippet":"AI pioneers John Hopfield and Geoffrey Hinton were both awarded the Physics prize, for using tools to develop methods that are the foundation of today’s machine learning. Widely credited as \"a godfather of AI\", British-Canadian Hinton invented a method that can autonomously find properties ...",
    "metadata":"None"
    },
    {
    "url":"https://new.nsf.gov/news/nsf-congratulates-laureates-2024-nobel-prize-physics",
    "name":"NSF congratulates laureates of the 2024 Nobel Prize in physics | NSF - National Science Foundation",
    "snippet":"Two researchers used fundamental knowledge of the physical properties of materials to create key innovations that make artificial intelligence work ... The U.S. National Science Foundation congratulates John J. Hopfield and Geoffrey E. Hinton for their Nobel Prize in physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/lists/all-nobel-prizes-in-physics/",
    "name":"All Nobel Prizes in Physics - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics has been awarded 118 times to 227 Nobel Prize laureates between 1901 and 2024. John Bardeen is the only laureate who has been awarded the Nobel Prize in Physics twice, in 1956 and 1972. This means that a total of 226 individuals have received the Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://en.wikipedia.org/wiki/List_of_Nobel_laureates_in_Physics",
    "name":"List of Nobel laureates in Physics - Wikipedia",
    "snippet":"The Nobel Prize in Physics has ... as of 2024. The first prize in physics was awarded in 1901 to Wilhelm Conrad Röntgen, of Germany, who received 150,782 SEK. John Bardeen is the only laureate to win the prize twice—in 1956 and 1972. William Lawrence Bragg was the youngest Nobel laureate in physics; he won the prize ...",
    "metadata":"None"
    },
    {
    "url":"https://www.reddit.com/r/math/comments/1fyzz6t/the_nobel_prize_in_physics_2024_was_awarded_to/",
    "name":"r/math on Reddit: The Nobel Prize in Physics 2024 was awarded to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "snippet":"I think the Boltzmann machine is a really beautiful model, even from the mathematical point of view. I’m still a little bit shocked when I learned that the Nobel Prize in Physics 2024 goes to ML/DL, as much as I also like (theoretical) computer science.",
    "metadata":"None"
    },
    {
    "url":"https://spectrum.ieee.org/nobel-prize-in-physics",
    "name":"Why the Nobel Prize in Physics Went to AI Research",
    "snippet":"The Nobel Prize Committee for Physics caught the academic community off-guard by handing the 2024 award to John J. Hopfield and Geoffrey E. Hinton for their foundational work in neural networks. The pair won the prize for their seminal papers, both published in the 1980s, that described rudimentary ...",
    "metadata":"None"
    },
    {
    "url":"https://www.nytimes.com/2024/10/08/science/nobel-prize-physics.html",
    "name":"Nobel Physics Prize Awarded for Pioneering A.I. Research by 2 Scientists - The New York Times",
    "snippet":"With work on machine learning that uses artificial neural networks, John J. Hopfield and Geoffrey E. Hinton “showed a completely new way for us to use computers,” the committee said.",
    "metadata":"None"
    },
    {
    "url":"https://www.reuters.com/world/nobel-prize-2024-live-physics-award-be-announced-2024-10-08/",
    "name":"Nobel Physics Prize 2024: Winners are machine learning pioneers Hopfield and Hinton - as it happened | Reuters",
    "snippet":"The award-giving body said the pair used tools from physics to develop methods \"that are the foundation of today\\'s powerful machine learning.\"",
    "metadata":"None"
    },
    {
    "url":"https://finshots.in/archive/whats-up-with-ai-and-the-2024-physics-nobel-prize/",
    "name":"What's up with AI and the 2024 Physics Nobel Prize?",
    "snippet":"An explainer of why two pioneers of AI, John Hopfield and Geoffrey Hinton, were awarded the 2024 Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.pbs.org/newshour/science/watch-live-the-winner-of-the-2024-nobel-prize-in-physics-is",
    "name":"WATCH: AI pioneers John Hopfield and Geoffrey Hinton win 2024 Nobel Prize in physics | PBS News",
    "snippet":"Hinton, who is known as the Godfather of artificial intelligence, is a citizen of Canada and Britain who works at the University of Toronto and Hopfield is an American working at Princeton.",
    "metadata":"None"
    },
    {
    "url":"https://en.wikipedia.org/wiki/Nobel_Prize_in_Physics",
    "name":"Nobel Prize in Physics - Wikipedia",
    "snippet":"The first Nobel Prize in Physics was awarded to German physicist Wilhelm Röntgen in recognition of the extraordinary services he rendered by the discovery of X-rays. This award is administered by the Nobel Foundation and is widely regarded as the most prestigious award that a scientist can receive in physics. It is presented in Stockholm at an annual ceremony on the 10th of December, the anniversary of Nobel's death. As of 2024...",
    "metadata":"None"
    },
    {
    "url":"https://www.jagranjosh.com/general-knowledge/list-of-2024-nobel-prize-winners-in-all-categories-1728376617-1",
    "name":"Nobel Prize 2024 Winners List: Recipient Name, Achievement from All Categories",
    "snippet":"Discover the complete list of Nobel Prize 2024 winners. Stay updated on the latest achievements and contributions recognized by the Nobel Committee this year.",
    "metadata":"None"
    },
    {
    "url":"https://www.artsci.utoronto.ca/news/geoffrey-hinton-wins-2024-nobel-prize-physics",
    "name":"Geoffrey Hinton wins 2024 Nobel Prize in Physics | Faculty of Arts & Science",
    "snippet":"Geoffrey Hinton, a University Professor Emeritus of the Department of Computer Science at the University of Toronto, has been awarded the 2024 Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.ap.org/news-highlights/spotlights/2024/pioneers-in-artificial-intelligence-win-the-nobel-prize-in-physics/",
    "name":"Pioneers in artificial intelligence win the Nobel Prize in physics | The Associated Press",
    "snippet":"This photo combo shows the 2024 Nobel Prize winners in Physics, professor John Hopfield, left, of Princeton University, and professor Geoffrey Hinton, of the University of Toronto, Tuesday, Oct. 8, 2024. (Princeton University via AP and Noah Berger/AP Photo) STOCKHOLM (AP) — Two pioneers of artificial intelligence — John Hopfield and Geoffrey Hinton — won ...",
    "metadata":"None"
    },
    {
    "url":"https://twitter.com/NobelPrize",
    "name":"The Nobel Prize (@NobelPrize) · X",
    "snippet":"The latest tweets from The Nobel Prize (@NobelPrize)",
    "metadata":"None"
    },
    {
    "url":"https://www.aljazeera.com/news/2024/10/8/john-hopfield-and-geoffrey-hinton-win-nobel-prize-in-physics-2024",
    "name":"AI scientists John Hopfield, Geoffrey Hinton win 2024 physics Nobel Prize | Science and Technology News | Al Jazeera",
    "snippet":"John Hopfield and Geoffrey Hinton have won the Nobel Prize in physics 2024 for their pioneering work in the field of machine learning.",
    "metadata":"None"
    }
    ]
    }
    
    
    

##

​

Explore our APIs

Unlock new possibilities with our suite of advanced APIs tailored to meet your
needs and explore more use cases.

## [Smart API](/api-modes/smart-api)## [Research API](/api-modes/research-
api)## [News API](/api-modes/news-api)## [Search API](/api-modes/search-api)

[Open Source Examples](/docs/opensource-examples)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

On this page

  * Introduction
  * Step 1: Set Up Your API Key
  * Step 2: Write the Search Function
  * Explore our APIs

[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

Initial Setup

Quickstart

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### Initial Setup

  * [Quickstart](/docs/quickstart)

##### More Examples

  * [Open Source Examples](/docs/opensource-examples)

Initial Setup

# Quickstart

##

​

Introduction

Welcome to the Quickstart Guide for integrating comprehensive, high-quality
answers with precise and reliable citations using our [Smart](/api-
modes/smart-api), [Research](/api-modes/research-api), [Search](/api-
modes/search-api) and [News](/api-modes/news-api) APIs. This guide will walk
you through the initial setup and provide you with sample code to perform
searches and retrieve results.

##

​

Step 1: Set Up Your API Key

**Before You Get Started**

To use the You.com Smart, Research, Search and News LLM endpoints, you can get
an API key through the self-serve portal at
[api.you.com](https://api.you.com). For support, please reach out via email at
[api@you.com](mailto:api@you.com).

Replace `X-API-Key` in the code with your actual API key:

API Key

    
    
    YOUR_API_KEY = "your_actual_api_key_here"
    

##

​

Step 2: Write the Search Function

Create a function to interact with the Research API:

  * Smart API
  * Research API
  * Search API
  * News API

Learn more about the [Smart API ](/api-modes/smart-api).

smart_api.py

    
    
    import requests
    
    def get_smart_results(query):
        headers = {"X-API-Key": YOUR_API_KEY}
        params = {"query": query, "instructions": instructions}
        return requests.get(
            "https://chat-api.you.com/smart?query={query}",
            params=params,
            headers=headers,
        ).json()
    

Use the function to search for AI snippets related to a specific topic:

  * Smart API
  * Research API
  * Search API
  * News API

smart_results.py

    
    
    get_smart_results("Who won the Nobel Prize in Physics in 2024?")
    

Answer

answer

    
    
    {
    "answer":"#### The 2024 Nobel Prize in Physics\n\n
    The 2024 Nobel Prize in Physics was awarded jointly to **John J. Hopfield**
    and **Geoffrey E. Hinton** \"for foundational discoveries and inventions that
    enable machine learning with artificial neural networks\".
    [[1]](https://www.nobelprize.org/prizes/physics/2024/summary/) [[2]](https://www.nobelprize.org/prizes/physics/2024/press-release/)\n\n      
    Hopfield and Hinton are pioneers in the field of artificial intelligence and
    machine learning. Their work in the 1980s laid the groundwork for the development of
    modern neural networks and deep learning algorithms, which are now widely used in
    various applications.
    [[3]](https://www.nobelprize.org/prizes/physics/2024/popular-information/) [[4]](https://spectrum.ieee.org/nobel-prize-in-physics)\n\n
    Specifically, Hopfield created a structure that can store and reconstruct information, while Hinton
    invented a method that can autonomously find properties in data, which are key
    innovations that make artificial intelligence work.
    [[5]](https://www.weforum.org/stories/2024/10/nobel-prize-winners-2024/)\n\n        
    The Nobel Prize committee recognized their \"foundational discoveries
    and inventions that enable machine learning with artificial neural networks\",
    highlighting how their work has been instrumental in the rapid progress of AI and machine
    learning in recent years.
    [[1]](https://www.nobelprize.org/prizes/physics/2024/summary/) [[2]](https://www.nobelprize.org/prizes/physics/2024/press-release/)"     
    
    "search_results":[
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/summary/",
    "name":"The Nobel Prize in Physics 2024 - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/press-release/",
    "name":"Press release: The Nobel Prize in Physics 2024 - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/",
    "name":"Nobel Prize in Physics",
    "snippet":"The Nobel Prize medal. ... A slide rule that physics laureate Toshihide Maskawa used as a high school student.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/all-nobel-prizes-2024/",
    "name":"All Nobel Prizes 2024 - NobelPrize.org",
    "snippet":"Ill. Niklas Elmehed © Nobel Prize Outreach · This year’s laureates used tools from physics to construct methods that helped lay the foundation for today’s powerful machine learning. John Hopfield created a structure that can store and reconstruct information.",
    "metadata":"None"
    },
    {
    "url":"https://www.aps.org/about/news/2024/10/nobel-physics-2024-winners",
    "name":"APS congratulates 2024 Nobel Prize winners",
    "snippet":"The latest news and announcements about APS and the global physics community.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/physics/2024/popular-information/",
    "name":"The Nobel Prize in Physics 2024 - Popular science background - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics 2024 was awarded jointly to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "metadata":"None"
    },
    {
    "url":"https://time.com/7065011/nobel-prize-2024-winners/",
    "name":"These Are the Winners of the 2024 Nobel Prizes",
    "snippet":"Victor Ambros and Gary Ruvkun were on Monday awarded the 2024 Nobel Prize in Physiology or Medicine for their discovery of microRNAs, a class of small molecules essential for gene regulation. Their research has uncovered how these microRNAs influence cellular behavior and contribute to various ...",
    "metadata":"None"
    },
    {
    "url":"https://www.reuters.com/science/hopfield-hinton-win-2024-nobel-prize-physics-2024-10-08/",
    "name":"Nobel physics prize 2024 won by AI pioneers John Hopfield and Geoffrey Hinton | Reuters",
    "snippet":"[1/6]John J Hopfield and Geoffrey E Hinton are awarded this year's Nobel Prize in Physics, announced at a press conference at the Royal Swedish Academy of Sciences in Stockholm, Sweden October 8, 2024.",
    "metadata":"None"
    },
    {
    "url":"https://www.weforum.org/stories/2024/10/nobel-prize-winners-2024/",
    "name":"These are the Nobel Prize winners of 2024 | World Economic Forum",
    "snippet":"AI pioneers John Hopfield and Geoffrey Hinton were both awarded the Physics prize, for using tools to develop methods that are the foundation of today’s machine learning. Widely credited as \"a godfather of AI\", British-Canadian Hinton invented a method that can autonomously find properties ...",
    "metadata":"None"
    },
    {
    "url":"https://new.nsf.gov/news/nsf-congratulates-laureates-2024-nobel-prize-physics",
    "name":"NSF congratulates laureates of the 2024 Nobel Prize in physics | NSF - National Science Foundation",
    "snippet":"Two researchers used fundamental knowledge of the physical properties of materials to create key innovations that make artificial intelligence work ... The U.S. National Science Foundation congratulates John J. Hopfield and Geoffrey E. Hinton for their Nobel Prize in physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.nobelprize.org/prizes/lists/all-nobel-prizes-in-physics/",
    "name":"All Nobel Prizes in Physics - NobelPrize.org",
    "snippet":"The Nobel Prize in Physics has been awarded 118 times to 227 Nobel Prize laureates between 1901 and 2024. John Bardeen is the only laureate who has been awarded the Nobel Prize in Physics twice, in 1956 and 1972. This means that a total of 226 individuals have received the Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://en.wikipedia.org/wiki/List_of_Nobel_laureates_in_Physics",
    "name":"List of Nobel laureates in Physics - Wikipedia",
    "snippet":"The Nobel Prize in Physics has ... as of 2024. The first prize in physics was awarded in 1901 to Wilhelm Conrad Röntgen, of Germany, who received 150,782 SEK. John Bardeen is the only laureate to win the prize twice—in 1956 and 1972. William Lawrence Bragg was the youngest Nobel laureate in physics; he won the prize ...",
    "metadata":"None"
    },
    {
    "url":"https://www.reddit.com/r/math/comments/1fyzz6t/the_nobel_prize_in_physics_2024_was_awarded_to/",
    "name":"r/math on Reddit: The Nobel Prize in Physics 2024 was awarded to John J. Hopfield and Geoffrey E. Hinton \"for foundational discoveries and inventions that enable machine learning with artificial neural networks\"",
    "snippet":"I think the Boltzmann machine is a really beautiful model, even from the mathematical point of view. I’m still a little bit shocked when I learned that the Nobel Prize in Physics 2024 goes to ML/DL, as much as I also like (theoretical) computer science.",
    "metadata":"None"
    },
    {
    "url":"https://spectrum.ieee.org/nobel-prize-in-physics",
    "name":"Why the Nobel Prize in Physics Went to AI Research",
    "snippet":"The Nobel Prize Committee for Physics caught the academic community off-guard by handing the 2024 award to John J. Hopfield and Geoffrey E. Hinton for their foundational work in neural networks. The pair won the prize for their seminal papers, both published in the 1980s, that described rudimentary ...",
    "metadata":"None"
    },
    {
    "url":"https://www.nytimes.com/2024/10/08/science/nobel-prize-physics.html",
    "name":"Nobel Physics Prize Awarded for Pioneering A.I. Research by 2 Scientists - The New York Times",
    "snippet":"With work on machine learning that uses artificial neural networks, John J. Hopfield and Geoffrey E. Hinton “showed a completely new way for us to use computers,” the committee said.",
    "metadata":"None"
    },
    {
    "url":"https://www.reuters.com/world/nobel-prize-2024-live-physics-award-be-announced-2024-10-08/",
    "name":"Nobel Physics Prize 2024: Winners are machine learning pioneers Hopfield and Hinton - as it happened | Reuters",
    "snippet":"The award-giving body said the pair used tools from physics to develop methods \"that are the foundation of today\\'s powerful machine learning.\"",
    "metadata":"None"
    },
    {
    "url":"https://finshots.in/archive/whats-up-with-ai-and-the-2024-physics-nobel-prize/",
    "name":"What's up with AI and the 2024 Physics Nobel Prize?",
    "snippet":"An explainer of why two pioneers of AI, John Hopfield and Geoffrey Hinton, were awarded the 2024 Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.pbs.org/newshour/science/watch-live-the-winner-of-the-2024-nobel-prize-in-physics-is",
    "name":"WATCH: AI pioneers John Hopfield and Geoffrey Hinton win 2024 Nobel Prize in physics | PBS News",
    "snippet":"Hinton, who is known as the Godfather of artificial intelligence, is a citizen of Canada and Britain who works at the University of Toronto and Hopfield is an American working at Princeton.",
    "metadata":"None"
    },
    {
    "url":"https://en.wikipedia.org/wiki/Nobel_Prize_in_Physics",
    "name":"Nobel Prize in Physics - Wikipedia",
    "snippet":"The first Nobel Prize in Physics was awarded to German physicist Wilhelm Röntgen in recognition of the extraordinary services he rendered by the discovery of X-rays. This award is administered by the Nobel Foundation and is widely regarded as the most prestigious award that a scientist can receive in physics. It is presented in Stockholm at an annual ceremony on the 10th of December, the anniversary of Nobel's death. As of 2024...",
    "metadata":"None"
    },
    {
    "url":"https://www.jagranjosh.com/general-knowledge/list-of-2024-nobel-prize-winners-in-all-categories-1728376617-1",
    "name":"Nobel Prize 2024 Winners List: Recipient Name, Achievement from All Categories",
    "snippet":"Discover the complete list of Nobel Prize 2024 winners. Stay updated on the latest achievements and contributions recognized by the Nobel Committee this year.",
    "metadata":"None"
    },
    {
    "url":"https://www.artsci.utoronto.ca/news/geoffrey-hinton-wins-2024-nobel-prize-physics",
    "name":"Geoffrey Hinton wins 2024 Nobel Prize in Physics | Faculty of Arts & Science",
    "snippet":"Geoffrey Hinton, a University Professor Emeritus of the Department of Computer Science at the University of Toronto, has been awarded the 2024 Nobel Prize in Physics.",
    "metadata":"None"
    },
    {
    "url":"https://www.ap.org/news-highlights/spotlights/2024/pioneers-in-artificial-intelligence-win-the-nobel-prize-in-physics/",
    "name":"Pioneers in artificial intelligence win the Nobel Prize in physics | The Associated Press",
    "snippet":"This photo combo shows the 2024 Nobel Prize winners in Physics, professor John Hopfield, left, of Princeton University, and professor Geoffrey Hinton, of the University of Toronto, Tuesday, Oct. 8, 2024. (Princeton University via AP and Noah Berger/AP Photo) STOCKHOLM (AP) — Two pioneers of artificial intelligence — John Hopfield and Geoffrey Hinton — won ...",
    "metadata":"None"
    },
    {
    "url":"https://twitter.com/NobelPrize",
    "name":"The Nobel Prize (@NobelPrize) · X",
    "snippet":"The latest tweets from The Nobel Prize (@NobelPrize)",
    "metadata":"None"
    },
    {
    "url":"https://www.aljazeera.com/news/2024/10/8/john-hopfield-and-geoffrey-hinton-win-nobel-prize-in-physics-2024",
    "name":"AI scientists John Hopfield, Geoffrey Hinton win 2024 physics Nobel Prize | Science and Technology News | Al Jazeera",
    "snippet":"John Hopfield and Geoffrey Hinton have won the Nobel Prize in physics 2024 for their pioneering work in the field of machine learning.",
    "metadata":"None"
    }
    ]
    }
    
    
    

##

​

Explore our APIs

Unlock new possibilities with our suite of advanced APIs tailored to meet your
needs and explore more use cases.

## [Smart API](/api-modes/smart-api)## [Research API](/api-modes/research-
api)## [News API](/api-modes/news-api)## [Search API](/api-modes/search-api)

[Open Source Examples](/docs/opensource-examples)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

On this page

  * Introduction
  * Step 1: Set Up Your API Key
  * Step 2: Write the Search Function
  * Explore our APIs

[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

API Guide

Search API

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### API Guide

  * [Smart API](/api-modes/smart-api)
  * [Research API](/api-modes/research-api)
  * [Search API](/api-modes/search-api)
  * [News API](/api-modes/news-api)

##### Custom

  * [Custom APIs](/api-modes/custom-api)

API Guide

# Search API

##

​

Accurate and Real-time Web Data

When trying to build applications that rely on integrating real-time web data,
solutions are very limited. LLMs are generally unable to extract and deliver
only snippets from sources without adding additional AI-generated content.

Our **Search API** provides you with direct snippets and URLs to stay
informed, ensuring an accurate and up-to-date understanding of the world.

## Access to Trusted Data

Our API integrates live web data, providing results from trusted sources
complete with URLs for verification.

## Uniquely Long Snippets

Ensure your responses are trustworthy and contain the information you need.

##

​

Use Cases

## Information from Trusted Sources

  

Scientific Articles

query.py

    
    
    import requests
    
    url = "https://api.ydc-index.io/search"
    
    query = {"query":"Search for Scientific Research Articles on Nanomotors for Cleaning Polluted Water"}
    
    headers = {"X-API-Key": "YOUR_API_KEY"}
    
    response = requests.request("GET", url, headers=headers, params=query)
    
    print(response.text)
    

Response

    
    
    {
    "hits": [
      {
        "description": "Self-propelled nanomotors hold considerable promise for developing innovative environmental applications.Self-propelled nanomotors hold considerable promise for developing innovative environmental applications. This review highlights the recent progress ...",
        "snippets": [
          "In addition, those nanoparticles cannot transport ions and pollutants from one place to another. Catalytically powered micro- and nanomotors have attracted a lot of attention over the last few years in multidisciplinary fields of chemistry and physics.5 Since the pioneering works a decade ago, synthetic nanomotors demonstrated the ability to efficiently convert chemical energy into motion like nature uses biochemistry to power biological motors.6,7 Fundamental research is being conducted in this field and a number of interesting applications are opening up in several different fields, such as",
          "The surface modification of some types of nanomotors allows them to capture oil from contaminated waters. Research by Pumera and co-workers described a sodium dodecyl sulfate (SDS)-loaded polysulfone (PSf) capsule that was used to shepherd several oil droplets and to merge them, cleaning the surface of the water.36 The driving force of self-propulsion is based in the Marangoni effect.",
          "These “self-powered remediation systems” could be seen as a new generation of “smart devices” for cleaning water in small pipes or cavities difficult to reach with traditional methods. With constant improvement and considering the key challenges, we expect that artificial nanomachines could play an important role in environmental applications in the near future. Pollution of water by contaminants and chemical threats is a prevalent topic in scientific, economic, political and, consequently, in the public media.",
          "Researchers and engineers are devoting considerable effort to produce more efficient technological solutions for cleaning environmental pollutants."
        ],
        "title": "Catalytic nanomotors for environmental monitoring and water remediation - PMC",
        "url": "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4080807/"
      },
      {
        "description": "The most critical challenge of the twenty-first century is to provide sufficient clean, cheap water for all. This is made worse by population increase…",
        "snippets": [
          "The most critical challenge of the twenty-first century is to provide sufficient clean, cheap water for all. This is made worse by population increase, climate change, and declining water quality. Technology innovation, such as nanotechnology, is essential for enabling integrated water management to increase treatment effectiveness and expand water supplies using unconventional water sources.",
          "Nanotechnology can improve access to clean, safe drinking water by providing innovative nanomaterials for treating surface water, groundwater, and wastewater contaminated by hazardous metal ions, inorganic and organic solutes, and microorganisms. As a result, the development of nanotechnology provided ground-breaking solutions to issues in engineering, physics, chemistry, and others.",
          "Considering the essential need to examine and handle the developing hazardous wastes with lower costs, less energy, and more efficiency, this review shines a light on the current advancements in nanotechnology. Numerous industries, such as scientific research, the medical field, and the food industry, have paid close attention to the expanding significance of nanotechnology and the unique qualities of nanobubbles."
        ],
        "title": "Smart and innovative nanotechnology applications for water purification - ScienceDirect",
        "url": "https://www.sciencedirect.com/science/article/pii/S2773207X23000271"
      },
      {
        "description": "We describe the use of catalytically self-propelled microjets (dubbed micromotors) for degrading organic pollutants in water via the Fenton oxidation process. The tubular micromotors are composed of rolled-up functional nanomembranes consisting of Fe/Pt ...",
        "snippets": [
          "Great efforts have been made to efficiently propel and accurately control micro- and nanomotors by different mechanisms.29−37 Most self-propelled systems are based on the conversion of chemical energy into mechanical motion.38 Nonetheless, there are also other ways to produce self-motion at the micro- and nanoscale, for instance electromagnetic fields,22,39,40 local electrical fields,41 thermal gradients,42,43 photoinduced motion,44−46 or the Marangoni effect.28 This variety of propulsion mechanisms gave rise to a rich diversity of designs of nanomotors such as nanorods,47,48 spherical particles,34,49 microhelices,22,39,40 polymeric capsules,28,50 and tubular microjets.51−53",
          "Paxton W. F.; Kistler K. C.; Olmeda C. C.; Sen A.; St Angelo S. K.; Cao Y. Y.; Mallouk T. E.; Lammert P. E.; Crespi V. H. Catalytic Nanomotors: Autonomous Movement of Striped Nanorods. J. Am. Chem. Soc. 2004, 126, 13424–13431.",
          "Self-propelled microjets have been fabricated by roll-up nanotechnology of thin films51,52 and later produced in porous templates combined with electrodeposition methods.53 However, in the latter case, parameters such as shape, length, and diameter are limited by the commercially available templates, reducing the versatility in the design of those nanomotors.",
          "Differently, roll-up nanotechnology of functional nanomembranes allows a reproducible mass production method54 of micro/nanomotors with custom-made dimensions, flexible in material composition and design."
        ],
        "title": "Self-Propelled Micromotors for Cleaning Polluted Water - PMC",
        "url": "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3872448/"
      },
      {
        "description": "Nano- and micromotors are machines designed to self-propel and—in the process of propelling themselves—perform specialized tasks like cleaning polluted waters. These motors offer distinct advantages over conventionally static decontamination methods, owing to their ability to move around ...",
        "snippets": [
          "Nano- and micromotors are machines designed to self-propel and—in the process of propelling themselves—perform specialized tasks like cleaning polluted waters. These motors offer distinct advantages over conventionally static decontamination methods, owing to their ability to move around and self-mix—which h Recent Review Articles",
          "In the last decade, considerable research efforts have been expended on exploring various mechanisms by which these motors can self-propel and remove pollutants, proving that the removal of oil droplets, heavy metals, and organic compounds using these synthetic motors is possible.",
          "A fundamental understanding of these removal mechanisms, with their attendant advantages and disadvantages, can help researchers fine-tune motor design in the future so that technical issues can be resolved before they are scaled-up for a wide variety of environmental applications."
        ],
        "title": "Nano- and micromotors for cleaning polluted waters: focused review on pollutant removal mechanisms - Nanoscale (RSC Publishing)",
        "url": "https://pubs.rsc.org/en/content/articlelanding/2017/nr/c7nr05494g"
      },
      {
        "description": "Sustainable nanotechnology has made substantial contributions in providing contaminant-free water to humanity. In this Review, we present the compelling need for providing access to clean water through nanotechnology-enabled solutions and the large disparities in ensuring their implementation.",
        "snippets": [
          "Topics discussed include: introduction; considerations for cellulose nanomaterial-based development for engineering applications (structures and nomenclature inconsistencies, comparisons to carbon nanotubes [CNT], cellulose nanomaterial manufg.); use of cellulose nanomaterials for water treatment technologies (nano-remediation strategies [as pollutant adsorbents, as scaffolds]); cellulose nanomaterials for water purifn.",
          "A review is given. Arsenic groundwater pollution has been reported for the Red River delta of Northern Vietnam and the Mekong delta of Southern Vietnam and Cambodia. Although the health of ∼10 million people is at risk from the drinking tube well water, little information is available on the health effects of As exposure in the residents of these regions.",
          "The countrywide survey on regional distribution of As pollution has not been conducted in these countries. As far as we know, symptoms of chronic As exposure have not yet been reported, probably due to the relative short-term usage of the tube wells in the regions.",
          "However, oxidative DNA damage has been obsd. in the residents of Cambodia and so further continuous usage of the tube well might cause severe damage to the health of the residents. We review literature concerning As pollution of groundwater and its health effects on residents of Vietnam and Cambodia."
        ],
        "title": "Clean Water through Nanotechnology: Needs, Gaps, and Fulfillment | ACS Nano",
        "url": "https://pubs.acs.org/doi/10.1021/acsnano.9b01730"
      },
      {
        "description": "Surface water is extremely susceptible to pollution stemming from human activities, such as the expansion of urban and suburban areas, industries, cit…",
        "snippets": [
          "In fact, sources of surface water have become the most common discharge sites for wastewater, which may contain microorganisms, pharmaceutical waste, heavy metals, and harmful pollutants. As a reference standard for clean water, the water quality standards and index of Malaysia were used.",
          "This prompts the use of nanotechnology applications to control surface water pollution and quality, as surface water is the main source of water consumption for humans, animals, and plants. This paper reviewed the application of nanotechnology for the detection and treatment of surface water pollution to ensure the sustainability of a green environment.",
          "Nanotechnologies for the detection and treatment of surface water pollution."
        ],
        "title": "A review of nanotechnological applications to detect and control surface water pollution - ScienceDirect",
        "url": "https://www.sciencedirect.com/science/article/pii/S2352186421006805"
      },
      {
        "description": "PDF | Nano- and micromotors are machines designed to self-propel and—in the process of propelling themselves—perform specialized tasks like cleaning... | Find, read and cite all the research you need on ResearchGate",
        "snippets": [
          "While offering autonomous propulsion, conventional micro-/nanomachines usually rely on the decomposition of external chemical fuels (e.g., H2 O2 ), which greatly hinders their applications in biologically relevant media. Recent developments have resulted in various micro-/nanomotors that can be powered by biocompatible fuels.",
          "Here, recent developments on fuel-free micro-/nanomotors (powered by various external stimuli such as light, magnetic, electric, or ultrasonic fields) are summarized, ranging from fabrication to propulsion mechanisms. The applications of these fuel-free micro-/nanomotors are also discussed, including nanopatterning, targeted drug/gene delivery, cell manipulation, and precision nanosurgery.",
          "Fuel-free synthetic micro-/nanomotors, which can move without external chemical fuels, represent another attractive solution for practical applications owing to their biocompatibility and sustainability.",
          "micromotor’s surface upon the nanomotor–oil interaction and"
        ],
        "title": "(PDF) Nano- and Micromotors for Cleaning Polluted Waters: Focused Review on Pollutant Removal Mechanisms",
        "url": "https://www.researchgate.net/publication/319642204_Nano-_and_Micromotors_for_Cleaning_Polluted_Waters_Focused_Review_on_Pollutant_Removal_Mechanisms"
      },
      {
        "description": "Important challenges in the global water situation, mainly resulting from worldwide population growth and climate change, require novel innovative water technologies in order to ensure a supply of drinking water and reduce global water pollution. Against ...",
        "snippets": [
          "The use of magnetic nanoparticles (magnetite Fe3O4) for separation of water pollutants has already been established in ground water remediation, in particular for the removal of arsenic.28 The conventionally applied “pump-and-treat” technology for groundwater treatment comprises pumping up the groundwater to the surface and further treatment, usually by activated carbon for final purification. The considerably extended operating hours and higher environmental clean-up costs can be reduced by applying in situ technologies.",
          "Even industrialized countries like the USA, providing highly innovative technologies for saving and purifying water, show the difficulty of exhausted water reservoirs due to the fact that more water is extracted than refilled. In the People’s Republic of China, 550 of the 600 largest cities suffer from a water shortage, since the biggest rivers are immensely polluted and even their use for irrigation has to be omitted, not to mention treatment for potable water.",
          "Photocatalysis is an advanced oxidation process that is employed in the field of water and wastewater treatment, in particular for oxidative elimination of micropollutants and microbial pathogens.48,49 As reported in the literature,50–52 most organic pollutants can be degraded by heterogeneous photocatalysis.",
          "Solids that are used to adsorb gases or dissolved substances are called adsorbents, and the adsorbed molecules are usually referred to collectively as the adsorbate.4 Due to their high specific surface area, nanoadsorbents show a considerably higher rate of adsorption for organic compounds compared with granular or powdered activated carbon. They have great potential for novel, more efficient, and faster decontamination processes aimed at removal of organic and inorganic pollutants like heavy metals and micropollutants."
        ],
        "title": "Innovations in nanotechnology for water treatment - PMC",
        "url": "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4294021/"
      },
      {
        "description": "Nowadays, global water scarcity is becoming a pressing issue, and the discharge of various pollutants leads to the biological pollution of water bodies, which further leads to the poisoning of living organisms. Consequently, traditional water treatment methods are proving inadequate in addressing ...",
        "snippets": [
          "Nowadays, global water scarcity is becoming a pressing issue, and the discharge of various pollutants leads to the biological pollution of water bodies, which further leads to the poisoning of living organisms. Consequently, traditional water treatment methods are proving inadequate in addressing the growing demands of various industries.",
          "Effects of radius and length on the nanomotor rotors in aqueous solution driven by the rotating electric field. J. Phys. Chem. C 123 (50), 30649–30656. doi:10.1021/acs.jpcc.9b07345 ... Fuller, R., Landrigan, P. J., Balakrishnan, K., Bathan, G., Bose-O'Reilly, S., Brauer, M., et al. (2022). Pollution and health: a progress update.",
          "In recent years, micro/nanorobots and micro/nanomotor technologies have shown great advantages such as low cost, high efficiency and environmental friendliness in environmental remediation and water purification applications, which have gained widespread attention and have great potential for development and application.",
          "Micro/nanorobots (MNRs) or micro/nanomotors (MNMs), usually refer to microscopic substances with actuation capability between 1 and 1 mm in size, which can be both organic or inorganic, even artificially edited and modified microorganisms from nature."
        ],
        "title": "Frontiers | Micro/nanorobots for remediation of water resources and aquatic life",
        "url": "https://www.frontiersin.org/articles/10.3389/fbioe.2023.1312074/full"
      },
      {
        "description": "Nano/micromotor technology is evolving as an effective method for water treatment applications in comparison to existing static mechanisms. The dynamic nature of the nano/micromotor particles enable faster mass transport and a uniform mixing ...",
        "snippets": [
          "Other applications include self-powered porous spore@Fe3O4 biohybrid micromotors20 for the removal of toxic lead ions; mesoporous CoNi@Pt nanomotors, T/Fe/Cr micromotors and Fe3O4 nanoparticles are utilized for degradation of organic pollutants26–28; SW-Fe2O3/MnO2 micromotors used for oxidation of anthraquinone dyes/chlorophenols29; and MnFe2O4/oleic acid micromotors and Mg/Ti/Ni/Au Janus micromotors for oil removal22,30.",
          "On the other hand, the fabrication process of these nanomotors is complex and for driving requires a specific wavelength light source, a costly metal catalyst (Pt, Au), and hazardous media (i.e., hydrogen peroxide). They also have weak mechanical properties, such as limited reusability as an absorbent in aqueous media.",
          "There are very few reusable nanomotors that have been reported in past years. For instance, V. Singh et al.59 employed reusable ZrNPs/graphene/Pt hybrid micromotors for the removal of organophosphate compounds; D. Vilela et al.60 reported GOx-microbot-based reusable micromotors for lead-ion decontamination (2-cycle reuse); J.",
          "The extraction and recovery of toxic pollutants were successfully performed for ten cycles. In contrast to typical nanomotors, this design could be utilized to adjust the surface property of the TM nanorobots by changing the type of functional groups (e.g., -OH, -NH2, and -COOH) according to practical needs."
        ],
        "title": "Pick up and dispose of pollutants from water via temperature-responsive micellar copolymers on magnetite nanorobots - PMC",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8888651/"
      }
    ],
    "latency": 0.6449015140533447
    }
    

##

​

Explore further

## [Quickstart](/docs/quickstart)## [API Reference](/api-reference)

[Research API](/api-modes/research-api)[News API](/api-modes/news-api)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

On this page

  * Accurate and Real-time Web Data
  * Use Cases
  * Explore further

[You.com API home page![light logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/light.svg)![dark logo](https://mintlify.s3.us-
west-1.amazonaws.com/you/logo/dark.svg)](/)

Search or ask...

  * [Discord](https://discord.com/invite/youdotcom)
  * [Support](mailto:api@you.com)
  * [Support](mailto:api@you.com)

Search...

Navigation

API Reference

Search

[Welcome](/welcome)[Quickstart](/docs/quickstart)[API Reference](/api-
reference/smart)[API Guide](/api-modes/smart-api)

##### API Reference

  * [POSTSmart API](/api-reference/smart)
  * [POSTResearch API](/api-reference/research)
  * [GETSearch](/api-reference/search)
  * [GETNews](/api-reference/news)

API Reference

# Search

GET

/

search

Try it

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request GET \
      --url https://chat-api.you.com/search \
      --header 'X-API-Key: <api-key>'

200

    
    
    {
      "hits": [
        {
          "url": "https://you.com",
          "title": "The World's Greatest Search Engine!",
          "description": "Search on YDC",
          "favicon_url": "https://someurl.com/favicon",
          "thumbnail_url": "https://www.somethumbnailsite.com/thumbnail.jpg",
          "snippets": [
            "I'm an AI assistant that helps you get more done. What can I help you with?"
          ]
        }
      ],
      "latency": 1
    }

**Before You Get Started**

To register for usage of our Search API, please reach out via email at
[api@you.com](mailto:api@you.com).

#### Authorizations

​

X-API-Key

string

header

required

#### Query Parameters

​

query

string

required

Search query used to retrieve relevant results from index

​

num_web_results

integer

Specifies the maximum number of web results to return. Range `1 ≤
num_web_results ≤ 20`.

​

offset

integer

Indicates the `offset` for pagination. The `offset` is calculated in multiples
of `num_web_results`. For example, if `num_web_results = 5` and `offset = 1`,
results 5–10 will be returned. Range `0 ≤ offset ≤ 9`.

​

country

string

Country Code, one of `['AR', 'AU', 'AT', 'BE', 'BR', 'CA', 'CL', 'DK', 'FI',
'FR', 'DE', 'HK', 'IN', 'ID', 'IT', 'JP', 'KR', 'MY', 'MX', 'NL', 'NZ', 'NO',
'CN', 'PL', 'PT', 'PH', 'RU', 'SA', 'ZA', 'ES', 'SE', 'CH', 'TW', 'TR', 'GB',
'US']`.

​

safesearch

string

Configures the safesearch filter for content moderation. `off` \- no filtering
applied.`moderate` \- moderate content filtering (default). `strict` \- strict
content filtering.

#### Response

200 - application/json

A JSON object containing array of search hits and request latency

​

hits

object[]

Show child attributes

​

hits.url

string

The URL of the specific search result.

​

hits.title

string

The title or name of the search result.

​

hits.description

string

A brief description of the content of the search result.

​

hits.favicon_url

string

The URL of the favicon of the search result's domain.

​

hits.thumbnail_url

string

URL of the thumbnail.

​

hits.snippets

string[]

An array of text snippets from the search result, providing a preview of the
content.

​

latency

number

Indicates the time (in seconds) taken by the API to generate the response.

[Research API](/api-reference/research)[News](/api-reference/news)

[twitter](https://twitter.com/youdotcom)[linkedin](https://www.linkedin.com/company/youdotcom)

[Powered by Mintlify](https://mintlify.com/preview-
request?utm_campaign=poweredBy&utm_medium=docs&utm_source=documentation.you.com)

cURL

Python

JavaScript

PHP

Go

Java

    
    
    curl --request GET \
      --url https://chat-api.you.com/search \
      --header 'X-API-Key: <api-key>'

200

    
    
    {
      "hits": [
        {
          "url": "https://you.com",
          "title": "The World's Greatest Search Engine!",
          "description": "Search on YDC",
          "favicon_url": "https://someurl.com/favicon",
          "thumbnail_url": "https://www.somethumbnailsite.com/thumbnail.jpg",
          "snippets": [
            "I'm an AI assistant that helps you get more done. What can I help you with?"
          ]
        }
      ],
      "latency": 1
    }

================
File: resources/you/you.txt
================
https://api.you.com/
https://documentation.you.com/docs/quickstart
https://documentation.you.com/docs/quickstart#step-2%3A-write-the-search-function
https://documentation.you.com/api-modes/search-api
https://documentation.you.com/api-reference/search

================
File: resources/pricing.md
================
### Key Points

- Research suggests You.com API costs around $8 to $8.50 for 1000 searches, depending on the plan.
- It seems likely that Brave API offers the lowest cost at $3 for 1000 searches with the Base plan.
- The evidence leans toward HasData being the cheapest at $0.99 for 1000 searches (prorated), but it's a web scraping API, not a traditional search API, which might be unexpected for users expecting direct search functionality.
- Costs for other APIs like Tavily, SerpAPI, Sonar Perplexity, and Critique vary, with some plans having fixed monthly fees that affect the cost for 1000 searches.

---

### Costs for 1000 Searches

Below is a breakdown of the costs for 1000 searches for each API, based on the available plans and pricing models. Note that some costs are prorated for comparison, while others reflect the actual monthly fee if 1000 searches are within the plan's limit.

- **You.com API**:

  - Explorer AI: $8.50 (prorated, $100/month for 11, 765 calls).
  - Discoverer AI: $8.00 (prorated, $250/month for 31, 250 calls).
  - To perform 1000 searches, you’d likely choose Explorer AI, costing $100 monthly, but for comparison, the per-search cost is used.

- **Brave API**:

  - Free: $0 for up to 2, 000 requests/month, so 1000 searches cost $0 if within limit.
  - Base: $3.00 for 1000 requests (pay-per-use, $3 per 1, 000 requests).
  - Pro: $5.00 for 1000 requests (pay-per-use, $5 per 1, 000 requests).
  - The Base plan is the most cost-effective at $3 for 1000 searches.

- **Tavily API**:

  - Free: $0 for up to 1, 000 credits/month, so 1000 searches cost $0 if within limit.
  - Pay As You Go: $8.00 for 1000 searches ($0.008 per credit, each search is one credit).
  - Bootstrap: $6.67 for 1000 searches (prorated, $100/month for 15, 000 credits, effectively $0.00667 per search), but actual cost is $100 monthly for up to 15, 000 searches.
  - For 1000 searches, Pay As You Go at $8 is more cost-effective than the $100 monthly fee for Bootstrap.

- **SerpAPI**:

  - Developer: $15.00 for 1000 searches (prorated, $75/month for 5, 000 searches).
  - Production: $10.00 for 1000 searches (prorated, $150/month for 15, 000 searches).
  - To do 1000 searches, you pay $75 for Developer or $150 for Production monthly, so costs are $75 or $150, respectively, but prorated for comparison.

- **Sonar Perplexity**:

  - All models list $5.00 for 1000 searches as the search cost, but this likely excludes token costs (input, reasoning, output), which can add significant expense based on usage. Actual cost could be higher, estimated around $5 to $10+ depending on token usage.

- **HasData**:

  - Startup: $2.45 for 1000 searches (prorated, $49/month for 200, 000 credits, 10 credits per search).
  - Business: $0.99 for 1000 searches (prorated, $99/month for 1, 000, 000 credits, 10 credits per search).
  - Note: HasData is a web scraping API, not a traditional search API, which might be unexpected for users. Actual monthly cost is $49 or $99, respectively, for the plans.

- **Critique API**:
  - Pro plan has no monthly fee but usage costs $0.50 per million tokens. Cost for 1000 searches is variable, estimated $0.50 to $5 based on assumed token usage (e.g., 1, 000 to 10, 000 tokens per search), but exact cost depends on actual usage and is hard to quantify without specifics.

---

### Unexpected Detail

An unexpected detail is that HasData, at $0.99 for 1000 searches (prorated), is the cheapest option, but it's primarily for web scraping, not direct search queries, which might not meet expectations for users seeking traditional search APIs like Google or Bing results.

---

---

### Comprehensive Analysis of Search/SERP API Pricing Models in Traditional and LLM-Enabled Services

This analysis, conducted as of 03:54 PM PST on Wednesday, February 26, 2025, provides a detailed examination of the pricing structures for various Search/SERP APIs, both traditional and LLM-enabled, focusing on the cost for 1000 searches. The report aims to assist developers and businesses in understanding cost implications, feature differentiation, and suitability for different use cases, ensuring a thorough comparison across twelve major providers.

#### API Overview and Pricing Models

The APIs under consideration include You.com API, Brave API, Tavily API, SerpAPI, Sonar Perplexity, HasData, and Critique API. Each offers unique functionalities, with pricing based on calls, requests, credits, or tokens, reflecting their approach to search and data retrieval.

##### You.com API

You.com API is designed for AI-powered search, providing access to search and news endpoints. The pricing plans are as follows:

- **Trial AI**: Offers 1, 000 calls per month for 60 days at no cost, ideal for initial testing. For 1000 searches, the cost is $0, but only for the trial period.
- **Explorer AI**: Costs $100 per month for 11, 765 calls, translating to approximately $0.0085 per call. For 1000 searches, the prorated cost is $8.50, but to perform 1000 searches, you pay $100 monthly, as it's a fixed fee for up to 11, 765 calls.
- **Discoverer AI**: Priced at $250 per month for 31, 250 calls, approximately $0.008 per call. For 1000 searches, the prorated cost is $8.00, but the monthly fee is $250 for up to 31, 250 calls.

A "call" here likely refers to a search query, given the context of search endpoints. This API is LLM-enabled, focusing on delivering factual and up-to-date information with citations, making it suitable for applications requiring advanced search capabilities. For comparison, the cost for 1000 searches is $100 for Explorer AI or $250 for Discoverer AI, but prorated costs are $8.50 and $8.00, respectively.

##### Brave API

Brave API offers a traditional search engine API with the following plans:

- **Free**: Allows 1 request per second, up to 2, 000 requests per month at $0, requiring a credit card via Stripe. For 1000 searches, the cost is $0 if within the 2, 000 request limit.
- **Base**: Costs $3.00 per 1, 000 requests, with a rate of 20 requests per second and a monthly limit of 20, 000, 000 requests. This equates to $0.003 per request, so for 1000 searches, the cost is $3.00.
- **Pro**: Priced at $5.00 per 1, 000 requests, with 50 requests per second and unlimited requests, equating to $0.005 per request, so for 1000 searches, the cost is $5.00.

The Base plan is cost-effective for high-volume traditional search needs at $3 for 1000 searches, while the Pro plan offers higher throughput for unlimited usage at $5. The Free plan is $0 for up to 2, 000 requests, making it viable for low-volume users.

##### Tavily API

Tavily API is optimized for AI agents, providing real-time, accurate, and factual search results. Its pricing structure is credit-based:

- **Free**: Provides 1, 000 API credits per month, no credit card required, suitable for testing. For 1000 searches, the cost is $0, but only for up to 1, 000 credits, assuming each search is one credit.
- **Pay As You Go**: Costs $0.008 per credit, flexible for variable usage. Assuming each search is one credit, for 1000 searches, the cost is $8.00.
- **Bootstrap**: Fixed at $100 per month for 15, 000 API credits, approximately $0.00667 per credit. For 1000 searches, the prorated cost is $6.67, but the actual monthly fee is $100 for up to 15, 000 credits, so for 1000 searches, the cost is $100 if subscribed to this plan.

An API credit likely corresponds to a search query, with costs varying by search depth and extraction needs. This makes Tavily suitable for LLM integrations, with Pay As You Go at $8 for 1000 searches being more cost-effective than the $100 monthly fee for Bootstrap for low volumes.

##### SerpAPI

SerpAPI focuses on accessing search results from engines like Google, with clear search-based pricing:

- **Developer**: $75 per month for 5, 000 searches, equating to $0.015 per search. For 1000 searches, the prorated cost is $15.00, but to perform 1000 searches, you pay $75 monthly for up to 5, 000 searches, so the cost is $75.
- **Production**: $150 per month for 15, 000 searches, equating to $0.01 per search. For 1000 searches, the prorated cost is $10.00, but the monthly fee is $150 for up to 15, 000 searches, so the cost is $150.

Additional options include Regular Speed (no extra cost), Ludicrous Speed (+$75/month for Developer, +$150/month for Production), and Ludicrous Speed Max (+$225/month for Developer, +$450/month for Production), likely enhancing response times. This API is traditional, ideal for scraping search engine results with structured data. For 1000 searches, costs are $75 for Developer or $150 for Production, but prorated at $15 and $10, respectively.

##### Sonar Perplexity

Sonar Perplexity, from Perplexity AI, offers an LLM-enabled search API with a complex pricing model based on tokens and searches:

- For all models (Sonar, Sonar Deep Research, etc.), the table lists "Price per 1000 searches" as $5, which is the search cost. However, the detailed pricing includes input tokens ($1-$3 per million), reasoning tokens ($3 per million for Deep Research), output tokens ($1-$15 per million), and searches at $5 per 1, 000 searches.
- A typical request might do 30 searches costing $0.15 for searches, with token costs adding to the total. Estimating, for 1000 searches, if each request does 30 searches, it's about 33.33 requests, and total cost includes token usage, which can vary. The search cost alone is $5 for 1000 searches, but actual cost could be $5 to $10+ depending on token usage (e.g., input 100 tokens, reasoning 150, output 200 per search, leading to higher costs).

This API is designed for real-time, fact-based search, with flexibility for complex queries. For 1000 searches, the cost is at least $5 for searches, with additional token costs making the total likely higher.

##### HasData

HasData is primarily a web scraping API, with pricing based on credits:

- **Startup**: $49 per month for 200, 000 API credits, 15 concurrent requests. Each search costs 10 credits, so 200, 000 credits allow 20, 000 searches. For 1000 searches (10, 000 credits), the prorated cost is $2.45 ($49/200, 000 \* 10, 000), but the actual monthly cost is $49 for up to 20, 000 searches.
- **Business**: $99 per month for 1, 000, 000 API credits, 30 concurrent requests. Each search costs 10 credits, so 1, 000, 000 credits allow 100, 000 searches. For 1000 searches (10, 000 credits), the prorated cost is $0.99 ($99/1, 000, 000 \* 10, 000), but the actual monthly cost is $99 for up to 100, 000 searches.

Credit consumption varies by result type, but for comparison, for 1000 searches, the prorated costs are $2.45 for Startup and $0.99 for Business. However, actual cost is $49 or $99 monthly, respectively, making it $49 or $99 for 1000 searches if subscribed. Note: HasData is not a traditional search API, focusing on extracting data from websites, which might surprise users expecting direct search functionality.

##### Critique API

Critique API appears to be a platform for publishing and using APIs, with pricing:

- **Starter**: Free, 10 API calls per minute, no token limit, includes streaming search endpoint. For 1000 searches, cost is $0 if within rate limits.
- **Pro**: $0.00 per month (usage costs only), 100 API calls per minute, $0.50 per million tokens total, with priority support and websocket streaming. Given the streaming search endpoint, it may offer search capabilities, but details on what constitutes an "API call" or "token" are unclear. Assuming each search uses tokens, for 1000 searches, if each uses 1, 000 to 10, 000 tokens, total tokens are 1, 000, 000 to 10, 000, 000, costing $0.50 to $5, respectively. Exact cost depends on usage and is hard to quantify without specifics.

#### Comparative Analysis

To compare, we standardize costs for 1000 searches, noting both prorated costs for comparison and actual costs if subscribed to plans:

| API Provider | Plan | Cost for 1000 Searches (Prorated) | Actual Cost for 1000 Searches (If Within Plan) |
| --- | --- | --- | --- |
| You.com API | Explorer AI | $8.50 | $100 (monthly fee for 11, 765 calls) |
| You.com API | Discoverer AI | $8.00 | $250 (monthly fee for 31, 250 calls) |
| Brave API | Free | $0.00 (up to 2, 000 requests) | $0 (if within limit) |
| Brave API | Base | $3.00 | $3 (pay-per-use) |
| Brave API | Pro | $5.00 | $5 (pay-per-use) |
| Tavily API | Free | $0.00 (up to 1, 000 credits) | $0 (if within limit) |
| Tavily API | Pay As You Go | $8.00 | $8 (pay-per-use) |
| Tavily API | Bootstrap | $6.67 | $100 (monthly fee for 15, 000 credits) |
| SerpAPI | Developer | $15.00 | $75 (monthly fee for 5, 000 searches) |
| SerpAPI | Production | $10.00 | $150 (monthly fee for 15, 000 searches) |
| Sonar Perplexity | Any | $5.00 (search cost only) | $5+ (includes token costs, estimated $5-$10+) |
| HasData | Startup | $2.45 | $49 (monthly fee for 20, 000 searches) |
| HasData | Business | $0.99 | $99 (monthly fee for 100, 000 searches) |
| Critique API | Pro | $0.50-$5 (estimated, token-based) | Variable (depends on token usage) |

#### Considerations and Recommendations

- **Traditional Search Needs**: For cost efficiency, Brave API's Base plan at $3 for 1000 searches is competitive, especially for pay-per-use models. The Free plan at $0 is viable for low volumes up to 2, 000 requests.
- **LLM-Enabled Search**: Sonar Perplexity offers a base search cost of $5 for 1000 searches, but token costs can increase the total, estimated at $5 to $10+. You.com API at $8.50 to $8.00 (prorated) is another option, with actual costs at $100 to $250 monthly.
- **Web Scraping for Search**: HasData at $0.99 prorated for 1000 searches (Business plan) is the cheapest, but its focus on scraping may not meet direct search API expectations. Actual cost is $99 monthly for up to 100, 000 searches, making it $99 for 1000 searches if subscribed.
- **Fixed vs. Pay-Per-Use**: Plans with fixed monthly fees (e.g., You.com, SerpAPI, HasData, Tavily Bootstrap) may be cost-effective for high volumes but expensive for low usage like 1000 searches. Pay-per-use models (Brave, Tavily Pay As You Go) are better for variable or low volumes.

Users should consider their specific use case, such as volume, complexity, and integration needs, and verify details on official websites like [You API Plans](https://api.you.com/plans), [Brave Search API](https://brave.com/search/api/), [Tavily](https://tavily.com/), [SerpApi](https://serpapi.com/), [Sonar Perplexity Docs](https://docs.perplexity.ai/), and [HasData Prices](https://hasdata.com/prices).

#### Key Citations

- [You API Plans Web LLM & Web Search Pricing](https://api.you.com/plans)
- [Brave Search API Power your search and AI apps](https://brave.com/search/api/)
- [Tavily Fast, reliable access with high rate limits](https://tavily.com/)
- [SerpApi Get Google results from anywhere in the world](https://serpapi.com/)
- [Sonar by Perplexity Power your products with real-time research](https://docs.perplexity.ai/)
- [HasData Our Prices Experience the incredible accuracy](https://hasdata.com/prices)

================
File: src/twat_search/web/engines/lib_falla/core/__init__.py
================


================
File: src/twat_search/web/engines/lib_falla/core/aol.py
================
class Aol(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://search.aol.com/aol/search?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/ask.py
================
class Ask(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://www.ask.com/web?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/bing.py
================
class Bing(Falla):
    def __init__(self) -> None:
        super().__init__(name="Bing")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.find("h2")
            return title_elem.get_text().strip()
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.find("a")
        if link_elem and isinstance(link_elem, Tag) and "href" in link_elem.attrs:
            return cast(str, link_elem.attrs["href"])
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.find("div", {"class": "b_caption"})
        if snippet_elem and isinstance(snippet_elem, Tag):
            p_elem = snippet_elem.find("p")
            if p_elem and isinstance(p_elem, Tag):
                return p_elem.get_text().strip()

================
File: src/twat_search/web/engines/lib_falla/core/dogpile.py
================
class DogPile(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://www.dogpile.com/serp?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/duckduckgo.py
================
logger = logging.getLogger(__name__)
class DuckDuckGo(Falla):
    def __init__(self) -> None:
        super().__init__(name="DuckDuckGo")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    async def _fetch_page(self, url: str) -> str:
            await self._initialize_browser()
                logger.error("Browser context not initialized")
            page = await self.browser_context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                    challenge_exists = await page.evaluate(f"""() => {{
                        logger.warning(f"Challenge detected on DuckDuckGo using selector: {selector}")
                        await page.screenshot(path="duckduckgo_challenge.png")
                        html_content = await page.content()
                        with open("duckduckgo_challenge.html", "w", encoding="utf-8") as f:
                            f.write(html_content)
                        logger.info("Saved challenge page content for debugging")
                logger.debug(f"Error checking for challenges: {e}")
                    logger.info(f"Waiting for selector: {self.wait_for_selector}")
                    await page.wait_for_selector(self.wait_for_selector, timeout=5000)
                    await asyncio.sleep(2)
                logger.warning(f"Timeout waiting for selector in {self.name}: {e}")
            return await page.content()
            logger.error(f"Error fetching page with Playwright: {e}")
                return await self._fetch_page(url)
                await page.close()
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.select_one(".result__title")
            return title_elem.get_text().strip()
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.select_one(".result__a")
            href = str(link_elem.attrs["href"])
            if href.startswith("/"):
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.select_one(".result__snippet")
            return snippet_elem.get_text().strip()
    def get_each_elements(self, elements: list) -> list[dict[str, str]]:
                link = self.get_link(elm)
                    title = self.get_title(elm) or ""
                    snippet = self.get_snippet(elm) or ""
                    elements_list.append(
                logger.debug(f"Error processing element: {e}")

================
File: src/twat_search/web/engines/lib_falla/core/falla.py
================
logger = logging.getLogger(__name__)
class Falla:
    def __init__(self, name: str) -> None:
    async def _initialize_browser(self) -> None:
            p = await async_playwright().start()
            self.browser = await p.chromium.launch(headless=True)
            self.browser_context = await self.browser.new_context(
    async def _close_browser(self) -> None:
            await self.browser_context.close()
            await self.browser.close()
    async def _fetch_page(self, url: str) -> str:
            await self._initialize_browser()
                logger.error("Browser context not initialized")
            page = await self.browser_context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                    logger.info(f"Waiting for selector: {self.wait_for_selector}")
                    await page.wait_for_selector(self.wait_for_selector, timeout=5000)
                    await asyncio.sleep(2)
                logger.warning(f"Timeout waiting for selector in {self.name}")
            return await page.content()
            logger.error(f"Error fetching page with Playwright: {e}")
                return await self._fetch_page(url)
                await page.close()
    def get_element_from_type(
            result = bs_obj.find(type_elem, attr_elem)
            return result if isinstance(result, bs4.element.Tag) else None
            logger.debug(f"Error getting element: {e}")
    def get_tag(
            result = element.find(_type, _attr)
            logger.debug(f"Error getting tag: {e}")
    async def parse_entry_point_async(self, entry_point: str) -> BeautifulSoup | None:
                content = await self._fetch_page(entry_point)
                return BeautifulSoup(content, "html.parser")
                return BeautifulSoup(self.scrapy_splash_request(entry_point), "html.parser")
            return BeautifulSoup(self.get_html_content(entry_point), "html.parser")
            logger.error(f"Error parsing entry point: {e}")
    def parse_entry_point(self, entry_point: str) -> BeautifulSoup | None:
                    loop = asyncio.get_running_loop()
                    if loop.is_running():
                        content_future = asyncio.create_task(self._fetch_page_sync(entry_point))
                        content = loop.run_until_complete(content_future)
                        content = loop.run_until_complete(self._fetch_page_sync(entry_point))
                    content = asyncio.run(self._fetch_page_sync(entry_point))
                    logger.warning(f"No content returned from {entry_point}")
            logger.error(f"Error parsing entry point: {e}", exc_info=True)
    async def _fetch_page_sync(self, url: str) -> str:
            async with async_playwright() as p:
                browser = await p.chromium.launch(headless=True)
                    context = await browser.new_context(
                    page = await context.new_page()
                    await page.goto(url, timeout=60000, wait_until="domcontentloaded")
                            await page.wait_for_selector(self.wait_for_selector, timeout=10000)
                    content = await page.content()
                    logger.info(f"Got content length: {len(content)}")
                    if len(content) > 0:
                        logger.debug(f"Content preview: {content[:200]}...")
                        logger.warning("Received empty content")
                    await browser.close()
                logger.info(f"Retrying in {wait_time} seconds (attempt {self.current_retry + 1}/{self.max_retries})")
                await asyncio.sleep(wait_time)
                return await self._fetch_page_sync(url)
    def get_each_elements(self, elements: bs4.element.ResultSet) -> list[dict[str, str]]:
                title = self.get_title(elm) or ""
                link = self.get_link(elm) or ""
                snippet = self.get_snippet(elm) or ""
                    elements_list.append(
                logger.debug(f"Error processing element: {e}")
    def scrapy_splash_request(self, entry_point: str) -> str:
            return requests.get(splash_url, timeout=30).text
            logger.error(f"Error using Splash: {e}")
    def get_html_content(self, url: str) -> str:
            response = requests.get(url, headers=headers, timeout=15)
            response.raise_for_status()  # Raise an exception for 4XX/5XX responses
            logger.error(f"Error getting HTML content: {e}")
    async def fetch_async(self, entry_point: str) -> list[dict[str, str]]:
            html_parser = await self.parse_entry_point_async(entry_point)
                elements = html_parser.find_all(self.container_element[0], attrs=self.container_element[1])
                return self.get_each_elements(elements)
            logger.error(f"Error fetching results: {e}")
    def fetch(self, entry_point: str) -> list[dict[str, str]]:
            html_parser = self.parse_entry_point(entry_point)
    def get_url(self, query: str) -> str:
        raise NotImplementedError(msg)
    def get_title(self, elm: bs4.element.Tag) -> str:
    def get_link(self, elm: bs4.element.Tag) -> str:
    def get_snippet(self, elm: bs4.element.Tag) -> str:
    def search(self, query: str, pages: str = "") -> list[dict[str, str]]:
        url = self.get_url(query)
        return self.fetch(url)
    async def search_async(self, query: str, pages: str = "") -> list[dict[str, str]]:
            return await self.fetch_async(url)
            await self._close_browser()
    async def close(self) -> None:

================
File: src/twat_search/web/engines/lib_falla/core/fetch_page.py
================
logging.basicConfig(
    handlers=[logging.StreamHandler(sys.stderr)],
logger = logging.getLogger(__name__)
async def fetch_page(url: str, wait_for_selector: str | None = None) -> str:
    logger.info(f"Fetching {url}")
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
            context = await browser.new_context(
            page = await context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                    await page.wait_for_selector(wait_for_selector, timeout=5000)
                    logger.warning(f"Timeout waiting for selector: {e}")
            content = await page.content()
            logger.info(f"Got content length: {len(content)}")
            await browser.close()
async def main_async():
    parser = argparse.ArgumentParser(description="Fetch a web page using Playwright")
    parser.add_argument("url", help="URL to fetch")
    parser.add_argument("--wait-for", help="CSS selector to wait for")
    args = parser.parse_args()
    await fetch_page(args.url, args.wait_for)
def main():
    asyncio.run(main_async())
    main()

================
File: src/twat_search/web/engines/lib_falla/core/gibiru.py
================
class Gibiru(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://gibiru.com/results.html?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/google.py
================
logger = logging.getLogger(__name__)
class Google(Falla):
    def __init__(self) -> None:
        super().__init__(name="Google")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.find("h3")
        if title_elem and isinstance(title_elem, Tag):
            return title_elem.get_text().strip()
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.find("a")
        if link_elem and isinstance(link_elem, Tag) and "href" in link_elem.attrs:
            href = cast(str, link_elem.attrs["href"])
            if href.startswith("/url?"):
                href = href.split("&")[0].replace("/url?q=", "")
                return urllib.parse.unquote(href)
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.find("div", {"class": "VwiC3b"})
        if not snippet_elem or not isinstance(snippet_elem, Tag):
            snippet_elem = elm.find("span", {"class": "aCOpRe"})
            snippet_elem = elm.find("div", {"class": "BNeawe s3v9rd AP7Wnd"})
            text_containers = elm.find_all(["div", "span", "p"], class_=True)
                    isinstance(container, Tag)
                    and container.get_text().strip()
                    and hasattr(container, "name")
        if snippet_elem and isinstance(snippet_elem, Tag):
            return snippet_elem.get_text().strip()
    def get_each_elements(self, elements: ResultSet) -> list[dict[str, str]]:
            if not isinstance(elm, Tag):
                title = self.get_title(elm)
                link = self.get_link(elm)
                snippet = self.get_snippet(elm)
                    elements_list.append(
                logger.debug(f"Error processing element: {e}")
    async def search_async(self, query: str, pages: str = "") -> list[dict[str, str]]:
            url = self.get_url(query)
            logger.info(f"Starting Google search for: {query}")
            logger.info(f"URL: {url}")
            await self._initialize_browser()
                logger.error("Browser context not initialized")
            page = await self.browser_context.new_page()
                await page.goto(url, timeout=60000, wait_until="domcontentloaded")
                logger.info("Page loaded, waiting for selector...")
                        await page.wait_for_selector(self.wait_for_selector, timeout=10000)
                        logger.info(f"Selector '{self.wait_for_selector}' found")
                    logger.warning(f"Timeout waiting for selector: {e}")
                    captcha_exists = await page.evaluate(f"""() => {{
                        logger.warning("CAPTCHA detected on Google search page")
                        await page.screenshot(path="google_captcha.png")
                    logger.error(f"Error checking for CAPTCHA: {e}")
                html_content = await page.content()
                logger.info(f"Retrieved HTML content, length: {len(html_content)}")
                debug_file = f"google_debug_{query.replace(' ', '_')}.html"
                with open(debug_file, "w", encoding="utf-8") as f:
                    f.write(html_content)
                logger.info(f"Wrote HTML content to {Path(debug_file).resolve()}")
                result_count = await page.evaluate("""() => {
                logger.info(f"JavaScript found {result_count} results with 'div.g' selector")
                        count = await page.evaluate(f"""() => {{
                        logger.info(f"Found {count} elements with selector: {selector}")
                        logger.error(f"Error evaluating selector {selector}: {e}")
                await page.close()
            results = await self.fetch_async(url)
            logger.info(f"Got {len(results)} results from fetch_async")
                logger.warning("No results found with standard method, trying alternate parsing")
                if Path(debug_file).exists():
                    with open(debug_file, encoding="utf-8") as f:
                        html_content = f.read()
                    soup = BeautifulSoup(html_content, "html.parser")
                        logger.info(f"Trying alternate selector: {selector_type}.{selector_attrs}")
                        elements = soup.find_all(selector_type, attrs=selector_attrs)
                        logger.info(f"Found {len(elements)} elements")
                            logger.info(f"Using alternate container: {self.container_element}")
                                if not isinstance(elem, Tag):
                                title = self.get_title(elem) or ""
                                link = self.get_link(elem) or ""
                                snippet = self.get_snippet(elem) or ""
                                    logger.info(f"Found result: {title} - {link}")
                                    manual_results.append(
                                logger.info(f"Found {len(manual_results)} results with alternate parsing")
            logger.error(f"Search failed: {e}", exc_info=True)
    def search(self, query: str, pages: str = "") -> list[dict[str, str]]:
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/mojeek.py
================
class Mojeek(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://www.mojeek.com/search?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/qwant.py
================
logger = logging.getLogger(__name__)
class Qwant(Falla):
    def __init__(self) -> None:
        super().__init__(name="Qwant")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    async def _fetch_page(self, url: str) -> str:
            await self._initialize_browser()
                logger.error("Browser context not initialized")
            page = await self.browser_context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                consent_button = page.locator('button:has-text("Accept all")')
                if await consent_button.count() > 0:
                    logger.info("Consent page detected, clicking 'Accept all'")
                    await consent_button.click()
                    await page.wait_for_load_state("networkidle")
                logger.debug(f"No consent page or error handling consent: {e}")
                    logger.info(f"Waiting for selector: {self.wait_for_selector}")
                    await page.wait_for_selector(self.wait_for_selector, timeout=5000)
                    await asyncio.sleep(2)
                logger.warning(f"Timeout waiting for selector in {self.name}: {e}")
            return await page.content()
            logger.error(f"Error fetching page with Playwright: {e}")
                return await self._fetch_page(url)
                await page.close()
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.select_one(".result__title")
            return title_elem.get_text().strip()
        title_elem = elm.select_one("a.url")
        title_elem = elm.select_one("h3")
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.select_one(".result__url")
            return str(link_elem.attrs["href"])
        link_elem = elm.select_one("a.url")
        link_elem = elm.select_one("a[href]")
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.select_one(".result__desc")
            return snippet_elem.get_text().strip()
        snippet_elem = elm.select_one(".result__snippet")
        snippet_elem = elm.select_one("p")
    def search(self, query: str, pages: str = "") -> list[dict[str, str]]:
        url = self.get_url(query)
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/searchencrypt.py
================
class SearchEncrypt(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://www.searchencrypt.com/search/?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/startpage.py
================
class StartPage(Falla):
    def __init__(self):
    def search(self, search_text, pages=""):
        url = "https://www.startpage.com/sp/search?q=" + search_text.replace(" ", "+") + pages
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/yahoo.py
================
logger = logging.getLogger(__name__)
class Yahoo(Falla):
    def __init__(self) -> None:
        super().__init__(name="Yahoo")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    async def _fetch_page(self, url: str) -> str:
            await self._initialize_browser()
                logger.error("Browser context not initialized")
            page = await self.browser_context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                consent_button = page.locator('button:has-text("Accept all")')
                if await consent_button.count() > 0:
                    logger.info("Consent page detected, clicking 'Accept all'")
                    await consent_button.click()
                    await page.wait_for_load_state("networkidle")
                logger.debug(f"No consent page or error handling consent: {e}")
                    logger.info(f"Waiting for selector: {self.wait_for_selector}")
                    await page.wait_for_selector(self.wait_for_selector, timeout=5000)
                    await asyncio.sleep(2)
                logger.warning(f"Timeout waiting for selector in {self.name}: {e}")
            return await page.content()
            logger.error(f"Error fetching page with Playwright: {e}")
                return await self._fetch_page(url)
                await page.close()
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.select_one("h3.title a")
            return title_elem.get_text().strip()
        title_elem = elm.select_one("h3")
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.select_one("h3.title a")
            return str(link_elem.attrs["href"])
        link_elem = elm.select_one("a[href]")
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.select_one("div.compText")
            return snippet_elem.get_text().strip()
        snippet_elem = elm.select_one("p")
    def search(self, query: str, pages: str = "") -> list[dict[str, str]]:
        url = self.get_url(query)
        return self.fetch(url)

================
File: src/twat_search/web/engines/lib_falla/core/yandex.py
================
class Yandex(Falla):
    def __init__(self) -> None:
        super().__init__(name="Yandex")
    def get_url(self, query: str) -> str:
        query_string = urllib.parse.urlencode(params)
    def get_title(self, elm: Tag) -> str:
        title_elem = elm.select_one("div.organic__url-text")
            return title_elem.get_text().strip()
    def get_link(self, elm: Tag) -> str:
        link_elem = elm.select_one("a.link")
            return cast(str, link_elem.attrs["href"])
    def get_snippet(self, elm: Tag) -> str:
        snippet_elem = elm.select_one("div.text-container")
            return snippet_elem.get_text().strip()

================
File: src/twat_search/web/engines/lib_falla/__init__.py
================
PACKAGE_PATH = Path(__file__).parent

================
File: src/twat_search/web/engines/lib_falla/main.py
================
async def async_main(args: argparse.Namespace) -> None:
        results = await get_results_async(args.engine, args.query, args.num)
            for _i, _result in enumerate(results, 1):
        logging.error(f"Error: {e}")
        sys.exit(1)
def main() -> None:
    parser = argparse.ArgumentParser(
    parser.add_argument("-e", "--engine", help="Search engine to use", required=False)
    parser.add_argument("-q", "--query", help="Search query", required=False)
    parser.add_argument("-n", "--num", help="Number of results to return", type=int, default=10)
    parser.add_argument("-l", "--list", help="List available engines", action="store_true")
    parser.add_argument("-v", "--version", help="Show version", action="store_true")
    parser.add_argument("-j", "--json", help="Output results as JSON", action="store_true")
    parser.add_argument("--async", dest="use_async", help="Use async version", action="store_true")
    args = parser.parse_args()
    logging.basicConfig(
        for _engine in list_engines():
        parser.print_help()
            asyncio.run(async_main(args))
            results = get_results(args.engine, args.query, args.num)
    main()

================
File: src/twat_search/web/engines/lib_falla/requirements.txt
================
# this_file: src/twat_search/web/engines/lib_falla/requirements.txt
# Falla search engine scraper dependencies

beautifulsoup4>=4.12.2
lxml>=4.9.3
playwright>=1.40.0
# Core dependencies
requests>=2.31.0

# For splash_scrap mode (optional)
# If you want to use the splash scraper, you'll need to run a splash container:
# docker run -p 8050:8050 scrapinghub/splash

================
File: src/twat_search/web/engines/lib_falla/settings.py
================
SPLASH_SCRAP_URL = os.environ.get("FALLA_SPLASH_SCRAP_URL", "http://localhost:8050")
FALLA_DIR = Path(__file__).parent

================
File: src/twat_search/web/engines/lib_falla/utils.py
================
logger = logging.getLogger(__name__)
class Bcolors:
def list_engines() -> list[str]:
    core_dir = Path(__file__).parent / "core"
    for file in core_dir.glob("*.py"):
        if file.name not in ["__init__.py", "falla.py"] and not file.name.startswith("__"):
            engines.append(engine_name)
    return sorted(engines)
def get_engine_class(engine: str) -> type[Falla]:
    engine_lower = engine.lower()
        available = ", ".join(ENGINES_MAP.keys())
        raise ValueError(msg)
def get_results(engine: str, query: str, num_results: int = 10) -> list[dict[str, str]]:
    engine_class = get_engine_class(engine)
    engine_instance = engine_class()
        results = engine_instance.search(query)
        if num_results and len(results) > num_results:
        logger.error(f"Error getting results from {engine}: {e}")
async def get_results_async(engine: str, query: str, num_results: int = 10) -> list[dict[str, str]]:
        results = await engine_instance.search_async(query)
        await engine_instance.close()

================
File: src/twat_search/web/engines/__init__.py
================
    __all__.extend(
    __all__.extend(["TavilySearchEngine", "tavily"])
    __all__.extend(["PerplexitySearchEngine", "pplx"])
    __all__.extend(["CritiqueSearchEngine", "critique"])
    __all__.extend(["DuckDuckGoSearchEngine", "duckduckgo"])
    __all__.extend(["BingScraperSearchEngine", "bing_scraper"])
    logger.warning(f"Failed to import bing_scraper: {e}")
    __all__.extend(["GoogleScraperEngine", "google_scraper"])
    logger.warning(f"Failed to import google_scraper module: {e}")
    __all__.extend(["SerpApiSearchEngine", "google_serpapi"])
    if is_falla_available():
        logger.warning("Falla search engines are not available")
    logger.warning(f"Failed to import falla module: {e}")
def is_engine_available(engine_name: str) -> bool:
    standardized_name = standardize_engine_name(engine_name)
def get_engine_function(
    return available_engine_functions.get(standardized_name)
def get_available_engines() -> list[str]:
    return list(available_engine_functions.keys())

================
File: src/twat_search/web/engines/base.py
================
logger = logging.getLogger(__name__)
class SearchEngine(abc.ABC):
    def __init__(self, config: EngineConfig, **kwargs: Any) -> None:
        self.num_results = kwargs.get("num_results", 5)
        self.country = kwargs.get("country")
        self.language = kwargs.get("language")
        self.safe_search = kwargs.get("safe_search", True)
        self.time_frame = kwargs.get("time_frame")
        self.timeout = kwargs.get("timeout", 10)
        self.retries = kwargs.get("retries", 2)
        self.retry_delay = kwargs.get("retry_delay", 1.0)
        self.use_random_user_agent = kwargs.get("use_random_user_agent", True)
            raise EngineError(self.engine_code, msg)
            logger.debug(f"Engine '{self.engine_code}' requires an API key")
            logger.debug(f"Config API key: {self.config.api_key is not None}")
                key_prefix = key_value[:4] if len(key_value) > 4 else "****"
                key_suffix = key_value[-4:] if len(key_value) > 4 else "****"
                logger.debug(f"Config API key value: {key_prefix}...{key_suffix}")
                env_value = os.environ.get(env_var)
                logger.debug(f"Environment variable {env_var}: {env_value is not None}")
                    env_prefix = env_value[:4] if len(env_value) > 4 else "****"
                    env_suffix = env_value[-4:] if len(env_value) > 4 else "****"
                    logger.debug(f"Env var {env_var} value: {env_prefix}...{env_suffix}")
            logger.debug(f"Final API key check before validation: {self.config.api_key is not None}")
                    f"Please set it via one of these env vars: {', '.join(self.env_api_key_names)}"
                logger.error(f"API key validation failed: {msg}")
            logger.debug(f"API key validation passed for {self.engine_code}")
    def _get_num_results(self, param_name: str = "num_results", min_value: int = 1) -> int:
        value = self.kwargs.get(param_name)
                return max(min_value, int(value))
                logger.warning(f"Invalid value for '{param_name}' ({value!r}) in {self.engine_code}, using default.")
        default = self.config.default_params.get(param_name) or self.config.default_params.get("num_results")
                return max(min_value, int(default))
                logger.warning(
    def max_results(self) -> int:
        return self._get_num_results(param_name="num_results", min_value=1)
    def limit_results(self, results: list[SearchResult]) -> list[SearchResult]:
        logger.debug(f"limit_results: Got {len(results)} results, self.num_results={self.num_results}")
        logger.debug(f"limit_results: Using max_results={max_results}")
        if max_results > 0 and len(results) > max_results:
            logger.debug(f"limit_results: Limiting to {len(limited)} results")
        logger.debug(f"limit_results: Returning all {len(results)} results (no limiting needed)")
    async def make_http_request(
        if self.use_random_user_agent and "user-agent" not in {k.lower() for k in headers}:
            headers["User-Agent"] = random.choice(USER_AGENTS)
        for attempt in range(1, actual_retries + 2):  # +2 because we want actual_retries+1 attempts
                async with httpx.AsyncClient(timeout=actual_timeout) as client:
                    response = await client.request(
                    response.raise_for_status()
                jitter = random.uniform(0.5, 1.5)
                await asyncio.sleep(actual_delay)
            last_error = httpx.RequestError("Unknown error occurred during HTTP request")
        raise EngineError(self.engine_code, msg) from last_error
    async def search(self, query: str) -> list[SearchResult]:
    def _get_api_key(self) -> str:
            raise EngineError(
                f"API key is required. Set it via one of these env vars: {', '.join(self.env_api_key_names)}",
def register_engine(engine_class: type[SearchEngine]) -> type[SearchEngine]:
        if not hasattr(engine_class, "engine_code") or not engine_class.engine_code:
            raise AttributeError(error_msg)
        if not hasattr(engine_class, "env_api_key_names"):
                engine_class.friendly_engine_name = ENGINE_FRIENDLY_NAMES.get(
        logger.error(f"Failed to register engine {engine_class.__name__}: {e}")
def get_engine(engine_name: str, config: EngineConfig, **kwargs: Any) -> SearchEngine:
    engines = get_registered_engines()
    std_engine_name = standardize_engine_name(engine_name)
    engine_class = engines.get(std_engine_name)
        engine_class = engines.get(engine_name)
        available_engines = ", ".join(sorted(engines.keys()))
        logger.error(msg)
        raise SearchError(msg)
            logger.warning(msg)
            raise EngineError(engine_name, msg)
        engine_instance = engine_class(config, **kwargs)
        logger.debug(f"Successfully initialized engine: {engine_name}")
        if "API key" in str(e):
            env_vars = getattr(engine_class, "env_api_key_names", [])
            env_vars_str = ", ".join(env_vars) if env_vars else "No environment variables defined"
            raise EngineError(engine_name, msg) from e
def get_registered_engines() -> dict[str, type[SearchEngine]]:
    return _engine_registry.copy()

================
File: src/twat_search/web/engines/bing_scraper.py
================
logger = logging.getLogger(__name__)
    class BingScraper:  # type: ignore
        def __init__(
        def search(self, query: str, num_results: int = 10) -> list[Any]:
class BingScraperResult(BaseModel):
class BingScraperSearchEngine(SearchEngine):
        super().__init__(config, **kwargs)
        self.max_retries: int = kwargs.get(
        ) or self.config.default_params.get("max_retries", 3)
        self.delay_between_requests: float = kwargs.get(
        ) or self.config.default_params.get("delay_between_requests", 1.0)
            unused_params.append(f"country='{country}'")
            unused_params.append(f"language='{language}'")
            unused_params.append(f"safe_search={safe_search}")
            unused_params.append(f"time_frame='{time_frame}'")
            logger.debug(
                f"Parameters {', '.join(unused_params)} set but not used by Bing Scraper",
    def _convert_result(self, result: Any) -> SearchResult | None:
            logger.warning("Empty result received from Bing Scraper")
        if not hasattr(result, "title") or not hasattr(result, "url"):
            logger.warning(f"Invalid result format: {result}")
            validated = BingScraperResult(
                description=result.description if hasattr(result, "description") else None,
            return SearchResult(
                    "url": str(result.url),
                    "description": result.description if hasattr(result, "description") else None,
            logger.warning(f"Validation error for result: {exc}")
            logger.warning(f"Unexpected error converting result: {exc}")
    async def search(self, query: str) -> list[SearchResult]:
            raise EngineError(self.engine_code, "Search query cannot be empty")
        logger.info(f"Searching Bing with query: '{query}'")
            scraper = BingScraper(
            raw_results = scraper.search(query, num_results=self.num_results)
                logger.info("No results returned from Bing Scraper")
                f"Received {len(raw_results)} raw results from Bing Scraper",
                search_result = self._convert_result(result)
                    results.append(search_result)
                    if len(results) >= self.num_results:
            logger.info(
                f"Returning {len(results)} validated results from Bing Scraper",
            return self.limit_results(results)
            logger.error(error_msg)
            raise EngineError(self.engine_code, error_msg) from exc
async def bing_scraper(
    config = EngineConfig(enabled=True)
    engine = BingScraperSearchEngine(
    return await engine.search(query)

================
File: src/twat_search/web/engines/brave.py
================
class BraveResult(BaseModel):
class BraveNewsResult(BaseModel):
class BaseBraveEngine(SearchEngine):
    def __init__(
        super().__init__(
            raise EngineError(self.engine_code, "API key is required")
    async def search(self, query: str) -> list[SearchResult]:
        count_param = min(self.max_brave_results, self.num_results)
        async with httpx.AsyncClient() as client:
                response = await client.get(
                response.raise_for_status()
                data = response.json()
                section = data.get(self.response_key, {})
                if section.get("results"):
                            parsed = self.result_model(**result)
                            results.append(self.convert_result(parsed, result))
                            if len(results) >= self.num_results:
                return self.limit_results(results)
                raise EngineError(
    def convert_result(self, parsed: BaseModel, raw: dict[str, Any]) -> SearchResult:
        snippet = getattr(parsed, "description", "")
            publisher = getattr(parsed, "publisher", None)
            published_time = getattr(parsed, "published_time", None)
        url = getattr(parsed, "url", None)
            url = HttpUrl("https://brave.com")
        return SearchResult(
            title=getattr(parsed, "title", ""),
    async def _make_api_call(self, query: str) -> dict[str, Any]:
            raise EngineError(self.engine_code, "Search query cannot be empty")
            "count": min(
        if hasattr(self, "freshness") and self.freshness:
        response = await self.make_http_request(
            data: dict[str, Any] = response.json()
    def limit_results(self, results: list[SearchResult]) -> list[SearchResult]:
class BraveSearchEngine(BaseBraveEngine):
        data = await self._make_api_call(query)
            web_result = data.get("web", {})
            items = web_result.get("results", [])
            for _idx, item in enumerate(items, start=1):
                title = item.get("title", "")
                url = item.get("url", "")
                description = item.get("description", "")
                results.append(
                    SearchResult(
class BraveNewsSearchEngine(BaseBraveEngine):
            items = data.get("results", [])
                if item.get("age") or item.get("source", {}).get("name"):
                    source_name = item.get("source", {}).get("name", "")
                    age = item.get("age", "")
                elif item.get("age"):
                    description = f"{description} - {item.get('age')}"
async def brave(
    config = EngineConfig(api_key=api_key, enabled=True)
    engine = BraveSearchEngine(
    return await engine.search(query)
async def brave_news(
    engine = BraveNewsSearchEngine(

================
File: src/twat_search/web/engines/critique.py
================
class CritiqueResult(BaseModel):
    url: str = Field(default="")  # URL of the result source
    title: str = Field(default="")  # Title of the result
    summary: str = Field(default="")  # Summary or snippet from the result
    source: str = Field(default="")  # Source of the result
class CritiqueResponse(BaseModel):
    results: list[CritiqueResult] = Field(default_factory=list)
class CritiqueSearchEngine(SearchEngine):
    def __init__(
        super().__init__(config)
        self.num_results = self._get_num_results(param_name="num_results", min_value=1)
        self.image_url = image_url or kwargs.get("image_url")
        self.image_base64 = image_base64 or kwargs.get("image_base64")
        self.source_whitelist = source_whitelist or kwargs.get(
        self.source_blacklist = source_blacklist or kwargs.get(
        self.output_format = output_format or kwargs.get("output_format")
        api_key_from_kwargs = kwargs.get("api_key")
            raise EngineError(
                f"API key is required for critique. Set it via one of these env vars: {', '.join(self.env_api_key_names)} or use the --api-key parameter",
    async def _convert_image_url_to_base64(self, image_url: str) -> str:
            async with httpx.AsyncClient() as client:
                response = await client.get(image_url, timeout=30)
                response.raise_for_status()
                encoded = base64.b64encode(response.content).decode("utf-8")
            raise EngineError(self.engine_code, f"Error processing image: {e}")
    async def _build_payload(self, query: str) -> dict[str, Any]:
            payload["image"] = await self._convert_image_url_to_base64(self.image_url)
    def _build_result(self, item: CritiqueResult, rank: int) -> SearchResult:
                HttpUrl(item.url)
                else HttpUrl(
            url_obj = HttpUrl("https://critique-labs.ai")
        return SearchResult(
            raw=item.model_dump(),
    def _parse_results(self, data: dict[str, Any]) -> list[SearchResult]:
        critique_data = CritiqueResponse(
            results=data.get("results", []),
            response=data.get("response"),
            structured_output=data.get("structured_output"),
            results.append(
                SearchResult(
                    url=HttpUrl("https://critique-labs.ai"),
        for idx, item in enumerate(critique_data.results, 1):
                results.append(self._build_result(item, idx))
    async def search(self, query: str) -> list[SearchResult]:
        payload = await self._build_payload(query)
                response = await client.post(
                data = response.json()
                results = self._parse_results(data)
                return self.limit_results(results)
async def critique(
    config = EngineConfig(api_key=api_key, enabled=True)
    engine = CritiqueSearchEngine(
    return await engine.search(query)

================
File: src/twat_search/web/engines/duckduckgo.py
================
logger = logging.getLogger(__name__)
class DuckDuckGoResult(BaseModel):
class DuckDuckGoSearchEngine(SearchEngine):
    def __init__(
        super().__init__(config, **kwargs)
        ) = self._map_init_params(
            logger.debug(
    def _map_init_params(
        num_results = kwargs.get(
        ) or config.default_params.get("num_results", 10)
        region = kwargs.get("region", country) or config.default_params.get(
        lang = language or config.default_params.get("language", None)
        timelimit = kwargs.get("timelimit", time_frame) or config.default_params.get(
        if timelimit and not kwargs.get("timelimit"):
            timelimit = time_mapping.get(timelimit.lower(), timelimit)
        safesearch = kwargs.get("safesearch", safe_search)
        if isinstance(safesearch, str):
            safesearch = safesearch.lower() not in ["off", "false"]
        proxy = kwargs.get("proxy") or config.default_params.get("proxy", None)
        timeout = kwargs.get(
        ) or config.default_params.get("timeout", 10)
    def _convert_result(self, raw: dict[str, Any]) -> SearchResult | None:
            ddg_result = DuckDuckGoResult(
            return SearchResult(
            logger.warning(f"Validation error for result: {exc}")
    async def search(self, query: str) -> list[SearchResult]:
            ddgs = DDGS(proxy=self.proxy, timeout=self.timeout)
            raw_results = ddgs.text(
                converted = self._convert_result(raw)
                    results.append(converted)
                    if len(results) >= self.num_results:
            raise EngineError(
async def duckduckgo(
    config = EngineConfig(enabled=True)
    engine = DuckDuckGoSearchEngine(
    return await engine.search(query)

================
File: src/twat_search/web/engines/falla.py
================
logger = logging.getLogger(__name__)
def is_falla_available() -> bool:
            _check_engine = Google()
            logger.warning(f"Falla engines are not available: {e}")
class FallaSearchEngine(SearchEngine):
    def __init__(self, config: Any, **kwargs: Any) -> None:
        super().__init__(config, **kwargs)
        self._falla_engine = self._create_engine_instance()
    def _create_engine_instance(self) -> Falla:
        return self._falla_engine_class()
    async def search(self, query: str, **_kwargs: Any) -> list[SearchResult]:
            raw_results = cast(list[dict[str, str]], await self._falla_engine.search_async(query=query))
            for i, item in enumerate(raw_results):
                url = item.get("link", "")
                    result = SearchResult(
                        title=item.get("title", ""),
                        url=HttpUrl(url),  # Convert to HttpUrl type
                        snippet=item.get("snippet", ""),
                    results.append(result)
                    logger.warning(f"Invalid URL '{url}' in {self.engine_code} result: {url_err}")
            return self.limit_results(results)
            logger.error(f"Search failed: {e!s}")
            raise EngineError(self.engine_code, msg) from e
class GoogleFallaEngine(FallaSearchEngine):
class BingFallaEngine(FallaSearchEngine):
class DuckDuckGoFallaEngine(FallaSearchEngine):
class YahooFallaEngine(FallaSearchEngine):
class AskFallaEngine(FallaSearchEngine):
class AolFallaEngine(FallaSearchEngine):
class DogpileFallaEngine(FallaSearchEngine):
class GibiruFallaEngine(FallaSearchEngine):
class MojeekFallaEngine(FallaSearchEngine):
class QwantFallaEngine(FallaSearchEngine):
class YandexFallaEngine(FallaSearchEngine):
async def google_falla(query: str, **kwargs: Any) -> list[SearchResult]:
    return await search(
async def bing_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def duckduckgo_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def yahoo_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def ask_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def aol_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def dogpile_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def gibiru_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def mojeek_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def qwant_falla(query: str, **kwargs: Any) -> list[SearchResult]:
async def yandex_falla(query: str, **kwargs: Any) -> list[SearchResult]:

================
File: src/twat_search/web/engines/google_scraper.py
================
    class GoogleSearchResult:  # type: ignore
        def __init__(self, url: str, title: str, description: str):
    def google_search(*args, **kwargs):  # type: ignore
logger = logging.getLogger(__name__)
class GoogleScraperResult(BaseModel):
class GoogleScraperEngine(SearchEngine):
    def __init__(
        super().__init__(config, **kwargs)
        self.num_results: int = num_results or self.config.default_params.get(
        self.language: str = language or self.config.default_params.get(
        self.region: str | None = country or self.config.default_params.get(
            else self.config.default_params.get("safe", "active")
        self.sleep_interval: float = kwargs.get(
        ) or self.config.default_params.get("sleep_interval", 0.0)
        self.ssl_verify: bool | None = kwargs.get(
        ) or self.config.default_params.get("ssl_verify", None)
        self.proxy: str | None = kwargs.get("proxy") or self.config.default_params.get(
        self.unique: bool = kwargs.get("unique") or self.config.default_params.get(
            unused_params.append(f"time_frame='{time_frame}'")
            logger.debug(
                f"Parameters {', '.join(unused_params)} set but not used by Google Scraper",
    def _convert_result(self, result: GoogleSearchResult) -> SearchResult | None:
            logger.warning("Empty result received from Google Scraper")
            title = getattr(result, "title", "") or ""
            description = getattr(result, "description", "") or ""
            validated = GoogleScraperResult(
                url=HttpUrl(result.url),
            return SearchResult(
                    "url": str(result.url),
            logger.warning(f"Validation error for result: {exc}")
            logger.warning(f"Unexpected error converting result: {exc}")
    async def search(self, query: str) -> list[SearchResult]:
            raise EngineError(self.engine_code, "Search query cannot be empty")
        logger.info(f"Searching Google with query: '{query}'")
            raw_results = list(
                google_search(
                logger.info("No results returned from Google Scraper")
                f"Received {len(raw_results)} raw results from Google Scraper",
            logger.error(error_msg)
            raise EngineError(self.engine_code, error_msg) from exc
            for search_result in (self._convert_result(cast(GoogleSearchResult, result)) for result in raw_results)
        logger.info(
            f"Returning {len(results)} validated results from Google Scraper",
        return self.limit_results(results)
async def google_scraper(
    return await search(

================
File: src/twat_search/web/engines/hasdata.py
================
class HasDataGoogleResult(BaseModel):
    def from_api_result(cls, result: dict[str, Any]) -> HasDataGoogleResult:
        return cls(
            title=result.get("title", ""),
            url=HttpUrl(result.get("link", "")),
            snippet=result.get("snippet", ""),
class HasDataBaseEngine(SearchEngine):
    def __init__(
        super().__init__(config)
        self.location = location or kwargs.get("location") or self.config.default_params.get("location")
            device_type or kwargs.get("device_type") or self.config.default_params.get("device_type", "desktop")
            raise EngineError(
                f"HasData API key is required. Set it via one of these env vars: {', '.join(self.env_api_key_names)}",
    async def search(self, query: str) -> list[SearchResult]:
        async with httpx.AsyncClient() as client:
                response = await client.get(
                response.raise_for_status()
                data = response.json()
                organic_results = data.get("organicResults", [])
                for i, result in enumerate(organic_results):
                        parsed = HasDataGoogleResult.from_api_result(result)
                        results.append(
                            SearchResult(
class HasDataGoogleEngine(HasDataBaseEngine):
class HasDataGoogleLightEngine(HasDataBaseEngine):
async def hasdata_google_full(
    config = EngineConfig(api_key=api_key, enabled=True)
    engine = HasDataGoogleEngine(
    return await engine.search(query)
async def hasdata_google(
    engine = HasDataGoogleLightEngine(

================
File: src/twat_search/web/engines/pplx.py
================
logger = logging.getLogger(__name__)
class PerplexityResult(BaseModel):
    answer: str = Field(default="")
    url: str = Field(default="https://perplexity.ai")
    title: str = Field(default="Perplexity AI Response")  # Default title
class PerplexitySearchEngine(SearchEngine):
    def __init__(
        super().__init__(config, **kwargs)
        self.model = self.kwargs.get("model") or self.config.default_params.get("model", "sonar")
    async def search(self, query: str) -> list[SearchResult]:
            raise EngineError(self.engine_code, "Search query cannot be empty")
            "search_recency_filter": self.kwargs.get("time_frame", ""),
            response = await self.make_http_request(
            data = response.json()
            raise EngineError(
                f"API request failed: {str(e)!s}",
                f"Unexpected error: {str(e)!s}",
        for choice in data.get("choices", []):
            answer = choice.get("message", {}).get("content", "")
                pr = PerplexityResult(answer=answer, url=url, title=title)
                url_obj = HttpUrl(pr.url)  # Validate URL format
                results.append(
                    SearchResult(
                if len(results) >= self.max_results:
                logger.warning(f"Invalid result from Perplexity: {e}")
        return self.limit_results(results)
async def pplx(
    logger.debug(f"pplx function called with api_key parameter: {api_key is not None}")
            env_value = os.environ.get(env_var)
            logger.debug(f"Environment variable {env_var} in pplx function: {env_value is not None}")
                logger.debug(f"Using API key from environment variable {env_var}")
        key_prefix = api_key[:4] if len(api_key) > 4 else "****"
        key_suffix = api_key[-4:] if len(api_key) > 4 else "****"
        logger.debug(f"Final API key value: {key_prefix}...{key_suffix}")
        logger.error(
    config = EngineConfig(
    logger.debug(f"Created EngineConfig with api_key: {config.api_key is not None}")
        logger.debug("Creating PerplexitySearchEngine instance")
        engine = PerplexitySearchEngine(
        logger.debug("PerplexitySearchEngine instance created successfully")
        logger.debug("Executing search with PerplexitySearchEngine")
        results = await engine.search(query)
        logger.debug(f"Search completed, got {len(results)} results")
        logger.error(f"Error in pplx function: {e}")

================
File: src/twat_search/web/engines/serpapi.py
================
class SerpApiResult(BaseModel):
class SerpApiResponse(BaseModel):
class SerpApiSearchEngine(SearchEngine):
    def __init__(
        super().__init__(config)
            "num": kwargs.get("num", num_results) or self.config.default_params.get("num", 10),
            "google_domain": kwargs.get("google_domain")
            or self.config.default_params.get("google_domain", "google.com"),
            "gl": kwargs.get("gl", country) or self.config.default_params.get("gl"),
            "hl": kwargs.get("hl", language) or self.config.default_params.get("hl"),
            "safe": _convert_safe(kwargs.get("safe", safe_search)) or self.config.default_params.get("safe"),
            "time_period": kwargs.get("time_period", time_frame) or self.config.default_params.get("time_period"),
            raise EngineError(
                f"SerpApi API key is required. Set it via one of these env vars: {', '.join(self.env_api_key_names)}",
    async def search(self, query: str) -> list[SearchResult]:
        params.update({k: v for k, v in self._params.items() if v is not None})
        async with httpx.AsyncClient() as client:
                response = await client.get(
                response.raise_for_status()
                data = response.json()
                serpapi_response = SerpApiResponse(**data)
                        results.append(
                            SearchResult(
                                raw=result.model_dump(),  # Include raw result for debugging
                return self.limit_results(results)
def _convert_safe(safe: bool | str | None) -> str | None:
    if isinstance(safe, bool):
async def google_serpapi(
    config = EngineConfig(
    engine = SerpApiSearchEngine(
    return await engine.search(query)

================
File: src/twat_search/web/engines/tavily.py
================
class TavilySearchResult(BaseModel):
class TavilySearchResponse(BaseModel):
class TavilySearchEngine(SearchEngine):
    def __init__(
        super().__init__(config, **kwargs)
            self.num_results = kwargs.get("num_results") or self.config.default_params.get(
        self.search_depth = search_depth or self.config.default_params.get("search_depth", "basic")
        self.include_domains = include_domains or self.config.default_params.get("include_domains", None)
        self.exclude_domains = exclude_domains or self.config.default_params.get("exclude_domains", None)
        self.include_answer = include_answer or self.config.default_params.get("include_answer", False)
        self.max_tokens = max_tokens or self.config.default_params.get("max_tokens", None)
        self.search_type = search_type or self.config.default_params.get("search_type", "search")
            raise EngineError(
                f"Tavily API key is required. Set it via one of these env vars: {', '.join(self.env_api_key_names)}",
    def _build_payload(self, query: str) -> dict:
    def _convert_result(self, item: dict, rank: int) -> SearchResult | None:
            validated_url = HttpUrl(item.get("url", ""))
            return SearchResult(
                title=item.get("title", ""),
                snippet=textwrap.shorten(
                    item.get("content", "").strip(),
    async def search(self, query: str) -> list[SearchResult]:
        payload = self._build_payload(query)
        async with httpx.AsyncClient() as client:
                response = await client.post(
                response.raise_for_status()
                data = response.json()
                raise EngineError(self.engine_code, f"HTTP error: {e}")
                raise EngineError(self.engine_code, f"Request error: {e}")
                raise EngineError(self.engine_code, f"Error: {e!s}")
            parsed_response = TavilySearchResponse.model_validate(data)
            items = [item.model_dump() for item in parsed_response.results]
            items = data.get("results", [])
        for idx, item in enumerate(items, start=1):
            converted = self._convert_result(item, idx)
                results.append(converted)
async def tavily(
    config = EngineConfig(
    engine = TavilySearchEngine(
    return await engine.search(query)

================
File: src/twat_search/web/engines/you.py
================
logger = logging.getLogger(__name__)
class YouSearchHit(BaseModel):
    snippet: str = Field(alias="description")
class YouSearchResponse(BaseModel):
    search_id: str | None = Field(None, alias="searchId")
class YouNewsArticle(BaseModel):
class YouNewsResponse(BaseModel):
class YouBaseEngine(SearchEngine):
    def __init__(
        super().__init__(config, **kwargs)
        self.country_code = kwargs.get("country") or self.config.default_params.get(
    async def _make_api_call(self, query: str) -> Any:
            params["safesearch"] = str(self.safe_search).lower()
        logger.debug(f"Making You.com API request to {self.base_url} with params: {params}")
            response = await self.make_http_request(
            return response.json()
            raise EngineError(self.engine_code, f"API request failed: {str(e)!s}")
            raise EngineError(self.engine_code, f"Unexpected error: {str(e)!s}")
class YouSearchEngine(YouBaseEngine):
    async def search(self, query: str) -> list[SearchResult]:
            raise EngineError(self.engine_code, "Search query cannot be empty")
        data = await self._make_api_call(query)
            you_response = YouSearchResponse(**data)
                    results.append(
                        SearchResult(
                            raw=hit.model_dump(by_alias=True),
                    if len(results) >= self.max_results:
                    logger.warning(f"Invalid result from You.com: {e}")
            return self.limit_results(results)
            raise EngineError(
class YouNewsSearchEngine(YouBaseEngine):
            you_response = YouNewsResponse(**data)
                            raw=article.model_dump(by_alias=True),
                    logger.warning(f"Invalid news result from You.com: {e}")
async def you(
    config = EngineConfig(
    engine = YouSearchEngine(
    return await engine.search(query)
async def you_news(
    engine = YouNewsSearchEngine(

================
File: src/twat_search/web/__init__.py
================
    __all__.extend(["Config", "EngineConfig", "SearchResult", "search"])
    __all__.extend(["brave", "brave_news"])
    __all__.extend(["pplx"])
    __all__.extend(["tavily"])
    __all__.extend(["you", "you_news"])
    __all__.extend(["critique"])
    __all__.extend(["duckduckgo"])
    __all__.extend(["bing_scraper"])
    __all__.extend(["serpapi"])

================
File: src/twat_search/web/api.py
================
logger = logging.getLogger(__name__)
def get_engine_params(
    std_engine_name = standardize_engine_name(engine_name)
    for k, v in kwargs.items():
        if k.startswith(std_engine_name + "_"):
            engine_specific[k[len(std_engine_name) + 1 :]] = v
        elif k.startswith(engine_name + "_"):  # For backward compatibility
            engine_specific[k[len(engine_name) + 1 :]] = v
    std_engines = [standardize_engine_name(e) for e in engines]
    non_prefixed = {k: v for k, v in kwargs.items() if not any(k.startswith(e + "_") for e in std_engines + engines)}
def init_engine_task(
    engine_config = config.engines.get(std_engine_name)
        engine_config = config.engines.get(engine_name)
            logger.warning(f"Engine '{engine_name}' not configured, using default configuration.")
            engine_config = EngineConfig(enabled=True)
    num_results = kwargs.get("num_results")
        logger.debug(f"Initializing engine '{engine_name}' with num_results={num_results}")
        engine_params = get_engine_params(
            engines=kwargs.get("engines", []),
            common_params=kwargs.get("common_params", {}),
        engine_instance: SearchEngine = get_engine(
        logger.info(f"🔍 Querying engine: {engine_name}")
        async def search_with_error_handling() -> list[SearchResult]:
                return await engine_instance.search(query)
                logger.error(f"Search with engine '{engine_name}' failed: {e}")
        return engine_name, search_with_error_handling()
        error_type = type(e).__name__
        error_msg = str(e)
            logger.error(
            logger.warning(f"Engine '{engine_name}' is disabled. Enable it in your configuration to use it.")
            logger.error(f"Failed to initialize engine '{engine_name}': {error_type}: {error_msg}")
async def search(
        config = config or Config()
        if engines is not None and len(engines) == 0:
            logger.error(msg)
            raise SearchError(msg)
        explicit_engines_requested = engines is not None and len(engines) > 0
        engines_to_try = engines or list(config.engines.keys())
        logger.debug(f"Search requested with num_results={num_results}")
        engines_to_try = [standardize_engine_name(e) for e in engines_to_try]
                            default_result_count = engine_config.default_params.get("result_count")
                task_result = init_engine_task(
                    engine_names.append(task_result[0])
                    tasks.append(task_result[1])
                    failed_engines.append(engine_name)
                logger.warning(f"Unexpected error initializing engine '{engine_name}': {e}")
            failed_engines_str = ", ".join(failed_engines)
            logger.warning(f"Failed to initialize engines: {failed_engines_str}")
                msg = f"No search engines could be initialized from requested engines: {', '.join(engines_to_try)}"
            logger.warning("Falling back to any available search engine...")
            for engine_name in get_registered_engines():
                        logger.info(f"Successfully fell back to engine: {engine_name}")
                    logger.debug(f"Failed to initialize fallback engine {engine_name}: {e}")
        results = await asyncio.gather(*tasks, return_exceptions=True)
        for engine_name, result in zip(engine_names, results, strict=False):
            if isinstance(result, Exception):
            elif isinstance(result, list):
                result_count = len(result)
                    logger.info(
                    flattened_results.extend(result)
                logger.warning(
                    f"⚠️ Engine '{engine_name}' returned unexpected type: {type(result)}",
        logger.error(f"Search failed: {e}")
    logger.info(f"Total results found across all engines: {len(flattened_results)}")

================
File: src/twat_search/web/cli.py
================
class CustomJSONEncoder(json_lib.JSONEncoder):
    def default(self, o: Any) -> Any:
            return str(o)
            return json_lib.JSONEncoder.default(self, o)
console = Console()
class SearchCLI:
    def __init__(self) -> None:
        self.logger = logging.getLogger("twat_search.cli")
        self.log_handler = RichHandler(rich_tracebacks=True)
        self._configure_logging()
        self.console = Console()
        available_engines = get_available_engines()
            self.logger.warning(
                f"{', '.join(missing_engines)}. "
    def _configure_logging(self, verbose: bool = False) -> None:
        logging.basicConfig(
        self.logger.setLevel(level)
        logging.getLogger("twat_search.web.api").setLevel(level)
        logging.getLogger("twat_search.web.engines").setLevel(level)
        logging.getLogger("httpx").setLevel(level)
    def _parse_engines(self, engines_arg: Any) -> list[str] | None:
        if isinstance(engines_arg, str):
            if engines_arg.strip().lower() == "free":
                self.logger.info(f"Using 'free' engines: {', '.join(engines)}")
            if engines_arg.strip().lower() == "best":
                self.logger.info(f"Using 'best' engines: {', '.join(engines)}")
            if engines_arg.strip().lower() == "all":
                engines = get_available_engines()
                self.logger.info(
                    f"Using 'all' available engines: {', '.join(engines)}",
            engines = [e.strip() for e in engines_arg.split(",") if e.strip()]
            return [standardize_engine_name(e) for e in engines]
        if isinstance(engines_arg, list | tuple):
            engines = [str(e).strip() for e in engines_arg if str(e).strip()]
            f"Unexpected engines type: {type(engines_arg)}. Using all available engines.",
    async def _run_search(
                standardized_name = standardize_engine_name(engine)
                    available.append(engine)
                    invalid_engines.append(engine)
                        f"Engine '{engine}' is not valid. Valid engines are: {', '.join(ALL_POSSIBLE_ENGINES)}",
                error_msg = f"None of the specified engines are valid: {', '.join(invalid_engines)}"
                self.logger.error(error_msg)
                _display_errors([error_msg])
            self.logger.debug(f"Attempting to search with engines: {engines}")
            results = await search(query=query, engines=engines, strict_mode=True, **kwargs)
            return _process_results(results)
            self.logger.error(f"Search failed: {e}")
            _display_errors([str(e)])
    async def _search_engine(
            engine_func = get_engine_function(engine)
                self.logger.warning(error_msg)
            registered_engines = get_registered_engines()
            engine_class = registered_engines.get(engine)
            friendly = engine_class.friendly_engine_name if engine_class else ENGINE_FRIENDLY_NAMES.get(engine, engine)
            friendly = ENGINE_FRIENDLY_NAMES.get(engine, engine)
            self.console.print(f"[bold]Searching {friendly}[/bold]: {query}")
            results = await engine_func(query=query, **params)
            processed_results = _process_results(results)
                _display_json_results(processed_results)
            _display_results(processed_results, verbose, plain)
            self.logger.error(f"{friendly} search failed: {e}")
    def q(
        self._configure_logging(verbose)
            self.logger.debug(f"Overriding num_results={num_results} with n={kwargs['n']}")
        self.logger.debug(f"Args - n: {kwargs.get('n')}, num_results: {num_results}")
        self.logger.debug(f"Using num_results={num_results}")
            self.logger.debug(
        engine_list = self._parse_engines(engines)
        common_params = {k: v for k, v in common_params.items() if v is not None}
        self.logger.debug(f"Right before executing search, num_results={num_results}")
            results = asyncio.run(
                self._run_search(
            with self.console.status(
            _display_json_results(results)
        _display_results(results, verbose, plain)
    def info(
            config = Config()
                self._display_engines_json(engine, config)
                self._display_engines_plain(engine, config)
                self._list_all_engines(config)
                self._show_engine_details(engine, config)
                self.logger.error(
    def _display_engines_plain(self, engine: str | None, config: Config) -> None:
                self.console.print(engine)
            for engine_name in sorted(config.engines.keys()):
                self.console.print(engine_name)
    def _list_all_engines(self, config: Config) -> None:
        table = Table(title="🔎 Available Search Engines")
        table.add_column("Engine", style="cyan", no_wrap=True)
        table.add_column("Enabled", style="magenta")
        table.add_column("API Key Required", style="yellow")
        sorted_engines = sorted(config.engines.items(), key=lambda x: x[0])
                hasattr(
                if engine_class and hasattr(engine_class, "env_api_key_names"):
                    api_key_required = bool(engine_class.env_api_key_names)
            table.add_row(
        self.console.print(table)
        self.console.print(
    def _show_engine_details(self, engine_name: str, config: Config) -> None:
            self.console.print("\nAvailable engines:")
                self.console.print(f"- {name}")
        api_key_required = hasattr(engine_config, "api_key") and engine_config.api_key is not None
            engine_class = registered_engines.get(engine_name)
            if not api_key_required and engine_class and hasattr(engine_class, "env_api_key_names"):
                if engine_class and hasattr(engine_class, "friendly_name")
                else ENGINE_FRIENDLY_NAMES.get(engine_name, engine_name)
                    value_status = "✅" if os.environ.get(env_name) else "❌"
                    self.console.print(f"  {env_name}: {value_status}")
            self.console.print("\n[bold]Default Parameters:[/bold]")
                for param, value in engine_config.default_params.items():
                    self.console.print(f"  {param}: {value}")
                self.console.print("  No default parameters specified")
                base_engine = engine_name.split("-")[0]
                engine_module = importlib.import_module(module_name)
                function_name = engine_name.replace("-", "_")
                if hasattr(engine_module, function_name):
                    func = getattr(engine_module, function_name)
                    self.console.print("\n[bold]Function Interface:[/bold]")
                        f"  [green]{function_name}()[/green] - {func.__doc__.strip().split('\\n')[0]}",
                    self.console.print("\n[bold]Example Usage:[/bold]")
            self.console.print("\n[bold]Basic Configuration:[/bold]")
    def _display_engines_json(self, engine: str | None, config: Config) -> None:
            result[engine] = _get_engine_info(
            for engine_name, engine_config in sorted(config.engines.items()):
                result[engine_name] = _get_engine_info(
    async def critique(
            params["source_whitelist"] = [domain.strip() for domain in source_whitelist.split(",")]
            params["source_blacklist"] = [domain.strip() for domain in source_blacklist.split(",")]
        params.update(kwargs)
        return await self._search_engine(
    async def brave(
        params = {k: v for k, v in params.items() if v is not None}
        return await self._search_engine("brave", query, params, json, verbose, plain)
    async def brave_news(
    async def serpapi(
        return await self._search_engine("serpapi", query, params, json, verbose, plain)
    async def tavily(
            params["include_domains"] = [s.strip() for s in include_domains.split(",") if s.strip()]
            params["exclude_domains"] = [s.strip() for s in exclude_domains.split(",") if s.strip()]
        return await self._search_engine("tavily", query, params, json, verbose, plain)
    async def pplx(
        self.logger.debug(f"CLI pplx method called with api_key: {api_key is not None}")
            env_value = os.environ.get(env_var)
            self.logger.debug(f"CLI pplx method - Environment variable {env_var}: {env_value is not None}")
        self.logger.debug(f"CLI pplx method - params: {params}")
        self.logger.debug(f"CLI pplx method - final params: {params}")
        return await self._search_engine("pplx", query, params, json, verbose, plain)
    async def you(
        return await self._search_engine("you", query, params, json, verbose, plain)
    async def you_news(
    async def duckduckgo(
    async def hasdata_google(
    async def hasdata_google_light(
def _check_engine_availability(engine_name: str) -> bool:
    return is_engine_available(engine_name)
def _get_engine_info(
    if hasattr(engine_config, "api_key") and engine_config.api_key is not None:
                {"name": env_name, "set": bool(os.environ.get(env_name))} for env_name in engine_class.env_api_key_names
        if hasattr(
        "enabled": engine_config.enabled if hasattr(engine_config, "enabled") else False,
def _process_results(results: list) -> list[dict[str, Any]]:
        engine_name = getattr(result, "source", None) or "unknown"
        engine_results.setdefault(engine_name, []).append(result)
    for engine, engine_results_list in engine_results.items():
            processed.append(
        for idx, result in enumerate(engine_results_list):
            url = str(result.url)
                    "snippet": result.snippet[:100] + "..." if len(result.snippet) > 100 else result.snippet,
                    "raw_result": getattr(result, "raw", None),
def _display_results(
        console.print("[bold red]No results found![/bold red]")
        urls = set()
                urls.add(result["url"])
        for url in sorted(urls):
            console.print(url)
    table = Table()  # Remove show_lines=True to eliminate row separator lines
        table.add_column("Status", style="magenta")
        table.add_column("Title", style="green")
        table.add_column("URL", style="blue", overflow="fold")
        table.add_column("URL", style="blue", overflow="fold", max_width=70)
            table.add_row(result["engine"], result["url"])
    console.print(table)
                console.print(result)
def _display_errors(error_messages: list[str]) -> None:
    table = Table(title="❌ Search Errors")
    table.add_column("Error", style="red")
        table.add_row(error)
def _display_json_results(processed_results: list[dict[str, Any]]) -> None:
        results_by_engine[engine]["results"].append(
                "snippet": result.get("snippet") if result.get("snippet") != "N/A" else None,
                "raw": result.get("raw_result"),
    console.print(json_lib.dumps(results_by_engine, indent=2, cls=CustomJSONEncoder))
def main() -> None:
    fire.core.Display = lambda lines, out: console.print(*lines)
    fire.Fire(SearchCLI)
    main()

================
File: src/twat_search/web/config.py
================
load_dotenv()
logger = logging.getLogger(__name__)
class EngineConfig(BaseModel):
    default_params: dict[str, Any] = Field(default_factory=dict)
    def __init__(self, **data: Any) -> None:
        super().__init__(**data)
            logger.debug(f"No API key provided for {self.engine_code}, checking environment variables")
                engine_class = get_registered_engines().get(self.engine_code)
                if engine_class and hasattr(engine_class, "env_api_key_names") and engine_class.env_api_key_names:
                    logger.debug(
                        env_value = os.environ.get(env_var)
                        logger.debug(f"Checking env var '{env_var}' in __init__: {env_value is not None}")
                            logger.debug(f"Using API key from environment variable '{env_var}'")
                logger.debug(f"Couldn't check API key requirements for {self.engine_code}: {e}")
    @field_validator("api_key")
    def validate_api_key(cls, v: str | None, info: Any) -> str | None:
        engine_code = info.data.get("engine_code")
        logger.debug(f"Validating API key for engine '{engine_code}', current value: {v is not None}")
                engine_class = get_registered_engines().get(engine_code)
                logger.debug(f"Found engine class for '{engine_code}': {engine_class is not None}")
                        logger.debug(f"Checking env var '{env_var}': {env_value is not None}")
                    logger.warning(
                        f"Please set one of these environment variables: {', '.join(engine_class.env_api_key_names)}",
                logger.debug(f"Couldn't check API key requirements for {engine_code}: {e}")
class Config(BaseModel):
    engines: dict[str, EngineConfig] = Field(default_factory=dict)
    def get_config_path(cls) -> Path:
            return Path(cls.config_path)
        env_path = os.environ.get("TWAT_SEARCH_CONFIG_PATH")
            return Path(env_path)
        home_config = Path.home() / ".twat" / "search_config.json"
        if home_config.exists():
        xdg_config = Path.home() / ".config" / "twat" / "search_config.json"
        if xdg_config.exists():
            config_data = json.loads(json.dumps(DEFAULT_CONFIG))  # Deep copy
        config_path = self.get_config_path()
        if config_path.exists():
                with open(config_path, encoding="utf-8") as f:
                    file_config = json.load(f)
                self._merge_config(config_data, file_config)
                logger.info(f"Loaded configuration from {config_path}")
                logger.error(f"Error loading configuration from {config_path}: {e}")
        _apply_env_overrides(config_data)
            self._merge_config(config_data, data)
        super().__init__(**config_data)
    def _merge_config(self, target: dict[str, Any], source: dict[str, Any]) -> None:
        for key, value in source.items():
            if key in target and isinstance(target[key], dict) and isinstance(value, dict):
                self._merge_config(target[key], value)
    def add_engine(
            engine_config.default_params.update(default_params)
            self.engines[engine_name] = EngineConfig(
def _apply_env_overrides(config_data: dict[str, Any]) -> None:
    for env_var, config_path in ENV_VAR_MAP.items():
            value = _parse_env_value(env_value)
            if isinstance(config_path, str):
                _set_nested_value(config_data, config_path, value)
                _set_nested_value(config_data, path, value)
def _parse_env_value(env_value: str) -> Any:
    if env_value.startswith("{") and env_value.endswith("}"):
            return json.loads(env_value)
    if env_value.lower() in ("true", "yes", "1"):
    if env_value.lower() in ("false", "no", "0"):
    if env_value.isdigit():
        return int(env_value)
    if env_value.replace(".", "", 1).isdigit():
        return float(env_value)
def _set_nested_value(config_data: dict[str, Any], path: list[str], value: Any) -> None:
    for i, path_part in enumerate(path):
        if i == len(path) - 1:
            if path_part not in current or not isinstance(current[path_part], dict):

================
File: src/twat_search/web/engine_constants.py
================
def standardize_engine_name(engine_name: str) -> str:
    return engine_name.replace("-", "_")

================
File: src/twat_search/web/exceptions.py
================
class SearchError(Exception):
    def __init__(self, message: str) -> None:
        super().__init__(message)
class EngineError(SearchError):
    def __init__(self, engine_name: str, message: str) -> None:
        super().__init__(f"Engine '{engine_name}': {message}")

================
File: src/twat_search/web/models.py
================
class SearchResult(BaseModel):
    @field_validator("source")
    def validate_non_empty(cls, v: str) -> str:
        if not v or not v.strip():
            raise ValueError(msg)
        return v.strip()
    @field_validator("title", "snippet")
    def ensure_string(cls, v: str) -> str:
        return v.strip() if v and v.strip() else ""

================
File: src/twat_search/web/utils.py
================
logger = logging.getLogger(__name__)
def load_environment(force_reload: bool = False) -> None:
    if not force_reload and os.environ.get(loaded_flag) == "1":
        logger.debug("Environment variables already loaded")
    load_dotenv()
    if logger.isEnabledFor(logging.DEBUG):  # Only in debug mode
        for key, value in os.environ.items():
                logger.debug(
        logger.info("Environment variables loaded")
class RateLimiter:
    def __init__(self, calls_per_second: float) -> None:
    async def wait(self) -> None:
        current_time = time.time()
            logger.debug(f"Rate limiter sleeping for {delay:.4f} seconds")
            time.sleep(delay)
        self.last_call_time = time.time()
    def wait_if_needed(self) -> None:
        if len(self.call_timestamps) >= self.calls_per_second:
            oldest_timestamp = min(self.call_timestamps)
        self.call_timestamps.append(time.time())
def extract_domain(url: str) -> str:
    parsed = urlparse(url)
        parsed = urlparse(f"https://{url}")
def extract_query_param(url: str, param: str) -> str | None:
    params = parse_qs(parsed.query)
    return params.get(param, [None])[0]

================
File: src/twat_search/__init__.py
================
    __all__.append("__version__")
    __all__.append("web")

================
File: src/twat_search/__main__.py
================
logging.basicConfig(
    handlers=[RichHandler(rich_tracebacks=True)],
logger = logging.getLogger(__name__)
console = Console()
SearchCLIType = TypeVar("SearchCLIType")
class TwatSearchCLI:
    def __init__(self) -> None:
            self.web: Any = web_cli.SearchCLI()
            logger.error(f"Web CLI not available: {e!s}")
            logger.error(
    def _cli_error(*args: Any, **kwargs: Any) -> int:
        console.print(
    def version() -> str:
def main() -> None:
    install(show_locals=True)
    ansi_decoder = AnsiDecoder()
    console = Console(theme=Theme({"prompt": "cyan", "question": "bold cyan"}))
    def display(lines, out):
        console.print(Group(*map(ansi_decoder.decode_line, lines)))
    fire.Fire(TwatSearchCLI, name="twat-search")
    main()

================
File: tests/unit/web/engines/__init__.py
================


================
File: tests/unit/web/engines/test_base.py
================
class TestSearchEngine(SearchEngine):
    async def search(self, query: str) -> list[SearchResult]:
            SearchResult(
                url=HttpUrl("https://example.com/test"),
register_engine(TestSearchEngine)
class DisabledTestSearchEngine(SearchEngine):
        raise NotImplementedError(msg)
register_engine(DisabledTestSearchEngine)
def test_search_engine_is_abstract() -> None:
    assert hasattr(SearchEngine, "__abstractmethods__")
    with pytest.raises(TypeError):
        SearchEngine(EngineConfig())  # type: ignore
def test_search_engine_name_class_var() -> None:
    assert hasattr(SearchEngine, "engine_code")
def test_engine_registration() -> None:
    class NewEngine(SearchEngine):
    returned_class = register_engine(NewEngine)
    engine_instance = get_engine("new_engine", EngineConfig())
    assert isinstance(engine_instance, NewEngine)
def test_get_engine_with_invalid_name() -> None:
    with pytest.raises(SearchError, match="Unknown search engine"):
        get_engine("nonexistent_engine", EngineConfig())
def test_get_engine_with_disabled_engine() -> None:
    config = EngineConfig(enabled=False)
    with pytest.raises(SearchError, match="is disabled"):
        get_engine("disabled_engine", config)
def test_get_engine_with_config() -> None:
    config = EngineConfig(
    engine = get_engine("test_engine", config)
def test_get_engine_with_kwargs() -> None:
    engine = get_engine("test_engine", EngineConfig(), **kwargs)

================
File: tests/unit/web/__init__.py
================


================
File: tests/unit/web/test_api.py
================
logging.basicConfig(level=logging.DEBUG)
T = TypeVar("T")
class MockSearchEngine(SearchEngine):
    def __init__(self, config: EngineConfig, **kwargs: Any) -> None:
        super().__init__(config, **kwargs)
        self.should_fail = kwargs.get("should_fail", False)
    async def search(self, query: str) -> list[SearchResult]:
            raise Exception(msg)
        result_count = self.kwargs.get("result_count", 1)
            SearchResult(
                url=HttpUrl(f"https://example.com/{i + 1}"),
            for i in range(result_count)
register_engine(MockSearchEngine)
def mock_config() -> Config:
    config = Config()
        "mock": EngineConfig(
async def setup_teardown() -> AsyncGenerator[None]:
    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
    with contextlib.suppress(asyncio.CancelledError):
        await asyncio.gather(*tasks)
async def test_search_with_mock_engine(
    results = await search("test query", engines=["mock"], config=mock_config)
    assert len(results) == 2
    assert all(isinstance(result, SearchResult) for result in results)
    assert all(result.source == "mock" for result in results)
async def test_search_with_additional_params(
    results = await search(
    assert len(results) == 3
async def test_search_with_engine_specific_params(
    assert len(results) == 4
async def test_search_with_no_engines(setup_teardown: None) -> None:
    with pytest.raises(SearchError, match="No search engines configured"):
        await search("test query", engines=[])
async def test_search_with_failing_engine(
    assert len(results) == 0
async def test_search_with_nonexistent_engine(
    with pytest.raises(SearchError, match="No search engines could be initialized"):
        await search("test query", engines=["nonexistent"], config=mock_config)
async def test_search_with_disabled_engine(
        await search("test query", engines=["mock"], config=mock_config)

================
File: tests/unit/web/test_config.py
================
def test_engine_config_defaults() -> None:
    config = EngineConfig()
def test_engine_config_values() -> None:
    config = EngineConfig(
def test_config_defaults(isolate_env_vars: None) -> None:
    config = Config()
    assert isinstance(config.engines, dict)
    assert len(config.engines) == 0
def test_config_with_env_vars(monkeypatch: MonkeyPatch, env_vars_for_brave: None) -> None:
def test_config_with_direct_initialization() -> None:
    custom_config = Config(
        engines={"test_engine": EngineConfig(api_key="direct_key", enabled=True, default_params={"count": 5})},
def test_config_env_vars_override_direct_config(monkeypatch: MonkeyPatch) -> None:
    monkeypatch.setenv("BRAVE_API_KEY", "env_key")
        engines={"brave": EngineConfig(api_key="direct_key", enabled=True, default_params={"count": 5})},

================
File: tests/unit/web/test_exceptions.py
================
def test_search_error() -> None:
    exception = SearchError(error_message)
    assert str(exception) == error_message
    assert isinstance(exception, Exception)
def test_engine_error() -> None:
    exception = EngineError(engine_name, error_message)
    assert str(exception) == f"Engine '{engine_name}': {error_message}"
    assert isinstance(exception, SearchError)
def test_engine_error_inheritance() -> None:
        raise EngineError(msg, "Test error")
        if isinstance(e, EngineError):
def test_search_error_as_base_class() -> None:
        raise SearchError(msg)
        exceptions.append(e)
        raise EngineError(msg, "API key missing")
    assert len(exceptions) == 2
    assert isinstance(exceptions[0], SearchError)
    assert isinstance(exceptions[1], EngineError)
    assert "General search error" in str(exceptions[0])
    assert "Engine 'brave': API key missing" in str(exceptions[1])

================
File: tests/unit/web/test_models.py
================
def test_search_result_valid_data() -> None:
    url = HttpUrl("https://example.com")
    result = SearchResult(
    assert str(result.url) == "https://example.com/"
def test_search_result_with_optional_fields() -> None:
def test_search_result_invalid_url() -> None:
    with pytest.raises(ValidationError):
        SearchResult.model_validate(
def test_search_result_empty_fields() -> None:
        SearchResult(
def test_search_result_serialization() -> None:
    result_dict = result.model_dump()
    assert str(result_dict["url"]) == "https://example.com/"
    result_json = result.model_dump_json()
    assert isinstance(result_json, str)
def test_search_result_deserialization() -> None:
    result = SearchResult.model_validate(data)

================
File: tests/unit/web/test_utils.py
================
def rate_limiter() -> RateLimiter:
    return RateLimiter(calls_per_second=5)
def test_rate_limiter_init() -> None:
    limiter = RateLimiter(calls_per_second=10)
def test_rate_limiter_wait_when_not_needed(rate_limiter: RateLimiter) -> None:
    with patch("time.sleep") as mock_sleep:
        rate_limiter.wait_if_needed()
        mock_sleep.assert_not_called()
        for _ in range(3):  # 4 total calls including the one above
def test_rate_limiter_wait_when_needed(rate_limiter: RateLimiter) -> None:
    now = time.time()
    rate_limiter.call_timestamps = [now - 0.01 * i for i in range(rate_limiter.calls_per_second)]
    with patch("time.sleep") as mock_sleep, patch("time.time", return_value=now):
        mock_sleep.assert_called_once()
def test_rate_limiter_cleans_old_timestamps(rate_limiter: RateLimiter) -> None:
    with patch("time.time", return_value=now):
    assert len(rate_limiter.call_timestamps) == len(recent_stamps) + 1  # +1 for the new call
@pytest.mark.parametrize("calls_per_second", [1, 5, 10, 100])
def test_rate_limiter_with_different_rates(calls_per_second: int) -> None:
    limiter = RateLimiter(calls_per_second=calls_per_second)
        for _ in range(calls_per_second):
            limiter.wait_if_needed()
        patch("time.sleep") as mock_sleep,
        patch("time.time", return_value=time.time()),

================
File: tests/unit/__init__.py
================


================
File: tests/unit/mock_engine.py
================
class MockSearchEngine(SearchEngine):
    def __init__(self, config: EngineConfig, **kwargs: Any) -> None:
        super().__init__(config, **kwargs)
        self.should_fail = kwargs.get("should_fail", False)
    async def search(self, query: str) -> list[SearchResult]:
            raise Exception(msg)
        result_count = self.kwargs.get("result_count", 1)
            SearchResult(
                url=HttpUrl(f"https://example.com/{i + 1}"),
            for i in range(result_count)
register_engine(MockSearchEngine)

================
File: tests/web/test_bing_scraper.py
================
class MockSearchResult:
    def __init__(self, title: str, url: str, description: str = "") -> None:
def engine_config() -> EngineConfig:
    return EngineConfig(enabled=True)
def engine(engine_config: EngineConfig) -> BingScraperSearchEngine:
    return BingScraperSearchEngine(config=engine_config, num_results=5)
def mock_results() -> list[MockSearchResult]:
        MockSearchResult(
class TestBingScraperEngine:
    @patch("twat_search.web.engines.bing_scraper.BingScraper")
    def test_init(self, mock_BingScraper: MagicMock, engine: Any) -> None:
        mock_BingScraper.assert_not_called()
    async def test_search_basic(
        mock_instance = MagicMock()
        results = await engine.search("test query")
        assert len(results) == 2
        assert isinstance(results[0], SearchResult)
        assert str(results[0].url) == "https://example.com/1"
        mock_BingScraper.assert_called_once_with(max_retries=3, delay_between_requests=1.0)
        mock_instance.search.assert_called_once_with("test query", num_results=5)
    async def test_custom_parameters(self, mock_BingScraper: MagicMock) -> None:
        engine = BingScraperSearchEngine(
            config=EngineConfig(enabled=True),
        await engine.search("test query")
        mock_BingScraper.assert_called_once_with(max_retries=5, delay_between_requests=2.0)
        mock_instance.search.assert_called_once_with("test query", num_results=10)
    async def test_invalid_url_handling(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        assert len(results) == 1
    @patch("twat_search.web.api.search")
    async def test_bing_scraper_convenience_function(self, mock_search: AsyncMock) -> None:
            SearchResult(
                url=HttpUrl("https://example.com"),
        results = await bing_scraper(
        mock_search.assert_called_once()
    async def test_empty_query(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        with pytest.raises(EngineError) as excinfo:
            await engine.search("")
        assert "Search query cannot be empty" in str(excinfo.value)
    async def test_no_results(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        assert isinstance(results, list)
        assert len(results) == 0
    async def test_network_error(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        mock_instance.search.side_effect = ConnectionError("Network timeout")
        assert "Network error connecting to Bing" in str(excinfo.value)
    async def test_parsing_error(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        mock_instance.search.side_effect = RuntimeError("Failed to parse HTML")
        assert "Error parsing Bing search results" in str(excinfo.value)
    async def test_invalid_result_format(self, mock_BingScraper: MagicMock, engine: BingScraperSearchEngine) -> None:
        class InvalidResult:
            def __init__(self):
        mock_instance.search.return_value = [InvalidResult()]

================
File: tests/conftest.py
================
@pytest.fixture(autouse=True)
def isolate_env_vars(monkeypatch: MonkeyPatch) -> None:
    for env_var in list(os.environ.keys()):
        if any(env_var.endswith(suffix) for suffix in ["_API_KEY", "_ENABLED", "_DEFAULT_PARAMS"]):
            monkeypatch.delenv(env_var, raising=False)
    monkeypatch.setenv("_TEST_ENGINE", "true")
def env_vars_for_brave(monkeypatch: MonkeyPatch) -> None:
        sys.path.insert(0, str(Path(__file__).parent.parent))
        class MockBraveEngine(SearchEngine):
        register_engine(MockBraveEngine)
    monkeypatch.setenv("BRAVE_API_KEY", "test_brave_key")
    monkeypatch.setenv("BRAVE_ENABLED", "true")
    monkeypatch.setenv("BRAVE_DEFAULT_PARAMS", '{"count": 10}')
    monkeypatch.delenv("_TEST_ENGINE", raising=False)

================
File: tests/test_twat_search.py
================
def test_version():

================
File: .gitignore
================
*_autogen/
.DS_Store
__version__.py
__pycache__/
_Chutzpah*
_deps
_NCrunch_*
_pkginfo.txt
_Pvt_Extensions
_ReSharper*/
_TeamCity*
_UpgradeReport_Files/
!?*.[Cc]ache/
!.axoCover/settings.json
!.vscode/extensions.json
!.vscode/launch.json
!.vscode/settings.json
!.vscode/tasks.json
!**/[Pp]ackages/build/
!Directory.Build.rsp
.*crunch*.local.xml
.axoCover/*
.builds
.cr/personal
.fake/
.history/
.ionide/
.localhistory/
.mfractor/
.ntvs_analysis.dat
.paket/paket.exe
.sass-cache/
.vs/
.vscode
.vscode/*
.vshistory/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
[Bb]in/
[Bb]uild[Ll]og.*
[Dd]ebug/
[Dd]ebugPS/
[Dd]ebugPublic/
[Ee]xpress/
[Ll]og/
[Ll]ogs/
[Oo]bj/
[Rr]elease/
[Rr]eleasePS/
[Rr]eleases/
[Tt]est[Rr]esult*/
[Ww][Ii][Nn]32/
*_h.h
*_i.c
*_p.c
*_wpftmp.csproj
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
*- [Bb]ackup.rdl
*.[Cc]ache
*.[Pp]ublish.xml
*.[Rr]e[Ss]harper
*.a
*.app
*.appx
*.appxbundle
*.appxupload
*.aps
*.azurePubxml
*.bim_*.settings
*.bim.layout
*.binlog
*.btm.cs
*.btp.cs
*.build.csdef
*.cab
*.cachefile
*.code-workspace
*.coverage
*.coveragexml
*.d
*.dbmdl
*.dbproj.schemaview
*.dll
*.dotCover
*.DotSettings.user
*.dsp
*.dsw
*.dylib
*.e2e
*.exe
*.gch
*.GhostDoc.xml
*.gpState
*.ilk
*.iobj
*.ipdb
*.jfm
*.jmconfig
*.la
*.lai
*.ldf
*.lib
*.lo
*.log
*.mdf
*.meta
*.mm.*
*.mod
*.msi
*.msix
*.msm
*.msp
*.ncb
*.ndf
*.nuget.props
*.nuget.targets
*.nupkg
*.nvuser
*.o
*.obj
*.odx.cs
*.opendb
*.opensdf
*.opt
*.out
*.pch
*.pdb
*.pfx
*.pgc
*.pgd
*.pidb
*.plg
*.psess
*.publishproj
*.publishsettings
*.pubxml
*.pyc
*.rdl.data
*.rptproj.bak
*.rptproj.rsuser
*.rsp
*.rsuser
*.sap
*.sbr
*.scc
*.sdf
*.sln.docstates
*.sln.iml
*.slo
*.smod
*.snupkg
*.so
*.suo
*.svclog
*.tlb
*.tlh
*.tli
*.tlog
*.tmp
*.tmp_proj
*.tss
*.user
*.userosscache
*.userprefs
*.vbp
*.vbw
*.VC.db
*.VC.VC.opendb
*.VisualState.xml
*.vsp
*.vspscc
*.vspx
*.vssscc
*.xsd.cs
**/[Pp]ackages/*
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.HTMLClient/GeneratedArtifacts
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
*~
~$*
$tf/
AppPackages/
artifacts/
ASALocalRun/
AutoTest.Net/
Backup*/
BenchmarkDotNet.Artifacts/
bld/
BundleArtifacts/
ClientBin/
cmake_install.cmake
CMakeCache.txt
CMakeFiles
CMakeLists.txt.user
CMakeScripts
CMakeUserPresets.json
compile_commands.json
coverage*.info
coverage*.json
coverage*.xml
csx/
CTestTestfile.cmake
dlldata.c
DocProject/buildhelp/
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/*.HxC
DocProject/Help/*.HxT
DocProject/Help/html
DocProject/Help/Html2
ecf/
FakesAssemblies/
FodyWeavers.xsd
Generated_Code/
Generated\ Files/
healthchecksdb
install_manifest.txt
ipch/
Makefile
MigrationBackup/
mono_crash.*
nCrunchTemp_*
node_modules/
nunit-*.xml
OpenCover/
orleans.codegen.cs
Package.StoreAssociation.xml
paket-files/
project.fragment.lock.json
project.lock.json
publish/
PublishScripts/
rcf/
ScaffoldingReadMe.txt
ServiceFabricBackup/
StyleCopReport.xml
Testing
TestResult.xml
UpgradeLog*.htm
UpgradeLog*.XML
x64/
x86/
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Distribution / packaging
!dist/.gitkeep

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
.ruff_cache/

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Project specific
__version__.py
_private

================
File: .pre-commit-config.yaml
================
repos:
  - repo: https://github.com/asottile/pyupgrade
    rev: v3.19.1
    hooks:
      - id: pyupgrade
        args: [--py311-plus]
  - repo: https://github.com/pycqa/isort
    rev: 6.0.0
    hooks:
      - id: isort
        args: ['--profile=black', '--line-length=120']
  - repo: https://github.com/MarcoGorelli/absolufy-imports
    rev: v0.3.1
    hooks:
      - id: absolufy-imports
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: check-yaml
      - id: requirements-txt-fixer
  - repo: https://github.com/asottile/add-trailing-comma
    rev: v3.1.0
    hooks:
      - id: add-trailing-comma
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.7
    hooks:
      - id: ruff
        types: [python]
        additional_dependencies: ['typing-extensions']
        args: [
          '--fix',
          '--ignore=ARG001,ARG002,ARG004,ARG005,B904,C901,DTZ005,E501,F401,F811,FBT001,FBT002,FBT003,I001,ISC001,N803,PLR0911,PLR0912,PLR0913,PLR0915,PLR2004,S311,S603,S607,T201,PLR1714,PYI056,PTH123,PLW0603,S110,PT013,SIM102,EM102'
        ]
      - id: ruff-format
        args: [--respect-gitignore]
        types: [python]

================
File: CHANGELOG.md
================
---
this_file: CHANGELOG.md
---

# Changelog

All notable changes to this project will be documented in this file.

## Unreleased Changes

### Added
- Added error handling in `init_engine_task` to prevent task cancellation issues
- Improved error messages for better debugging
- Added detailed logging for search engine initialization and execution
- Added check for empty engines list in `search` function, raising a `SearchError` with appropriate message
- Added proper handling of mock engine parameters, ensuring correct result count

### Changed
- Enhanced error handling in `get_engine` function to raise `SearchError` with correct message
- Improved mock engine handling in `search` function to properly set `result_count`
- Modified `Config` class to check for `_TEST_ENGINE` environment variable
- Enhanced `_parse_env_value` function to handle JSON strings for engine default parameters
- Added `BRAVE_DEFAULT_PARAMS` to `ENV_VAR_MAP` for proper configuration
- Standardized engine names for more consistent lookups
- Improved error handling patterns across the codebase

### Fixed
- Fixed issue with environment variable parsing for engine default parameters
- Fixed handling of empty engines list in search function
- Fixed mock engine result count handling
- Fixed error handling in `get_engine` function to use the correct exception type
- Fixed environment variable application to engine configurations

## 0.1.2 (2024-05-15)

### Fixed
- Fixed linting errors in `google.py` and `test_google_falla_debug.py`
- Replaced insecure usage of temporary file directory `/tmp` with `tempfile.gettempdir()`
- Replaced `os.path` functions with `pathlib.Path` methods for better path handling
- Removed unused imports (`os` and `NavigableString`) from `google.py`

## 0.1.1 (2024-05-10)

### Added
- Added support for Falla-based search engines
- Added refactored search engine initialization
- Added wrapper coroutine to handle exceptions during search process
- Added detailed logging for engine initialization and search processes

### Changed
- Improved error handling for search engines
- Enhanced configuration system
- Standardized engine names for more consistent lookups

## 0.1.0 (2024-05-01)

### Added
- Initial release
- Support for multiple search engines
- Asynchronous search capabilities
- Rate limiting
- Strong typing with Pydantic validation

### Changed
- Updated the `config.py` file to correctly import BaseSettings from the pydantic-settings package
- Updated the `pyproject.toml` file to add pydantic-settings as a dependency
- Updated the example usage in `example.py`
- Completed the implementation of the web search functionality as specified in TODO.md
- Planned comprehensive tests for the package

### 2024-02-25 - Initial Development

- Created initial project structure and files
- Created a preliminary TODO.md, PROGRESS.md, and research.txt

---

================
File: cleanup.py
================
LOG_FILE = Path("CLEANUP.txt")
os.chdir(Path(__file__).parent)
def new() -> None:
    if LOG_FILE.exists():
        LOG_FILE.unlink()
def prefix() -> None:
    readme = Path(".cursor/rules/0project.mdc")
    if readme.exists():
        log_message("\n=== PROJECT STATEMENT ===")
        content = readme.read_text()
        log_message(content)
def suffix() -> None:
    todo = Path("TODO.md")
    if todo.exists():
        log_message("\n=== TODO.md ===")
        content = todo.read_text()
def log_message(message: str) -> None:
    timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
    with LOG_FILE.open("a") as f:
        f.write(log_line)
def run_command(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess:
        result = subprocess.run(
            log_message(result.stdout)
        log_message(f"Command failed: {' '.join(cmd)}")
        log_message(f"Error: {e.stderr}")
        return subprocess.CompletedProcess(cmd, 1, "", str(e))
def check_command_exists(cmd: str) -> bool:
        return which(cmd) is not None
class Cleanup:
    def __init__(self) -> None:
        self.workspace = Path.cwd()
    def _print_header(self, message: str) -> None:
        log_message(f"\n=== {message} ===")
    def _check_required_files(self) -> bool:
            if not (self.workspace / file).exists():
                log_message(f"Error: {file} is missing")
    def _generate_tree(self) -> None:
        if not check_command_exists("tree"):
            log_message("Warning: 'tree' command not found. Skipping tree generation.")
            rules_dir = Path(".cursor/rules")
            rules_dir.mkdir(parents=True, exist_ok=True)
            tree_result = run_command(["tree", "-a", "-I", ".git", "--gitignore", "-n", "-h", "-I", "*_cache"])
            with open(rules_dir / "filetree.mdc", "w") as f:
                f.write("---\ndescription: File tree of the project\nglobs: \n---\n")
                f.write(tree_text)
            log_message("\nProject structure:")
            log_message(tree_text)
            log_message(f"Failed to generate tree: {e}")
    def _git_status(self) -> bool:
        result = run_command(["git", "status", "--porcelain"], check=False)
        return bool(result.stdout.strip())
    def _venv(self) -> None:
        log_message("Setting up virtual environment")
            run_command(["uv", "venv"])
            if venv_path.exists():
                os.environ["VIRTUAL_ENV"] = str(self.workspace / ".venv")
                log_message("Virtual environment created and activated")
                log_message("Virtual environment created but activation failed")
            log_message(f"Failed to create virtual environment: {e}")
    def _install(self) -> None:
        log_message("Installing package with all extras")
            self._venv()
            run_command(["uv", "pip", "install", "-e", ".[test,dev]"])
            log_message("Package installed successfully")
            log_message(f"Failed to install package: {e}")
    def _run_checks(self) -> None:
        log_message("Running code quality checks")
            log_message(">>> Running code fixes...")
            run_command(
            log_message(">>>Running type checks...")
            run_command(["python", "-m", "mypy", "src", "tests"], check=False)
            log_message(">>> Running tests...")
            run_command(["python", "-m", "pytest", "tests"], check=False)
            log_message("All checks completed")
            log_message(f"Failed during checks: {e}")
    def status(self) -> None:
        prefix()  # Add README.md content at start
        self._print_header("Current Status")
        self._check_required_files()
        self._generate_tree()
        result = run_command(["git", "status"], check=False)
        self._print_header("Environment Status")
        self._install()
        self._run_checks()
        suffix()  # Add TODO.md content at end
    def venv(self) -> None:
        self._print_header("Virtual Environment Setup")
    def install(self) -> None:
        self._print_header("Package Installation")
    def update(self) -> None:
        self.status()
        if self._git_status():
            log_message("Changes detected in repository")
                run_command(["git", "add", "."])
                run_command(["git", "commit", "-m", commit_msg])
                log_message("Changes committed successfully")
                log_message(f"Failed to commit changes: {e}")
            log_message("No changes to commit")
    def push(self) -> None:
        self._print_header("Pushing Changes")
            run_command(["git", "push"])
            log_message("Changes pushed successfully")
            log_message(f"Failed to push changes: {e}")
def repomix(
            cmd.append("--compress")
            cmd.append("--remove-empty-lines")
            cmd.append("-i")
            cmd.append(ignore_patterns)
        cmd.extend(["-o", output_file])
        run_command(cmd)
        log_message(f"Repository content mixed into {output_file}")
        log_message(f"Failed to mix repository: {e}")
def print_usage() -> None:
    log_message("Usage:")
    log_message("  cleanup.py status   # Show current status and run all checks")
    log_message("  cleanup.py venv     # Create virtual environment")
    log_message("  cleanup.py install  # Install package with all extras")
    log_message("  cleanup.py update   # Update and commit changes")
    log_message("  cleanup.py push     # Push changes to remote")
def main() -> NoReturn:
    new()  # Clear log file
    if len(sys.argv) < 2:
        print_usage()
        sys.exit(1)
    cleanup = Cleanup()
            cleanup.status()
            cleanup.venv()
            cleanup.install()
            cleanup.update()
            cleanup.push()
        log_message(f"Error: {e}")
    repomix()
    sys.stdout.write(Path("CLEANUP.txt").read_text())
    sys.exit(0)  # Ensure we exit with a status code
    main()

================
File: debug_fetch.py
================
logging.basicConfig(
    handlers=[logging.StreamHandler(sys.stdout)],
logger = logging.getLogger(__name__)
class DebugFetcher:
    def __init__(self):
        self.output_dir = Path("debug_output")
    async def fetch_page(self, url: str, engine: str) -> str:
        logger.info(f"Fetching {url}")
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
                context = await browser.new_context(
                page = await context.new_page()
                await page.goto(url, timeout=60000, wait_until="networkidle")
                await page.screenshot(path=self.output_dir / f"{engine}_screenshot.png")
                content = await page.content()
                logger.info(f"Got content length: {len(content)}")
                await browser.close()
    def save_html(self, content: str, engine: str) -> None:
        path.write_text(content, encoding="utf-8")
        logger.info(f"Saved HTML content to {path}")
    def analyze_selectors(self, content: str, engine: str) -> None:
        soup = BeautifulSoup(content, "html.parser")
        with open(self.output_dir / f"{engine}_analysis.txt", "w", encoding="utf-8") as f:
            f.write(f"Analysis for {engine}\n")
            f.write("=" * 80 + "\n\n")
            f.write("Potential containers found:\n")
                elements = soup.select(selector)
                f.write(f"{selector}: {len(elements)} elements found\n")
                if elements and len(elements) > 0:
                    f.write(f"\nSample structure of {selector}:\n")
                    f.write(str(sample)[:500] + "...\n\n")
            f.write("\nOther potential elements:\n")
                elements = soup.select(tag)
                    f.write(f"{tag}: {len(elements)} elements found\n")
                    if len(elements) < 5:  # Only show samples for a small number
                        for i, elem in enumerate(elements):
                            f.write(f"  {i + 1}. {elem.get_text().strip()[:100]}\n")
    async def process_engine(self, engine: str, query: str) -> None:
            logger.error(f"Unsupported engine: {engine}")
        url = self.engines[engine].format(query.replace(" ", "+"))
        content = await self.fetch_page(url, engine)
        self.save_html(content, engine)
        self.analyze_selectors(content, engine)
    async def run(self, engines: list[str], query: str) -> None:
        self.output_dir.mkdir(exist_ok=True)
        logger.info(f"Processing engines: {', '.join(engines)}")
            await self.process_engine(engine, query)
async def main_async() -> None:
    parser = argparse.ArgumentParser(description="Fetch search engine HTML for debugging")
    parser.add_argument("query", help="Search query")
    parser.add_argument(
    args = parser.parse_args()
    fetcher = DebugFetcher()
    await fetcher.run(engines, args.query)
def main() -> None:
    asyncio.run(main_async())
    main()

================
File: falla_search.py
================
logging.basicConfig(
    handlers=[logging.StreamHandler(sys.stdout)],
logger = logging.getLogger(__name__)
class SimpleFallaSearch:
    def __init__(self, engine: str = "google"):
    def get_url(self, query: str) -> str:
        query = query.replace(" ", "+")
        raise ValueError(error_msg)
    async def fetch_page(self, url: str) -> str | None:
        logger.info(f"Fetching {url}")
            async with async_playwright() as p:
                browser = await p.chromium.launch(headless=True)
                    context = await browser.new_context(
                    page = await context.new_page()
                    await page.goto(url, timeout=30000, wait_until="domcontentloaded")
                            await page.wait_for_selector(selector, timeout=5000)
                            logger.warning(f"Timeout waiting for selector: {e}")
                    content = await page.content()
                    logger.info(f"Got content length: {len(content)}")
                    logger.info(f"Content preview: {content[:500]}")
                    await browser.close()
            logger.error(f"Error fetching page: {e}")
    def parse_results(self, html: str) -> list[dict[str, str]]:
        soup = BeautifulSoup(html, "html.parser")
        containers = soup.select(container_selector)
        logger.info(f"Found {len(containers)} result containers")
                title_elem = container.select_one(self.selectors[self.engine]["title"])
                title = title_elem.get_text().strip() if title_elem else ""
                link_elem = container.select_one(self.selectors[self.engine]["link"])
                link = str(link_elem.get("href")) if link_elem and link_elem.get("href") else ""
                snippet_elem = container.select_one(self.selectors[self.engine]["snippet"])
                snippet = snippet_elem.get_text().strip() if snippet_elem else ""
                    results.append({"title": title, "link": link, "snippet": snippet})
                logger.error(f"Error parsing result: {e}")
    async def search(self, query: str) -> list[dict[str, str]]:
        url = self.get_url(query)
        html = await self.fetch_page(url)
            logger.warning("No HTML content returned")
        return self.parse_results(html)
    def search_sync(self, query: str) -> list[dict[str, str]]:
        return asyncio.run(self.search(query))
async def main_async():
    parser = argparse.ArgumentParser(description="Search using Falla")
    parser.add_argument("query", help="Search query")
    parser.add_argument(
    args = parser.parse_args()
    search = SimpleFallaSearch(engine=args.engine)
    results = await search.search(args.query)
        for _i, _result in enumerate(results, 1):
def main():
    asyncio.run(main_async())
    main()

================
File: google_debug_Python_programming_language.html
================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="origin-trial" content="A/kargTFyk8MR5ueravczef/wIlTkbVk1qXQesp39nV+xNECPdLBVeYffxrM8TmZT6RArWGQVCJ0LRivD7glcAUAAACQeyJvcmlnaW4iOiJodHRwczovL2dvb2dsZS5jb206NDQzIiwiZmVhdHVyZSI6IkRpc2FibGVUaGlyZFBhcnR5U3RvcmFnZVBhcnRpdGlvbmluZzIiLCJleHBpcnkiOjE3NDIzNDIzOTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content="initial-scale=1"><title>https://www.google.com/search?q=Python+programming+language&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=V3_GZ4bVMa-Mxc8PmfaSgAU</title></head>
<body style="font-family: arial, sans-serif; background-color: #fff; color: #000; padding:20px; font-size:18px; overscroll-behavior:contain;" onload="e=document.getElementById('captcha');if(e){e.focus();} if(solveSimpleChallenge) {solveSimpleChallenge(0,0);}">
<div style="max-width:400px;">
<hr noshade="" size="1" style="color:#ccc; background-color:#ccc;"><br>
<form id="captcha-form" action="index" method="post">
<noscript>
<div style="font-size:13px;">
  In order to continue, please enable javascript on your web browser.
</div>
</noscript>
<script type="text/javascript" async="" charset="utf-8" src="https://www.gstatic.com/recaptcha/releases/rW64dpMGAGrjU7JJQr9xxPl8/recaptcha__en.js" crossorigin="anonymous" integrity="sha384-stI8i0l4UnrupDOI6In0RQyfmG7x4RHoRSlzjf/yDu+T9clp2es/I4WNYpU4isM0"></script><script src="https://www.google.com/recaptcha/api.js" async="" defer=""></script>
<script>var submitCallback = function(response) {document.getElementById('captcha-form').submit();};</script>
<div id="recaptcha" class="g-recaptcha" data-sitekey="6LfwuyUTAAAAAOAmoS0fdqijC2PbbdH4kjq62Y1b" data-callback="submitCallback" data-s="2PCOkW9zecXmuwvrhgPcpcw_x_FYf41FDpdcdvcuH75pD6YHnEr3IMqaldQ6BBWhjf7hNEe43XOAQINFMpjBrZN9AYoPKVQ8EdY5ezYpG_U2ff1VWdJoen6rzZnuzrMcYnyRbMdmYQOpb2iOnyVec9iIHi9JlX2CpnKr6o613bYAGHxlnpzycDiMilWJBrDI7I-zz4ErCkNgczFfu4GU_okWdfs-Rwr_dDC3YEBmWyW1XIh7xeO615YYQY-T0Hs2_ZbYU9XD9qesC1gth_3l7awQQiCV_Hg"></div>
<input type="hidden" name="q" value="EhAqAqMSyMhKAIkbml3BFgvLGNj-mb4GIjCNaWGW1Jn0FAd7D6NUQ1h7QQJSSo_pe7URjP4b1z0SdZHf7dSw1kCExJN1AZBFZHUyAXJaAUM"><input type="hidden" name="continue" value="https://www.google.com/search?q=Python+programming+language&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=V3_GZ4bVMa-Mxc8PmfaSgAU">
</form>
<hr noshade="" size="1" style="color:#ccc; background-color:#ccc;">
<div style="font-size:13px; line-break: anywhere;">
<b>About this page</b><br><br>
Our systems have detected unusual traffic from your computer network.  This page checks to see if it's really you sending the requests, and not a robot.  <a href="#" onclick="document.getElementById('infoDiv').style.display='block';">Why did this happen?</a><br><br>
<div id="infoDiv" style="display:none; background-color:#eee; padding:10px; margin:0 0 15px 0; line-height:1.4em;">
This page appears when Google automatically detects requests coming from your computer network which appear to be in violation of the <a href="//www.google.com/policies/terms/">Terms of Service</a>. The block will expire shortly after those requests stop.  In the meantime, solving the above CAPTCHA will let you continue to use our services.<br><br>This traffic may have been sent by malicious software, a browser plug-in, or a script that sends automated requests.  If you share your network connection, ask your administrator for help — a different computer using the same IP address may be responsible.  <a href="//support.google.com/websearch/answer/86640">Learn more</a><br><br>Sometimes you may be asked to solve the CAPTCHA if you are using advanced terms that robots are known to use, or sending requests very quickly.
</div>
IP address: 2a02:a312:c8c8:4a00:891b:9a5d:c116:bcb<br>Time: 2025-03-04T04:19:36Z<br>URL: https://www.google.com/search?q=Python+programming+language&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=V3_GZ4bVMa-Mxc8PmfaSgAU<br>
</div>
</div>
</body></html>

================
File: google_debug_test_query.html
================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="origin-trial" content="A/kargTFyk8MR5ueravczef/wIlTkbVk1qXQesp39nV+xNECPdLBVeYffxrM8TmZT6RArWGQVCJ0LRivD7glcAUAAACQeyJvcmlnaW4iOiJodHRwczovL2dvb2dsZS5jb206NDQzIiwiZmVhdHVyZSI6IkRpc2FibGVUaGlyZFBhcnR5U3RvcmFnZVBhcnRpdGlvbmluZzIiLCJleHBpcnkiOjE3NDIzNDIzOTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content="initial-scale=1"><title>https://www.google.com/search?q=test+query&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=4YbGZ-DbL4yNxc8P4uOmgQg</title></head>
<body style="font-family: arial, sans-serif; background-color: #fff; color: #000; padding:20px; font-size:18px; overscroll-behavior:contain;" onload="e=document.getElementById('captcha');if(e){e.focus();} if(solveSimpleChallenge) {solveSimpleChallenge(0,0);}">
<div style="max-width:400px;">
<hr noshade="" size="1" style="color:#ccc; background-color:#ccc;"><br>
<form id="captcha-form" action="index" method="post">
<noscript>
<div style="font-size:13px;">
  In order to continue, please enable javascript on your web browser.
</div>
</noscript>
<script type="text/javascript" async="" charset="utf-8" src="https://www.gstatic.com/recaptcha/releases/rW64dpMGAGrjU7JJQr9xxPl8/recaptcha__en.js" crossorigin="anonymous" integrity="sha384-stI8i0l4UnrupDOI6In0RQyfmG7x4RHoRSlzjf/yDu+T9clp2es/I4WNYpU4isM0"></script><script src="https://www.google.com/recaptcha/api.js" async="" defer=""></script>
<script>var submitCallback = function(response) {document.getElementById('captcha-form').submit();};</script>
<div id="recaptcha" class="g-recaptcha" data-sitekey="6LfwuyUTAAAAAOAmoS0fdqijC2PbbdH4kjq62Y1b" data-callback="submitCallback" data-s="FqngvDzHeZnU97lmKD1UxwWETdILMoDw8MPTPlsKvh_DUItYKzRxxheg4ttQqMSmncOae3bMD4rAgM0_4aTE6nfRoyJIv6bKITJtcEM3dPdhunKfIzoBMotBAt83t0iBpUPOp8sMUzY-6pvdwGGqEcND2GILtsz_7j6-htwn0-wVK96f9yq_Dl6-jNBenTMPhdmb1k4tJFZ066jMqLFl8AmvC1Kc1IKcKTqQDoSR7Kozs5nn5j8M4KI-hz0HLDFeFYFIZXASnCWF8c9DZQ1-QfrhWKqZ1vY"></div>
<input type="hidden" name="q" value="EhAqAqMSyMhKAIkbml3BFgvLGOKNmr4GIjBO7UBahpD_eHomWH46AYpWusU92R1i9lWqHXc-RRZMKtceXQDkLhqsMpEbCCRe_jsyAXJaAUM"><input type="hidden" name="continue" value="https://www.google.com/search?q=test+query&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=4YbGZ-DbL4yNxc8P4uOmgQg">
</form>
<hr noshade="" size="1" style="color:#ccc; background-color:#ccc;">
<div style="font-size:13px; line-break: anywhere;">
<b>About this page</b><br><br>
Our systems have detected unusual traffic from your computer network.  This page checks to see if it's really you sending the requests, and not a robot.  <a href="#" onclick="document.getElementById('infoDiv').style.display='block';">Why did this happen?</a><br><br>
<div id="infoDiv" style="display:none; background-color:#eee; padding:10px; margin:0 0 15px 0; line-height:1.4em;">
This page appears when Google automatically detects requests coming from your computer network which appear to be in violation of the <a href="//www.google.com/policies/terms/">Terms of Service</a>. The block will expire shortly after those requests stop.  In the meantime, solving the above CAPTCHA will let you continue to use our services.<br><br>This traffic may have been sent by malicious software, a browser plug-in, or a script that sends automated requests.  If you share your network connection, ask your administrator for help — a different computer using the same IP address may be responsible.  <a href="//support.google.com/websearch/answer/86640">Learn more</a><br><br>Sometimes you may be asked to solve the CAPTCHA if you are using advanced terms that robots are known to use, or sending requests very quickly.
</div>
IP address: 2a02:a312:c8c8:4a00:891b:9a5d:c116:bcb<br>Time: 2025-03-04T04:51:46Z<br>URL: https://www.google.com/search?q=test+query&amp;num=100&amp;hl=en&amp;gl=us&amp;sei=4YbGZ-DbL4yNxc8P4uOmgQg<br>
</div>
</div>
</body></html>

================
File: LICENSE
================
MIT License

Copyright (c) 2025 Adam Twardoch

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================
File: pyproject.toml
================
[build-system]
requires = ['hatchling>=1.27.0', 'hatch-vcs>=0.4.0']
build-backend = 'hatchling.build'
[tool.hatch.build.targets.wheel]
packages = ['src/twat_search']
[tool.hatch.build.hooks.vcs]
version-file = 'src/twat_search/__version__.py'

[tool.hatch.version]
source = 'vcs'

[tool.hatch.version.raw-options]
version_scheme = 'post-release'

[tool.hatch.metadata]
allow-direct-references = true

[tool.hatch.envs.default]
dependencies = [
    'pytest>=1.3.4',
    'pytest-cov>=1.0.0',
    'mypy>=1.15.0',
    'ruff>=0.9.7',
    'absolufy-imports>=0.3.1',
    'pre-commit>=4.1.0',
    'pyupgrade>=3.19.1',
    'isort>=6.0.0',
]

[tool.hatch.envs.default.scripts]
test = 'pytest {args:tests}'
test-cov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src/twat_search --cov=tests {args:tests}'
type-check = 'mypy src/twat_search tests'
lint = ['ruff check src/twat_search tests', 'ruff format src/twat_search tests']
[[tool.hatch.envs.all.matrix]]
python = ['3.10', '3.11', '3.12']

[tool.hatch.envs.lint]
detached = true
dependencies = [
    'mypy>=1.15.0',
    'ruff>=0.9.7',
    'absolufy-imports>=0.3.1',
    'pre-commit>=4.1.0',
    'pyupgrade>=3.19.1',
    'isort>=6.0.1',
]

[tool.hatch.envs.lint.scripts]
typing = 'mypy --install-types --non-interactive {args:src/twat_search tests}'
style = ['ruff check {args:.}', 'ruff format {args:.}']
fmt = ['ruff format {args:.}', 'ruff check --fix {args:.}']
all = ['style', 'typing']

[tool.hatch.envs.test]
dependencies = ['.[test]']

[tool.hatch.envs.test.scripts]
test = 'python -m pytest -n auto {args:tests}'
test-cov = 'python -m pytest -n auto --cov-report=term-missing --cov-config=pyproject.toml --cov=src/twat_search --cov=tests {args:tests}'
bench = 'python -m pytest -v -p no:briefcase tests/test_benchmark.py --benchmark-only'
bench-save = 'python -m pytest -v -p no:briefcase tests/test_benchmark.py --benchmark-only --benchmark-json=benchmark/results.json'

[tool.ruff]
target-version = 'py310'
line-length = 120

[tool.ruff.lint]
select = [
    'A',
    'ARG',
    'B',
    'C',
    'DTZ',
    'E',
    'EM',
    'F',
    'FBT',
    'I',
    'ICN',
    'ISC',
    'N',
    'PLC',
    'PLE',
    'PLR',
    'PLW',
    'PT',
    'PTH',
    'PYI',
    'RET',
    'RSE',
    'RUF',
    'S',
    'SIM',
    'T',
    'TCH',
    'TID',
    'UP',
    'W',
    'YTT',
]
ignore = [
    'B027',
    'C901',
    'FBT003',
    'PLR0911',
    'PLR0912',
    'PLR0913',
    'PLR0915',
    'PLR1714',
    'PLW0603',
    'PT013',
    'PTH123',
    'PYI056',
    'S105',
    'S106',
    'S107',
    'S110','SIM102'
]
unfixable = [
    # Don't touch unused imports
    'F401',
]

[tool.ruff.lint.isort]
known-first-party = ['twat_search']

[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = 'all'

[tool.ruff.lint.per-file-ignores]
# Tests can use magic values, assertions, and relative imports
'tests/**/*' = ['PLR2004', 'S101', 'TID252']

[tool.coverage.run]
source_pkgs = ['twat_search', 'tests']
branch = true
parallel = true
omit = ['src/twat_search/__about__.py']

[tool.coverage.paths]
twat_search = ['src/twat_search', '*/twat-search/src/twat_search']
tests = ['tests', '*/twat-search/tests']

[tool.coverage.report]
exclude_lines = [
    'no cov',
    'if __name__ == .__main__.:',
    'if TYPE_CHECKING:',
    'pass',
    'raise NotImplementedError',
    'raise ImportError',
    'except ImportError',
    'except KeyError',
    'except AttributeError',
    'except NotImplementedError',
]

[project]
name = 'twat-search'
description = 'Web search plugin for twat'
readme = 'README.md'
requires-python = '>=3.10'
license = { text = 'MIT' }
keywords = []
dynamic = ["version"]
classifiers = [
    'Development Status :: 4 - Beta',
    'Programming Language :: Python',
    'Programming Language :: Python :: 3.10',
    'Programming Language :: Python :: 3.11',
    'Programming Language :: Python :: 3.12',
    'Programming Language :: Python :: Implementation :: CPython',
    'Programming Language :: Python :: Implementation :: PyPy',
]
dependencies = [
    'twat>=1.8.1',
    'pydantic>=2.10.6',
    'pydantic-settings>=2.8.1',
    'httpx>=0.28.1',
    'python-dotenv>=1.0.1',
    'fire>=0.7.0',
    'rich>=13.9.4',
    'requests>=2.32.3',
    'beautifulsoup4>=4.13.0',
]

[[project.authors]]
name = 'Adam Twardoch'
email = 'adam+github@twardoch.com'

[project.urls]
Documentation = 'https://github.com/twardoch/twat-search#readme'
Issues = 'https://github.com/twardoch/twat-search/issues'
Source = 'https://github.com/twardoch/twat-search'
[project.entry-points."twat.plugins"]
search = 'twat_search'

[project.optional-dependencies]
test = [
    'pytest>=8.3.4',
    'pytest-cov>=6.0.0',
    'pytest-xdist>=3.6.1',
    'pytest-benchmark[histogram]>=5.1.0',
    'pytest-asyncio>=0.25.3',
]
dev = [
    'pre-commit>=4.1.0',
    'ruff>=0.9.7',
    'mypy>=1.15.0',
    'absolufy-imports>=0.3.1',
    'pyupgrade>=3.19.1',
    'isort>=6.0.1',
]
brave = []
duckduckgo = ['duckduckgo-search>=7.5.0']
bing_scraper = ['scrape-bing>=0.1.2.1']
tavily = ['tavily-python>=0.5.1']
pplx = []
serpapi = ['serpapi>=0.1.5']
hasdata = []
falla = [    "lxml>=5.3.1",
    "playwright>=1.50.0",
]
google_scraper = ['googlesearch-python>=1.3.0']
all = [
    'twat',
    'duckduckgo-search>=7.5.0',
    'scrape-bing>=0.1.2.1',
    'tavily-python>=0.5.1',
    'serpapi>=0.1.5',
    'googlesearch-python>=1.3.0',
    'beautifulsoup4>=4.13.0',
    'lxml>=5.3.1',
    'playwright>=1.50.0',
]

[project.scripts]
twat-search = 'twat_search.__main__:main'
twat-search-web = 'twat_search.web.cli:main'

================
File: README.md
================
---
this_file: README.md
---

# Twat Search

A multi-engine web search aggregator that provides a unified interface for searching across various search engines.

## Features

- **Multi-engine search**: Search across various providers including Brave, Google (via SerpAPI), Bing, and more
- **Asynchronous operation**: Uses `asyncio` for efficient concurrent searches
- **Rate limiting**: Built-in rate limiting to prevent API throttling
- **Strong typing**: Pydantic validation for all data models
- **Robust error handling**: Graceful handling of engine failures and empty engine lists
- **Flexible configuration**: Configure via environment variables, `.env` files, or directly in code
- **CLI interface**: Interactive command-line interface with rich output formatting
- **JSON output**: Standardized JSON output format for all search results
- **Modern path handling**: Uses `pathlib` for cross-platform path operations
- **Secure temp files**: Uses `tempfile` for secure temporary file operations

## Recent Improvements

- Enhanced error handling for search engines, including proper handling of empty engine lists
- Standardized engine names for more consistent lookups
- Detailed logging for search engine initialization and execution
- Improved environment variable handling for engine configuration
- Fixed issues with mock engine result count handling
- Added proper JSON string parsing for engine default parameters
- Fixed error handling in `get_engine` function to use the correct exception type
- Improved handling of engine-specific parameters in the search function
- Enhanced configuration system with better environment variable support

## Installation

```bash
pip install twat-search
```

## Usage

### Basic Usage

```python
import asyncio
from twat_search.web.api import search

async def main():
    results = await search("Python programming", engines=["brave", "google"])
    for result in results:
        print(f"Title: {result.title}")
        print(f"URL: {result.url}")
        print(f"Description: {result.description}")
        print("---")

asyncio.run(main())
```

### Configuration

You can configure the search engines using environment variables:

```bash
# Enable/disable engines
export BRAVE_ENABLED=true
export GOOGLE_ENABLED=false

# Set API keys
export SERPAPI_API_KEY=your_api_key
export TAVILY_API_KEY=your_api_key

# Configure engine parameters
export BRAVE_DEFAULT_PARAMS='{"count": 10, "country": "US"}'
```

Or directly in code:

```python
from twat_search.web.config import Config

config = Config(
    brave={"enabled": True, "default_params": {"count": 10}},
    google={"enabled": False}
)
```

### Command Line Interface

```bash
# Basic search
twat-search web q "Python programming"

# Specify engines
twat-search web q "Python programming" --engines brave,google

# Get JSON output
twat-search web q "Python programming" --json

# List available engines
twat-search web info --plain
```

## Error Handling

The package provides robust error handling with custom exception classes:

- `SearchError`: Base exception for all search-related errors
- `EngineError`: Raised when there's an issue with a specific engine

Example:

```python
from twat_search.web.api import search
from twat_search.web.exceptions import SearchError, EngineError

try:
    results = await search("Python programming")
except EngineError as e:
    print(f"Engine error: {e}")
except SearchError as e:
    print(f"Search error: {e}")
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Project Documentation

The project maintains several key documentation files:

- **README.md**: This file, containing an overview of the project, installation instructions, and usage examples.
- **CHANGELOG.md**: Documents all notable changes to the project, organized by version.
- **TODO.md**: Contains a prioritized list of tasks and improvements planned for the project.
- **LICENSE**: The project's license information.

## Development Workflow

When contributing to this project, please follow these guidelines:

1. Check the **TODO.md** file for prioritized tasks that need attention.
2. Run `./cleanup.py status` regularly to check for linting errors and test failures.
3. Document all changes in **CHANGELOG.md** under the appropriate version section.
4. Add comprehensive tests for new features and bug fixes.
5. Ensure all code passes linting and type checking before submitting.

### Code Quality Tools

The project uses several tools to maintain code quality:

- **Ruff**: For linting and formatting Python code
- **Mypy**: For static type checking
- **Pytest**: For running tests
- **Pre-commit hooks**: To ensure code quality before commits

Run these tools regularly during development:

```bash
# Format code
ruff format --respect-gitignore --target-version py312 .

# Lint code
ruff check --output-format=github --fix --unsafe-fixes .

# Run tests
python -m pytest
```

## Quick start guide

### Python API

```python
import asyncio
from twat_search.web import search

async def main():
    # Search across all configured engines
    results = await search("quantum computing applications")

    # Print results
    for result in results:
        print(f"[{result.source}] {result.title}")
        print(f"URL: {result.url}")
        print(f"Snippet: {result.snippet}\n")

# Run the async function
asyncio.run(main())
```

### Command line interface

```bash
# Search using all available engines
twat-search web q "climate change solutions"

# Search with specific engines
twat-search web q "machine learning frameworks" -e brave,tavily

# Get json output
twat-search web q "renewable energy" --json

# Use engine-specific command
twat-search web q -e brave "web development trends" --count 10
```

## Core architecture

### Module structure

```
twat_search/
└── web/
    ├── engines/            # Individual search engine implementations
    │   ├── __init__.py     # Engine registration and availability checks
    │   ├── base.py         # Base SearchEngine class definition
    │   ├── brave.py        # Brave search implementation
    │   ├── bing_scraper.py # Bing scraper implementation
    │   └── ...             # Other engine implementations
    │   └── lib_falla/      # Falla-based search engine implementations
    │       ├── core/       # Core Falla functionality
    │       │   ├── falla.py    # Base Falla class
    │       │   ├── google.py   # Google search implementation
    │       │   └── ...         # Other Falla-based implementations
    ├── __init__.py         # Module exports
    ├── api.py              # Main search API
    ├── cli.py              # Command-line interface
    ├── config.py           # Configuration handling
    ├── exceptions.py       # Custom exceptions
    ├── models.py           # Data models
    └── utils.py            # Utility functions
```

## Supported search engines

Twat Search provides a consistent interface to the following search engines:

| Engine | Module | API Key Required | Description | Package Extra |
| --- | --- | --- | --- | --- |
| Brave | `brave` | Yes | Web search via Brave Search API | `brave` |
| Brave News | `brave_news` | Yes | News search via Brave API | `brave` |
| You.com | `you` | Yes | Web search via You.com API | - |
| You.com News | `you_news` | Yes | News search via You.com API | - |
| Tavily | `tavily` | Yes | Research-focused search API | `tavily` |
| Perplexity | `pplx` | Yes | AI-powered search with detailed answers | `pplx` |
| SerpAPI | `serpapi` | Yes | Google search results via SerpAPI | `serpapi` |
| HasData Google | `hasdata-google` | Yes | Google search results via HasData API | `hasdata` |
| HasData Google Light | `hasdata-google-light` | Yes | Light version of HasData API | `hasdata` |
| Critique | `critique` | Yes | Visual and textual search capabilities | - |
| DuckDuckGo | `duckduckgo` | No | Privacy-focused search results | `duckduckgo` |
| Bing Scraper | `bing_scraper` | No | Web scraping of Bing search results | `bing_scraper` |
| Google Falla | `google_falla` | No | Google search via Playwright-based scraping | `falla` |

## Configuration management

### Environment variables

Configure engines using environment variables:

```bash
# Api keys
BRAVE_API_KEY=your_brave_api_key
TAVILY_API_KEY=your_tavily_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key
YOU_API_KEY=your_you_api_key
SERPAPI_API_KEY=your_serpapi_api_key
CRITIQUE_API_KEY=your_critique_api_key
HASDATA_API_KEY=your_hasdata_api_key

# Engine enablement
BRAVE_ENABLED=true
TAVILY_ENABLED=true
PERPLEXITY_ENABLED=true
YOU_ENABLED=true
SERPAPI_ENABLED=true
CRITIQUE_ENABLED=true
DUCKDUCKGO_ENABLED=true
BING_SCRAPER_ENABLED=true
HASDATA_GOOGLE_ENABLED=true

# Default parameters (json format)
BRAVE_DEFAULT_PARAMS='{"count": 10, "safesearch": "off"}'
TAVILY_DEFAULT_PARAMS='{"max_results": 5, "search_depth": "basic"}'
PERPLEXITY_DEFAULT_PARAMS='{"model": "pplx-7b-online"}'
YOU_DEFAULT_PARAMS='{"safe_search": true, "count": 8}'
SERPAPI_DEFAULT_PARAMS='{"num": 10, "gl": "us"}'
HASDATA_GOOGLE_DEFAULT_PARAMS='{"location": "Austin,Texas,United States", "device_type": "desktop"}'
DUCKDUCKGO_DEFAULT_PARAMS='{"max_results": 10, "safesearch": "moderate", "time": "d"}'
BING_SCRAPER_DEFAULT_PARAMS='{"max_retries": 3, "delay_between_requests": 1.0}'

# Global default for all engines
NUM_RESULTS=5
```

You can store these in a `.env` file in your project directory, which will be automatically loaded by the library using `python-dotenv`.

### Programmatic configuration

Configure engines programmatically when using the Python API:

```python
from twat_search.web import Config, EngineConfig, search

# Create custom configuration
config = Config(
    engines={
        "brave": EngineConfig(
            api_key="your_brave_api_key",
            enabled=True,
            default_params={"count": 10, "country": "US"}
        ),
        "bing_scraper": EngineConfig(
            enabled=True,
            default_params={"max_retries": 3, "delay_between_requests": 1.0}
        ),
        "tavily": EngineConfig(
            api_key="your_tavily_api_key",
            enabled=True,
            default_params={"search_depth": "advanced"}
        )
    }
)

# Use the configuration
results = await search("quantum computing", config=config)
```

## Error Handling Framework

Twat Search provides a robust error handling framework to ensure graceful failure and clear error messages:

### Exception Hierarchy

- `SearchError`: Base exception for all search-related errors
- `EngineError`: Specific exception for engine-related issues

### Key Error Handling Features

- **Empty Engine List Detection**: The search function now checks for empty engine lists and raises a clear error
- **Standardized Error Messages**: All error messages follow a consistent format for better debugging
- **Detailed Logging**: Comprehensive logging throughout the search process
- **Graceful Engine Failures**: Individual engine failures don't crash the entire search process
- **Environment Variable Validation**: Proper parsing and validation of environment variables

### Example Error Scenarios

```python
# No engines configured
try:
    results = await search("query", engines=[])
except SearchError as e:
    print(e)  # "No search engines specified or available"

# Non-existent engine
try:
    results = await search("query", engines=["nonexistent_engine"])
except SearchError as e:
    print(e)  # "Engine 'nonexistent_engine': not found"

# Disabled engine
try:
    results = await search("query", engines=["disabled_engine"])
except SearchError as e:
    print(e)  # "Engine 'disabled_engine': is disabled"
```

## Recent Fixes and Improvements

The latest version includes several important fixes and improvements:

1. **Fixed Environment Variable Parsing**: Properly handles JSON strings in environment variables for engine default parameters
2. **Empty Engine List Handling**: Added explicit check and error for empty engine lists
3. **Mock Engine Parameter Handling**: Improved handling of mock engine parameters for testing
4. **Standardized Error Messages**: Enhanced error messages for better debugging
5. **Config Class Improvements**: Modified to properly check for test environment variables
6. **Enhanced Logging**: Added detailed logging throughout the search process
7. **Improved Exception Handling**: Better handling of exceptions during engine initialization and search

These improvements make the package more robust, easier to debug, and more reliable in various usage scenarios.

## Development Status

The project is actively maintained and regularly updated. All unit tests are passing, and the codebase is continuously improved based on user feedback and identified issues.

Current focus areas include:
- Fixing Falla-based search engines
- Addressing type errors in the codebase
- Improving integration with Playwright
- Enhancing documentation and standardizing JSON output formats

For a complete list of planned improvements, see the TODO.md file.

## License

This project is licensed under the MIT License - see the LICENSE file for details.

---

## Appendix: available engines and requirements

| Engine | Package Extra | API Key Required | Environment Variable | Notes |
| --- | --- | --- | --- | --- |
| Brave | `brave` | Yes | `BRAVE_API_KEY` | General web search engine |
| Brave News | `brave` | Yes | `BRAVE_API_KEY` | News-specific search |
| You.com | - | Yes | `YOU_API_KEY` | AI-powered web search |
| You.com News | - | Yes | `YOU_API_KEY` | News-specific search |
| Tavily | `tavily` | Yes | `TAVILY_API_KEY` | Research-focused search |
| Perplexity | `pplx` | Yes | `PPLX_API_KEY` | AI-powered search with detailed answers |
| SerpAPI | `serpapi` | Yes | `SERPAPI_API_KEY` | Google search results API |
| HasData Google | `hasdata` | Yes | `HASDATA_API_KEY` | Google search results API |
| HasData Google Light | `hasdata` | Yes | `HASDATA_API_KEY` | Lightweight Google search API |
| Critique | - | Yes | `CRITIQUE_API_KEY` | Supports image analysis |
| DuckDuckGo | `duckduckgo` | No | - | Privacy-focused search |
| Bing Scraper | `bing_scraper` | No | - | Uses web scraping techniques |

================
File: requirements.txt
================
beautifulsoup4>=4.12.2 
playwright>=1.40.0

================
File: test_async_falla.py
================
async def test_async():
    d = DuckDuckGo()
        return await d.search_async("FontLab")
        results = asyncio.run(test_async())

================
File: test_falla.py
================
async def test():
    d = DuckDuckGo()
        await d._initialize_browser()
        return await d._fetch_page("https://duckduckgo.com/?q=FontLab")
        await d._close_browser()
    with contextlib.suppress(Exception):
        result = asyncio.run(test())

================
File: test_google_falla_debug.py
================
logging.basicConfig(
    handlers=[logging.StreamHandler()],
logger = logging.getLogger("google_falla_debug")
src_path = Path(__file__).parent / "src"
sys.path.insert(0, str(src_path))
    logger.error(f"Failed to import Google engine: {e}")
    logger.error("Make sure the path is correct and all dependencies are installed.")
    sys.exit(1)
async def main():
        engine = Google()
        logger.info(f"Testing Google Falla engine with query: {query}")
        logger.info("Engine configuration:")
        logger.info(f"  - Name: {engine.name}")
        logger.info(f"  - Method: {engine.use_method}")
        logger.info(f"  - Container element: {engine.container_element}")
        logger.info(f"  - Wait for selector: {engine.wait_for_selector}")
        logger.info(f"  - Max retries: {engine.max_retries}")
        logger.info("\nRunning search...")
        results = await engine.search_async(query)
        logger.info(f"\nSearch completed. Found {len(results)} results.")
        for i, result in enumerate(results, 1):
            logger.info(f"\nResult {i}:")
            logger.info(f"  Title: {result.get('title', 'N/A')}")
            logger.info(f"  Link: {result.get('link', 'N/A')}")
            snippet = result.get("snippet", "N/A")
                logger.info(f"  Snippet: {snippet[:100]}...")
                logger.info("  Snippet: N/A")
        temp_dir = tempfile.gettempdir()  # Use tempfile module for secure temp directory
        html_files = [f for f in os.listdir(temp_dir) if f.startswith("google_debug_") and f.endswith(".html")]
            logger.info("\nDebug HTML files were saved:")
                logger.info(f"  - {Path(temp_dir) / html_file}")
            logger.warning("No debug HTML files were found.")
        logger.error(f"Error during search: {e}")
        logger.error(traceback.format_exc())
                await engine.close()
                logger.info("Engine resources cleaned up.")
                logger.error(f"Error during cleanup: {e}")
    exit_code = asyncio.run(main())
    sys.exit(exit_code)

================
File: test_simple.py
================
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def fetch_page(url):
    logger.info(f"Fetching {url}")
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
            context = await browser.new_context(
            page = await context.new_page()
            await page.goto(url, timeout=30000, wait_until="domcontentloaded")
            await page.wait_for_selector("body", timeout=5000)
            content = await page.content()
            logger.info(f"Got content length: {len(content)}")
            await browser.close()
def fetch_page_sync(url):
        return asyncio.run(fetch_page(url))
        logger.error(f"Error in fetch_page_sync: {e}")
    content = fetch_page_sync("https://www.google.com/search?q=FontLab")
    content = fetch_page_sync("https://html.duckduckgo.com/html/?q=FontLab")

================
File: test_sync_falla.py
================
def test_sync():
    d = DuckDuckGo()
        return d.search("FontLab")
    results = test_sync()

================
File: TODO.md
================
--- 
this_file: TODO.md
--- 

# TODO

Tip: Periodically run `./cleanup.py status` to see results of lints and tests. Use `uv pip ...` not `pip ...`


## Phase 1

- [ ] Fix Falla-based search engines
  - [ ] Resolve Playwright dependency issues (ModuleNotFoundError: No module named 'playwright')
  - [ ] Ensure proper error handling for browser automation
  - [ ] Add retry mechanism for flaky browser interactions
  - [ ] Update selectors in search engine implementations to match current page structures
  - [ ] Implement proper handling of CAPTCHA challenges and consent pages

- [ ] Address type errors in the codebase
  - [ ] Fix type error in `wait_for_selector` where `self.wait_for_selector` could be `None`
  - [ ] Fix type error in `find_all` where `attrs` parameter has incompatible type
  - [ ] Fix type error in `get_title`, `get_link`, and `get_snippet` where `elem` parameter has incompatible type
  - [ ] Fix type error in `elem.find` where `PageElement` has no attribute `find`
  - [ ] Fix FBT001/FBT002 errors (Boolean-typed positional arguments)
  - [ ] Fix unused argument warnings (ARG001/ARG002)
  - [ ] Fix line length issues (E501)

- [ ] Improve integration with Playwright
  - [ ] Add proper browser context management
  - [ ] Implement headless mode configuration
  - [ ] Add proxy support for browser-based engines
  - [ ] Implement specific exception handling for common Playwright errors

## Phase 2

- [ ] Improve code quality
  - [ ] Refactor CLI module to reduce complexity
  - [ ] Add more comprehensive docstrings
  - [ ] Standardize error handling patterns across all engines
  - [ ] Add try-except blocks for all external API calls
  - [ ] Create custom exception classes for different error scenarios
  - [ ] Add graceful fallbacks for common error cases

- [ ] Enhance documentation
  - [ ] Create detailed API documentation
  - [ ] Add examples for each search engine
  - [ ] Document configuration options comprehensively
  - [ ] Add detailed docstrings to all classes and methods

- [ ] Standardize JSON output formats
  - [ ] Ensure consistent field names across all engines
  - [ ] Add schema validation for engine outputs
  - [ ] Implement proper JSON serialization for all models
  - [ ] Utilize the existing `SearchResult` model consistently
  - [ ] Remove utility functions like `_process_results` and `_display_json_results`
  - [ ] Remove `CustomJSONEncoder` class
  - [ ] Update engine `search` methods to return list of `SearchResult` objects

- [ ] Improve test coverage
  - [ ] Add unit tests for all search engine implementations
  - [ ] Add integration tests for the entire search pipeline
  - [ ] Implement mock responses for external API calls in tests
  - [ ] Add performance benchmarks for search operations

## Low Priority

- [ ] Add more search engines
  - [ ] Add support for Kagi search
  - [ ] Implement Ecosia search
  - [ ] Implement Startpage search
  - [ ] Implement Qwant AI engine using the QwantAI package
  - [ ] Integrate with more specialized search APIs

- [ ] Implement caching mechanism
  - [ ] Add Redis-based result caching
  - [ ] Implement TTL for cached results
  - [ ] Add result deduplication across engines

- [ ] Performance optimizations
  - [ ] Profile and optimize slow code paths
  - [ ] Reduce memory usage for large result sets
  - [ ] Optimize concurrent search operations
  - [ ] Implement timeout handling for slow search engines

- [ ] Enhance result processing
  - [ ] Add result ranking based on relevance
  - [ ] Implement result filtering options
  - [ ] Add support for different result formats (HTML, Markdown, etc.)

- [ ] Improve CLI functionality
  - [ ] Add interactive mode for search operations
  - [ ] Implement result pagination in CLI output
  - [ ] Add support for saving search results to file
  - [ ] Implement search history functionality

## Completed

- [x] Set up Falla module
- [x] Create base search engine class
- [x] Implement Brave search engine
- [x] Implement Google search via SerpAPI
- [x] Implement Falla-based engines (Google, Bing, etc.)
- [x] Fix linting errors in google.py and test_google_falla_debug.py
- [x] Improve error handling in get_engine function
- [x] Fix handling of empty engines list in search function
- [x] Fix mock engine result count handling
- [x] Fix environment variable parsing for engine default parameters
- [x] Add BRAVE_DEFAULT_PARAMS to ENV_VAR_MAP
- [x] Modify Config class to check for _TEST_ENGINE environment variable
- [x] Replace `os.path.abspath()` with `Path.resolve()` in `google.py`
- [x] Replace `os.path.exists()` with `Path.exists()` in `google.py`
- [x] Replace insecure usage of temporary file directory `/tmp` with `tempfile.gettempdir()` in `test_google_falla_debug.py`
- [x] Replace `os.path.join()` with `Path` and the `/` operator in `test_google_falla_debug.py`
- [x] Remove unused imports (`os` and `NavigableString`) from `google.py`
- [x] Add descriptive error messages when engines are not found or disabled
- [x] Handle engine initialization failures gracefully
- [x] Improve error handling in `init_engine_task` function
- [x] Update `search` function to handle the changes to `init_engine_task`
- [x] Add standardization of engine names for more consistent lookups
- [x] Add wrapper coroutine to handle exceptions during search process
- [x] Add detailed logging for engine initialization and search processes
- [x] Return empty results on failure instead of raising exceptions

Tip: Periodically run `./cleanup.py status` to see results of lints and tests.

This is the test command that we are targeting: 

```bash
for engine in $(twat-search web info --plain); do echo; echo; echo; echo ">>> $engine"; twat-search web q -e $engine "Adam Twardoch" -n 1 --json --verbose; done;
```

## High Priority

### Phase 1: Fix Falla-based Search Engines

- [ ] Fix Yahoo and Qwant search engines
  - [ ] Update selectors in Yahoo implementation to match current page structure
  - [ ] Update selectors in Qwant implementation to match current page structure
  - [ ] Test with various search queries to ensure reliability
  - [ ] Handle consent pages and other interactive elements

- [ ] Fix Google and DuckDuckGo search engines
  - [ ] Update selectors in Google implementation to match current page structure
  - [ ] Update selectors in DuckDuckGo implementation to match current page structure
  - [ ] Implement proper handling of CAPTCHA challenges
  - [ ] Test with various search queries to ensure reliability

- [ ] Fix type errors in `google.py`:
  - [ ] Fix type error in `wait_for_selector` where `self.wait_for_selector` could be `None`
  - [ ] Fix type error in `find_all` where `attrs` parameter has incompatible type
  - [ ] Fix type error in `get_title`, `get_link`, and `get_snippet` where `elem` parameter has incompatible type
  - [ ] Fix type error in `elem.find` where `PageElement` has no attribute `find`

- [ ] Improve Falla integration with Playwright:
  - [ ] Ensure proper browser and context management for efficient resource usage
  - [ ] Implement specific exception handling for common Playwright errors
  - [ ] Add comprehensive type hinting throughout the codebase
  - [ ] Improve method docstrings for better code documentation

### Phase 2: Address Remaining Engine Issues

- [ ] Fix engines returning empty results
  - [ ] Identify and address common failure patterns
  - [ ] Add detailed logging for debugging
  - [ ] Create test script to isolate issues

- [ ] Fix linting errors in the codebase:
  - [ ] Address FBT001/FBT002 errors in CLI functions (Boolean-typed positional arguments)
  - [ ] Fix E501 line length issues in various files
  - [ ] Address F401 unused import errors in `__init__.py` and other files
  - [ ] Fix B904 exception handling issues (use `raise ... from err` pattern)
  - [ ] Address PLR2004 magic value comparison issues

## Medium Priority

### Improve Code Quality

- [ ] Implement comprehensive error handling:
  - [ ] Add try-except blocks for all external API calls
  - [ ] Create custom exception classes for different error scenarios
  - [ ] Add graceful fallbacks for common error cases

- [ ] Improve test coverage:
  - [ ] Add unit tests for all search engine implementations
  - [ ] Add integration tests for the entire search pipeline
  - [ ] Implement mock responses for external API calls in tests
  - [ ] Add performance benchmarks for search operations

- [ ] Enhance documentation:
  - [ ] Add detailed docstrings to all classes and methods
  - [ ] Create comprehensive API documentation
  - [ ] Add usage examples for all search engines
  - [ ] Document configuration options and environment variables

### Standardize JSON Output Format

- [ ] Standardize JSON output across all engines
  - [ ] Utilize the existing `SearchResult` model consistently
  - [ ] Remove utility functions like `_process_results` and `_display_json_results`
  - [ ] Remove `CustomJSONEncoder` class
  - [ ] Update engine `search` methods to return list of `SearchResult` objects

- [ ] Update API function return types
  - [ ] Change return type to `list[SearchResult]`
  - [ ] Ensure proper handling of results from engines

- [ ] Update CLI display functions
  - [ ] Use `model_dump` for JSON serialization
  - [ ] Implement simplified result display

## Low Priority

### Feature Enhancements

- [ ] Add support for additional search engines:
  - [ ] Implement Ecosia search
  - [ ] Implement Startpage search
  - [ ] Implement other alternative search engines
  - [ ] Implement Qwant AI engine using the QwantAI package (https://pypi.org/project/QwantAI/)

- [ ] Enhance result processing:
  - [ ] Implement result deduplication across engines
  - [ ] Add result ranking based on relevance
  - [ ] Implement result filtering options
  - [ ] Add support for different result formats (HTML, Markdown, etc.)

- [ ] Improve CLI functionality:
  - [ ] Add interactive mode for search operations
  - [ ] Implement result pagination in CLI output
  - [ ] Add support for saving search results to file
  - [ ] Implement search history functionality

- [ ] Add advanced search features:
  - [ ] Implement image search capabilities
  - [ ] Add support for news search
  - [ ] Implement video search functionality
  - [ ] Add support for academic/scholarly search

- [ ] Optimize performance:
  - [ ] Implement caching for search results
  - [ ] Optimize concurrent search operations
  - [ ] Reduce memory usage during search operations
  - [ ] Implement timeout handling for slow search engines

## Completed Tasks

- [x] Setup and dependencies
  - [x] Create new module `src/twat_search/web/engines/falla.py`
  - [x] Add necessary dependencies to `pyproject.toml`
  - [x] Define engine constants in `src/twat_search/web/engine_constants.py`
  - [x] Update `src/twat_search/web/engines/__init__.py` to import and register new engines
  - [x] Create utility function to check if Falla is installed and accessible

- [x] Create base `FallaSearchEngine` class
  - [x] Inherit from `SearchEngine`
  - [x] Implement `search` method with proper error handling and retries
  - [x] Create fallback implementation for when Falla is not available

- [x] Implement specific Falla-based engines
  - [x] `google-falla`: Google search using Falla
  - [x] `bing-falla`: Bing search using Falla
  - [x] `duckduckgo-falla`: DuckDuckGo search using Falla
  - [x] `yahoo-falla`: Yahoo search using Falla
  - [x] `qwant-falla`: Qwant search using Falla
  - [x] And other engines (Aol, Ask, Dogpile, Gibiru, Mojeek, Yandex)

- [x] Fix linting errors in the codebase:
  - [x] Replace `os.path.abspath()` with `Path.resolve()` in `google.py`
  - [x] Replace `os.path.exists()` with `Path.exists()` in `google.py`
  - [x] Replace insecure usage of temporary file directory `/tmp` with `tempfile.gettempdir()` in `test_google_falla_debug.py`
  - [x] Replace `os.path.join()` with `Path` and the `/` operator in `test_google_falla_debug.py`
  - [x] Remove unused imports (`os` and `NavigableString`) from `google.py`

- [x] Improve `get_engine` function and error handling
  - [x] Add descriptive error messages when engines are not found or disabled
  - [x] Handle engine initialization failures gracefully
  - [x] Improve error handling in `init_engine_task` function
  - [x] Update `search` function to handle the changes to `init_engine_task`
  - [x] Add standardization of engine names for more consistent lookups
  - [x] Add wrapper coroutine to handle exceptions during search process
  - [x] Add detailed logging for engine initialization and search processes
  - [x] Return empty results on failure instead of raising exceptions

================
File: VERSION.txt
================
v2.5.3



================================================================
End of Codebase
================================================================
