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

# How to Integrate Dify with Zenrows

> Install the official Zenrows plugin from the Dify Marketplace and add Fetch, Extract, and Batch tools to your Dify workflows and agents, including pages behind anti-bot protection and heavy JavaScript.

Install the official Zenrows plugin from the <a href="https://marketplace.dify.ai/plugin/zenrows/zenrows" target="_blank" rel="nofollow noopener noreferrer">Dify Marketplace</a> and your Dify workflows and agents can read live web pages, including the ones that return a block page to an ordinary HTTP request. There's no custom code to write, no API schema to import, and no HTTP node to configure: the plugin adds five ready-made tools to the Dify tool picker.

## What Is Dify?

<a href="https://dify.ai" target="_blank" rel="nofollow noopener noreferrer">Dify</a> is an open-source platform for building LLM applications. You assemble workflows, chatflows, and agents on a visual canvas by connecting nodes such as LLM calls, knowledge retrieval, code, and tools. It runs as a hosted service at `cloud.dify.ai` or self-hosted on your own infrastructure.

Dify's plugin system lets third parties ship tools that show up next to the built-in ones. The Zenrows plugin is one of them, published and maintained by Zenrows.

## Why Connect Zenrows to Dify?

* **Workflows that don't get blocked:** a plain HTTP request to a site behind Cloudflare, DataDome, or similar gets a challenge page, and the LLM node then reasons over the wrong content. Zenrows returns the real page.
* **Markdown by default:** the Fetch tool returns clean Markdown, which costs far fewer tokens than raw HTML when you pass it to an LLM node.
* **Structured data without parsing code:** the Extract tool returns JSON fields, so you don't need a Code node to pull prices or titles out of HTML.
* **Many URLs in one job:** the Batch tools submit up to 1,000 URLs per call as an asynchronous job (a plugin limit), instead of looping a Fetch node.
* **One credential for the workspace:** you authorize the plugin once, and every member of the workspace can use it in their apps.

## Available Tools

The plugin adds five tools under the **Zenrows** provider:

| Tool | What it does |
| - | - |
| **Fetch** | Retrieves one page as Markdown, HTML, plain text, or PDF. A separate **Screenshot** option returns an image instead. Supports JavaScript rendering, Premium Proxies, proxy country, wait conditions, and JavaScript instructions. |
| **Extract** | Returns structured JSON from a page. Pick a method: `auto` (site-tailored, falls back to autoparse), `autoparse` (any site), `css` (your own CSS selectors), or `outputs` (built-in filters such as emails, links, and tables). |
| **Batch Create** | Submits 1 to 1,000 URLs per call as one asynchronous job and returns a job ID. The 1,000 limit comes from the plugin; the Batch API itself accepts up to 100,000 URLs per job. It can also wait up to about 100 seconds for a small job to finish. |
| **Batch Status** | Reports a job's progress: completed, successful, and failed task counts, failure reasons, and credits spent. |
| **Batch Results** | Collects the scraped content of a finished job, 25 results by default and up to 200 per call. |

Use Fetch when you want the page, Extract when you want fields from the page, and Batch when you have more URLs than one request should carry.

## Prerequisites

* A Dify workspace, either on <a href="https://cloud.dify.ai" target="_blank" rel="nofollow noopener noreferrer">Dify Cloud</a> or self-hosted. Self-hosted instances need Dify 1.11.4 or later.
* A Zenrows API key from your <a href="https://app.zenrows.com/settings/api-keys" target="_blank" rel="nofollow noopener noreferrer">Zenrows dashboard</a>.
* For self-hosted Dify: outbound HTTPS access to `api.zenrows.com` and `async.api.zenrows.com`. The plugin needs no inbound connections.

## Set Up the Zenrows Plugin

