> ## 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 Node.js SDK

> Understand the Response object returned by every ZenRows Node.js SDK call.

Every method on `ZenRows` (`get` and `post`) resolves with a standard <a href="https://nodejs.org/api/globals.html#response" target="_blank" rel="noopener noreferrer nofollow">`Response`</a> object, the same one native `fetch` returns. The SDK doesn't wrap or transform it, so everything you already know about the Fetch API applies directly.

## Commonly used properties and methods

| Property / method              | Returns                          | Use it when                                      |
| ------------------------------ | -------------------------------- | ------------------------------------------------ |
| `await response.text()`        | Response body as a string        | Reading HTML or plain text                       |
| `await response.json()`        | Parsed JSON                      | The body is JSON (e.g. `json_response: true`)    |
| `await response.arrayBuffer()` | Response body as raw bytes       | Handling binary data (PDFs, screenshots, images) |
| `response.status`              | HTTP status code, e.g. `200`     | Checking exactly what happened                   |
| `response.ok`                  | `true` if `status` is 200-299    | Quick success check                              |
| `response.headers`             | `Headers` object                 | Reading ZenRows monitoring headers               |
| `response.url`                 | The final URL that was requested | Debugging what was actually sent                 |

<Warning>
  `response.text()` and `response.json()` are asynchronous, they return a `Promise` and must be awaited. This is different from libraries where the body is already available as a plain property.
</Warning>

<Tabs>
  <Tab title="Text / HTML">
    ```javascript theme={null} theme={null}
    const response = await client.get(url);
    const html = await response.text();
    ```
  </Tab>

  <Tab title="Binary (PDF, screenshot)">
    ```javascript theme={null} theme={null}
    const fs = require("fs/promises");

    const response = await client.get(url, { response_type: "pdf", js_render: true });
    const buffer = Buffer.from(await response.arrayBuffer());

    await fs.writeFile("page.pdf", buffer);
    ```

    <Tip>
      Use `response.arrayBuffer()` (not `response.text()`) when the target returns binary data. For example, a PDF from `response_type: "pdf"` or a screenshot.
    </Tip>
  </Tab>

  <Tab title="JSON">
    ```javascript theme={null} theme={null}
    const response = await client.get(url, { json_response: true, js_render: true });
    const data = await response.json();
    ```
  </Tab>
</Tabs>

## Reading ZenRows-specific headers

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

```javascript theme={null} theme={null}
const response = await client.get(url);

console.log(response.headers.get("X-Request-Id"));          // unique ID for this request
console.log(response.headers.get("X-Request-Cost"));        // dollar cost of this request (e.g., 0.001)
console.log(response.headers.get("X-Request-Credits"));     // number of credits consumed by this request
console.log(response.headers.get("Concurrency-Remaining"));  // concurrency slots left on your plan
console.log(response.headers.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-` to distinguish them from ZenRows' own headers. See the full list in the [Universal Scraper API setup guide](/universal-scraper-api/universal-scraper-api-setup#response-headers).

## Checking success before using the body

Because the SDK resolves with the response as-is rather than throwing on error status codes, always confirm the request succeeded first:

```javascript theme={null} theme={null}
const response = await client.get(url);

if (response.ok) {
  const data = await response.text();
} else {
  console.log(`Request failed: ${response.status}`);
}
```

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

## Troubleshooting

* **`await response.json()` throws a `SyntaxError`**: The body isn't JSON. Confirm you requested `json_response: true` or that the target actually returns JSON before calling `.json()`.
* **Saved file (PDF, screenshot, image) is corrupted**: You wrote `response.text()` instead of `response.arrayBuffer()`, or forgot to wrap it in `Buffer.from(...)` before writing to disk.
* **Calling `response.text()` twice throws an error**: A `Response` body can only be read once. Store the result of the first call in a variable and reuse it instead of calling `.text()`/`.json()` again.
* **`response.url` doesn't match the URL you passed**: This is expected. It's the full URL sent to ZenRows' API (including your `apikey` and config as query parameters), not the target URL by itself.

## 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 config used:

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

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

## FAQ (Frequently Asked Questions)

<AccordionGroup>
  <Accordion title="Is the response object specific to ZenRows?">
    No. It's the standard `Response` object from the Fetch API. Any Fetch API documentation or Stack Overflow answer about it applies here too.
  </Accordion>

  <Accordion title="How do I get the response as a JavaScript object?">
    Call `await response.json()` if the body is JSON. For example, when using `json_response: true` or `autoparse: true` on structured data.
  </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`) and `X-Request-Credits` gives you the number of credits consumed. Read them with `response.headers.get("X-Request-Cost")` and `response.headers.get("X-Request-Credits")`.
  </Accordion>
</AccordionGroup>
