Metadata-Version: 2.4
Name: cloro
Version: 0.1.0
Summary: Official Python SDK for the cloro API — one API for Google Search and every AI answer engine (ChatGPT, Gemini, Perplexity, Copilot, Grok, AI Overview, AI Mode).
Project-URL: Homepage, https://cloro.dev
Project-URL: Documentation, https://cloro.dev/docs
Project-URL: Source, https://github.com/cloro-dev/cloro-python
Project-URL: Issues, https://github.com/cloro-dev/cloro-python/issues
Author-email: cloro <support@cloro.dev>
License: MIT
License-File: LICENSE
Keywords: ai search,ai visibility,chatgpt,cloro,copilot,gemini,geo,google search,perplexity,seo,serp,serp api,web scraping
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: httpx<1,>=0.23
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# cloro Python SDK

The official Python client for [**cloro**](https://cloro.dev) — one API for
Google Search and every AI answer engine (ChatGPT, Gemini, Perplexity, Copilot,
Grok, AI Overview, AI Mode). Real-time, structured JSON.

Use the SDK, or [just `curl` it](https://cloro.dev/docs) — same clean response
either way. The SDK adds typed methods, sensible retries, and a polling helper
for the async task queue so you don't hand-roll it.

## Installation

```bash
pip install cloro
```

Requires Python 3.8+.

## Quickstart

```python
from cloro import Cloro

client = Cloro(api_key="sk_live_...")  # or set 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"])
```

The API key is read from the `CLORO_API_KEY` environment variable when you don't
pass `api_key=`. Get a key (and 500 free credits) at
[dashboard.cloro.dev](https://dashboard.cloro.dev/).

## Engines

Every engine is a method on `client.monitor`. AI engines take a `prompt`;
Google Search and Google News take a `query`.

```python
client.monitor.chatgpt(prompt="...", country="US")
client.monitor.gemini(prompt="...", country="US")
client.monitor.perplexity(prompt="...", country="US")
client.monitor.copilot(prompt="...", country="US")
client.monitor.grok(prompt="...", country="US")
client.monitor.aimode(prompt="...", country="US")           # Google AI Mode

client.monitor.google(query="best crm", country="US", pages=1)
client.monitor.google_news(query="acme corp", country="US")
```

Pass `include={...}` to request extra formats — `markdown`, `html`,
`searchQueries`, `shopping`, and more, depending on the engine.

## Async task queue

For high-volume or long-running work, enqueue tasks and poll them to completion.
`run()` does create-then-wait in one call:

```python
result = client.async_tasks.run(
    task_type="CHATGPT",
    payload={"prompt": "What is cloro?", "country": "US"},
)
print(result["response"])       # present once COMPLETED
print(result["credits"])        # credits reserved / charged
```

Prefer to manage the lifecycle yourself:

```python
task = client.async_tasks.create(
    task_type="GOOGLE",
    payload={"query": "serp api", "country": "US"},
    priority=5,
)
status = client.async_tasks.retrieve(task)   # non-blocking snapshot
result = client.async_tasks.wait(task, timeout=120, poll_interval=2)
```

Batch up to 500 tasks in a single request (results preserve input order):

```python
results = client.async_tasks.create_batch([
    {"task_type": "CHATGPT", "payload": {"prompt": "q1", "country": "US"}},
    {"task_type": "PERPLEXITY", "payload": {"prompt": "q2", "country": "GB"}},
])
for item in results:
    if item["success"]:
        client.async_tasks.wait(item["task"]["id"])
    else:
        print("failed:", item["error"]["message"])
```

Queue-wide status:

```python
client.async_tasks.status()   # queued / processing counts, concurrency usage
```

Valid `task_type` values: `CHATGPT`, `GEMINI`, `PERPLEXITY`, `COPILOT`, `GROK`,
`AIMODE`, `GOOGLE`, `GOOGLE_NEWS`.

## Configuration

```python
client = Cloro(
    api_key="sk_live_...",
    base_url="https://api.cloro.dev",  # override if needed
    timeout=60.0,                       # per-request seconds
    max_retries=2,                      # timeouts, connection errors, 429/5xx
)
```

The client is a context manager and pools connections:

```python
with Cloro() as client:
    client.monitor.chatgpt(prompt="...", country="US")
```

## Error handling

All errors subclass `CloroError`. HTTP failures map to status-specific types:

```python
from cloro import Cloro, AuthenticationError, RateLimitError, CloroError

try:
    client.monitor.chatgpt(prompt="...", country="US")
except AuthenticationError:
    ...  # 401 — bad or missing API key
except RateLimitError as e:
    ...  # 429 — back off and retry
except CloroError as e:
    ...  # everything else
```

`BadRequestError` (400), `PermissionDeniedError` (403), `NotFoundError` (404),
`ConflictError` (409), and `InternalServerError` (5xx) are also available, along
with `TaskFailedError` / `TaskTimeoutError` from the poller and
`APITimeoutError` / `APIConnectionError` from the transport.

## Reference data

```python
client.countries()             # supported countries
client.countries(model="chatgpt")
client.states()                # US states for location-targeted Google
```

## Links

- Docs: <https://cloro.dev/docs>
- API reference (OpenAPI): <https://cloro.dev/docs/api-reference/openapi.json>
- Dashboard: <https://dashboard.cloro.dev/>
- TypeScript SDK: [cloro-node](https://github.com/cloro-dev/cloro-node)

## License

MIT