<Steps>
  <Step title="Install the plugin from the Dify Marketplace">
    Open the <a href="https://marketplace.dify.ai/plugin/zenrows/zenrows" target="_blank" rel="nofollow noopener noreferrer">Zenrows plugin page</a> and click **Install**. Dify opens your workspace and installs the plugin. You can also search for **Zenrows** from **Marketplace** in the Dify sidebar.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-marketplace-zenrows-plugin.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=bbb915eab4b61fecc44690e14b1a54f5" alt="The Zenrows plugin page on the Dify Marketplace, showing the Install button and the five tools it provides" width="1212" height="980" data-path="images/integrations/dify/dify-marketplace-zenrows-plugin.png" />
    </Frame>

    When installation finishes, Dify shows an **Installation successful** dialog, and Zenrows appears under **Integrations** > **Tools** > **Tool Plugin**.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-plugin-installed.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=c4a2bc952b9db12a8a3364d4f7f0138a" alt="Dify's Installation successful dialog for the Zenrows plugin, version 0.1.0" width="1511" height="795" data-path="images/integrations/dify/dify-plugin-installed.png" />
    </Frame>
  </Step>

  <Step title="Authorize the plugin with your API key">
    In **Integrations** > **Tools** > **Tool Plugin**, click the **Zenrows** card, then click **API Key Authorization Configuration**. Fill in the dialog:

    * **Authorization Name**: any label, for example `Zenrows`.
    * **Zenrows API Key**: paste your key from the Zenrows dashboard.
    * **Who can use**: leave **All team members**, or restrict it.

    Click **Save**. Dify validates the key with Zenrows before saving it, and the check doesn't consume credits.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-zenrows-api-key-dialog.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=3fc1270866b2b1dda7df1bae9c73d834" alt="The API Key Authorization Configuration dialog with Authorization Name, Zenrows API Key, and Who can use fields" width="1512" height="795" data-path="images/integrations/dify/dify-zenrows-api-key-dialog.png" />
    </Frame>

    The plugin panel now shows **1 Authorization** with a green indicator, and lists the five actions.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-zenrows-plugin-authorized.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=9464401cfb7cc0e0cd3c5a84e82774f9" alt="The Zenrows plugin panel in Dify showing 1 Authorization and the Fetch, Extract, Batch Create, Batch Status, and Batch Results actions" width="1512" height="795" data-path="images/integrations/dify/dify-zenrows-plugin-authorized.png" />
    </Frame>
  </Step>
</Steps>

## Build a Workflow That Summarizes Any Web Page

This example builds a four-node workflow: it takes a URL, fetches the page through Zenrows as Markdown, has an LLM summarize it, and returns the summary.

