# StockAnalysis.com Stock & ETF Screener (`scrapyx/stockanalysis-screener-scraper`) Actor

Full US stock and ETF market screener from stockanalysis.com: ticker, name, market cap/AUM, price, day change %, industry/asset class, volume, PE ratio/holdings for the entire tracked universe in one run, with optional ticker or top-N filtering.

- **URL**: https://apify.com/scrapyx/stockanalysis-screener-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.84 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## StockAnalysis.com Stock & ETF Screener

The entire US stock and/or ETF market from [stockanalysis.com](https://stockanalysis.com)'s
own screener pages, in one or two HTTP requests — no pagination, no
per-symbol lookups, no authentication.

***

### What you get

**`market: "stocks"`** — one `SCREENER_SUMMARY` + one `STOCK` row per
ticker: symbol, name, market cap, price, day change %, industry, volume,
PE ratio. 5,610 tickers as of 2026-08-16.

**`market: "etfs"`** — one `SCREENER_SUMMARY` + one `ETF` row per fund:
symbol, name, asset class, AUM, price, day change %, volume, holdings
count. 5,582 funds as of 2026-08-16.

**`market: "both"`** (default) — both of the above in one run.

Rows are pre-sorted by upstream in market-cap / AUM descending order.

***

### Input

```jsonc
{
  "market": "both",
  "symbols": [],
  "limit": null
}
```

- **`market`** — `"both"` (default), `"stocks"`, or `"etfs"`.
- **`symbols`** — optional ticker whitelist (e.g. `["AAPL", "VOO"]`),
  case-insensitive. Applied after the fetch — upstream doesn't support
  server-side filtering (verified: query strings don't change the
  response), so this controls rows *returned*, not requests made. A
  symbol not found in the fetched universe gets its own `ERROR` row.
- **`limit`** — optional cap on rows returned per market, applied after
  any `symbols` filter. Since upstream is pre-sorted by size, this is an
  honest "top N by market cap / AUM", not an arbitrary truncation.

Leave `symbols` empty and `limit` unset to get the full market (the
default).

***

### Known limits

**1. Column set is fixed.** The site's marketing mentions "313 different
metrics," but those are only reachable through the site's own client-side
JS after the page loads — every query-string combination tested during
recon returned an identical server-rendered payload. This actor exposes
the 8 fields per market that the server-rendered page actually carries;
it does not (and cannot, HTTP-only) request a custom column set.

**2. No per-symbol detail pages (financials, dividends, history) yet.**
This version is the bulk screener only. See `CRAWLING_METHOD.md` §7 for
why, and what a follow-up would look like.

**3. `change` is upstream's raw percentage number** (e.g. `-0.06` means
`-0.06%`, not `-6%`), passed through as-is.

***

### Errors are honest, no disguised-200 traps

A bad `symbols` entry doesn't get silently dropped — it produces an
`ERROR` row naming the missing ticker and the size of the universe that
was actually searched. `SCREENER_SUMMARY` rows carry `honestCountMatch`:
upstream's own claimed total compared against what this actor actually
extracted, checked fresh on every run (not just at build time), so a
future silent truncation on stockanalysis.com's side would show up as
`false` here rather than quietly under-counting.

### Anti-bot posture

**None encountered.** 3/3 `curl_cffi` TLS profiles (chrome124/safari17\_0/
firefox133) clean 200 on both screener paths, byte-identical response
sizes across profiles — no Cloudflare/Akamai/DataDome/PerimeterX marker
in the response body.

### Policy

`https://stockanalysis.com/robots.txt` has a single `User-agent: *` group
— no ClaudeBot/anthropic-ai/CCBot/GPTBot-specific group at all. Only
`/e/` (analytics beacon, unused here) and `/p/` are disallowed, plus three
unrelated named scraper bots blocked outright.

# Actor input Schema

## `market` (type: `string`):

Which screener(s) to fetch. Each market is ONE HTTP request that returns its entire tracked universe (no pagination): 5,610 tickers for stocks, 5,582 funds for ETFs, measured 2026-08-16. 'both' issues both requests.

## `symbols` (type: `array`):

Optional. Keep only these tickers (e.g. 'AAPL', 'VOO'), case-insensitive. Applied AFTER the fetch -- upstream does not support server-side filtering (verified: query strings do not change the response), so this does not reduce request count, only rows returned. A symbol not found in the fetched universe gets its own ERROR row. Leave empty to return the full market.

## `limit` (type: `integer`):

Optional. Cap the number of rows returned per market, applied after any 'symbols' filter. Upstream returns tickers pre-sorted by market cap / AUM descending, so this is an honest 'top N by size', not a random truncation. Leave empty for the full market.

## `maxConcurrency` (type: `integer`):

How many requests may be in flight at once. A run fetches at most 2 requests total (one per market), so this mainly matters if it is reused as a library call pattern.

## `minRequestInterval` (type: `number`):

The actual speed control: the shortest gap between two requests. No rate-limiting or WAF was observed during testing, so this is modest routine pacing rather than a defensive measure.

## `proxyConfiguration` (type: `object`):

Residential with no country pin is the cloud default. No WAF or geography-based gating was observed during testing (3/3 TLS profiles clean, byte-identical responses).

## Actor input object example

```json
{
  "market": "both",
  "symbols": [],
  "maxConcurrency": 3,
  "minRequestInterval": 0.5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/stockanalysis-screener-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/stockanalysis-screener-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call scrapyx/stockanalysis-screener-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/stockanalysis-screener-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/24ytjGFXpfFIw9lcH/builds/epl3sWOC079211KLC/openapi.json
