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

# Go SDK

> The official Go SDK for the Decodo Web Scraping API, with typed, target-specific request parameters and sync, async, and batch scraping methods.

<Info>
  View the [Go SDK GitHub repository](https://github.com/Decodo/sdk-go) for the latest installation instructions, examples, and source code.
</Info>

Build typed scraping workflows for search engines, eCommerce platforms, social media, AI tools, and more with the official Decodo Go SDK for [Web Scraping API](https://decodo.com/scraping/web).

* Typed, target-specific request parameters with editor autocomplete
* Sync, async, and batch scraping methods
* Runtime validation against the current Decodo target schema
* Typed error set for safer integrations
* One dependency beyond the standard library; requires Go 1.21 or later

## What is the Decodo Go SDK?

The Decodo Go SDK provides a typed interface for interacting with Decodo targets like Google, Amazon, TikTok, Reddit, YouTube, ChatGPT, Perplexity, and more. Instead of assembling HTTP requests and validating payloads by hand, you work with typed constructors and target-specific parameter structs directly in your editor.

## Why use the SDK?

* **Typing and autocomplete** – each target has its own parameter struct, so your editor knows which fields it accepts.
* **Unified scraping interface** – work with search engines, eCommerce platforms, social media, and AI tools through one SDK.
* **Async and batch workflows** – create scraping tasks, poll task status, and process batches at scale.
* **Typed errors** – handle authentication, validation, timeout, and rate-limit failures explicitly.
* **Generated from the schema** – target constants and parameter structs are generated from the Decodo schema, which is also used for runtime validation.
* **Minimal setup** – one dependency for schema validation, and the standard library for everything else.

## Requirements

* Go 1.21 or later. Run `go version` to check, or [install Go](https://go.dev/doc/install).

## Installation

```bash theme={null}
go get github.com/decodo/sdk-go
```

## Quick start

Create a new project:

```bash theme={null}
mkdir scraper
cd scraper
go mod init scraper
go get github.com/decodo/sdk-go
touch main.go
```

Get your Web Scraping API Basic Auth token from the [**Decodo dashboard**](https://dashboard.decodo.com/welcome). Keep it out of your source by exporting it:

```bash theme={null}
export DECODO_TOKEN=your_token
```

Every target has a constructor that returns its parameter struct. Create the one you need, set its fields, and pass it to `Scrape`:

```go theme={null}
// main.go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/decodo/sdk-go"
)

func main() {
	client := decodo.NewClient(decodo.Config{
		WebScrapingAPI: &decodo.WebScrapingAPIConfig{
			Token: os.Getenv("DECODO_TOKEN"),
		},
	})

	params := decodo.NewGoogleSearchParams()
	params.Query = decodo.Ptr("coffee shops")
	params.Geo = decodo.Ptr("United States")
	params.Parse = decodo.Ptr(true)

	result, err := client.WebScrapingAPI.Scrape(context.Background(), params)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(result.Results[0].Content)
}
```

Run the program:

```bash theme={null}
go run main.go
```

Each constructor pins its own target and returns a struct that carries only the fields that target supports, so you never pass a target name or assemble a generic parameter map.

Your editor flags misspelled or unsupported fields, and the SDK validates values against the target schema before sending the request.

## Setting optional parameters

Optional parameters are pointer fields, so an unset field is distinguishable from a zero value. Use `decodo.Ptr` to set them inline:

```go theme={null}
params.Query = decodo.Ptr("shoes")
params.Parse = decodo.Ptr(true)
params.PageFrom = decodo.Ptr(1)
```

## Configuration

```go theme={null}
client := decodo.NewClient(decodo.Config{
	WebScrapingAPI: &decodo.WebScrapingAPIConfig{
		Token:             "<token>",
		IntegrationHeader: "my-app",
	},
	TimeoutMs: 120_000, // optional, request timeout in ms (default: 180000)
})
```

| Parameter                          | Description                                                                                                        |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `WebScrapingAPI.Token`             | Web Scraping API Basic Auth token. This is the base64-encoded `user:password` string from the dashboard. Required. |
| `WebScrapingAPI.IntegrationHeader` | Identifies the calling integration in requests (default: `sdk-go`)                                                 |
| `TimeoutMs`                        | Request timeout in milliseconds (default: 180000)                                                                  |
| `Schema`                           | Target schema used for request validation (default: loaded automatically)                                          |

## Web Scraping API

Access the API via `client.WebScrapingAPI`.

| Method                     | Returns                                                  |
| -------------------------- | -------------------------------------------------------- |
| `Scrape(ctx, params)`      | Returns the scraping result after the request completes. |
| `ScrapeAsync(ctx, params)` | Returns a scraping task immediately.                     |
| `GetStatus(ctx, taskID)`   | The current status of a task, as a `TaskStatus` constant |
| `GetResults(ctx, taskID)`  | The results of a task, or `nil` if not ready             |
| `ScrapeBatch(ctx, params)` | A batch task containing one query per input              |

### Sync scrape

Waits for the scraping result before returning:

```go theme={null}
params := decodo.NewAmazonProductParams()
params.Query = decodo.Ptr("B09H74FXNW")
params.Parse = decodo.Ptr(true)

result, err := client.WebScrapingAPI.Scrape(context.Background(), params)
if err != nil {
	log.Fatal(err)
}
fmt.Println(result.Results[0].Content)
```

### Async scrape

Creates a scraping task and returns immediately. You then poll for its status and results:

```go theme={null}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()

params := decodo.NewGoogleSearchParams()
params.Query = decodo.Ptr("laptop reviews")
params.Parse = decodo.Ptr(true)

task, err := client.WebScrapingAPI.ScrapeAsync(ctx, params)
if err != nil {
	log.Fatal(err)
}

for {
	status, err := client.WebScrapingAPI.GetStatus(ctx, task.ID)
	if err != nil {
		log.Fatal(err)
	}
	if status.Status == decodo.TaskStatusDone {
		break
	}
	if status.Status == decodo.TaskStatusFaulted {
		log.Fatalf("Scraping task %s failed.", task.ID)
	}
	time.Sleep(2 * time.Second)
}

results, err := client.WebScrapingAPI.GetResults(ctx, task.ID)
if err != nil {
	log.Fatal(err)
}
fmt.Println(results.Results[0].Content)
```

`GetStatus` returns one of `decodo.TaskStatusPending`, `decodo.TaskStatusDone`, or `decodo.TaskStatusFaulted`. `GetResults` returns `nil` until results are available.

### Batch scrape

Every supported target also has a batch constructor, such as `NewGoogleSearchBatchParams()`. For batch requests, fields such as `URL` or `Query` accept a slice, with each value becoming a separate task:

```go theme={null}
params := decodo.NewGoogleSearchBatchParams()
params.Query = []string{"coffee", "tea", "juice"}
params.Parse = decodo.Ptr(true)

batch, err := client.WebScrapingAPI.ScrapeBatch(ctx, params)
if err != nil {
	log.Fatal(err)
}

for _, query := range batch.Queries {
	for {
		status, err := client.WebScrapingAPI.GetStatus(ctx, query.ID)
		if err != nil {
			log.Fatal(err)
		}
		if status.Status == decodo.TaskStatusDone {
			break
		}
		if status.Status == decodo.TaskStatusFaulted {
			log.Fatalf("Scraping task %s failed.", query.ID)
		}
		time.Sleep(2 * time.Second)
	}
	result, err := client.WebScrapingAPI.GetResults(ctx, query.ID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(result.Results[0].Content)
}
```

<Note>
  A batch runs against a single target, which the constructor pins for you. `URL` and `Query` are the only fields that accept multiple values; all other fields use their regular types.

  Some targets aren't available through `ScrapeBatch`. Use `ScrapeAsync` for those instead. Batch requests are limited to one per second and skip schema validation because the schema describes single values.
</Note>

## Targets and parameter constructors

Every target has a matching constructor. The target name is converted to PascalCase, prefixed with `New`, and suffixed with `Params` – for example, `google_search` → `NewGoogleSearchParams()`. Batch constructors follow the same pattern, for example `NewGoogleSearchBatchParams()`.

You don't need to pass a target explicitly because each constructor pins its own target. Each parameter struct also carries a `Target` field, and `GetTarget()` returns it as a string.

Each target takes one primary input field (`URL`, `Query`, `ProductID`, or `Prompt`) together with optional configuration such as `Parse`, `Markdown`, `Geo`, or `CallbackURL`. Available optional fields vary by target, so use editor autocomplete or the [parameters documentation](/docs/web-scraping-api-parameters).

### Search engines

| Target          | Description                       | Primary input | Constructor               |
| --------------- | --------------------------------- | ------------- | ------------------------- |
| `google_search` | Google Search results for a query | `Query`       | `NewGoogleSearchParams()` |
| `google_lens`   | Google Lens reverse image search  | `Query`       | `NewGoogleLensParams()`   |
| `google_ads`    | Google Ads results for a query    | `Query`       | `NewGoogleAdsParams()`    |
| `bing_search`   | Bing Search results               | `Query`       | `NewBingSearchParams()`   |
| `bing`          | Raw Bing URL scraping             | `URL`         | `NewBingParams()`         |

### eCommerce

| Target               | Description                           | Primary input | Constructor                    |
| -------------------- | ------------------------------------- | ------------- | ------------------------------ |
| `amazon_product`     | Amazon product detail page by ASIN    | `Query`       | `NewAmazonProductParams()`     |
| `amazon_search`      | Amazon search results                 | `Query`       | `NewAmazonSearchParams()`      |
| `amazon_pricing`     | Amazon pricing and offers             | `Query`       | `NewAmazonPricingParams()`     |
| `amazon_sellers`     | Amazon seller listings                | `Query`       | `NewAmazonSellersParams()`     |
| `amazon_bestsellers` | Amazon bestsellers by category        | `Query`       | `NewAmazonBestsellersParams()` |
| `walmart_product`    | Walmart product page by product ID    | `ProductID`   | `NewWalmartProductParams()`    |
| `walmart_search`     | Walmart search results                | `Query`       | `NewWalmartSearchParams()`     |
| `walmart`            | Raw Walmart URL scraping              | `URL`         | `NewWalmartParams()`           |
| `target_product`     | Target.com product page by product ID | `ProductID`   | `NewTargetProductParams()`     |
| `target_search`      | Target.com search results             | `Query`       | `NewTargetSearchParams()`      |
| `target`             | Raw Target.com URL scraping           | `URL`         | `NewTargetParams()`            |

### Social media

| Target                | Description                            | Primary input | Constructor                    |
| --------------------- | -------------------------------------- | ------------- | ------------------------------ |
| `reddit_post`         | Reddit post by URL                     | `URL`         | `NewRedditPostParams()`        |
| `reddit_subreddit`    | Reddit subreddit by URL                | `URL`         | `NewRedditSubredditParams()`   |
| `reddit_user`         | Reddit user profile by URL             | `URL`         | `NewRedditUserParams()`        |
| `youtube_search`      | YouTube search results                 | `Query`       | `NewYoutubeSearchParams()`     |
| `youtube_metadata`    | YouTube video metadata by ID           | `Query`       | `NewYoutubeMetadataParams()`   |
| `youtube_subtitles`   | YouTube video subtitles by ID          | `Query`       | `NewYoutubeSubtitlesParams()`  |
| `youtube_channel`     | YouTube channel by handle or ID        | `Query`       | `NewYoutubeChannelParams()`    |
| `tiktok_post`         | TikTok post by URL                     | `URL`         | `NewTiktokPostParams()`        |
| `tiktok_shop_search`  | TikTok Shop search results             | `Query`       | `NewTiktokShopSearchParams()`  |
| `tiktok_shop_product` | TikTok Shop product page by product ID | `ProductID`   | `NewTiktokShopProductParams()` |
| `tiktok`              | Raw TikTok URL scraping                | `URL`         | `NewTiktokParams()`            |

### AI tools

| Target           | Description                      | Primary input | Constructor               |
| ---------------- | -------------------------------- | ------------- | ------------------------- |
| `chatgpt`        | ChatGPT response for a prompt    | `Prompt`      | `NewChatgptParams()`      |
| `perplexity`     | Perplexity response for a prompt | `Prompt`      | `NewPerplexityParams()`   |
| `gemini`         | Gemini response for a prompt     | `Prompt`      | `NewGeminiParams()`       |
| `google_ai_mode` | Google AI Mode response          | `Query`       | `NewGoogleAiModeParams()` |

### Universal scraping

| Target      | Description                       | Primary input | Constructor            |
| ----------- | --------------------------------- | ------------- | ---------------------- |
| `universal` | Any URL via the universal scraper | `URL`         | `NewUniversalParams()` |
| `google`    | Raw Google URL scraping           | `URL`         | `NewGoogleParams()`    |
| `amazon`    | Raw Amazon URL scraping           | `URL`         | `NewAmazonParams()`    |

<Note>
  `universal_ecommerce` isn't included in the table because its parameter struct exposes only `Target` and `CallbackURL`, with no primary input. Use `ecommerce` for generic product pages or `universal` for any URL.
</Note>

For the full target list and parameter details, see [**Target list**](/docs/web-scraping-api-targets) and [**Parameters**](/docs/web-scraping-api-parameters).

## Schema validation

Go checks that a field exists and holds the right type at compile time. Values are checked separately, at runtime, against the Decodo target schema.

When no `Schema` is configured, the client uses `decodo.SharedDefaultSchema`, which loads the latest schema on first use and caches it locally for 24 hours. If the fetch fails, the SDK logs a warning and continues with validation disabled for that session.

```go theme={null}
schema, err := decodo.LoadRemoteSchema(decodo.RemoteSchemaOptions{
	TTLMs: 3_600_000, // re-fetch after an hour instead of the default 24
})
if err != nil {
	log.Fatal(err)
}

client := decodo.NewClient(decodo.Config{
	WebScrapingAPI: &decodo.WebScrapingAPIConfig{Token: token},
	Schema:         schema,
})
```

## Error handling

The SDK returns typed errors that map to API error codes:

```go theme={null}
result, err := client.WebScrapingAPI.Scrape(ctx, params)
if err != nil {
	switch e := err.(type) {
	case *decodo.AuthenticationError:
		log.Fatalf("Invalid token (HTTP %d). Check the Basic auth token in your dashboard.", e.StatusCode)
	case *decodo.RateLimitError:
		time.Sleep(5 * time.Second)
		result, err = client.WebScrapingAPI.Scrape(ctx, params)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(result.Results[0].Content)
	case *decodo.ValidationError:
		fmt.Println("Payload rejected:", e.Errors)
	case *decodo.TimeoutError:
		fmt.Println("Timed out. Increase TimeoutMs or switch to ScrapeAsync for slow targets:", e.Msg)
	case *decodo.CancellationError:
		fmt.Println("Cancelled:", e.Msg)
	default:
		fmt.Printf("Request failed: %v\n", err)
	}
}
```

`AuthenticationError`, `RateLimitError`, and `ValidationError` embed `DecodoError` and implement `Unwrap`. As a result, `errors.Is` and `errors.As` also work with `*decodo.DecodoError`.

| Error                 | Returned when                                                             | Useful fields                           |
| --------------------- | ------------------------------------------------------------------------- | --------------------------------------- |
| `AuthenticationError` | The API returns `401` or `403`                                            | `StatusCode`, `APIStatus`, `Message`    |
| `RateLimitError`      | The API returns `429`                                                     | `StatusCode`, `APIStatus`, `Message`    |
| `ValidationError`     | The API returns `422`, or `400` with validation errors                    | `Errors`, plus the `DecodoError` fields |
| `TimeoutError`        | The request exceeds `TimeoutMs`                                           | `Msg`                                   |
| `CancellationError`   | The caller's context is cancelled                                         | `Msg`                                   |
| `DecodoError`         | Any other unsuccessful response - embedded by the three HTTP errors above | `StatusCode`, `APIStatus`, `Message`    |

<Note>
  `TimeoutError` and `CancellationError` sit outside the `DecodoError` hierarchy and only carry `Msg`, so checks against `*decodo.DecodoError` won't match them.

  Schema validation may also be skipped if the target schema can't be fetched. In that case, invalid values may reach the API and be returned as API errors instead of compile-time or local validation errors.
</Note>

***

## Related

* **[CLI](/docs/cli)** – Run Decodo scraping workflows from the command line.
* [**TypeScript SDK**](/docs/typescript-sdk) – Integrate the Web Scraping API into TypeScript and JavaScript projects.
* [**Python SDK**](/docs/python-sdk) – Integrate the Web Scraping API into Python projects.
* [**MCP Server**](/docs/mcp) – Connect AI agents and MCP-compatible tools to Decodo.
* [GitHub repository ](https://github.com/Decodo/sdk-go)– View the Go SDK source code, examples, and latest releases.

***

<Columns cols={2}>
  <Card title="Support" href="https://direct.lc.chat/12092754" cta="Let's chat!">
    Need help or just want to say hello? Our support is available 24/7. \
    You can also reach us anytime via email at [support@decodo.com](mailto:support@decodo.com).
  </Card>

  <Card title="Feedback" href="mailto:feedback@decodo.com" cta="Share feedback">
    Can't find what you're looking for? Request an article! \
    Have feedback? Share your thoughts on how we can improve.
  </Card>
</Columns>
