# Screener.in Indian Stock Fundamentals Scraper (`scrapyx/screener-in-stocks-scraper`) Actor

Indian stock fundamentals from Screener.in by NSE/BSE ticker: valuation ratios, up to 13 years of quarterly results, profit & loss, balance sheet, cash flow, ratio trends, shareholding pattern and recent announcements.

- **URL**: https://apify.com/scrapyx/screener-in-stocks-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Business, Automation, Developer tools
- **Stats:** 2 total users, 0 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

## Screener.in Indian Stock Fundamentals Scraper

Scrapes Indian stock fundamentals from [Screener.in](https://www.screener.in),
the most widely used free fundamental-analysis tool for the Indian market:
valuation ratios, up to 13 years of quarterly results, profit & loss,
balance sheet, cash flow, ratio trends, shareholding pattern and recent
stock-exchange announcements — by NSE or BSE ticker.

***

### What you get

One `STOCK` row per ticker.

`companyName` · `bseCode` · `nseCode` · `website` · `broadSector` ·
`sector` · `broadIndustry` · `industry` · `about` (company description) ·
`ratios` (Market Cap, Current Price, High/Low, Stock P/E, Book Value,
Dividend Yield, ROCE, ROE, Face Value) · `quarterlyResults` ·
`profitAndLoss` · `balanceSheet` · `cashFlow` · `ratiosOverTime`
(Debtor Days, Inventory Days, ROCE %, and more, per period) ·
`shareholdingPattern` (Promoters/FIIs/DIIs/Public/Government % per quarter)
· `recentAnnouncements` (title, PDF/link URL, date — up to 20)

Each of the six financial tables (`quarterlyResults`, `profitAndLoss`,
`balanceSheet`, `cashFlow`, `ratiosOverTime`, `shareholdingPattern`) has
the same shape: `{"periods": [...], "rows": {"<line item>": [<value per
period>, ...]}}`.

***

### Input

```jsonc
{
  "tickers": ["RELIANCE", "TCS", "INFY"],
  "consolidated": true,
  "includeAnnouncements": true
}
```

#### There is no name search — a ticker IS the URL

`screener.in/company/{TICKER}/` resolves directly, no search or
disambiguation step. This is not a shortcut this actor takes: screener.in's
own top-search-box query string (`?q=`) is `robots.txt`-disallowed, so
there is no policy-compliant way to search by company name at all. An
unrecognised ticker answers a genuine HTTP 404 (a small, distinct error
page) — never a silently-wrong company.

#### `consolidated` changes which figures you get, not just formatting

Consolidated (includes subsidiaries) and standalone (parent company only)
are genuinely different pages with genuinely different numbers — verified
on Reliance Industries: consolidated FY2015 sales ₹374,372 Cr. vs
standalone ₹328,013 Cr., same year, same company. `consolidated: true`
(default) is the more complete figure for a typical conglomerate; set to
`false` for the parent entity alone.

***

### Read this before parsing the numbers

**Figures are in Rs. Crores (1 crore = 10 million), Indian digit
grouping** — e.g. `"17,72,762"` for a market cap, not `"1,772,762"`. Both
conventions collapse to the same integer once commas are stripped, but
this actor does **not** attempt that conversion: every table cell is kept
as the exact string screener.in renders (percentages keep their trailing
`%`, blank cells are `"-"`, negative figures keep a leading `-`). Convert
on your end rather than trust a silently-reformatted number — a value
that looked like it meant one thing while actually meaning another is
exactly the kind of trap this portfolio's actors are built to avoid, not
reproduce.

***

### Known limits

**1. Peer comparison is not included.** The `#peers` section is present in
the page but carries zero rows server-side — the comparison table loads
via a separate client-side call this actor does not reverse-engineer for
v1 (a real feature, deferred rather than half-built).

**2. Only the "Recent" announcements tab, not "Important" or full search.**
The default tab is server-rendered in the same page fetch (no extra
request), but the other two tabs are separate AJAX calls not fetched here.

**3. Expandable schedule breakdowns are not fetched.** Some row labels on
screener.in (e.g. "Sales" broken down by business segment) are expandable
via a per-row AJAX call — an unbounded multiplier this actor does not
chase; the top-level line item is what's returned.

**4. Not every ticker was verified to have both a standalone and a
consolidated version that meaningfully differ** — a company with no
subsidiaries would be expected to converge on the two, but this was
checked only on a handful of large-cap tickers, not exhaustively.

***

### Anti-bot posture

**None observed.** 8/8 TLS profiles clean, no interstitial. The actor
still ships a rotating profile pool, a retry ladder and challenge-marker
detection, and paces requests by default — a target being clean in local
recon has not always meant the same from Apify's cloud egress elsewhere in
this portfolio.

### Policy

`robots.txt` (`User-agent: *`) names no `ClaudeBot`/`anthropic-ai`/`GPTBot`
group. It disallows the site's own search query string (`?q=`), `?sort=`,
`?limit=`, `?page=`, `/user/*`, and `/company/source/quarter/*` — this
actor never uses the search parameter (there is no policy-compliant way
to, see above) and never touches the other disallowed paths.

# Actor input Schema

## `tickers` (type: `array`):

NSE or BSE ticker symbols, e.g. 'RELIANCE', 'TCS', 'INFY', 'HDFCBANK'. A ticker IS the URL on this site (screener.in/company/{TICKER}/) — there's no name-based search to fall back on (the site's own search box is robots.txt-disallowed), so an unrecognised symbol is refused with a 404 rather than resolved to the wrong company.

## `consolidated` (type: `boolean`):

Consolidated (includes subsidiaries) vs standalone (parent company only) financials — these are genuinely different pages on screener.in, not a cosmetic toggle. Consolidated is the more complete figure for a typical conglomerate and is the default.

## `includeAnnouncements` (type: `boolean`):

Include the company's most recent stock-exchange announcements (title, PDF/link URL, date) — up to 20, from the same page fetch at no extra request cost.

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

How many requests may be in flight at once. This absorbs latency variance; it is NOT the throttle — the crawl rate is set by 'Minimum interval between requests' below.

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

The actual speed control: the shortest gap between two requests, across all workers. No bot mitigation was observed during recon (8/8 TLS profiles clean).

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

Residential with no country pin is the cloud default. No WAF was observed anywhere during recon, so there's no known reason to narrow the exit-IP pool.

## Actor input object example

```json
{
  "tickers": [
    "RELIANCE",
    "TCS",
    "INFY"
  ],
  "consolidated": true,
  "includeAnnouncements": true,
  "maxConcurrency": 6,
  "minRequestInterval": 0.3,
  "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 = {
    "tickers": [
        "RELIANCE",
        "TCS",
        "INFY"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/screener-in-stocks-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 = { "tickers": [
        "RELIANCE",
        "TCS",
        "INFY",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/screener-in-stocks-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 '{
  "tickers": [
    "RELIANCE",
    "TCS",
    "INFY"
  ]
}' |
apify call scrapyx/screener-in-stocks-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/screener-in-stocks-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/HvdA79dgKa3SjSAOa/builds/hecZNvKC84limYk86/openapi.json
