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

# Best Practices

> Production-ready patterns for retries, timeouts, concurrency, and idempotency when calling the Geekflare.

These patterns apply across all Geekflare endpoints. Following them will make your integration resilient to transient failures and easier to reason about at scale.

## Retries

Not every failure should be retried. Retry `429` and `5xx` responses; do **not** retry `401`, `402`, `403`, or `404` — those indicate a problem with the request itself, and retrying it will fail the same way every time.

| Code  | Retry? | Why                                                            |
| ----- | ------ | -------------------------------------------------------------- |
| `429` | Yes    | Transient — respect `x-geekflare-ratelimit-reset`, then retry. |
| `5xx` | Yes    | Transient infrastructure issue.                                |
| `401` | No     | Fix the API key first.                                         |
| `402` | No     | Add credits first.                                             |
| `403` | No     | Upgrade your plan first.                                       |
| `404` | No     | Fix the endpoint path or method first.                         |

### Exponential backoff with jitter

```typescript theme={null}
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error: any) {
      const status = error?.apiCode ?? error?.status;
      const retryable = status === 429 || (status >= 500 && status < 600);

      if (!retryable || attempt === maxRetries) throw error;

      const baseDelay = 2 ** attempt * 1000;
      const jitter = Math.random() * 500;
      await new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
    }
  }
  throw new Error("Unreachable");
}
```

<Tip>
  If the response includes an `x-geekflare-ratelimit-reset` header, wait at
  least that long before your first retry. Don't rely on backoff alone. See
  [Rate Limit Exceeded](/rate-limit-exceeded) for details on the rate-limit
  headers.
</Tip>

## Timeouts

Set a client-side timeout on every request. Endpoints that render JavaScript or capture screenshots can take longer than simple lookups (DNS, ping). Don't apply the same timeout to both.

* **Fast endpoints** (DNS Lookup, Ping, Site Status, TLS Scan): 10–15 seconds is generally enough.
* **Browser-based endpoints** (Web Scraping with rendering, Screenshot, Lighthouse): allow 30–60 seconds, especially for heavy or slow-loading pages.

A request that hangs without a timeout ties up a connection in your pool indefinitely and can cascade into broader outages under load.

## Concurrency

Your [rate limit](/rate-limit-exceeded) caps requests per second, not concurrent connections. But sending far more concurrent requests than your rate limit allows just means most of them queue or get `429`s. Size your concurrency to roughly match your plan's requests-per-second limit, and use a queue or semaphore to stay under it rather than firing requests unbounded.

```typescript theme={null}
import pLimit from "p-limit";

const limit = pLimit(5); // match your plan's RPS

const results = await Promise.all(
  urls.map((url) => limit(() => client.webScrape({ url }))),
);
```

## Idempotency

Geekflare endpoints are stateless HTTP calls. Retrying an identical request (same URL, same parameters) simply re-runs it and consumes credits again. If you're retrying after a timeout where you're unsure whether the original request completed, prefer checking your [API Logs](/api-request-logs) for the original request before firing a duplicate, especially for credit-heavy calls like AI Extraction or Lighthouse audits.

## Monitoring

Every response includes headers you can log or check inline, without a separate dashboard call:

| Header                                   | Tells you                                           |
| ---------------------------------------- | --------------------------------------------------- |
| `x-geekflare-ratelimit-second`           | Max requests per second for your plan               |
| `x-geekflare-ratelimit-remaining-second` | Requests remaining in the current 1-second window   |
| `x-geekflare-ratelimit-reset`            | How long until the current rate-limit window resets |
| `x-geekflare-credits-used`               | Credits used                                        |
| `x-geekflare-credits-remaining`          | Credits remaining in your balance                   |

* Watch `x-geekflare-ratelimit-remaining-second` to anticipate `429`s before they happen.
* Watch `x-geekflare-credits-remaining` to avoid a [402 Credit Exhausted](/credit-exhausted) error mid-batch, especially before starting a large scrape or search job.
* Check [status.geekflare.com](https://status.geekflare.com/) if you see a spike in `5xx` errors — it's the fastest way to confirm whether an issue is on Geekflare's side before opening a support ticket.

## Next Steps

<CardGroup cols={2}>
  <Card title="Error Code Reference" icon="triangle-exclamation" href="/error-codes">
    Every error code and what to do about it.
  </Card>

  <Card title="Rate Limit Exceeded" icon="gauge" href="/rate-limit-exceeded">
    Headers, backoff strategy, and per-plan limits.
  </Card>
</CardGroup>
