> ## 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.

# Output Filters

> Extract only the data types you need from any scraped page using the outputs parameter.

The `outputs` parameter lets you specify exactly which data types to extract from a scraped page. Instead of parsing raw HTML yourself, ZenRows does the extraction for you and returns a clean, structured JSON response.

This is useful when you only need specific elements (like emails, links, or headings) and want to skip the overhead of processing full HTML responses.

<Tip>The parameter accepts a comma-separated list of filter names. You can also use `outputs=*` to retrieve all available data types at once.</Tip>

<CodeGroup>
  ```python Python theme={null}
  import requests

  url = "https://www.scrapingcourse.com/ecommerce/"
  apikey = "YOUR_ZENROWS_API_KEY"

  params = {
      "url": url,
      "apikey": apikey,
      "outputs": "emails,headings,menus",
  }

  response = requests.get("https://api.zenrows.com/v1/", params=params)
  print(response.text)
  ```

  ```javascript Node.js theme={null}
  import axios from "axios";

  const url = "https://www.scrapingcourse.com/ecommerce/";
  const apikey = "YOUR_ZENROWS_API_KEY";

  const response = await axios.get("https://api.zenrows.com/v1/", {
  params: {
      url,
      apikey,
      outputs: "emails,headings,menus",
  },
  });

  console.log(response.data);
  ```

  ```java Java theme={null}
  import org.apache.hc.client5.http.fluent.Request;

  public class APIRequest {
      public static void main(final String... args) throws Exception {
          String apiUrl = "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&outputs=emails,headings,menus";
          String response = Request.get(apiUrl)
                  .execute().returnContent().asString();
          System.out.println(response);
      }
  }
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&outputs=emails,headings,menus");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $response = curl_exec($ch);
  echo $response . PHP_EOL;
  curl_close($ch);
  ?>
  ```

  ```go Go theme={null}
  package main

  import (
      "io"
      "log"
      "net/http"
  )

  func main() {
      client := &http.Client{}
      req, err := http.NewRequest("GET", "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&outputs=emails,headings,menus", nil)
      if err != nil {
          log.Fatalln(err)
      }

      resp, err := client.Do(req)
      if err != nil {
          log.Fatalln(err)
      }
      defer resp.Body.Close()

      body, err := io.ReadAll(resp.Body)
      if err != nil {
          log.Fatalln(err)
      }

      log.Println(string(body))
  }
  ```

  ```ruby Ruby theme={null}
  require "faraday"

  url = URI.parse("https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&outputs=emails,headings,menus")
  conn = Faraday.new()
  conn.options.timeout = 180
  res = conn.get(url, nil, nil)
  print(res.body)
  ```

  ```bash cURL theme={null}
  curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&outputs=emails,headings,menus"
  ```
</CodeGroup>

## Available filters

