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

# The Response Object with the Go SDK

> Understand the *scraperapi.Response type returned by every ZenRows Go SDK call.

Every method on `*scraperapi.Client` (`Get`, `Post`, `Put`, `Scrape`) returns a `*scraperapi.Response` on success. It wraps an underlying `go-resty` response, and also exposes the original `*http.Response` if you need it.

## Commonly used methods

| Method                  | Returns                           | Use it when                                      |
| ----------------------- | --------------------------------- | ------------------------------------------------ |
| `response.String()`     | Response body as a `string`       | Reading HTML or plain text                       |
| `response.Body()`       | Response body as `[]byte`         | Handling binary data (PDFs, screenshots, images) |
| `response.StatusCode()` | HTTP status code, e.g. `200`      | Checking exactly what happened                   |
| `response.Status()`     | Status text, e.g. `"200 OK"`      | Logging or display                               |
| `response.IsSuccess()`  | `true` if status is 200 to 299    | Quick success check                              |
| `response.IsError()`    | `true` if status is 400 or higher | Quick failure check                              |
| `response.Header()`     | `http.Header` of response headers | Reading ZenRows monitoring headers               |
| `response.RawResponse`  | The original `*http.Response`     | Anything the wrapper doesn't expose              |

<Tabs>
  <Tab title="Text / HTML">
    ```go theme={null} theme={null}
    response, err := client.Get(context.Background(), url, nil)
    html := response.String()
    ```
  </Tab>

  <Tab title="Binary (PDF, screenshot)">
    ```go theme={null} theme={null}
    response, err := client.Get(context.Background(), url, &scraperapi.RequestParameters{
        JSRender:     true,
        ResponseType: scraperapi.ResponseTypePDF,
    })
    if err != nil {
        log.Fatal(err)
    }

    if err := os.WriteFile("page.pdf", response.Body(), 0o644); err != nil {
        log.Fatal(err)
    }
    ```

    <Tip>
      Use `response.Body()` (not `response.String()`) when the target returns binary data, like a PDF from `ResponseType: scraperapi.ResponseTypePDF` or a screenshot. `Body()` gives you the raw `[]byte`, ready to write straight to a file.
    </Tip>
  </Tab>

  <Tab title="JSON">
    ```go theme={null} theme={null}
    response, err := client.Get(context.Background(), url, &scraperapi.RequestParameters{
        JSRender:     true,
        JSONResponse: true,
    })
    if err != nil {
        log.Fatal(err)
    }

    var data map[string]any
    if err := json.Unmarshal(response.Body(), &data); err != nil {
        log.Fatal(err)
    }
    ```
  </Tab>
</Tabs>

## Reading ZenRows-specific headers

ZenRows adds monitoring headers to every response, useful for debugging and tracking usage:

```go theme={null} theme={null}
response, err := client.Get(context.Background(), url, nil)

fmt.Println(response.Header().Get("X-Request-Id"))          // unique ID for this request
fmt.Println(response.Header().Get("X-Request-Cost"))        // dollar cost of this request (e.g., 0.001)
fmt.Println(response.Header().Get("X-Request-Credits"))     // number of credits consumed by this request
fmt.Println(response.Header().Get("Concurrency-Remaining")) // concurrency slots left on your plan
fmt.Println(response.Header().Get("Zr-Final-Url"))          // final URL after redirects
```

<Tip>
  If you ever contact ZenRows support about a failed request, include the `X-Request-Id` header value. It lets the team trace the exact request in the logs.
</Tip>

Headers coming from the target website itself are prefixed with `Zr-` (for example, `Zr-Content-Encoding`, `Zr-Cookies`). See the full list in the [Universal Scraper API setup guide](/universal-scraper-api/universal-scraper-api-setup#response-headers).

<Note>
  The SDK also exposes `response.TargetHeaders()` and `response.TargetCookies()` as shortcuts for reading target-site headers and cookies. If they return fewer headers than you expect for a given response, fall back to filtering `response.Header()` yourself for keys with the `Zr-` prefix shown above, that always works regardless of which prefix the shortcut methods look for internally.
</Note>

## Checking success before using the body

Because the SDK returns a response as-is rather than turning HTTP errors into a Go `error`, always confirm the request succeeded first:

```go theme={null} theme={null}
response, err := client.Get(context.Background(), url, nil)
if err != nil {
    log.Fatal(err)
}

if response.IsSuccess() {
    data := response.String()
} else {
    fmt.Println("Request failed:", response.StatusCode())
    if prob := response.Problem(); prob != nil {
        fmt.Println("Detail:", prob.Detail)
    }
}
```

`response.Problem()` parses a structured error body into a `*problem.Problem` when the response is an error and the `Content-Type` is JSON. `response.Error()` does the same thing but returns it as a plain Go `error`, so `if err := response.Error(); err != nil { ... }` works too.

<Card title="Error Handling and Retries" icon="shield-halved" href="/universal-scraper-api/sdk/go/error-handling-and-retries">
  More on this pattern, plus how to configure automatic retries.
</Card>

## Troubleshooting

* **`json.Unmarshal` fails on the response body**: The body isn't JSON. Confirm you requested `JSONResponse: true` (with `JSRender: true`) or that the target actually returns JSON.
* **Saved file (PDF, screenshot, image) is corrupted**: You wrote `response.String()` instead of `response.Body()`. `String()` can mangle binary data; always use `Body()` for non-text responses.
* **`response.TargetHeaders()` or `TargetCookies()` return nothing**: Fall back to reading `response.Header()` directly and filtering for the `Zr-` prefix, as noted above.
* **`response.Problem()` returns `nil` on a failed request**: This method only parses a body when `IsError()` is true and the response `Content-Type` is JSON. A non-JSON error body (or a successful response) always returns `nil`.

## Pricing

The response itself doesn't add cost. ZenRows adds two headers to help you track usage:

* `X-Request-Cost`: the dollar cost of the request (e.g., `0.001`)
* `X-Request-Credits`: the number of credits consumed by the request

Both values are based on the parameters used:

| Configuration                                | Cost multiplier vs. basic |
| -------------------------------------------- | ------------------------- |
| Basic request                                | 1x                        |
| `JSRender: true`                             | 5x                        |
| `UsePremiumProxies: true`                    | 10x                       |
| `JSRender: true` + `UsePremiumProxies: true` | 25x                       |

See [ZenRows Pricing](/first-steps/pricing).

## FAQ (Frequently Asked Questions)

<AccordionGroup>
  <Accordion title="Is the Response type specific to ZenRows, or is it go-resty's type directly?">
    It's a thin ZenRows-specific wrapper around a `go-resty` response, plus the original `*http.Response` exposed as the `RawResponse` field. You don't need `go-resty` imported in your own code to use it.
  </Accordion>

  <Accordion title="How do I get the response as a Go struct instead of a map?">
    Define a struct matching the expected JSON shape and pass a pointer to it in `json.Unmarshal(response.Body(), &yourStruct)`, the same as unmarshaling any other JSON in Go.
  </Accordion>

  <Accordion title="Where do I find how much a request cost?">
    Check the response headers: `X-Request-Cost` gives you the dollar cost (e.g., `0.001`), read with `response.Header().Get("X-Request-Cost")`. `X-Request-Credits` gives you the number of credits consumed, read with `response.Header().Get("X-Request-Credits")`.
  </Accordion>
</AccordionGroup>
