Categories:Scraping Use Cases,Scraping Tools

How to Build a Bulk Web Scraper in Power Automate with Scrape.do (No Code)

Clock8 Mins Read
calendarCreated Date: June 29, 2026
calendarUpdated Date: June 29, 2026

Power Automate is great at moving data between the apps you already use. But the moment you point it at the open web — a competitor's pricing page, a directory of listings, a search results page — it falls apart. The built-in HTTP action fetches raw HTML with no browser, no proxy rotation, and no defense against the anti-bot walls protecting almost every page worth scraping. You get blocked, rate-limited, or served a CAPTCHA, and your flow fails silently.

This guide shows a cleaner path. You'll wrap Scrape.do as a native Power Automate custom connector, then build a cloud flow that reads a list of URLs from a Google Sheet, scrapes each page through that connector, and writes the fully rendered HTML back next to each URL. Proxy rotation, anti-bot bypass, CAPTCHA handling, and JavaScript rendering all happen on Scrape.do's side. Your flow just sends a URL and gets clean HTML back — no scraper code required.

Two ready-to-import files are attached at the bottom of this post: the custom connector and its Swagger definition. You can install them as-is and be scraping in a few minutes.

What You'll Build

A two-part, plug-and-play setup:

  1. The Scrape.do custom connector — a reusable connector that exposes the Scrape.do API as a native Power Automate action called "Scrape a URL." You plug in your API token once.
  2. A cloud flow — reads a Google Sheet of URLs, calls that action for each row, and writes the scraped HTML back next to it.

The end result: drop a list of URLs into a spreadsheet, run the flow, and the scraped HTML fills in row by row.

Why Scrape.do Does the Hard Part

Power Automate's HTTP action talks to a URL and hopes for the best. Scrape.do sits in between and does the work that actually makes scraping succeed. You send it a target URL and it returns the page's raw HTML or fully rendered content. Behind that single request it handles:

  • Proxy rotation across residential and mobile IPs, so you don't get blocked for hammering a site from one address.
  • Anti-bot and CAPTCHA bypass, handled before the page ever reaches your flow.
  • Full JavaScript rendering through a real headless browser, so pages that build themselves client-side return complete HTML instead of an empty shell.

Two practical details matter for this integration. You're only charged for successful (2xx) requests — failed calls from timeouts, blocks, or rotation failures cost nothing, which is forgiving while you're testing. And the free tier includes 1,000 requests per month, more than enough to build, test, and run this whole tutorial before you commit to anything.

If you don't have a token yet, sign up for free here and follow along. It's the same web scraping API you'd reach for in a Python scraping project, just exposed to Power Automate instead of code.

Step 1 — Create the Custom Connector

The connector is the bridge between Power Automate and the Scrape.do API. If you'd rather not build it by hand, import the attached connector package and skip to Step 2 — the walkthrough below is what that package contains.

In Power Automate, go to Custom connectors and choose New custom connector → Create from blank. Name it Scrapedo.

On the General tab:

  • Host: api.scrape.do
  • Base URL: /
  • Scheme: HTTPS

On the Security tab, choose API Key, then set:

  • Parameter label: API Token
  • Parameter name: token
  • Parameter location: Query

This is the detail that trips people up: Scrape.do authenticates with a ?token= query parameter, not an authorization header. Send it as a header and you'll get an access-denied response every time.

On the Definition tab, add a New action with:

  • Summary: Scrape a URL
  • Operation ID: ScrapeUrl

Under Request, click Import from sample, choose GET, and paste this URL:

https://api.scrape.do/?url=https%3A%2F%2Fexample.com&render=true&returnJSON=true

Power Automate reads three query parameters out of that sample — url, render, and returnJSON. Open the url parameter and mark it Required. Leave the other two optional.