<AccordionGroup>
  <Accordion title="emails" icon="envelope">
    Extracts email addresses from the page using CSS selectors and regular expressions. This includes standard formats like `example@example.com` as well as obfuscated versions like `example[at]example.com` and `support at support dot com`.

    Example: `outputs=emails`

    ```json theme={null}
    {
      "emails": [
        "example@example.com",
        "info@website.com",
        "contact[at]domain.com",
        "support at support dot com"
      ]
    }
    ```
  </Accordion>

  <Accordion title="phone_numbers" icon="phone">
    Extracts phone numbers by targeting `tel:` protocol links and applying regular expressions to detect common formats.

    Example: `outputs=phone_numbers`

    ```json theme={null}
    {
      "phone_numbers": [
        "+1-800-555-5555",
        "(123) 456-7890",
        "+44 20 7946 0958"
      ]
    }
    ```
  </Accordion>

  <Accordion title="headings" icon="heading">
    Extracts all heading text from `h1` through `h6` elements, giving you a quick structural outline of the page.

    Example: `outputs=headings`

    ```json theme={null}
    {
      "headings": [
        "Welcome to Our Website",
        "Our Services",
        "Contact Us",
        "FAQ"
      ]
    }
    ```
  </Accordion>

  <Accordion title="images" icon="image">
    Extracts image sources from `img` tags. Only the `src` attribute is returned.

    Example: `outputs=images`

    ```json theme={null}
    {
      "images": [
        "https://example.com/image1.jpg",
        "https://example.com/image2.png"
      ]
    }
    ```
  </Accordion>

  <Accordion title="audios" icon="volume">
    Extracts audio sources from `source` elements nested inside `audio` tags. Only the `src` attribute is returned.

    Example: `outputs=audios`

    ```json theme={null}
    {
      "audios": [
        "https://example.com/audio1.mp3",
        "https://example.com/audio2.wav"
      ]
    }
    ```
  </Accordion>

  <Accordion title="videos" icon="video">
    Extracts video sources from `source` elements nested inside `video` tags. Only the `src` attribute is returned.

    Example: `outputs=videos`

    ```json theme={null}
    {
      "videos": [
        "https://example.com/video1.mp4",
        "https://example.com/video2.webm"
      ]
    }
    ```
  </Accordion>

  <Accordion title="links" icon="link">
    Extracts all URLs from `a` tags on the page. Only the `href` attribute is returned.

    Example: `outputs=links`

    ```json theme={null}
    {
      "links": [
        "https://example.com/page1",
        "https://example.com/page2"
      ]
    }
    ```
  </Accordion>

  <Accordion title="menus" icon="bars">
    Extracts navigation menu items from `li` elements inside `menu` tags.

    Example: `outputs=menus`

    ```json theme={null}
    {
      "menus": [
        "Home",
        "About Us",
        "Services",
        "Contact"
      ]
    }
    ```
  </Accordion>

  <Accordion title="hashtags" icon="hashtag">
    Extracts hashtags from page content using regular expressions, matching standard formats like `#example`.

    Example: `outputs=hashtags`

    ```json theme={null}
    {
      "hashtags": [
        "#vacation",
        "#summer2024",
        "#travel"
      ]
    }
    ```
  </Accordion>

  <Accordion title="metadata" icon="tag">
    Extracts `name` and `content` attributes from `meta` tags in the `head` section. Each entry is returned in `name: content` format.

    Example: `outputs=metadata`

    ```json theme={null}
    {
      "metadata": [
        "description: This is an example webpage.",
        "keywords: example, demo, website",
        "author: John Doe"
      ]
    }
    ```
  </Accordion>

  <Accordion title="tables" icon="table">
    Extracts data from `table` elements and returns it as structured JSON, including the table dimensions, column headings, and row content.

    Example: `outputs=tables`

    ```json theme={null}
    {
      "dimensions": {
        "rows": 4,
        "columns": 4,
        "heading": true
      },
      "heading": ["A", "B", "C", "D"],
      "content": [
        {"A": "1", "B": "1", "C": "1", "D": "1"},
        {"A": "2", "B": "2", "C": "2", "D": "2"},
        {"A": "3", "B": "3", "C": "3", "D": "3"},
        {"A": "4", "B": "4", "C": "4", "D": "4"}
      ]
    }
    ```
  </Accordion>

  <Accordion title="favicon" icon="star">
    Extracts the favicon URL from the `link` element in the `head` section.

    Example: `outputs=favicon`

    ```json theme={null}
    {
      "favicon": "https://example.com/favicon.ico"
    }
    ```
  </Accordion>
</AccordionGroup>

## When to use output filters

Output filters are the right choice when you know exactly which data types you need and don't want to deal with raw HTML. They're particularly well-suited for:

* **Lead generation and outreach** — use `emails` and `phone_numbers` to collect contact information from directories, company pages, or listings.
* **SEO and content audits** — combine `headings`, `metadata`, `links`, and `favicon` to analyze page structure and on-page signals across multiple URLs.
* **E-commerce and media monitoring** — use `images`, `videos`, and `tables` to track product listings, pricing tables, or media assets.
* **Social and community research** — use `hashtags` to monitor trending topics or branded tags across public pages.
* **Navigation and site mapping** — use `menus` and `links` to map out a site's structure without scraping full page content.

<Note>Output filters work on the final rendered HTML. If the data you need is loaded dynamically via JavaScript, enable `js_render=true` alongside your `outputs` parameter.</Note>

## Best practices

**Only request what you need:** <br />Each filter adds a small processing overhead. Requesting `outputs=*` is convenient during exploration, but in production you should specify only the filters relevant to your use case.

**Combine filters in a single request:** <br />You can pass multiple filters as a comma-separated list (`outputs=emails,links,metadata`) rather than making separate requests. This keeps your credit usage efficient.

**Use `js_render` for dynamic content:** <br />If a page loads its content via JavaScript (single-page apps, lazy-loaded sections), the filters will only capture what's present in the initial HTML unless you also pass `js_render=true`.

**Use `wait` or `wait_for` for delayed content:** <br />If the content is loaded after a delay or via JavaScript, use `wait` or `wait_for` to wait for the content to load before extracting it.

<Tip>Find more details on our [Wait Documentation](/universal-scraper-api/features/wait) or [Wait For Selector Documentation](/universal-scraper-api/features/wait-for).</Tip>

**Validate output shape before parsing:** <br />Some filters return a flat array (like `emails` or `links`) while others return structured objects (like `tables`). Check the response shape for each filter before building your parser.

