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

# Python SDK

> Official cloro Python SDK reference: install, authenticate, and call Google Search, ChatGPT, Gemini, Perplexity, Copilot, Grok, and AI Mode.

export const GrokStatus = ({variant = "warning", endpoint, consequence, children}) => {
  const unavailable = true;
  if (!unavailable) return null;
  if (variant === "note") {
    return <Note>
        {children} the provider is <a href="/docs/guides/providers">temporarily unavailable</a> —{" "}
        {consequence ?? "calls to it will fail until Grok access is restored."}
      </Note>;
  }
  return <Warning>
      <p><strong>Grok is temporarily unavailable</strong></p>
      <p>
        Grok has blocked anonymous access for the time being. Requests to{" "}
        {endpoint ?? <a href="/docs/api-reference/endpoint/monitor-grok">the Grok endpoint</a>}{" "}
        will fail.
      </p>
    </Warning>;
};

The [`cloro`](https://pypi.org/project/cloro/) Python package is the official SDK for the cloro API — one typed client for Google Search and every AI answer engine, where each call is a single authenticated request that returns structured JSON with sources. The source lives in the [cloro-python repository](https://github.com/cloro-dev/cloro-python).

## Prerequisites

* Python 3.8 or newer
* A cloro API key from the [dashboard](https://dashboard.cloro.dev) (see [Authentication](/docs/guides/authentication))

## Install the package

```bash theme={null}
pip install cloro
```

## Configure your API key

The client reads `CLORO_API_KEY` from the environment automatically:

```bash theme={null}
export CLORO_API_KEY="YOUR_API_KEY"
```

Or pass it to the constructor:

```python theme={null}
from cloro import Cloro

client = Cloro(api_key="YOUR_API_KEY")
```

## Quickstart

```python theme={null}
from cloro import Cloro

client = Cloro()  # reads CLORO_API_KEY

res = client.monitor.chatgpt(
    prompt="What do you know about Acme Corp?",
    country="US",
    include={"markdown": True},
)

print(res["result"]["text"])
for source in res["result"]["sources"]:
    print(source["position"], source["url"], source["label"])
```

Every call returns the `{"success": ..., "result": {...}}` envelope. Pass `include={...}` to request extra formats (`markdown`, `html`, `searchQueries`, `shopping`, and more, depending on the engine).

## Every engine, one client

AI engines take a `prompt`; Google Search and Google News take a `query`. Each method is a thin wrapper over one endpoint.

| Method | Endpoint |
| - | - |
| `client.monitor.google(query, country)` | [`POST /v1/monitor/google`](/docs/api-reference/endpoint/monitor-google) |
| `client.monitor.chatgpt(prompt, country)` | [`POST /v1/monitor/chatgpt`](/docs/api-reference/endpoint/monitor-chatgpt) |
| `client.monitor.gemini(prompt, country)` | [`POST /v1/monitor/gemini`](/docs/api-reference/endpoint/monitor-gemini) |
| `client.monitor.perplexity(prompt, country)` | [`POST /v1/monitor/perplexity`](/docs/api-reference/endpoint/monitor-perplexity) |
| `client.monitor.copilot(prompt, country)` | [`POST /v1/monitor/copilot`](/docs/api-reference/endpoint/monitor-copilot) |
| `client.monitor.grok(prompt, country)` | [`POST /v1/monitor/grok`](/docs/api-reference/endpoint/monitor-grok) |
| `client.monitor.aimode(prompt, country)` | [`POST /v1/monitor/aimode`](/docs/api-reference/endpoint/monitor-aimode) |
| `client.monitor.google_news(query, country)` | [`POST /v1/monitor/google/news`](/docs/api-reference/endpoint/monitor-google-news) |

`client.monitor.google` also accepts `location`, `uule`, `device`, and `pages` (1–10). The client exposes `client.countries()` and `client.states()` for the [supported countries](/docs/api-reference/endpoint/countries) and states.

<GrokStatus variant="note"><code>client.monitor.grok</code> is available, but</GrokStatus>

## Async task queue

For large batches, don't loop synchronous calls — enqueue tasks and poll them. `create_batch` submits up to 500 tasks in one request; `wait` polls a task to completion with interval backoff. See [Async requests](/docs/guides/making-requests/async).

```python theme={null}
from cloro import Cloro

client = Cloro()

KEYWORDS = ["best running shoes", "trail running shoes", "waterproof running shoes"]

# Enqueue up to 500 tasks in a single call.
results = client.async_tasks.create_batch(
    [{"task_type": "GOOGLE", "payload": {"query": kw, "country": "US"}} for kw in KEYWORDS]
)

for item in results:
    if item["success"]:
        done = client.async_tasks.wait(item["task"]["id"])
        organic = done["response"]["organicResults"]
        if organic:
            print(item["task"]["id"], "→", organic[0]["link"])
        else:
            print(item["task"]["id"], "→ no results")
    else:
        print("failed:", item["error"]["message"])
```

For a single task, `client.async_tasks.run(task_type=..., payload=...)` creates it and blocks until it completes. Valid `task_type` values: `CHATGPT`, `GEMINI`, `PERPLEXITY`, `COPILOT`, `GROK`, `AIMODE`, `GOOGLE`, `GOOGLE_NEWS`.

## Reliability and configuration

The client retries timeouts, connection errors, and `429`/`5xx` responses with exponential backoff — tune it with `Cloro(max_retries=2, timeout=60.0)`. Cap your own concurrency to your plan's limit (see [Concurrency](/docs/guides/concurrency)), read the key from `CLORO_API_KEY` rather than hardcoding it, and access response fields with `.get()` since shapes vary by query (a Google result with no AI Overview omits `aioverview`).

## Error handling

Every error subclasses `CloroError`, so one `except CloroError` catches everything. HTTP failures map to status-specific types:

```python theme={null}
from cloro import Cloro, AuthenticationError, RateLimitError, CloroError

client = Cloro()

try:
    res = client.monitor.chatgpt(prompt="...", country="US")
except AuthenticationError:
    ...  # 401 — bad or missing API key
except RateLimitError:
    ...  # 429 — the client already retried; back off further if it persists
except CloroError as exc:
    ...  # everything else
```

| Exception | Meaning |
| - | - |
| `AuthenticationError` | `401` — missing or invalid API key |
| `BadRequestError` | `400` — malformed request or failed validation; `422` — async task validation failed |
| `PermissionDeniedError` | `403` — key not allowed for this action, or insufficient credits |
| `NotFoundError` | `404` — resource does not exist |
| `ConflictError` | `409` — conflicts with current state (e.g. concurrency limit) |
| `RateLimitError` | `429` — too many requests |
| `InternalServerError` | `5xx` — the API failed to process the request |
| `APITimeoutError` | request timed out before a response |
| `TaskFailedError` / `TaskTimeoutError` | async task failed, or did not finish within the poll timeout |

## Next steps

* [Python API guide](https://cloro.dev/integrations/python/) — the landing-page walkthrough with recipes, pricing, and production patterns
* [TypeScript SDK](/docs/integrations/typescript) — the same client surface in TypeScript/Node
* [Python web scraping pillar](https://cloro.dev/blog/web-scraping-with-python/) — Python data-extraction fundamentals
* [Google SERP API](https://cloro.dev/serp-api/) — the SERP endpoint this SDK wraps
* [Making requests](/docs/guides/making-requests/sync) — the raw sync and [async](/docs/guides/making-requests/async) HTTP contracts
* [Providers](/docs/guides/providers) and [Billing & credits](/docs/guides/billing) — per-engine credit costs
* [API reference](/docs/api-reference/endpoint/monitor-google) — full request and response schemas
* [cloro-python on GitHub](https://github.com/cloro-dev/cloro-python) and [on PyPI](https://pypi.org/project/cloro/)
