CSS Selector Extractor for JavaScript Sites (Browser) avatar

CSS Selector Extractor for JavaScript Sites (Browser)

Pricing

from $1.80 / 1,000 pages

Go to Apify Store
CSS Selector Extractor for JavaScript Sites (Browser)

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

Murat Uzun

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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) whenUse 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 scrollYou only need the page as served
The page is empty or shows "Enable JavaScript" to a plain fetchSpeed 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

FieldDefaultWhat it does
waitForSelectornoneElement that must appear before the page is read
waitTimeoutSecs15How long to wait for it (1 to 60)
waitUntilloaddomcontentloaded (fastest), load, or networkidle (slowest)
scrollToBottomfalseScroll repeatedly for infinite lists
maxScrolls10Scroll steps per page (1 to 100)
clickSelectornoneButton or link to click for "load more"
maxClicks5Clicks per page (1 to 50)
blockResourcestrueBlocks 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:

  • maxConcurrency defaults to 3 and is capped at 10 (each page is a browser tab).
  • proxyMode: always routes every page through Apify Proxy. auto and never load 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; set proxyMode to always for 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 ApifyClient
client = 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.