**Handle empty results gracefully:** <br />If a filter finds no matching elements on the page, it returns an empty array. Credits are still charged for any request that returns a `200` status code, regardless of whether the filters matched anything. Make sure your pipeline verifies that the target page actually contains the data you need before running it at scale.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The response is empty or missing expected data">
    This usually means the target content is loaded dynamically via JavaScript. Add `js_render=true` to your request to render the page before extraction. If the data still doesn't appear, inspect the raw HTML response first (without `outputs`) to confirm the elements are present in the DOM.

    Also, enable `js_render=true` and `wait` or `wait_for` to wait for the content to load before extracting it. You can find more details on our [Troubleshooting Partial or Empty Responses](/universal-scraper-api/troubleshooting/empty-or-partialresponses) guide.
  </Accordion>

  <Accordion title="emails returns obfuscated or partial addresses">
    ZenRows detects common obfuscation patterns like `[at]` and `at domain dot com`, but some sites use custom JavaScript-based obfuscation that only resolves after rendering. Enable `js_render=true` to capture those cases. If the email is injected purely via client-side script with no HTML representation, it may not be extractable with output filters alone.
  </Accordion>

  <Accordion title="tables returns unexpected or malformed data">
    The `tables` filter targets standard HTML `table` elements. If the site renders its tables as `div` grids or uses CSS to simulate table layout, the filter won't pick them up. In that case, use `css_extractor` with a custom CSS selector instead.
  </Accordion>

  <Accordion title="links includes relative or irrelevant URLs">
    The `links` filter returns all `href` values from `a` tags as-is, including relative paths, anchor links (`#section`), and `mailto:` links. Filter the results in your own code to keep only the URLs relevant to your use case.
  </Accordion>

  <Accordion title="menus returns an empty array on a page that clearly has navigation">
    The `menus` filter targets `li` elements inside semantic `menu` tags. Many modern sites use `nav > ul > li` structures instead. If `menus` returns empty, use `css_extractor` with a selector like `nav a` to capture navigation links directly.
  </Accordion>
</AccordionGroup>

## Pricing

The `autoparse=true` parameter is included at **no additional cost** with all ZenRows requests. You only pay extra for JavaScript Render and Premium Proxy when used.

<Tip>
  You can monitor your ZenRows usage in multiple ways to stay informed about your account activity and prevent unexpected overages.

  **Dashboard monitoring**: View real-time usage statistics, remaining requests, success rates, and request history on your [Analytics Page](https://app.zenrows.com/analytics/scraper-api). You can also set up usage alerts in your [notification settings](https://app.zenrows.com/account/notifications) to receive notifications when you approach your limits.

  **Programmatic monitoring**: For automated monitoring in your applications, call the `/v1/subscriptions/self/details` endpoint with your API key in the `X-API-Key` header. This returns real-time usage data that you can integrate into your monitoring systems. [Learn more about the usage endpoint](https://docs.zenrows.com/universal-scraper-api/features/other#plan-usage).

  **Response header monitoring**: Track your concurrency usage through response headers included with each request:

  * `Concurrency-Limit`: Your maximum concurrent requests
  * `Concurrency-Remaining`: Available concurrent request slots
  * `X-Request-Cost`: Cost of the current request
</Tip>

## FAQ (Frequently Asked Questions)

<Accordion title="Can I use output filters alongside other parameters like js_render or premium_proxy?">
  Yes, output filters are fully compatible with all other ZenRows parameters. You can combine `outputs` with `js_render`, `autoparse`, `custom_headers`, and any other parameter your request needs.
</Accordion>

<Accordion title="Do output filters count as additional credits?">
  No, using the `outputs` parameter does not add extra credit cost. You pay the same credit rate as a standard request for that URL, regardless of how many filters you include.
</Accordion>

<Accordion title="What happens if I request a filter and the page has no matching elements?">
  The filter returns an empty array for that key, and the rest of your requested filters are still returned normally. Keep in mind that credits are charged based on a successful `200` response, not on whether the filters returned data. If you're running filters at scale, validate that the target pages actually contain the elements you're looking for before sending large batches.
</Accordion>

<Accordion title="Can I use outputs=* in production?">
  You can, but it's not recommended for high-volume pipelines. Requesting all filters adds unnecessary processing for data types you don't need. Use `outputs=*` during development to explore what's available, then narrow it down to the specific filters your use case requires before going to production.
</Accordion>

<Accordion title="Do output filters work with the Scraping Browser?">
  Output filters are a feature of the Universal Scraper API and are passed as query parameters. They are not available in Scraping Browser (CDP/Playwright) sessions, where you handle data extraction directly in your script using standard browser APIs.
</Accordion>

<Accordion title="Is there a limit to how many filters I can combine in one request?">
  There is no hard limit on the number of filters you can combine. You can pass all available filters in a single request using `outputs=*` or by listing them individually. In practice, the response size grows with each filter, so only request what you actually need.
</Accordion>
