Add live web data to Activepieces flows — Google SERPs, local business results, Amazon products — using the Scrapeless Scraper API.
Works today with the built-in HTTP piece; scrapeless-openapi.yaml is included as a validated schema if you'd rather generate a custom piece.
Activepieces orchestrates apps and can't fetch a protected page. This supplies the data step for:
- Rank tracking — a scheduled SERP snapshot into Sheets, Airtable, or Postgres.
- Local lead generation — businesses by category and city, into your CRM.
- Price monitoring — an Amazon check on a cron with a Slack alert.
- Enrichment — a webhook triggers a lookup and writes the result back.
- Activepieces — cloud or self-hosted
- A Scrapeless API key — create a free account
Add HTTP → Send HTTP request:
| Field | Value |
|---|---|
| Method | POST |
| URL | https://api.scrapeless.com/api/v1/scraper/request |
| Headers | x-api-token → your key |
| Body type | JSON |
| Body | see below |
| Failure Mode | retry_all — see the quirks section |
{ "actor": "scraper.google.search", "input": { "q": "web scraping api" } }Then add Loop on Items over {{step_1.body.organic_results}} (or {{step_1.body.local_results.places}}) so each result is handled individually.
Keep the key in a connection or a project variable rather than pasting it into the header field of every flow — flows get exported and shared.
| Goal | Body |
|---|---|
| Google SERP | {"actor":"scraper.google.search","input":{"q":"web scraping api"}} |
| Local businesses | {"actor":"scraper.google.search","input":{"q":"plumbers in Austin, TX","tbm":"lcl"}} |
| Next page of local results | add "start": 20 — 20 per page, num is ignored |
| Amazon product | {"actor":"scraper.amazon","input":{"action":"product","url":"https://www.amazon.com/dp/B09B8V1LZ3"}} |
| Amazon search | {"actor":"scraper.amazon","input":{"action":"keywords","keywords":"smart speaker"}} |
scraper.google.shopping is retired (15002); tbm: "shop" returns no shopping results.
scraper.google.searchreturns results at the top level —body.organic_results[], orbody.local_results.places[]withtbm: lcl.scraper.amazonnests the product underbody.result.
All observed live:
- Sporadic
400s that succeed on retry. The HTTP piece has its own Failure Mode dropdown — set it toretry_all. Do not pickretry_5xx: Scrapeless's transient failures come back as400, so a 5xx-only policy skips exactly the case you need. The default iscontinue_none, which lets one transient 400 kill the run. - Padded strings — local-pack
phone,type, andhourshave a leading space. Trim in a Code piece. - Empty local fields —
place_id,gps_coordinates,thumbnailare empty for local results. - Prices are display strings —
"$49.99". Parse before comparing in a Branch condition.
A Code piece is the cleanest place to normalize before storage:
export const code = async (inputs) => {
const clean = (v) => (typeof v === 'string' ? v.trim() : v);
const places = inputs.response?.local_results?.places ?? [];
return places.map((p) => ({
name: clean(p.title),
category: clean(p.type),
rating: p.rating ?? null,
reviews: p.reviews ?? 0,
phone: clean(p.phone),
address_snippet: clean(p.address),
}));
};| Symptom | Cause and fix |
|---|---|
401 |
Header must be x-api-token, not Authorization. |
| Reference resolves to nothing | Remember body — it is {{step_1.body.organic_results}}, not {{step_1.organic_results}}. |
| Only one row stored | Add Loop on Items over the results array. |
400 that passes on re-run |
Known API behavior — set the HTTP step's Failure Mode to retry_all (not retry_5xx). |
Empty local_results |
Query lacks local intent. "plumbers in Austin, TX" works; "plumbing" often does not. |
| Branch on price never fires | Comparing "$49.99" as text. Parse to a number in a Code piece first. |
A flow built from this README was published and run on a self-hosted Activepieces 0.82.0 CE (2026-08-12), with piece-http 0.11.18. The run reached SUCCEEDED:
| Claim | Result |
|---|---|
HTTP piece config above (POST + x-api-token + JSON body) |
HTTP 200, local_results.places = 20 |
{{step_1.body...}} is the right reference shape |
{{step_1.body}} resolved to the full SERP inside the next step |
| Local-pack strings arrive padded | Confirmed in the run: phone came through as " (512) 690-4935", type as " Plumber" |
| The Code piece below, verbatim | Returned 20 normalized rows, phone trimmed to "(512) 690-4935" |
- The API calls are verified live — every actor and body here was executed against the real Scrapeless API on 2026-08-11; the quirks come from those runs.
- The schema is validated —
scrapeless-openapi.yamlpassesopenapi-spec-validatoras OpenAPI 3.0.3. - No flow JSON is shipped, on purpose. Flow exports carry a
pieceVersionand are tied to the instance that produced them, so a stale export fails to import for a reader on a different version — worse than following six setup fields. The setup above is what was actually executed.
scrapeless-activepieces/
├── scrapeless-openapi.yaml # validated OpenAPI 3.0.3, for the custom-piece route
└── LICENSE
- Product: Scraping API · Deep SERP API
- Integration page: Scrapeless with Activepieces
MIT — see LICENSE.