<Steps>
  <Step title="Create a workflow with a URL input">
    In **Studio**, click **Create from Blank**, choose **Workflow**, name it, and click **Create**. Pick **User Input** as the start node, then click **+** next to **Input Field** and add a **Short Text** field with the variable name `url`.
  </Step>

  <Step title="Add the Zenrows Fetch tool">
    Under **Next Step**, click **Select Next Step**, open the **Tools** tab, search for `zenrows`, and click **Fetch**.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-add-zenrows-tool.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=f61665077e5633b75c7dd39d6002fa0c" alt="The Dify node picker on the Tools tab, filtered to Zenrows, listing Fetch, Extract, Batch Create, Batch Status, and Batch Results" width="1512" height="795" data-path="images/integrations/dify/dify-add-zenrows-tool.png" />
    </Frame>

    In the Fetch node's **URL** field, type `/` and select the **User Input** `url` variable. Leave **Response format** on **Markdown** and the other settings at their defaults.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-fetch-node-settings.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=dee415794aa782264f01607808f972ff" alt="The Fetch node settings in Dify, with URL set to the User Input url variable and Response format set to Markdown" width="1512" height="795" data-path="images/integrations/dify/dify-fetch-node-settings.png" />
    </Frame>
  </Step>

  <Step title="Pass the page to an LLM node">
    From the Fetch node, add an **LLM** node. In its **System** prompt, write an instruction such as `Summarize the following web page in five bullet points. Use only what the page says.` On a new line, type `{` and select the Fetch node's **`text`** variable.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-llm-node-prompt.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=19c80adccfe9af78c631e98f87b9f0ce" alt="The LLM node's system prompt in Dify, with the Fetch text variable inserted after the instruction" width="1512" height="795" data-path="images/integrations/dify/dify-llm-node-prompt.png" />
    </Frame>

    <Warning>
      **Use `text`, not `content`.** The Fetch node's output list in Dify also shows `content`, `url`, and `status_code`, but in plugin version 0.1.0 those aren't populated as variables. Referencing `content` fails the run with `Variable ... content# not found`. The page content arrives in `text`, and the same fields are available inside the `json` output.
    </Warning>
  </Step>

  <Step title="Return the summary and run it">
    From the LLM node, add an **Output** node with one variable, `summary`, set to the LLM node's `text`. The finished workflow looks like this:

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-zenrows-workflow.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=e4ccfb7e973d79fc8bd6179f84a23133" alt="The finished Dify workflow: User Input, Fetch, LLM, and Output nodes connected left to right" width="1512" height="795" data-path="images/integrations/dify/dify-zenrows-workflow.png" />
    </Frame>

    Click **Test Run**, enter `https://www.scrapingcourse.com/ecommerce/` as the URL, and click **Start Run**. The **Result** tab shows the summary.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-test-run-result.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=e805bd54878f1283aa6de2c12de37e3e" alt="The Test Run Result tab in Dify, showing a bullet-point summary of the ScrapingCourse ecommerce page with product names and prices" width="1512" height="795" data-path="images/integrations/dify/dify-test-run-result.png" />
    </Frame>

    The **Tracing** tab shows each node's input and output. For Fetch, you can confirm the parameters sent to Zenrows and the Markdown that came back.

    <Frame>
      <img src="https://mintcdn.com/zenrows/nExGoTW4OqstnyeN/images/integrations/dify/dify-fetch-trace.png?fit=max&auto=format&n=nExGoTW4OqstnyeN&q=85&s=e16baa8f12e2b3d76b860359bd448f3b" alt="The Tracing tab in Dify with the Fetch node expanded, showing its input parameters and the Markdown text output" width="1512" height="795" data-path="images/integrations/dify/dify-fetch-trace.png" />
    </Frame>
  </Step>
</Steps>

## Handle Protected and JavaScript-Heavy Pages

Fetch and Extract have **Adaptive stealth** turned on by default. With it on, Zenrows starts with a basic request and escalates to JavaScript rendering or Premium Proxies only when the target needs them, so most protected pages work without changing any settings. See [Adaptive Stealth Mode](/fetch/features/adaptive-stealth-mode) for how escalation works and what it costs.

Leave the Fetch and Extract settings at their defaults unless you have a specific reason to change them. Adaptive stealth already decides when a page needs a browser or a residential IP.

## Work with Tool Outputs

Each tool returns its result in Dify's standard `text` and `json` outputs. Some also return named variables you can reference directly:

| Tool | Use downstream |
| - | - |
| **Fetch** | `text` holds the page content. `json` holds `content`, `url`, and `status_code`. A screenshot or PDF arrives in `files`. |
| **Extract** | `text` holds the extracted data as a JSON string, or a "No structured data found" message. `json` holds `data`, `method_used`, `fell_back_to_autoparse`, `empty`, and `url`. |
| **Batch Create** | `job_id`, `run_id`, `status`, `finished`, and `accepted_tasks` variables. |
| **Batch Status** | `job_id`, `status`, `finished`, `total`, `completed`, `successful`, `failed`, `failure_reasons`, and `spend` variables. |
| **Batch Results** | `results`, `returned`, and `truncated` variables. Each result has `url`, `status`, and, unless **Include page content** is off, `content`. |

For a batch, chain the tools: Batch Create, then Batch Status with the `job_id` until `finished` is `true`, then Batch Results. Leave **Wait for completion** off for more than a few dozen URLs. A tool call can't run longer than about 100 seconds, so a large job won't finish inside one call.