Skip the Code step (it's optional), then click Create connector.

Step 2 — Test the Connector

On the Test tab, create a new connection and paste your Scrape.do API token, which you can grab from your Scrape.do dashboard. Then run the action with:

  • url: https://example.com
  • render: true
  • returnJSON: true

A status 200 with a body like {"statusCode": 200, "content": "<!DOCTYPE html>..."} means the connector works. The content field holds the page's full HTML. Keep an eye on that field — how you pull it out in the flow is where most setups go wrong, which is what Step 5 is about.

Step 3 — Prepare Your Spreadsheet

The flow uses a spreadsheet as its input and output surface. Create a Google Sheet with two columns:

url result
https://example.com
https://example.org
https://quotes.toscrape.com

Column A holds your target URLs, one per row. Column B (result) stays empty — the flow fills it. Clear column B before every run so old HTML doesn't get read back in and confuse the next pass.

Step 4 — Build the Flow

Create a new Instant cloud flow with a Manually trigger a flow trigger. Name it Scrape Do Bulk Scraper. Then add these actions in order:

  1. Get rows (Google Sheets) — point it at your file and worksheet. This reads every URL.
  2. Apply to each — set its input to the value output of Get rows. This loops over every row.

Inside the loop:

  1. Scrape a URL (your Scrapedo connector) — set Url to the url column from Get rows. Set render to true for JavaScript-heavy pages.
  2. Update row (Google Sheets) — set File and Worksheet to the same sheet, Row id to __PowerAppsId__, and the result column to the scraped HTML using the expression in the next step.

Save the flow.

Step 5 — Map the Scraped HTML Correctly

This is the single most important step, and the one that fails most often. The Scrape.do action returns its body as a string, not a parsed object, so you can't just point at a content field — Power Automate doesn't see one.

In the Update row action, open the result field, switch to the expression (fx) editor, and enter exactly:

json(body('Scrape_a_URL'))?['content']

The json() wrapper parses the string body into an object first, then ?['content'] pulls out the HTML. Without json(), you'll get the error "property 'content' cannot be selected... property selection is not supported on values of type 'String'."

Save, then run the flow. Each row's result cell fills with the scraped HTML.

How the Flow Actually Works

If you want to understand or modify it, here's the logic end to end. Get rows pulls your URL list into memory. Apply to each walks the list one row at a time. For each row, the Scrapedo connector sends https://api.scrape.do/?token=...&url=...&render=true&returnJSON=true as a GET request. Scrape.do routes that through its proxy network, renders the page in a headless browser, bypasses any anti-bot checks, and returns the HTML wrapped in JSON. Update row then parses that JSON and writes the content field back to the sheet, matched to the correct row by its __PowerAppsId__.

Things Worth Knowing Before You Ship

A few realities to plan around:

  • Custom connectors are a premium feature in Power Automate. Any flow that uses one requires a Power Automate Premium license. If you don't have one, start the free 90-day Premium trial from the Power Automate portal — no admin needed — which covers premium and custom connectors for the duration.
  • The response is a string, not an object. This is why Step 5 exists, and it's the number one reason these flows fail. Always wrap the body in json() before selecting content.
  • Google Sheets rate-limits aggressively. Run the flow on a large list back-to-back and the Sheets API returns 429 Too Many Requests, which can break the action's column schema mid-edit. If your result and url columns vanish from the editor, that's the cause. Wait a few minutes, re-select the worksheet to refresh the schema, and space out your runs.
  • Spreadsheet cells cap at 50,000 characters. A large rendered page overflows a single cell and the write fails. For demos and moderate pages this is a non-issue. At scale, extract just the fields you need instead of dumping full HTML, or write to a roomier destination than a spreadsheet cell.
  • Rendering costs more credits. render=true spins up a headless browser per row and costs more than a plain fetch. Turn it off for static pages that don't need JavaScript and the requests get cheaper and faster.
  • Install order matters. When you share these files, import the connector first, then the flow. The flow references the connector by key, so importing it into an environment that doesn't have the connector yet will fail to resolve the action.

Run It on Your Own Data

Replace the sample URLs in column A with your own list, make sure your Scrape.do token is in the connection, and run the flow. Column B fills in one row at a time with the real page content for each URL — the same pattern you'd wire up in a hand-rolled Python web scraper, minus the scraper code and the proxy babysitting.

Downloads:

With the connector in place, web scraping inside Power Automate stops being a proxy-management project and becomes a single action you can drop into any flow. You hand Scrape.do a URL, it deals with the hostile parts of the open web, and you get clean content back into your process. The free tier gives you 1,000 requests a month with no credit card, and you're only ever charged for the requests that actually succeed.

Start scraping with Scrape.do — free tier, 1,000 requests/month →