# Pagination and depth

> Page through Google results with page, or fetch up to the top 100 in one call with num. num=100 is a depth bundle that costs 7 credits instead of 10.

Google serves results ten at a time. SerpKite gives you two ways to go deeper: request pages one by one with `page`, or ask for up to 100 results in a single call with `num`.

## page

`page` selects the results page, from 1 (default) to 10. Each page is a separate Google fetch and a separate credit.

cURL:

```bash
curl https://api.serpkite.com/v1/search \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q":"espresso grinder","country":"us","page":2}'
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite(); // reads SERPKITE_API_KEY
const res = await sk.search({ q: "espresso grinder", country: "us", page: 2 });
console.log(res.results[0].title, res.meta.credits_used);
```

Python:

```python
from serpkite import SerpKite

sk = SerpKite()  # reads SERPKITE_API_KEY
res = sk.search("espresso grinder", country="us", page=2)
print(res.results[0].title, res.meta.credits_used)
```

Go:

```go
package main

import (
	"context"
	"fmt"
	"log"

	serpkite "github.com/serpkite/serpkite-go"
)

func main() {
	ctx := context.Background()
	c := serpkite.NewClient() // reads SERPKITE_API_KEY
	res, err := c.Search(ctx, serpkite.SearchParams{Q: "espresso grinder", Country: "us", Page: 2})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(res.Results[0].Title, res.Meta.CreditsUsed)
}
```

`page` works on every paged endpoint (search, news, images, videos, maps, places, shopping, scholar, patents).

## num and the depth bundle

On [/v1/search](https://serpkite.com/docs/endpoints/search) and [/v1/news](https://serpkite.com/docs/endpoints/news), `num` above 10 fetches several pages in one request and merges them into one `results` list. SerpKite fetches `ceil(num / 10)` pages and bills one credit per page that returned results, capped at 7:

| `num` | Pages fetched | Credits (at most) |
| --- | --- | --- |
| 1–10 | 1 | 1 |
| 20 | 2 | 2 |
| 30 | 3 | 3 |
| 50 | 5 | 5 |
| 70 | 7 | 7 |
| 100 | 10 | **7** |

So the top 100 costs 7 credits instead of the 10 you would pay with ten `page` calls, and it comes back in one response with consistent positions. Pages that come back empty are free: a long-tail query with results on only two pages costs 2 credits, whatever `num` you asked for. A cache hit with `max_age` costs half of what the cached result cost.

cURL:

```bash
curl https://api.serpkite.com/v1/search \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q":"espresso grinder","country":"us","num":100}'
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite(); // reads SERPKITE_API_KEY
const res = await sk.search({ q: "espresso grinder", country: "us", num: 100 });
console.log(res.results[0].title, res.meta.credits_used);
```

Python:

```python
from serpkite import SerpKite

sk = SerpKite()  # reads SERPKITE_API_KEY
res = sk.search("espresso grinder", country="us", num=100)
print(res.results[0].title, res.meta.credits_used)
```

Go:

```go
package main

import (
	"context"
	"fmt"
	"log"

	serpkite "github.com/serpkite/serpkite-go"
)

func main() {
	ctx := context.Background()
	c := serpkite.NewClient() // reads SERPKITE_API_KEY
	res, err := c.Search(ctx, serpkite.SearchParams{Q: "espresso grinder", Country: "us", Num: 100})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(res.Results[0].Title, res.Meta.CreditsUsed)
}
```

Rules:

- `num` must be between 1 and 100. Values up to 10 behave like 10.
- `num` above 10 requires `page: 1` (or no `page`). Combining them returns `400 invalid_request`.
- On other endpoints `num` above 10 is treated as 10; use `page` to go deeper. [/v1/reviews](https://serpkite.com/docs/endpoints/reviews) is the exception: `num` up to 50 reviews, billed 1 credit per 10 reviews actually returned.
- Google sometimes returns fewer than `num` results for a query. You are billed for the pages actually fetched, and a page that comes back empty is refunded.

> **Batch it for rank tracking**
> The depth bundle combines with the batch lane: `num: 100` in a [`POST /v1/batches`](https://serpkite.com/docs/batch) request costs 3.5 credits for the top 100. See [Batch requests](https://serpkite.com/docs/batch) and [Rank tracking](https://serpkite.com/docs/guides/rank-tracking).

## Custom Search pagination

The CSE-compatible [`/customsearch/v1`](https://serpkite.com/docs/endpoints/customsearch) keeps Google's CSE paging: `start` is the index of the first result (1, 11, 21 … up to 91) and `num` is 1 to 10 per call. Each call is one credit.

```bash
curl "https://api.serpkite.com/customsearch/v1?q=asyncio&start=11&num=10" \
  -H "Authorization: Bearer $SERPKITE_API_KEY"
```

## Paging through reviews

[/v1/reviews](https://serpkite.com/docs/endpoints/reviews) uses a cursor instead of page numbers. Each response includes `next_page_token`; send it back as `page_token` to get the next batch, and stop when it is absent.

- The token is opaque and bound to the place and `sort` it came from. Send it unchanged with the same `place_id` (or `cid`/`fid`) and `sort`; anything else is a `400`.
- Paging reaches the first 100 reviews of a place per sort order. The page that reaches review 100 has no `next_page_token`.
- A page can hold fewer than `num` reviews when Google stops loading early. Its `next_page_token` resumes right after it, and you're billed for the reviews returned.

Python:

```python
from serpkite import SerpKite

sk = SerpKite()
reviews, token = [], None
while True:
    res = sk.reviews(place_id="ChIJLU7jZClu5kcR4PcOOO6p3I0", sort="newest", num=50, page_token=token)
    reviews += res.results
    token = res.next_page_token
    if not token:  # absent on the last page (at most 100 reviews)
        break
print(len(reviews), "reviews")
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite();
const reviews = [];
let page_token: string | undefined;
do {
  const res = await sk.reviews({ place_id: "ChIJLU7jZClu5kcR4PcOOO6p3I0", sort: "newest", num: 50, page_token });
  reviews.push(...res.results);
  page_token = res.next_page_token;
} while (page_token); // absent on the last page (at most 100 reviews)
console.log(reviews.length, "reviews");
```

cURL:

```bash
curl https://api.serpkite.com/v1/reviews \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"place_id":"ChIJLU7jZClu5kcR4PcOOO6p3I0","sort":"newest","num":50,"page_token":"<next_page_token>"}'
```

Related: [Credits and billing](https://serpkite.com/docs/credits-and-billing), [Common parameters](https://serpkite.com/docs/parameters).