## Troubleshooting

### The Zenrows tools don't appear in the node picker

The plugin isn't installed in this workspace, or it has no authorization. Open **Integrations** > **Tools** > **Tool Plugin**, click **Zenrows**, and confirm the panel shows **1 Authorization**. If it shows **API Key Authorization Configuration** instead, add your key.

### Authorization fails when saving the key

Copy the key again from your <a href="https://app.zenrows.com/settings/api-keys" target="_blank" rel="nofollow noopener noreferrer">Zenrows dashboard</a> and check for leading or trailing spaces. On self-hosted Dify, confirm the instance can reach `api.zenrows.com` over HTTPS.

### `Variable ... not found` in the node after Fetch or Extract

The downstream node references `content`, `url`, `status_code`, or `data` from Fetch or Extract. Those aren't populated as variables in plugin version 0.1.0. Reference `text` instead, or read the field from the `json` output.

### "Turn off Adaptive stealth" error

The plugin rejects the request before it reaches Zenrows when Adaptive stealth is on together with **Render JavaScript**, **Premium proxy**, **Screenshot**, **PDF** as the response format, **Wait for selector**, **Wait (ms)**, or **JavaScript instructions**. Zenrows doesn't accept those combinations either.

* If you set **Render JavaScript** or **Premium proxy** to **True**, set it back to **False**. Adaptive stealth turns them on automatically when a page needs them.
* If you need a screenshot, a PDF, a wait condition, or JavaScript instructions, turn Adaptive stealth off for that node. Those options require a browser, so you also control rendering and proxies yourself.

### The page comes back empty or incomplete

Open the **Tracing** tab and check the Fetch node's output. If the text is a login wall or a cookie banner rather than the page you expected, the content isn't publicly available at that URL. If the target is consistently returning incomplete content, contact <a href="mailto:success@zenrows.com" rel="nofollow">Zenrows support</a> with the URL.

### Batch Create times out with Wait for completion on

Waiting gives up after about 100 seconds. Turn **Wait for completion** off and poll with Batch Status instead.

## Further Reading

* <a href="https://marketplace.dify.ai/plugin/zenrows/zenrows" target="_blank" rel="nofollow noopener noreferrer">Zenrows Plugin on the Dify Marketplace</a>
* <a href="https://github.com/ZenRows/dify-zenrows" target="_blank" rel="nofollow noopener noreferrer">Plugin Source Code on GitHub</a>
* <a href="https://docs.dify.ai/en/cloud/use-dify/nodes/tools" target="_blank" rel="nofollow noopener noreferrer">Dify Tool Node Documentation</a>
* [Fetch API Reference](/fetch/api-reference)
* [Batch Introduction](/batch/introduction)

## Frequently Asked Questions

<Accordion title="Is the Zenrows plugin for Dify official?">
  Yes. Zenrows publishes and maintains it, and its source is at `github.com/ZenRows/dify-zenrows`.
</Accordion>

<Accordion title="Does it work on self-hosted Dify?">
  Yes, on Dify 1.11.4 or later, as long as the instance can make outbound HTTPS requests to `api.zenrows.com` and `async.api.zenrows.com`.
</Accordion>

<Accordion title="Can I use the Zenrows tools in a Dify agent, not just a workflow?">
  Yes. The tools are available anywhere Dify offers tools, including agents. Each tool ships a model-facing description, so an agent can decide when to fetch a page, extract fields, or start a batch.
</Accordion>

<Accordion title="Does validating my API key cost credits?">
  No. Dify validates the key when you save the authorization, and that check doesn't consume Zenrows credits. Each tool call is billed like the equivalent Zenrows API request.
</Accordion>

<Accordion title="How is this different from calling the Zenrows API with an HTTP Request node?">
  The plugin handles authentication, parameter validation, and error messages for you, and exposes each option as a field in the node. An HTTP Request node works too, but you build the query string, handle errors, and parse the response yourself.
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.