CSS Selector Extractor for JavaScript Sites (Browser)
Pricing
from $1.80 / 1,000 pages
CSS Selector Extractor for JavaScript Sites (Browser)
Extract any CSS selector from pages that need JavaScript: a real Chromium browser renders each page, waits for content, scrolls or clicks "load more", then returns text, HTML, attributes, tables or counts. One row per page, pay per page. For static pages use the cheaper CSS Selector Extractor.
Pricing
from $1.80 / 1,000 pages
Rating
0.0
(0)
Developer
Murat Uzun
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Extract any CSS selector from pages that need JavaScript. A real Chromium browser (Crawlee PlaywrightCrawler) opens each page, waits for the content, can click "load more" and scroll infinite lists, then runs your selectors on the rendered HTML. You get text, HTML, attributes, tables or counts, one dataset row per page. No login.
Pay per use: $0.005 per run start (browser launch, default 1 GB memory) plus $0.003 per page on the free plan, lower on higher Apify plans. Failed pages produce a row with error
set and the other fields null.
When to use this Actor, and when not to
| Use this one (browser) when | Use the sibling CSS Selector Extractor (HTTP only) when |
|---|---|
| The data appears only after JavaScript runs (SPA, React/Vue pages, client-side lists) | The HTML already contains the data (view-source shows it) |
| You need "wait for element", "click load more" or infinite scroll | You only need the page as served |
| The page is empty or shows "Enable JavaScript" to a plain fetch | Speed and cost matter most |
The browser is slower and uses more memory (1024 MB default), so the sibling is cheaper and faster on static sites. (Run durations were not recorded for these cloud tests, so no speed figure is quoted here.) Use the same JSON input in both: the field names and the output rows are the same.
Quick start
Default input loads https://quotes.toscrape.com/js/ and returns the quote text and author of each quote as items:
{"urls": ["https://quotes.toscrape.com/js/"],"itemSelector": ".quote","selectors": [{ "name": "text", "selector": ".text", "type": "text" },{ "name": "author", "selector": ".author", "type": "text" }]}
Examples
Follow pagination (3 pages): add linkSelector and maxPages. Each followed page is one result and billed as one page.
{"urls": ["https://quotes.toscrape.com/js/"],"itemSelector": ".quote","selectors": [{ "name": "text", "selector": ".text", "type": "text" }],"linkSelector": "li.next a","maxPages": 3}
Infinite scroll: scrollToBottom scrolls until the page stops growing, up to maxScrolls.
{"urls": ["https://quotes.toscrape.com/scroll"],"itemSelector": ".quote","selectors": [{ "name": "text", "selector": ".text", "type": "text" }],"scrollToBottom": true,"maxScrolls": 5}
"Load more" button: clickSelector clicks the element again and again until it is gone or hidden, up to maxClicks.
{"urls": ["https://example.com/listing"],"selectors": [{ "name": "items", "selector": ".product", "type": "count" }],"clickSelector": "button.load-more","maxClicks": 10}
Wait for content: waitForSelector waits up to waitTimeoutSecs for the element before reading the page. If it never
appears, the page is still read and the row's renderNotes says so.
Browser options
| Field | Default | What it does |
|---|---|---|
waitForSelector | none | Element that must appear before the page is read |
waitTimeoutSecs | 15 | How long to wait for it (1 to 60) |
waitUntil | load | domcontentloaded (fastest), load, or networkidle (slowest) |
scrollToBottom | false | Scroll repeatedly for infinite lists |
maxScrolls | 10 | Scroll steps per page (1 to 100) |
clickSelector | none | Button or link to click for "load more" |
maxClicks | 5 | Clicks per page (1 to 50) |
blockResources | true | Blocks images, fonts and media while rendering (cheaper, faster) |
Order of steps on each page: wait for waitForSelector, then clickSelector clicks, then scrollToBottom, then the
selectors run on the final HTML.
The shared options
urls, selectors (up to 25; text, html, attr, count, table), firstMatchOnly, maxMatchesPerSelector,
trimWhitespace, itemSelector and maxItemsPerPage, linkSelector, sameDomainOnly, urlPattern, urlTemplate with
pageRange, sitemapUrls, maxPages, includeMetadata, headers, cookies, proxyMode, proxyConfiguration,
inputDatasetId and inputField. They work the same as in the sibling Actor.
Differences from the sibling:
maxConcurrencydefaults to 3 and is capped at 10 (each page is a browser tab).proxyMode:alwaysroutes every page through Apify Proxy.autoandneverload pages directly. A blocked page (HTTP 403, 429, 503 or a short challenge page) is reported as an error row. This Actor does not switch to the proxy on its own for a blocked page; setproxyModetoalwaysfor those sites.
Output
One row per page:
{"url": "https://quotes.toscrape.com/js/","finalUrl": "https://quotes.toscrape.com/js/","statusCode": 200,"contentType": "text/html; charset=utf-8","fields": null,"matchCounts": null,"htmlSizeBytes": 8985,"usedProxy": false,"scrapedAt": "2026-10-11T17:02:57.954Z","error": null,"items": [{ "text": "...", "author": "Albert Einstein" }],"itemCount": 10}
fields and matchCounts appear in page mode (no itemSelector); items and itemCount in item mode. renderNotes
appears only when a browser step did not finish as asked. foundOn appears on pages reached by following links.
A row over 9 MB is replaced by an error row with the fields left out.
Using the API, Python and n8n
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('webdatatools/css-selector-extractor-js').call({ urls: ['https://quotes.toscrape.com/js/'], itemSelector: '.quote', selectors: [{ name: 'text', selector: '.text', type: 'text' }] });const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(token)run = client.actor("webdatatools/css-selector-extractor-js").call(run_input={"urls": ["https://quotes.toscrape.com/js/"], "itemSelector": ".quote", "selectors": [{"name": "text", "selector": ".text", "type": "text"}]})items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
In n8n, use the Apify node with this Actor's ID and the same JSON input.
Cost
Each run pays $0.005 once at start (one event per GB of memory; the default 1 GB is one event), then $0.003 per page on the free plan; higher plans pay less per page. 100 pages on the free plan: $0.005 + $0.30. Failed pages are still rows in the dataset and are billed like any other row. Set Maximum cost per run to cap spending. The Actor stops at what the budget covers and says so in the status message.
Feedback
Found a bug or a page that does not render? Leave a review at https://apify.com/webdatatools/css-selector-extractor-js/reviews and include the input (without any cookies or headers) and the URL that failed.